iOS基礎深入補完計劃--帶你重識Property

靈劍山扉頁182.jpg

知識基礎不夠牢。
一知半解诉瓦、想當然的用沒準將來會出大問題。
借用@我就叫Sunny怎么了的一句話:
一個人iOS的基礎如何、只問一個property就夠了
決定(深入?)總結(jié)一下暫時所能想到的property慧瘤。

受篇幅所限、把一些相對冗余的原理探究放到了其他帖子固该。有興趣的童鞋可以去看(個人覺得還是挺有用的)

目錄

  • ※ARC下锅减,不顯式指定任何屬性關鍵字時,默認的關鍵字都有哪些伐坏?
  • ※@property中有哪些屬性關鍵字怔匣?
  • 原子性關鍵字
  • nonatomic/atomic
  • atomic---原子性(atomic內(nèi)部實現(xiàn))
  • ※※※atomic聲明的屬性一定是線程安全的么
  • ※※※copy關鍵字
  • ※何時用copy關鍵字聲明
  • ※※※block(block作用域/__block、__weak桦沉、__strong的原理)
  • NSString每瞒、NSArray、NSDictionary
  • ※※深拷貝淺拷貝
  • ※※weak/assign關鍵字
  • 相似纯露、區(qū)別剿骨、assign如何修飾對象、ib對象為什么用weak
  • strong關鍵字
  • unsafe_unretained關鍵字
  • readonly/readwrite關鍵字
  • 可選值: nullable埠褪、nonnull浓利、null_resettable、null_unspecified關鍵字

※ARC下组橄,不顯式指定任何屬性關鍵字時荞膘,默認的關鍵字都有哪些?

  • 對應基本數(shù)據(jù)類型默認關鍵字是
    atomic,readwrite,assign
    
  • 對于普通的OC對象
    atomic,readwrite,strong
    

※@property中有哪些屬性關鍵字玉工?

按照性質(zhì)可以分為四類羽资。(原子性/內(nèi)存管理語義/讀寫權(quán)限/setter/getter別名)

  • 原子性: nonatomic、atomic
  • 內(nèi)存管理:assign遵班、strong屠升、 weak潮改、unsafe_unretained、copy
  • 讀寫權(quán)限:readwrite(讀寫)腹暖、readooly
  • 方法名:getter=汇在、setter=
  • 可選值: nullable、nonnull脏答、null_resettable糕殉、null_unspecified

其中atomic,nonatomic殖告,copy在setter/getter中實現(xiàn)阿蝶。
而weak和strong等則是直接作用于成員變量上。


  • 原子性關鍵字

首先黄绩、nonatomic以及atomic除了自動合成中的setter/getter方法內(nèi)部不同羡洁、其他并沒有任何不同。

所以爽丹、如果你自己重寫了setter/getter筑煮。那么‘原子性’標簽將失效、只起到提示作用粤蝎。

  • nonatomic---非原子
  • 單純的自動生成setter/getter方法真仲。
  • 讀寫速度優(yōu)于atomic、如果不需要保證數(shù)據(jù)完整性(如多線程)诽里。盡量使用nonatomic袒餐。
  • atomic---原子性
  • 在自動合成setter/getter方法的過程中、為對象添加條件鎖谤狡。

  • 那么灸眼、atomic究竟是如何保護對象的原子性/這種保護是否需要可靠呢。
想再了解深入一些墓懂、可以參閱延展篇《原子性相關延伸》

  • ※※※copy關鍵字

拋開一搜一大把的解釋焰宣、這里還需要分為兩部分來看:何時用copy關鍵字聲明/深拷貝淺拷貝

  • ※何時用copy關鍵字聲明

為了確保屬性對象的完整性以及封裝性、只要實現(xiàn)屬性所用的對象是“可變的” 捕仔、就應該在設置新屬性值時拷貝一份匕积。

  • ※※※block

  • 在MRC中、block內(nèi)部的代碼塊依舊是在棧區(qū)的榜跌、使用copy可以把它放到堆區(qū)闪唆。
  • 在ARC中、使用copy還是strong效果是一樣的钓葫。使用copy更多的是為了語義化(詳見官方文檔)悄蕾。
