重慶分公司,新征程啟航
為企業提供網站建設、域名注冊、服務器等服務
為企業提供網站建設、域名注冊、服務器等服務
同時重寫了setter和getter方法,@property不會自動生成(成員變量/實例變量)
成都創新互聯公司-專業網站定制、快速模板網站建設、高性價比龍泉驛網站開發、企業建站全套包干低至880元,成熟完善的模板庫,直接使用。一站式龍泉驛網站制作公司更省心,省錢,快速模板網站建設找我們,業務覆蓋龍泉驛地區。費用合理售后完善,十余年實體公司更值得信賴。
@property的作用是定義屬性,聲明getter,setter方法。(注意:屬性不是變量)
@synthesize的作用是實現屬性的,如getter,setter方法.
在聲明屬性的情況下如果重寫setter,getter,方法,就需要把未識別的變量在@synthesize中定義,把屬性的存取方法作用于變量。如:
.h文件中
后來因為使用@property灰常頻繁,就簡略了@synthesize的表達。
從Xcode4.4以后@property已經獨攬了@synthesize的功能主要有三個作用:
(1)生成了私有的帶下劃線的的成員變量因此子類不可以直接訪問,但是可以通過get/set方法訪問。那么如果想讓定義的成員變量讓子類直接訪問那么只能在.h文件中定義成員變量了,因為它默認是@protected
(2)生成了get/set方法的實現
當:
用@property聲明的成員屬性,相當于自動生成了setter getter方法,如果重寫了set和get方法,與@property聲明的成員屬性就不是一個成員屬性了,是另外一個實例變量,而這個實例變量需要手動聲明。所以會報錯誤。
總結:一定要分清屬性和變量的區別,不能混淆。@synthesize 聲明的屬性=變量。意思是,將屬性的setter,getter方法,作用于這個變量。
@property有兩個對應的詞,一個是 @synthesize,一個是 @dynamic。如果 @synthesize和 @dynamic都沒寫,那么默認的就是@syntheszie var = _var;
在Xcode4.5和以后的版本中,可以省略@synthesize,編譯器會自動加上setter和getter方法的實現。并且默認會去訪問_age這個成員變量,如果找不到_age這個成員變量,會自動生成一個叫做_age的私有成員變量。
@synthesize 的語義是如果你沒有手動實現 setter 方法和 getter 方法,那么編譯器會自動為你加上這兩個方法。
@dynamic 告訴編譯器:屬性的 setter 與 getter 方法由用戶自己實現,不自動生成。(當然對于 readonly 的屬性只需提供 getter 即可)。假如一個屬性被聲明為 @dynamic var,然后你沒有提供 @setter方法和 @getter 方法,編譯的時候沒問題,但是當程序運行到 instance.var = someVar,由于缺 setter 方法會導致程序崩潰;或者當運行到 someVar = var 時,由于缺 getter 方法同樣會導致崩潰。編譯時沒問題,運行時才執行相應的方法,這就是所謂的動態綁定。
[鏈接]( ;request_id=163548685316780261954394biz_id=0utm_medium=distribute.pc_search_result.none-task-blog-2 all sobaiduend~default-2-84540175.first_rank_v2_pc_rank_v29utm_term=synthesizespm=1018.2226.3001.4187)
在開發的過程中,對一個NSMutableDictionary(可變字典)設置鍵值對的時候,一般會采用setObject這個方法,但是在項目中,去云捕上看到的用戶出錯,好多都是報這樣的錯誤。
很明顯就是在setObject方法中插入了空值而導致的報錯。解決的辦法是將setObject替換成setValue就可以了。雖然解決了,但是他們之間的區別以及為什么setValue就可以呢?
因為setObject方法中,值必須是不為空的任意類型(nonnull),而setValue方法中,值可以為空值(nullable),并且在setValue方法中,假如你傳的值為空的話,那么他會調用- (void)removeObjectForKey:(id)aKey;這個方法。所以用setValue方法可以有效的防止值為空所出現的炸裂現象。
注意:在系統給出的方法中,我們可以明顯的看到,setValue方法中,key必須是不為空的字符串(nonnull NSString),而setObject方法中,可以傳入不為空的id類型。
setValue和setObject的一些拓展?:
1.setObject方法是NSDictionary這個類中特有的,而setValue是KVC(key-value-coding ?鍵值編碼)中的主要方法。
2.setObject方法中,雖然值不能為nil,但是可以為[NSNull null],并且key可以為NSString, NSNumber等類型。
3.當 setValue:forKey:方法調用者是對象的時候:
setValue:forKey:方法是在NSObject對象中創建的,也就是說所有的oc對象都有這個方法,所以可以用于任何類。
比如使用一個person類:
Person *person = [[Person alloc] init];
[person setValue:self forKey:@"delegate"];
表示的意思是:對象person設置他的delegate屬性的值為當前類,當然調用此方法的對象必須要有delegate屬性才能設置,不然調用了也沒效果。(這條目前還不太理解,希望有看到的大神指教)
setValue和setObject參考鏈接:
賦值的 時候調用set方法,如self.age = 18;//在等號左邊,即左值時調用
取值的時候調用get方法,如age = self.age;//等號右邊或者運算、輸出時
注意_age = 18 不會調用set方法
對已經學會的知識,不斷地總結,可以讓你變得更強的。
什么情況下會調用kvo。
什么情況下不會調用kvo。
kvo的底層原理實現。
我們對name,哪些會真正的觸發kvo呢
我可以告訴你,1 2 4 6會監聽到kvo的變化,而其他的則檢測不到。
又比如下面這個例子。
當我們對animal進行kvo監聽,然后修改name的值,是否會被kvo監聽到。
當我們對personclass對象重新賦值一個AnimalClass對象,是否會被kvo監聽到。
我可以告訴你,第一種情況是監聽不到的,第二種情況是可以監聽到的。
然后,為什么呢?
我這里有兩張圖片。
當我們對一個對象進行kvo監聽的時候,會生成一個NSKVONotifying_前綴的類,然后我們實際的操作是對這個類進行的。
通俗的講,對對象的進行kvo監聽后,這個對象的isa指針已經指向了NSKVONotifying_前綴的類,NSKVONotifying_Person。這個類是person的子類,他的superclass就是person類對象。
我們在調用setage方法的時候,會根據對象的isa找到NSKVONotifying_Person,然后在他的類里面找setage的實現。
那么有沒有疑惑,setage中到底做了什么操作呢?
_NSsetIntValueAndNotify記住這個函數。
我們可以這樣打印出setage的方法實現。
可以打印出
這個_NSsetIntValueAndNotify方法就是setage的實現,具體的實現,請再往后看。
Foundation框架中還有很多例如_NSSetBoolValueAndNotify、_NSSetCharValueAndNotify、_NSSetFloatValueAndNotify、_NSSetLongValueAndNotify等等函數。
繼續往下看。
打印結果如下
在kvo監聽下,包含了四個方法,setAge: class dealloc _isKVOA
我們先從clas來進行入手。
打印結果都是person。為什么呢?
進行kvo監聽之后,不是進行變為NSKVONotifyin_Person這個類嗎?怎么打印出來都是person。
其實是蘋果不希望將這個NSKVONotifyin_Person暴露出來。然后在類的內部,重寫了clas方法。
setAge方法的再深一層的內部實現?
我相信看完都會有所收獲。
看完這些最開始的例子,我覺得會懂了。
我們來看下kvc的原理:
觸發kvc的set方法才可以觸發kvo機制。
所以這兩種情況
在程序設計中,我們經常會使用 懶加載 ,顧名思義,就是用到的時候再開辟空間,比如iOS開發中的最常用控件UITableView,實現數據源方法的時候,通常我們都會這樣寫Objective-C- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.dataArray.count; }- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ //1.得到cell XWShopCell *cell = [XWShopCell cellWithTableView:tableView]; //2.傳遞模型 cell.wine = self.dataArray[indexPath.row]; //3.回傳cell return cell; }上面的的代碼中return self.dataArray.count;其實就是利用@property (nonatomic, strong) NSArray *dataArray;@property 的特性,為屬性生成了get和set方法,而這里是調用的get方法,但是上述代碼中return self.dataArray.count 會調用- (NSArray *)dataArray{ return _dataArray}這樣調用,如果成員屬性dataArray 開始沒有賦值的,那么在使用的時候,調用get方法,不重寫的話,會報錯,空指針,所以一般我們會重寫get方法//重寫get方法 - (NSArray *)dataArray { if (nil == _dataArray){ _dataArray = [NSArray array]; } return _dataArray }這樣寫,就防止了成員屬性為沒有賦值的情況綜上所述,Objective-C的懶加載,其實就是調用成員屬性的get方法,初始化值,而Swift的懶加載,是和Objective-C不同的Swift//MARK tablview的 dataSource 代理方法 func tableView(tableView: UITableView, numberOfRowsInSection section: Int) - Int{ return self.dataArray.count } func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) - UITableViewCell{ //1.得到cell let cell = XWShopCell.cellWithTableView(tableView) //2.傳遞模型 cell.wine = self.dataArray[indexPath.row] //3.回傳cell return cell }而這句return self.dataArray.count在Swift 存儲屬性必須初始化,確認類型,或者用可選類型,總之要確認類型,畢竟Swfit是類型安全語言,所以Swift提出了lazy屬性,用法//1.分析 NSArray 是一個閉包的返回值,而這是一個沒有參數的閉包 lazy var dataArray:NSArray = { [] }() //2.也可以寫成這樣 lazy var dataArray:NSArray = { return NSArray() }()//3.從plist文件加載 lazy var dataArray:ArrayXWWine = { let winePath = NSBundle.mainBundle().pathForResource("wine.plist", ofType: nil)! let winesM = NSMutableArray(contentsOfFile: winePath); var tmpArray:ArrayXWWine! = [] for tmpWineDict in winesM! { var wine:XWWine = XWWine.wineWithDict(tmpWineDict as! NSDictionary) tmpArray.append(wine) } print("我就運行一次") return tmpArray }()上述的代碼,有點難理解,如果之前會Objective-C的block 或者對C語言的函數指針理解透徹的,可以看成是一個代碼塊,然后self.dataArray的時候,就執行了代碼塊,但是重復調用,Lazy 屬性的代碼塊只會調用一次,lazy修飾的是一個存儲屬性,而存放的是閉包,我想內部,應該進行了優化。