Objective-C 懶加載沒有調用?

外包出去的項目,然后二期拿回來自己做,今天改BUG時發現了一個很有意思的地方:請看圖:

懶加載


亮點自己找

? ?個人推測,可能是寫這個代碼的哥們用了懶加載,然后發現給dataArray數組賦值后,數組還是nil,所以在轉Model之前又初始化了一次,至于原因請看我慢慢分析:


1、getter和setter方法:

property直譯就是屬性,一般我們用來保存和操作對象的數據。那么當我們用@property申明了一個屬性后,Xcode為我們做了什么呢?

(1)、setter和getter的寫法

在Objective-C中通常申明一個屬性的寫法為:

```

@property (strong, nonatomic) NSString *Data;

```

@property (strong, nonatomic) NSString *Data;

此時Xcode IDE已經自動的為開發者生成了getter方法("讀取")和setter方法("設置"),此時,默認這個屬性是可讀可修改的;

@property (strong, nonatomic, readwrite) NSString *Data;

以上兩種申明屬性產生的效果是相同的,雖然我們沒有用readwrite關鍵字,但是Xcode已經為我們自動生成了這個屬性的getter和setter方法;

為了近一步說明getter和setter方法,請看下面兩段代碼:

代碼1:

@property (assign, nonatomic) int Numcode;

代碼2:

-(int) Numcode;//getter 
-(void) setNumcode:(int)numcode;//setter

上面的兩種寫法產生的效果是一樣的。從我的個人角度來說,初期的學習很多的教材上都使用的是上面的第一種代碼,而且相對于第二種寫法第一種寫法也比較簡便易懂,再加上大家都習慣了這種寫法,所有在我的項目中我都使用的是第一種寫法;

當然也不一定,在一些比較老的項目中會使用以下的方法來申明:

@property int age; //表示聲明了一個屬性和getter和setter
@synthesize age = _age; //表示實現setteer和getter

(2)、setter和getter的調用:

setter和getter的調用其實就是對屬性的讀取和賦值操作,不說廢話直接上代碼吧:

#import"EOCClass.h"@implementation EOCClass+(EOCClass*)sharedInstance{? ? static dispatch_once_t EOCClassperonce;? ? static EOCClass* eOCClass;? ? dispatch_once(&EOCClassperonce, ^{? ? ? ? eOCClass = [[EOCClass alloc]init];? ? ? ? eOCClass.Numcode = 10086;? ? });  return eOCClass;}
EOCClass *eClass = [EOCClass sharedInstance];//單利模式初始化一個類//--------------操作類屬性-------------eClass.Numcode = 1008611;?  [eClass setNumcode:1008611]; //setter方法調用,兩種寫法是等效的
int lsCode = eClass.Numcode; int lsNum = [eClass Numcode];//getter方法調用,兩種寫法是等效的

(3)、other

至于在申明屬性時用到的一些關鍵字如:

atomic?  nonatomic? readonly? readwirte?  assgin? strong?  weak? copy? retain

等等的區別這里就不做贅述了。


?2、self和下劃線_的使用:

(1)、self和下劃線_的區別

? ? ? 1、 self.是調用屬性的getter和setter方法,編譯器在生成getter,setter方法時,編譯器首先查找當前的類中用戶是否定義屬性的getter,setter方法,如果有,則編譯器會跳過,不會再生成,使用用戶定義的方法。

? ? ? 2、使用 self.賦值操作的時候實際上會先調 release(就是retainCount -1)一次,然后再把指針指向這個屬性,下劃線_賦值時沒有release操作,直接把指針指向這個屬性的實例變量。

? ? ? 3、 在使用self.時是調用一個getter和setter方法。會使引用計數加一當這個屬性在調用下劃線_是直接對屬性的實例變量進行操作;

? ? ? 4、下劃線_Numcode實際上和self->_Numcode;的效果是相同的;

? ? ?5、 下劃線_Numcode只能獲取局部變量,不能獲取到父類的屬性或方法;

請看下面的代碼:

-(void)DatafromServer{?  //--------------------?  //setter?  self.Numcode = 1008611;?  //getter?  int digital = self.Numcode;?  //getter?  int digitaltoo = [self Numcode];?  printf("\\DatafromServer=========%d,%d\n",digital,digitaltoo);}
-(int)DatafromServertoo{ ?  //--------------------?  //setter?  [self setNumcode:1008611]; ?  //getter?  int digital = self.Numcode;?  //getter?  int digitaltoo = [self Numcode];?  printf("\nDatafromServertoo=========%d,%d\n",digital,digitaltoo);}
EOCClass*eClass = [EOCClasssharedInstance];[eClassDatafromServer];[eClassDatafromServertoo];,

最后可以看到DatafromServer方法Log值和DatafromServertoo方法Log值都是1008611.


最終Log值

總結:self.對屬性的get和set方法間接調用,下劃線_是直接對實例變量操作。


3、懶加載:

前面已經說到,在iOS 5之后,使用`@property`定義一個屬性后,系統會默認生成`getter`和`setter`方法。我們申明了一個屬性,但并不是立即就要使用這個對象,沒必要把所有的屬性都放在`viewDidLoad`方法中初始化,等到要使用時再加載(初始化)。

使用懶加載需要注意:

**

(1)、當開發者使用懶加載本質就是重寫了getter()方法;

(2)、懶加載在加載時必須判空;

(3)、懶加載判空必須使用下劃線,如下面代碼,Xcode100%會報錯的,前面已經說明,self就是調用了setter跟getter方法,懶加載本質就是重寫了getter方法,但在此處屬性本身還沒初始化,是nil,但是getter返回的也是nil,那在判斷時就會進入死循環;

**

//錯誤的懶加載示范一-(NSArray*)PageddatafromServerList{?  if(self.PageddatafromServerList == nil)?  {? ? ? self.PageddatafromServerList = [NSArray array];? ? }? return self.PageddatafromServerList;}
//錯誤的懶加載示范二-(NSArray*)PageddatafromServerList{?  if(self.PageddatafromServerList) //此處一定要判空?  {? ?  self.PageddatafromServerList = [NSArray array];? ? }? return self.PageddatafromServerList;}
//正確的懶加載方式-(NSArray *)DepartmentArray{?  if(_DepartmentArray == nil)?  { ? ?  _DepartmentArray = [NSArray array];?  }return _DepartmentArray;}

分析:最上面貼出的代碼出現的原因:

? 由于這個寫這個代碼的哥們使用了懶加載,而懶加載本質上是重寫了屬性的getter方法,本文第二條也說明了self.和_的區別,所以在賦值時使用_dataArray,就沒有調dataArray的getter方法,懶加載根本就沒有調!!!所以出現的情況就是給dataArray賦值后依舊是nil!

? ?直接就舉個??來說明吧:我買了個超級省電的臺燈,回家后我給臺燈通上電后發現怎么折騰這個臺燈都不亮,為什么呢?因為我沒有摁臺燈的開關!!

那么懶加載的正確打開方式是怎樣的呢?請看代碼:

@interface EOCClass :NSObject@property (strong, nonatomic) NSArray *LazyLoading;-(void)LazyLoadingData;@end
-(void)LazyLoadingData{
? ? NSLog(@"_LazyLoading============%@",_LazyLoading);? ? NSLog(@"self.LazyLoading=============%@",self.LazyLoading);? ? NSLog(@"=============%@",[self LazyLoading]);}
-(NSArray*)LazyLoading{?  if(!_LazyLoading)?  {? ?  _LazyLoading= [NSArray array];?  }? return _LazyLoading;}

最終Log出來的結果請看圖:

懶加載的正確打開方式

那么,通過上面的代碼,可以看出,使用了懶加載后,當要使用這個對象時可以用self.調用該對象或者直接調用這個對象的getter方法,如果用下劃線調用實例變量那么懶加載就沒有調用,最終造成的結果就是賦值了也是nil;


以上是個人的一些理解和總結,如果有錯誤的地方請指出。

本文demo請戳這里;

本文參考了: ??Encapsulating Data

? ? ? ? ? ? ? ? ? ??《Objective-C編程全解》?

? ? ? ? ? ? ? ? ? ??《Effective Objective-C 2.0》

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容