WechatIMG201.jpeg
  • 那么、block究竟有哪些特殊。究竟__block帆调、__weak奠骄、__strong是如何工作的呢。
想再了解深入一些番刊、可以參閱延展篇《Block相關延伸》
  • ※NSString含鳞、NSArray、NSDictionary

簡而言之芹务、因為父類指針可以指向子類對象蝉绷。通常我們?yōu)榱吮Wo變量的完整性、不希望這個對象被賦值之后又在不知情的情況下被改變锄禽。就像下面這樣:
 @interface ViewController ()
 
 @property (nonatomic,strong,readwrite) NSString * strongedStr;
 @property (nonatomic,copy,readwrite) NSString * copyedStr;
 
 @end
 
 @implementation ViewController
 
 - (void)viewDidLoad {
 [super viewDidLoad];
 // Do any additional setup after loading the view, typically from a nib.
 
 NSMutableString * mOStr = [[NSMutableString alloc]initWithString:@"123123"];
 
 self.strongedStr = mOStr;
 self.copyedStr = mOStr;
 
 NSLog(@"原對象改變前的strongedStr---%@",self.strongedStr);
 NSLog(@"原對象改變前的copyedStr---%@",self.copyedStr);
 
 [mOStr appendString:@"lalala"];
 
 NSLog(@"原對象改變后的strongedStr---%@",self.strongedStr);
 NSLog(@"原對象改變后的copyedStr---%@",self.copyedStr);
 
 }

結(jié)果

 原對象改變前的strongedStr---123123
 原對象改變前的copyedStr---123123
 原對象改變后的strongedStr---123123lalala
 原對象改變后的copyedStr---123123
如上所示潜必、無論原對象如何改變。copy聲明的對象都可以保持當初被賦值的樣子沃但。
  • 那么、copy到底是如何工作的佛吓、他和strong的聲明還有哪些不同宵晚、這里的copy和copy/mutableCopy是否相同呢。
想再了解深入一些维雇、可以參閱延展篇《strong&&copy聲明相關延伸》

  • ※※深拷貝淺拷貝

關于深拷貝和淺拷貝的概念淤刃、這是基礎中的基礎。

  • 淺拷貝
  • 源對象和副本對象是同一對象吱型;
  • 源對象(也就是副本對象)引用計數(shù)器+1逸贾。
  • 本質(zhì):并未產(chǎn)生新對象。(由于源對象本身就不可變)津滞。
  • 深拷貝
  • 源對象和副本對象是不同的兩個對象
  • 源對象引用計數(shù)器不變铝侵,副本對象計數(shù)器為1。
  • 本質(zhì):產(chǎn)生了新對象触徐。(由于源對象本身就可變咪鲜、需要分離)。
  • 再簡單點說

  • 只有不可變對象的copy方式撞鹉,是淺復制疟丙,其他都是深復制。
  • copy與mutableCopy

不論源對象是否可變
  • copy復制出的對象都是不可變對象
  • mutableCopy復制出的對象都是可變對象
  • 基本類型不允許copy
  • 自定義對象

  • 需要實現(xiàn)對應協(xié)議NSCopying/NSMutableCopying

    - (id)copyWithZone:(NSZone *)zone{
       PersonModel *model = [[[self class] allocWithZone:zone] init];
       model.firstName = self.firstName;
       model.lastName  = self.lastName;
       //未公開的成員--將其拷貝成不可變
       model->_friends = [[NSMutableSet alloc] initWithSet:_friends copyItems:YES];
       return model;
    }
    
    - (id)mutableCopyWithZone:(NSZone *)zone{
       PersonModel *model = [[[self class] allocWithZone:zone] init];
       model.firstName = self.firstName;
       model.lastName  = self.lastName;
       //未公開的成員--將其拷貝成可變
       model->_friends = [_friends mutableCopy];
       return model;
    }
    
  • 需要注意一點

  • 對集合對象而言鸟雏、即使的深拷貝享郊。也只是拷貝了自身容器、對象內(nèi)部的元素依舊是淺拷貝孝鹊。

