首頁 >Java >java教程 >介紹@dynamic的用法

介紹@dynamic的用法

高洛峰
高洛峰原創
2016-12-13 09:18:512671瀏覽

介紹@dynamic的用法 

    Objective-C 2.0提供了屬性(@property),可以讓編譯器自動產生setter和getter方法。如果不想編譯器自作主張產生這些setter和getter方法,則使用@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 sent to instance 0x1001149d0」。如果將@dynamic註解掉,則一切Ok。

    這裡由於使用@dynamic,我們需要自己提供setter和getter方法。一般有兩種方法:1)自己提供setter和getter方法,將編譯器自動產生的setter和getter方法手動再寫一遍;2)動態方法決議(DynamicMethod Resolution),在運行時提供setter和getter對應實現的C函數。

    對於第一種方法,需要在類別中明確提供實例變量,因為@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

    第二種方法,在執行時決定setter和getter對應實現的C函數,使用了NSObject提供的resolveInstanceMethod:方法。在C函數中不能直接使用實例變量,需要將ObjC物件self轉成C中的結構體,因此在Person類別同樣需要明確聲明實例變數而且存取層級是@public,為了隱藏該實例變量,將聲明放在擴充(extension)中

#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方法:1)自己提供setter和getter方法;2)方法動態決議(DynamicMethod Resolution)。

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn