ホームページ  >  記事  >  Java  >  @dynamicの使い方を紹介します

@dynamicの使い方を紹介します

高洛峰
高洛峰オリジナル
2016-12-13 09:18:512661ブラウズ

@dynamic の使用法を紹介します

Objective-C 2.0 は、コンパイラーが setter メソッドと getter メソッドを自動的に生成できるようにするプロパティ (@property) を提供します。コンパイラがこれらのセッター メソッドとゲッター メソッドを独自に生成したくない場合は、@dynamic を使用します。簡単な例を挙げると、次のようになります。

#import <Foundation/Foundation.h>  
  
@interface Person : NSObject  
@property (copy) NSString *name;  
@end  
  
@implementation Person  
// @dynamic tells compiler don&#39;t generate setter and getter automatically  
@dynamic name;  
@end  
  
int main(int argc, const charchar * argv[])  
{  
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];  
      
    Person *a = [[Person alloc] init];  
      
    a.name = @"Hello"; // will crash here  
    NSLog(@"%@", a.name);  
      
    [a release];  
    [pool drain];  
      
    return 0;  
} // main

プログラムを実行すると、Xcode はエラー「-[PersonsetName:]: unrecognized selector send to instance 0x1001149d0」を報告します。 @dynamic がコメントアウトされている場合は、すべて問題ありません。

ここでは @dynamic を使用しているため、setter メソッドと getter メソッドを自分で提供する必要があります。一般に 2 つの方法があります: 1) セッター メソッドとゲッター メソッドを自分で提供し、コンパイラーによって自動的に生成されたセッター メソッドとゲッター メソッドを手動で書き換える; 2) 動的メソッド解決 (DynamicMethod Resolution)、実行時にセッターとゲッターの対応する実装を提供します。関数。

最初のメソッドでは、@dynamic は @synthesize のように実装ファイル (.m) にインスタンス変数を提供できないため、インスタンス変数をクラス内で明示的に提供する必要があります。

#import <Foundation/Foundation.h>  
  
@interface Person : NSObject  
{  
    // must provide a ivar for our setter and getter  
    NSString *_name;  
}  
@property (copy) NSString *name;  
@end  
  
@implementation Person  
// @dynamic tells compiler don&#39;t generate setter and getter automatically  
@dynamic name;  
  
// We provide setter and getter here  
- (void) setName:(NSString *)name  
{  
    if (_name != name) {  
        [_name release];  
        _name = [name copy];  
    }  
}  
  
- (NSString *) name  
{  
    return _name;  
}  
@end // Person  
  
int main(int argc, const charchar * argv[])  
{  
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];  
      
    Person *a = [[Person alloc] init];  
      
    a.name = @"Hello"; // Ok, use our setter  
    a.name = @"Hello, world";  
    NSLog(@"%@", a.name); // Ok, use our getter  
      
    [a release];  
    [pool drain];  
      
    return 0;  
} // main

2 番目のメソッドでは、NSObject によって提供されるsolveInstanceMethod: メソッドを使用して、実行時にセッターとゲッターの実装に対応する C 関数を決定します。インスタンス変数を C 関数で直接使用することはできません。ObjC オブジェクト自身を C の構造体に変換する必要があります。そのため、インスタンス変数も Person クラスで明示的に宣言し、アクセス レベルを @public にする必要があります。インスタンス変数を非表示にし、拡張子

#import <Foundation/Foundation.h>  
#import <objc/objc-runtime.h> // for class_addMethod()  
  
// ------------------------------------------------------  
// A .h file  
@interface Person : NSObject  
@property (copy) NSString *name;  
- (void) hello;  
@end  
  
// ------------------------------------------------------  
// A .m file  
// Use extension to override the access level of _name ivar  
@interface Person ()  
{  
@public  
    NSString *_name;  
}  
@end  
  
@implementation Person  
// @dynamic implies compiler to look for setName: and name method in runtime  
@dynamic name;  
  
// Only resolve unrecognized methods, and only load methods dynamically once  
+ (BOOL) resolveInstanceMethod:(SEL)sel  
{  
    // Capture setName: and name method  
    if (sel == @selector(setName:)) {  
        class_addMethod([self class], sel, (IMP)setName, "v@:@");  
        return YES;  
    }  
    else if (sel == @selector(name)) {  
        class_addMethod([self class], sel, (IMP)getName, "@@:");  
        return YES;  
    }  
      
    return [super resolveInstanceMethod:sel];  
}  
  
void setName(id self, SEL _cmd, NSString* name)  
{  
    // Implement @property (copy)  
    if (((Person *)self)->_name != name) {  
        [((Person *)self)->_name release];  
        ((Person *)self)->_name = [name copy];  
    }  
}  
  
NSString* getName(id self, SEL _cmd)  
{  
    return ((Person *)self)->_name;  
}  
  
- (void) hello  
{  
    NSLog(@"Hello, world");  
}  
  
@end // Person  
  
int main(int argc, const charchar * argv[])  
{  
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];  
      
    Person *a = [[Person alloc] init];  
    [a hello]; // never call resolveInstanceMethod  
      
    a.name = @"hello1";  
    NSLog(@"%@", a.name);  
    a.name = @"hello2";  
    NSLog(@"%@", a.name);  
      
    [a release];  
    [pool drain];  
      
    return 0;  
} // main

に宣言を入れます。 上記を要約すると、@dynamic の機能は、コンパイラが @property の setter メソッドと getter メソッドを生成することを禁止することです。 setter メソッドと getter メソッドを実装するには、次の 2 つの方法があります。 1) セッター メソッドとゲッター メソッドを自分で提供する。 2) メソッドの動的解決 (DynamicMethod Resolution)。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。