解決的方式就是手動對內(nèi)部元素進行copy炊琉。網(wǎng)上看到兩種比較方便的解決辦法。


  • ※※weak/assign關鍵字

之所以把這兩個關鍵字放在一起講惶室。是因為在ARC下温自、他倆很相似玄货。
相似點:
  • 都不會讓對象的引用計數(shù)+1;
也有區(qū)別:
  • weak在指針對象釋放的時候會自動置nil、assign則不進行任何操作悼泌。
  • weak修飾對象類型松捉、assign修飾基本類型。

其實這兩個區(qū)別本質(zhì)上就是第一種馆里、因為基本類型通常被分配在棧上隘世、由系統(tǒng)自動釋放。而如果對象釋放鸠踪、指針指向沒有釋放丙者。那么就會出現(xiàn)野指針

WechatIMG214.jpeg

什么時候用weak:

當你不希望你的屬性营密、需要被本類手動釋放的時候械媒。
最典型的例子就是代理、當外界主體被消滅评汰。本類delegate指針也指向nil纷捞。

什么時候用assign:

幾乎所有的普通類型變量。

assign能不能修飾對象:
  • 可以被去。

既然我們知道二者的區(qū)別主儡。那么只要讓assign聲明的對象、在本身釋放的時候?qū)⒅羔樦赶蛑胣il就可以了惨缆。
具體寫要分情況糜值。
比如可以在自己VC被釋放的時候、將引用自己的代理手動置nil坯墨。

 -(void)dealloc {
     self.xxx.delegate =  nil;
 }
  • 如何讓沒有聲明weak屬性的對象寂汇、擁有weak屬性。

weak聲明的對象在runtime布局的時候畅蹂、會被放入一個hash表中健无。
以對象的內(nèi)存地址作為key、本身作為value液斜。
當對象被釋放累贤、再以其地址作為索引去搜索hash表。
找出value少漆、并將其置nil臼膏。
具體實現(xiàn)有空再新開帖補上~

  • ib創(chuàng)建的對象為什么用weak

簡單來講、ib創(chuàng)建的對象在ib中就已經(jīng)被其父view強引用了一次示损。
只要父view沒有被釋放渗磅、其自然不會被釋放。
然后、怎么證明呢始鱼?

  #define TLog(prefix,Obj) {NSLog(@"變量指針:%p,變量值地址:%p, 指向?qū)ο笾担?@, 變量類型:%@--%@",&Obj,Obj,Obj,[Obj class],prefix);}

  @interface ViewController ()
     @property(nonatomic,weak) UIButton *btn;
     @property(nonatomic,weak) UIButton *btn2;
  @end

  @implementation ViewController

  - (void)viewDidLoad {
     [self test];
     TLog(@"btn", _btn);
     TLog(@"btn2", _btn2);
  }

  -(void)test {
     UIButton *button = [[UIButton alloc]init];
     _btn = button;
      [self.view addSubview:_btn];
     UIButton *button2 = [[UIButton alloc]init];
     _btn2 = button2;
  }

我沒有將button2添加到view上仔掸、在出了局部作用域之后、button2被系統(tǒng)釋放医清。_btn2自然也指向空對象起暮。

打印結(jié)果
  變量指針:0x7f8538502600,變量值地址:0x7f8538609af0, 指向?qū)ο笾担?lt;UIButton: 0x7f8538609af0; frame = (0 0; 0 0); opaque = NO; layer = <CALayer: 0x6000000286c0>>, 變量類型:UIButton--btn
  變量指針:0x7f8538502608,變量值地址:0x0, 指向?qū)ο笾担?null), 變量類型:(null)--btn2

  • strong關鍵字

其實strong想不起好說的、因為都用的太熟了~

