外包出去的項目,然后二期拿回來自己做,今天改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.
總結: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》