一、@dynamic與@synthesize的區別
@property有兩個對應的詞,一個是@synthesize,一個是@dynamic。如果@synthesize和@dynamic都沒寫,那麼預設的就是@syntheszie var = _var;
@synthesize的語義是如果你沒有手動實現setter方法和getter方法,那麼編譯器會自動為你加上這兩個方法。
@dynamic告訴編譯器,屬性的setter與getter方法由使用者自己實現,不自動產生。 (當然對於readonly的屬性只需提供getter即可)。假如一個屬性被宣告為@dynamic var,然後你沒有提供@setter方法和@getter方法,編譯的時候沒問題,但是當程式運行到instance.var =someVar,由於缺setter方法會導致程式崩潰;或者當運行到someVar = var時,由於缺getter方法同樣會導致崩潰。編譯時沒問題,執行時才執行對應的方法,這就是所謂的動態綁定。
二、透過私有變數實現@dynamic的存取方法
1)Book.h
#import
#import { @private __strong NSString *_name; (nonatomic, copy) NSString *name; @property(nonatomic , copy) NSString *author; @property(nonatomic, copy) NSString*version; @end } }程式碼可以看出,用@dynamic後,可以在存取方法中存取私有變數來賦值或取值。而@synthesize則直接用@synthesize var = _var;來讓屬性和私有變數直接等同起來。這就是二者在書寫形式上的差異。 三、透過訊息轉發來實現@dynamic的存取方法 若對於一個屬性使用了@dynamic var = _var,則編譯器立刻報錯。這樣你就無法像@synthesize那樣在var的setter方法和getter方法中使用_var,當然你更不能寫如下的setter方法和getter方法 - (void)setVar:(id)newVar { self.var =newVar; } - (void)var { return self.var;崩潰。 這裡提供一個利用訊息轉發機制來實作@dynamic的setter和getter方法。 先上程式碼: 1)Book.h #import @interface Bookpriv ary *_propertiesDict; } @property (nonatomic, copy) NSString *name; @property (nonatomic, copy) HString*author) @propertymic(nonato), @end 2) Book.m #import "Book.h" @implementation Book @dynamic name; // thesizeversion; - (id)init { self = [super init]; ? *)methodSignatureForSelector:(SEL)選擇器 key= [ [ key substringWithRange:NSMakeRange(3, [key length]-4)] lowercaseString]; NSString *obj; [調用 getArgument:&objatIndex:2] ࠦ; Book *book = [[Book alloc] init]; 書名= @ "c++ Primer"; book.author = @"Stanley B.Lippman"; book. ; NSLog (@ "%@", book.author); NSLog(@"%@", book.version); 3)在main.m中有一段程式碼是book.name = @"c++ Primer";程式運行到這裡時,會去Book.m中找setName:這個賦值方法。方法,於是程式進入methodSignatureForSelector:中進行訊息轉發。 這裡v@:@是什麼東西呢?實際上,這裡的第一個字元v代表函數的回傳類型是void,後面三個字元參考上面2)中的解釋就可以知道,分別是self, _cmd, name這三個參數的類型id, SEL, NSString。 接著程序進入forwardInvocation方法。得到的key為方法名稱setName:,然後利用[invocationgetArgument:&objatIndex:2];取得到參數值,這裡是「c++ primer」。這裡的index為什麼要取2呢?如前面分析,第0個參數是self,第1個參數是_cmd,第2個參數才是方法後面帶的那個參數。 最後利用一個變動字典來賦值。這樣就完成了整個setter流程。 4)在main.m中有一句程式碼是 NSLog(@"%@", book.name);,程式運作到這裡時,會去Book.m中尋找name這個取值方法 。但是Book.m裡並沒有這個取值方法,於是程式進入methodSignatureForSelector:中進行訊息轉發。執行完之後,以"@@:"作為方法簽名類型傳回。這裡第一個字元@代表函數傳回型別NSString,第二個字元@代表self的型別id,第三個字元:代表_cmd的型別SEL。 接著程序進入forwardInvocation方法。得到的key為方法名稱name。最後根據這個key從字典取得對應的值,這樣就完成了整個getter過程。 5)注意,調試程式碼的過程,我們發現只有name和author的賦值和值進入methodSignatureForSelector:和forwardInvocation:這兩個方法。還有一個屬性version的賦值和值,並沒有進入methodSignatureForSelector:和forwardInvocation:這兩個方法。這是因為,version屬性被標識為@synthesize,編譯器自動會加上setVersion和version兩個方法,所以就不用訊息轉發了。 四、@dynamic在NSManagedObject的子類別中的使用 @dynamic最常用的使用是在NSManagedObject中,此時不需要顯示程式設計setter和getter方法。原因是:@dynamic告訴編譯器不做處理,使編譯通過,其getter和setter方法會在運行時動態創建,由Core Data框架為此類屬性生成訪問方法。