只有當strong不能滿足我們需求的情況下会烙、才會去用其他的修飾符负懦。
  • 當需要解決循環(huán)引用或者自身已經(jīng)對其有過一次強引用的時候、用weak柏腻。
  • 當NSString纸厉、NSArray、NSDictionary等需要保持自身完整性五嫂、不希望外界修改或者傳進來一個可變類型的時候颗品、用copy。

  • unsafe_unretained關鍵字

我入行的晚沃缘、unsafe_unretained基本沒用過~
只知道是對象版本的assign抛猫。
修飾對象、但不會自動置nil孩灯。
但因為不需要創(chuàng)建hash表檢測對象的存活情況、在明確知曉生命周期的時候逾滥。unsafe_unretained相比weak有一定的性能提升峰档。


  • readonly/readwrite關鍵字

表示屬性的讀寫權(quán)限。
  • readwrite系統(tǒng)會自動合成setter&&getter方法
  • readonly系統(tǒng)則只合成了get方法寨昙。
似乎也沒什么太深的東西讥巡、不過還是有幾點可以提一句的。
  • 如果你自己實現(xiàn)了set/get或者聲明了@dynamic(這個不屬于property舔哪、所以先不寫~大概就是告訴系統(tǒng)不要幫你合成)欢顷。那么系統(tǒng)將不再為你自動合成。
  • readonly雖然不可以直接修改捉蚤、但是可以用KVC修改抬驴。
  • 網(wǎng)上有說KVO無法監(jiān)聽readonly的屬性、但只要你實現(xiàn)了內(nèi)部的set方法缆巧。當對象被釋放的時候布持、你依然可以收到通知。(具體什么時候用呢陕悬、比如單例對象的代理题暖。當外部代理對象釋放、你可以這樣監(jiān)聽。讓自身調(diào)用某個方法)胧卤。

  • getter=/setter=

  • setter= 重寫set聲明唯绍。沒見誰用...如果哪位大佬有實用的地方、可以告訴小弟枝誊、不勝感激况芒。
  • setter= 重寫get聲明。起到方便閱讀的作用唄~
    @property (nonatomic, getter=isOn) BOOL on;
    

  • 可選值聲明

nullable侧啼、nonnull牛柒、null_resettable、null_unspecified

這四個聲明是xcode6新出的痊乾、應該是為了迎合swift中的optional皮壁、non-optional吧。方便我們的混編哪审、而且可以讓代碼更加規(guī)范蛾魄、易懂。在發(fā)生了不符合規(guī)定的行為時湿滓、編譯器會發(fā)出警告滴须。(雖然不會崩潰)

  • nullable:可以為空

作為屬性、可以有三種聲明規(guī)范:
// 方式一:
@property (nonatomic, copy, nullable) NSString *name;
// 方式二:
@property (nonatomic, copy) NSString *_Nullable name;
// 方式三:
@property (nonatomic, copy) NSString *__nullable name;

也可以聲明在方法里

- (nullable NSString *)test1 {
    return nil;
}
- (NSString * _Nullable)test2 {
    return nil;
}
- (NSString * __nullable)test3 {
    return nil;
}

規(guī)律就這樣~沒啥必要再總結(jié)下劃線和大小寫了吧叽奥。
效果長這樣:


WechatIMG215.jpeg
  • nonnull:不能為空

和nullable相對扔水、用法相同。

但有一點需要注意朝氓。

oc中的nonnull和swift中的non-optional不同魔市。即使聲明成nonnull、你依然可以讓他為空赵哲。編譯器只會提示警告待德、依舊會通過編譯。


屏幕快照 2017-12-11 下午5.28.55.png
  • null_unspecified不確定是否為空枫夺。

和nonnull/nullable一樣将宪、有三種聲明方法。

  • null_resettable:get:不能返回空, set可以為空

只有一種聲明方法

  @property (nonatomic, copy, null_resettable) NSString *name; 
需要注意的是:如果選用此聲明橡庞、編譯器會提示你自己實現(xiàn)get/set方法去處理nil的情況较坛。

我一般是在懶加載的時候用。你可以把我置nil毙死、但只要你需要我燎潮、我就是在的。(控制器的view也是)

  • NS_ASSUME_NONNULL_BEGIN以及NS_ASSUME_NONNULL_END

