1. 程式人生 > >@dynamic、@synthesize

@dynamic、@synthesize

一、@dynamic與@synthesize的區別

1、@property有兩個對應的詞,一個是@synthesize,一個是@dynamic。如果@synthesize和@dynamic都沒寫,那麼預設的就是@syntheszie var = _var;

2、@synthesize的語義是如果你沒有手動實現setter方法和getter方法,那麼編譯器會自動為你加上這兩個方法。

3、@dynamic訴編譯器,屬性的settergetter方法由用自己實現,不自生成。(當然對於readonly的屬性只需提供getter即可)。假如一個屬性被宣告為@dynamic var,然後你沒有提供@setter方法和@getter方法,編譯的時候沒問題,但是當程式執行到instance.var =someVar,由於缺setter方法會導致程式崩潰;或者當執行到 someVar = var時,由於缺getter方法同樣會導致崩潰。編譯時沒問題,執行時才執行相應的方法,這就是所謂的動態繫結。

@dynamic 就是要來告訴編譯器,程式碼中用@dynamic修飾的屬性,其getter和setter方法會在程式執行的時候或者用其他方式動態繫結,以便讓編譯器通過編譯。其主要的作用就是用在NSManageObject物件的屬性宣告上,由於此類物件的屬性一般是從Core Data的屬性中生成的,Core Data框架會在程式執行的時候為此類屬性生成getter和Setter方法。

@dynamic這個關鍵詞,通常是用不到的。

它與@synthesize的區別在於:

使用@synthesize,編譯器會確實的產生getter和setter方法,而@dynamic僅僅是告訴編譯器這兩個方法在執行期會有的,無需產生警告。

假設有這麼個場景,B類,C類分別繼承A類,A類實現某個協議(@protocol),協議中某個屬性( somePropety )我不想在A中實現,而在B類,C類中分別實現。如果A中不寫任何程式碼,編譯器就會給出警告:

“use @synthesize, @dynamic or provide a method implementation"

這時你給用@dynamic somePropety; 編譯器就不會警告,同時也不會產生任何預設程式碼。


二、通過私有變數來實現@dynamic的存取方法

1)Book.h

#import <Foundation/Foundation.h>

#import 

<CoreData/CoreData.h>

@interface Book :NSObject

{

 @private

    __strong NSString *_name;

    __strong NSString *_author;

}