在此之間的屬性扼倘、都會被設置為nonnull(非空)

@interface ViewController ()
  NS_ASSUME_NONNULL_BEGIN
  @property (nonatomic,weak) MyObject * obj;
  @property (nonatomic,assign) MyObject * obj2;
  @property(nonatomic,null_unspecified) UIButton *btn;
  @property(nonatomic,weak) UIButton *btn2;
  @property (nonatomic, copy,null_resettable) NSString * name;
  NS_ASSUME_NONNULL_END
@end

  • 結(jié)尾

暫時就能想到這么多關于property的東西确封。如果有問題除呵、歡迎留言。哪里寫的不對更歡迎斧正爪喘。

感謝您的閱讀颜曾、希望我的這篇總結(jié)能起到一些幫助。


最后

本文主要是自己的學習與總結(jié)秉剑。如果文內(nèi)存在紕漏泛豪、萬望留言斧正。如果不吝賜教小弟更加感謝侦鹏。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末诡曙,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子略水,更是在濱河造成了極大的恐慌价卤,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,607評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件渊涝,死亡現(xiàn)場離奇詭異慎璧,居然都是意外死亡,警方通過查閱死者的電腦和手機跨释,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評論 3 395
  • 文/潘曉璐 我一進店門胸私,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人鳖谈,你說我怎么就攤上這事岁疼。” “怎么了缆娃?”我有些...
    開封第一講書人閱讀 164,960評論 0 355
  • 文/不壞的土叔 我叫張陵五续,是天一觀的道長。 經(jīng)常有香客問我龄恋,道長,這世上最難降的妖魔是什么凶伙? 我笑而不...
    開封第一講書人閱讀 58,750評論 1 294
  • 正文 為了忘掉前任郭毕,我火速辦了婚禮,結(jié)果婚禮上函荣,老公的妹妹穿的比我還像新娘显押。我一直安慰自己,他們只是感情好傻挂,可當我...
    茶點故事閱讀 67,764評論 6 392
  • 文/花漫 我一把揭開白布乘碑。 她就那樣靜靜地躺著,像睡著了一般金拒。 火紅的嫁衣襯著肌膚如雪兽肤。 梳的紋絲不亂的頭發(fā)上套腹,一...
    開封第一講書人閱讀 51,604評論 1 305
  • 那天,我揣著相機與錄音资铡,去河邊找鬼电禀。 笑死,一個胖子當著我的面吹牛笤休,可吹牛的內(nèi)容都是我干的尖飞。 我是一名探鬼主播,決...
    沈念sama閱讀 40,347評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼店雅,長吁一口氣:“原來是場噩夢啊……” “哼政基!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起闹啦,我...
    開封第一講書人閱讀 39,253評論 0 276
  • 序言:老撾萬榮一對情侶失蹤沮明,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后亥揖,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體珊擂,經(jīng)...
    沈念sama閱讀 45,702評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,893評論 3 336
  • 正文 我和宋清朗相戀三年费变,在試婚紗的時候發(fā)現(xiàn)自己被綠了摧扇。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,015評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡挚歧,死狀恐怖扛稽,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情滑负,我是刑警寧澤在张,帶...
    沈念sama閱讀 35,734評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站矮慕,受9級特大地震影響帮匾,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜痴鳄,卻給世界環(huán)境...
    茶點故事閱讀 41,352評論 3 330
  • 文/蒙蒙 一瘟斜、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧痪寻,春花似錦螺句、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至顾画,卻和暖如春取劫,著一層夾襖步出監(jiān)牢的瞬間匆笤,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評論 1 270
  • 我被黑心中介騙來泰國打工勇凭, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留疚膊,地道東北人。 一個月前我還...
    沈念sama閱讀 48,216評論 3 371
  • 正文 我出身青樓虾标,卻偏偏與公主長得像寓盗,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子璧函,可洞房花燭夜當晚...
    茶點故事閱讀 44,969評論 2 355

推薦閱讀更多精彩內(nèi)容