@property(nonatomiccopyNSString *name;

@property(nonatomiccopyNSString *author;

@property(nonatomiccopyNSString*version;

@end

2)Book.m

#import "Book.h"

@implementation Book

@dynamic name;

@dynamicauthor;

@synthesizeversion = _version;

- (id)init

{

    self = [super init];

    if(self)

    {

    }

    return self;

}

- (NSString *)name

{

    if(nil == _name)

    {

        _name = @"you forgot inputbook name";

    }

    return _name;

}

- (void)setName:(NSString *)name

{

    _name = name;

    NSLog(@"_name address:%p"_name);

}

- (NSString *)author

{

    if(nil == _author)

    {

        _author = @"you forgot inputbook author";

    }

    return _author;

}

- (void)setAuthor:(NSString *)author

{

    _author = author;

}

@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 <Foundation/Foundation.h>

@interface Book :NSObject

{

 @private

    NSMutableDictionary *_propertiesDict;

}

@property (nonatomiccopyNSString *name;

@property (nonatomiccopyNSString*author;

@property (nonatomiccopyNSString*version;

@end

2)Book.m

#import "Book.h"

@implementation Book

@dynamic    name; // 不能寫成name = _name;否則編譯器馬上報錯

@dynamic    author;

@synthesizeversion;

- (id)init

{

    self = [super init];

    if(self)

    {

        _propertiesDict = [[NSMutableDictionary allocinit];

    }

    return self;

}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector

{

    NSString *sel = NSStringFromSelector(selector);

    if ([sel rangeOfString:@"set"].location == 0)

    {

        return [NSMethodSignature signatureWithObjCTypes:"[email protected]:@"];

    }

    else

    {

        return [NSMethodSignature signatureWithObjCTypes:"@@:"];

    }

}

- (void)forwardInvocation:(NSInvocation *)invocation

{

    NSString *key = NSStringFromSelector([invocation selector]);

    if ([key rangeOfString:@"set"].location == 0)

    {

        key= [[key substringWithRange:NSMakeRange(3, [key length]-4)] lowercaseString];

        NSString *obj;

       [invocation getArgument:&objatIndex:2];

        [_propertiesDict setObject:obj forKey:key];

    }

    else

    {

        NSString *obj = [_propertiesDict objectForKey:key];

       [invocation setReturnValue:&obj];

    }

}

@end

3)main.m

#import <Foundation/Foundation.h>

#import "Book.h"

int main(int argc, const char * argv[])

{

    @autoreleasepool

    {

        Book *book = [[Book allocinit];

       book.name = @"c++ primer";

       book.author = @"Stanley B.Lippman";

        book.version = @"5.0";

        NSLog(@"%@", book.name);

        NSLog(@"%@", book.author);

        NSLog(@"%@", book.version);

    }

    return 0;

}

程式分析:

1)程式新增訊息轉發功能以前,必覆蓋兩個方法,即methodSignatureForSelector:和forwardInvocation:。methodSignatureForSelector:的作用在於另一個類實現的訊息建一個有效的方法名。forwardInvocation:選擇轉發給一個真正實現訊息的象。

2)Objective-C中的方法預設被隱藏了兩個引數:self和_cmd。self指向物件本身,_cmd指向方法本身。舉兩個例子來說明:

例一:- (NSString *)name

這個方法實際上有兩個引數:self和_cmd。

例二:- (void)setValue:(int)val

這個方法實際上有三個引數:self, _cmd和val。

被指定為動態實現的方法的引數型別有如下的要求:

    A.第一個引數型別必須是id(就是self的型別)

    B.第二個引數型別必須是SEL(就是_cmd的型別)

    C.從第三個引數起,可以按照原方法的引數型別定義。舉兩個例子來說明:

例一:setHeight:(CGFloat)height中的引數height是浮點型的,所以第三個引數型別就是f。

例二:再比如setName:(NSString *)name中的引數name是字串型別的,所以第三個引數型別就是@

3)在main.m中有一句程式碼是book.name = @"c++ primer";程式執行到這裡時,會去Book.m中尋找setName:這個賦值方法。但是Book.m裡並沒有這個方法,於是程式進入methodSignatureForSelector:中進行訊息轉發。執行完之後,以"[email protected]:@"作為方法簽名型別返回。

    這裡[email protected]:@是什麼東西呢?實際上,這裡的第一個字元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框架屬性生成存取方法。

相關推薦

@dynamic@synthesize

一、@dynamic與@synthesize的區別 1、@property有兩個對應的詞,一個是@synthesize,一個是@dynamic。如果@synthesize和@dynamic都沒寫,那麼預設的就是@syntheszie var = _var; 2、@synth

@dynamic 與 @synthesize 關鍵詞個人理解

@synthesize的語義是如果你沒有手動實現setter方法和getter方法,那麼編譯器會自動為你加上這兩個方法。 @dynamic告訴編譯器,屬性的setter與getter方法由使用者自己實現,不自動生成。 (當然對於readonly的屬性只需提供getter即

@property@synthesize關鍵字的用法

由於OC中每次給屬性宣告get、set方法以及在實現類中要實現這些get、set方法,非常麻煩,所以OC給我們提供了@property、@synthesize關鍵字 @property:在interface介面中宣告get、set方法。 @synthesize:在實現類.m

@property@synthesize關鍵字和點語法

在面向物件程式設計的時候,我們常會為物件的一些屬性寫上set、get方法(設定器和訪問器),而不直接訪問成員變數,這樣一來提升了安全性(不太懂),二來可以在設定和訪問的時候加上判斷,過濾不符合條件的值。 當屬性比較多的時候,為每個屬性寫設定器和訪問器方法比較繁瑣,可用@p

Objective-C中.h檔案.m檔案中@interface@synthesize及其它

很多開發iOS好幾年的老鳥,可能都不太分的清.h檔案和.m檔案裡各種結構的用途和區別。最近仔細研究了一下,寫一篇文章記下來。 一般的,寫一個Class的時候,經常是這種格式(以UIViewController為例): .h檔案: @interface ClassName{ NS

動態規劃(dynamic programming)(二最優子問題與重疊子問題,以及與貪心的區別)

貪心策略 找到 算法 找問題 貪心 模式 解決 策略 最優 一、動態規劃基礎   雖然我們在(一)中討論過動態規劃的裝配線問題,但是究竟什麽時候使用動態規劃?那麽我們就要清楚動態規劃方法的最優化問題中的兩個要素:最優子結構和重疊子問題。   1、最優子結構     1)如果

Objective-C基礎之@synthesize, @dynamic

not getter var 實例 利用 基礎 PE category protoc Objective-C基礎之@synthesize, @dynamic OC屬性用一個表達式最能清楚的解釋其實質:property = ivar + setter+getter,也就是說一

22-思科防火墻:Dynamic Identity NATStatic Identity NAT

size com ... ear http in use password term sed 一、實驗拓撲:二、實驗要求:實驗一:Dinamic Identity NATR1、R2都有默認路由,下一跳為ASA對應的接口地址。實驗二:Static Identity NAT三、

C# 匿名物件(匿名型別)var動態型別 dynamic

本文是要寫的下篇《C#反射及優化用法》的前奏,不能算是下一篇文章的基礎的基礎吧,有興趣的朋友可以關注一下。 隨著C#的發展,該語音內容不斷豐富,開發變得更加方便快捷,C# 的鋒利盡顯無疑。C# 語言從誕生起就是強型別語音,這一性質到今天不曾改變,我想以後也不會變。既然是強型別語音,那編寫任一程式

OC MRC 成員變數, property, synthesize, dynamic

iOS @property、@synthesize和@dynamic MRC 環境下: 建立一個 Person 類,  有 name, age, gender, weight 屬性: 最早的寫法: 成員變數 .h 檔案 @interface Person : NSObject

代寫CSCE 351作業代做Dynamic Storage Allocator作業代寫C/C++程式作業代做C/C++作業

代寫CSCE 351作業、代做Dynamic Storage Allocator作業、代寫C/C++程式作業、代做C/C++作業CSCE 351Malloc Assignment : Writing a Dynamic Storage AllocatorDue: See Canvas for more inf

@synthesize與@dynamic

@property有兩個對應的詞,一個是 @synthesize,一個是 @dynamic。如果 @synthesize和 @dynamic都沒寫,那麼預設的就是@syntheszie var = _var;  在Xcode4.5和以後的版本中,可以省略@synthesi

C# 匿名對象(匿名類型)var動態類型 dynamic——實用之:過濾類屬性字段實用dynamic

轉換成 常見 生成 ram 作用 基礎 bsp teacher 模擬 例子 返回一個LIst<oject>類型 而oject含有 30個字段 而我只需要兩個字段。這裏實用dynamic 和 linq。 上代碼: 註意select new {} 為匿名

《Oracle PL/SQL開發指南》學習筆記27——動態SQL(Dynamic SQL)(章節回顧測試)

動態SQL語句是一種強大的技術,通過它可以在程式執行時寫和執行查詢,修改DDL和DML語句。 本地動態SQL(Native Dynamic SQL (NDS)) Review Section This section has described the following

@property @synthesize @dynamic

@property 的本質是什麼?ivar、getter、setter 是如何生成並新增到這個類中的 @property 的本質是什麼? @property = ivar + getter + setter; 下面解釋下: “屬性”

(最短路徑算法整理)dijkstrafloydbellman-fordspfa算法模板的整理與介紹

void empty borde fast 默認 grand else 理解 scan 這一篇博客以一些OJ上的題目為載體。整理一下最短路徑算法。會陸續的更新。。。 一、多源最短路算法——floyd算法 floyd算法主要用於求隨意兩點間的最短路徑。也成

6自學——Linux的學習進度與任務【FHS】

include 同名 med 可選 第三方 安裝 lin 三方 引導 FHS:文件層次標準 FHS:文件層次標準    / : 代表根目錄    /bin: 二進制文件,可執行程序,所有用戶都能用。   /sbin: 只有管理員執行的,二進制可執行程序。

【BZOJ37812038】莫隊算法2水題

bsp space har 情況 ros clu while 給定 print 【BZOJ3781】小B的詢問 題意:有一個序列,包含N個1~K之間的整數。他一共有M個詢問,每個詢問給定一個區間[L..R],求Sigma(c(i)^2)的值,其中i的值從1到K,其中c(i

第六課算法效率的度量

分享 turn 結構 sin 效率 mage alt exit 額外 一、常見的時間復雜度 常見時間復雜度的比較 二、算法分析 定義一個數組 此算法最好的情況時執行一次 而最壞的情況卻要執行n次 註意:數據結構課程中,在沒有特殊說明時,所分析算法的時間復雜度都是

Visual Studio 2017各版本安裝包離線下載安裝全解析

pla 離線文件 win10 unit splay and 文件下載 python擴展 erl 轉自 寂靜·櫻花雨 Visual Studio 2017各版本安裝包離線下載、安裝全解析 感謝IT之家網友 寂靜·櫻花雨 的投稿 關於Visual