ios中屬性修飾符的作用

屬性修飾符簡述

ios5之前是MRC,內(nèi)存需要程序員進行管理重罪,ios5之后是ARC哀九,除非特殊情況勾栗,比如C框架或者循環(huán)引用围俘,其他時候是不需要程序員手動管理內(nèi)存的琢融。
? ios中當我們定義屬性@property的時候就需要屬性修飾符漾抬,下面我們就看一下不同屬性修飾符的作用纳令。有錯誤和不足的地方還請大家諒解并批評指正。

主要的屬性修飾符有下面幾種:

  • copy
  • assign
  • retain
  • strong
  • weak
  • readwrite/readonly (讀寫策略圈匆、訪問權限)
  • nonatomic/atomic (安全策略)

如果以MRC和ARC進行區(qū)分修飾符使用情況跃赚,可以按照如下方式進行分組:

 1. MRC: assign/ retain/ copy/  readwrite纬傲、readonly/ nonatomic肤频、atomic  等。
 2. ARC: assign/ strong/ weak/ copy/ readwrite汁雷、readonly/ nonatomic摔竿、atomic  等继低。

屬性修飾符對retainCount計數(shù)的影響稍走。

  1. alloc為對象分配內(nèi)存,retainCount 為1 粱胜。
  2. retain MRC下 retainCount + 1焙压。
  3. copy 一個對象變成新的對象,retainCount為 1野哭, 原有的對象計數(shù)不變拨黔。
  4. release 對象的引用計數(shù) -1绰沥。
  5. autorelease 對象的引用計數(shù) retainCount - 1,如果為0零截,等到最近一個pool結束時釋放疟位。

不管MRC還是ARC甜刻,其實都是看reference count是否為0得院,如果為0那么該對象就被釋放章贞,不同的地方是MRC需要程序員自己主動去添加retain 和 release鸭限,而ARC apple已經(jīng)給大家做好,自動的在合適的地方插入retain 和 release類似的內(nèi)存管理代碼兜喻,具體原理如下朴皆,圖片摘自官方文檔。

MRC 和 ARC原理

下面就詳述上所列的幾種屬性修飾符的使用場景肮疗,應用舉例和注意事項伪货。

屬性修飾符詳述

一超歌、copy

使用場景

  1. 一般情況下巍举,copy可以用于對不可變?nèi)菀椎膶傩孕揎椫邪妹酰饕荖SArray /NSDictionary/NSString梦皮, 也可以用來修飾block剑肯。
  2. 在MRC和ARC下都可以使用。
  3. 其setter方法呀忧,與retain處理流程一樣而账,先舊值release因篇,再copy出新的對象竞滓。

應用舉例

@property (nonatomic, copy) NSString* name;
@property (nonatomic, copy) void(^typeBlock)(BOOL selected);
@property (nonatomic, copy) void(^cancelBlock)();

注意事項

  1. 要注意的就是深淺拷貝商佑,這個也是使用copy這個屬性修飾符最重要的地方莉御,這以后會在另一篇文章里面單獨講。
  2. MRC 和 ARC 都可以用copy牍颈。
  3. copy下的setter方法煮岁。
-(void)setName: (id)newName {
      if (name != newName) {
        [name release];
        name = [newName copy];
     }
}
  1. 用copy修飾block時在MRC和ARC下的區(qū)別
  • MRC環(huán)境下
    (1)block訪問外部局部變量画机,block存放在棧里面步氏。
    (2)只要block訪問整個app都存在的變量,那么肯定是在全局區(qū)芋类。
    (3)不能使用retain引用block侯繁,因為block不在堆區(qū)里面贮竟,只有使用copy才會把block放在堆區(qū)里面咕别。

  • ARC環(huán)境下
    (1)只要block訪問外部局部變量重付,block就會存放在堆區(qū)顷级。
    (2)可以使用strong去引用凫乖,因為本身就已經(jīng)存放在堆區(qū)了确垫。
    (3)也可以使用copy進行修飾,但是strong性能更好帽芽。

  1. 當使用block的時候注意循環(huán)引用删掀,引起內(nèi)存無法釋放,造成內(nèi)存泄漏导街。

AddSignHeaderView.h文件中定義block
@property (nonatomic, copy) void (^addMembersBtnOnClick)();

AddSignViewController.m文件中調用block

// 懶加載控件
- (AddSignHeaderView *)headerView {
    if (!_headerView) {
        _headerView = [[AddSignHeaderView alloc] initWithFrame:CGRectMake(0, 0, ScreenWidth, 170)];
    }
    return _headerView;
}

// 調用block
-(void) viewDidLoad {
    __weak typeof(self) weakSelf = self;
    self.headerView.addMembersBtnOnClick = ^() {
        AddSignContactsSelectVC *addSign = [[AddSignContactsSelectVC alloc] initWithBlockSelectedUsernames:weakSelf.contactsSource];
        addSign.hidesBottomBarWhenPushed = YES;
        addSign.title = @"選擇聯(lián)系人";
        addSign.delegate = weakSelf;
        [weakSelf.navigationController pushViewController:addSign animated:YES];
    };
}

下面說一下披泪,為什么會引起循環(huán)引用搬瑰?
? ?從上面我們可以看到,controller引用了headerView卡乾,headerView里面擁有block屬性,在執(zhí)行block時候误堡,又引用了self,這就造成了循環(huán)引用,相互引用造成循環(huán)引用基跑,內(nèi)存泄漏,如下圖所示篱竭。

block造成循環(huán)引用

想解決循環(huán)引用的問題瓤介,就是打破這個引用循環(huán)氯质。將self進行弱化__weak typeof(self) weakSelf = self,如下圖所示呢灶。

打破block的循環(huán)引用

二、assign

使用場景

  1. 在MRC 和 ARC下都可以使用。
  2. 一般用來修飾基礎數(shù)據(jù)類型(NSInteger, CGFloat) 和 C數(shù)據(jù)類型(int ,float, double)等宏蛉。它的setter方法直接賦值,不進行任何retain操作。

應用舉例

@property (nonatomic, assign) NSInteger  studentNum;
@property (nonatomic, assign) CGFloat  cellHeight;

注意事項

  1. MRC 和 ARC 都可以用assign之碗。
  2. assign下的setter方法:
-(void)setName :(id)str
{
        name = str;
}

三、retain

使用場景

  1. 一般情況下博敬,retain用在MRC情況下,被retain修飾的對象,引用計數(shù)retainCount要加1的链沼。
  2. retain只能修飾oc對象曲掰,不能修飾非oc對象乱豆,比如說CoreFoundation對象就是C語言框架,它沒有引用計數(shù),也不能用retain進行修飾岩榆。
  3. retain一般用來修飾非NSString 的NSObject類和其子類折联。

應用舉例

@property (nonatomic, retain) DDDemoObject *modelObject;

注意事項

1. 要注意的就是循環(huán)引用造成的內(nèi)存泄漏,對于兩個對象A和B执赡,如果A對象中引用B對象,并且用retain修飾首懈;B對象中引用A對象脸狸,并且也用retain修飾泥彤。這個時候就是A和B相互引用,無法釋放浙宜,造成內(nèi)存泄漏。

retain MRC循環(huán)引用

如上圖所示鳖轰,A和B相互引用,造成A和B的引用計數(shù)都不為0辱志,無法釋放而留在內(nèi)存中已球,造成內(nèi)存泄漏点待,當這種內(nèi)存泄漏很嚴重時聋呢,會出現(xiàn)閃退等問題瓦呼。
解決辦法:將A和B其中的一端改成assign進行修飾碗啄,打斷這個循環(huán)引用的鏈,就解決了循環(huán)引用的問題。

retain/assign MRC下解除循環(huán)引用

如上圖所示昌讲,由于B引用A的時候用的是assign進行修飾车吹,那么A的引用計數(shù)可以為0乐埠,那么自然就解除了A對B的強引用洞拨,B的retainCount也可以為0烦衣,就解決了內(nèi)存泄漏的問題厨姚。

2. 下面說一下MRC下assign和retain的區(qū)別:assign只是簡單的賦值操 作拭抬,它引用的對象被釋放纷闺,會造成野指針,可能出現(xiàn)crash情況戒努;retain會使對象的retainCount計數(shù)加1储玫,獲得對象的擁有權,只有對象的引用計數(shù)為0的時候才會被釋放,避免訪問一個被釋放的對象蚀同。

3. retain下的setter方法

-(void) setName: (id) nameStr
{
      if (name != nameStr) {
        [name release];
        name = [nameStr retain];
     }
}

四娜睛、strong

使用場景

  1. strong表示對對象的強引用分预。
  2. ARC下也可以用來修飾block酪穿,strong 和 weak兩個修飾符默認是strong经磅。
  3. 用于指針變量元媚,setter方法對參數(shù)進行release舊值再retain新值。

應用舉例

@property (nonatomic, strong) NSArray  *dataArr;
@property (nonatomic, strong) NSMutableArray *btnArray;
@property (nonatomic, strong) UILabel *descLabel;
  //  對于控件也可以用weak屿笼,因為controller已經(jīng)對root view有一個強引用休雌,view addSubview 子控件担扑,所以即使用weak也不會提前釋放。
@property (nonatomic, strong) CompleteDatePicker *preciseDatePicker;
 //  CompleteDatePicker在這里是自定義類轴捎。
@property (nonatomic ,strong) NSString *signupId;
 // 字符串除了用copy,用strong也是可以的穴张。


注意事項

  1. strong修飾的屬性璧瞬,對屬性進行的是強引用渔欢,對象的引用計數(shù)retainCount + 1九榔;
  2. 注意兩個對象之間相互強引用造成循環(huán)引用,內(nèi)存泄漏。

五就漾、weak

使用場景

  1. weak 表示對對象的弱引用呐能,被weak修飾的對象隨時可被系統(tǒng)銷毀和回收。
  2. weak比較常用的地方就是delegate屬性的設置抑堡。
  3. 用weak修飾弱引用摆出,不會使傳入對象的引用計數(shù)加1朗徊。

應用舉例

@protocol DDCollegePickerVCDelegate <NSObject>
- (void)didSelectedCollegePicker:(DDCollegePickerVC *)picker
                       collegeID:(NSString *)collegeID
                     collegeName:(NSString *)collegeName;
@end

@interface DDCollegePickerVC : UIViewController
@property (nonatomic, weak) id <DDCollegePickerVCDelegate> delegate;
@property (nonatomic, weak) UIView *inputView;
@end
 // 上面自定義一個protocol DDCollegePickerVCDelegate,且在interface中將delegate屬性定義為weak偎漫,并且定義了一個inputView的控件荣倾。

注意事項

  1. 下面說一下前面所述的assign和weak的區(qū)別:當它們指向的對象釋放以后,weak會被自動設置為nil骑丸,而assign不會舌仍,所以會導致野指針的出現(xiàn),可能會導致crash通危。
  2. 下面說一下strong和weak的區(qū)別:
  • strong :表明是一個強引用铸豁,相當于MRC下的retain,只要被strong引用的對象就不會被銷毀菊碟,當所有的強引用消除時节芥,對象的引用計數(shù)為0時,對象才會被銷毀逆害。
  • weak : 表明是一個弱引用头镊,相當于MRC下的assign,不會使對象的引用計數(shù)+1魄幕。
  1. 兩個不同對象相互strong引用對象相艇,會導致循環(huán)引用造成對象不能釋放,造成內(nèi)存泄漏纯陨。

六坛芽、readwrite/readonly

使用場景

1. 當我們用readwrite修飾的時候表示該屬性可讀可改,用readonly修飾的時候表示這個屬性只可以讀取翼抠,不可以修改咙轩,一般常用在我們不希望外界改變只希望外界讀取這種情況。
2. readwrite 程序自動創(chuàng)建setter/getter方法阴颖,readonly 程序創(chuàng)建getter方法活喊。此外還可以自定義setter/getter方法。
3. 系統(tǒng)默認的情況就是 readwrite量愧。

應用舉例

1. 一般我們封裝屬性只希望外界能看到钾菊,自己能夠修改的時候,在.h文件里用readonly修飾侠畔,在.m文件里面用readwrite修飾结缚。

h文件readonly
m文件readwrite

由上兩圖可知,m文件內(nèi)部readwrite修飾屬性cityName软棺,可以修改屬性值红竭,h文件暴露在外面的是onlyread屬性,這樣外面只能讀取不能修改該屬性值。

注意事項

1. 當希望外界能讀取我們這個屬性茵宪,但是不希望被外界改變的時候就用readonly最冰。


七、nonatomic/atomic

使用場景

1. nonatomic 非原子屬性稀火。它的特點是多線程并發(fā)訪問性能高暖哨,但是訪問不安全;與之相對的就是atomic凰狞,特點就是安全但是是以耗費系統(tǒng)資源為代價篇裁,所以一般在工程開發(fā)中用nonatomic的時候比較多。
2. 系統(tǒng)默認的是atomic赡若,為setter方法加鎖达布,而nonatomic 不為setter方法加鎖。
3. 如1所述逾冬,使用nonatomic要注意多線程間通信的線程安全黍聂。

應用舉例

// 這個例子就比較多了,基本上我們項目中都用nonatomic身腻,雖然setter方法不安全但是性能高产还。

@property (nonatomic, strong) UIImage *imagePicture;
@property (nonatomic, strong) UIImageView *pictureLinkView;
@property (nonatomic, strong) UILabel *labelLocation;
@property (nonatomic, strong) UILabel *labelCreateTime;
@property (nonatomic, strong) UIButton *btnDelete;
@property (nonatomic, strong) UIButton *btnInteract;
@property (nonatomic, strong) DDCommentMenuView *menuView;
@property (nonatomic, strong) DDShareLinkView *shareLinkView;

上面舉了幾個例子,實際上很多嘀趟,具體工程中都用nonatomic脐区,所以大家就不用糾結這兩個修飾符到底用哪一個了。

注意事項

1. 為了提高性能去件,一般我們就用nonatomic坡椒。所以對這個屬性修飾符我們可以不必過于糾結。
2. 注意atomic設置成員變量的@property屬性尤溜,提供多線程安全。在多線程中汗唱,原子操作是必須的宫莱。加入atomic屬性修飾符以后,setter函數(shù)會變成下面這樣:

{lock}
    if (property != newValue) {
         [property release];
         property = [newValue retain];
     }
{unlock}

之所以這么做哩罪,是因為防止在寫未完成的時候被另外一個線程讀取授霸,造成數(shù)據(jù)錯誤。
3. 下面說一下為什么nonatomic要比atomic快际插。原因是:它直接訪問內(nèi)存中的地址碘耳,不關心其他線程是否在改變這個值,并且中間沒有死鎖保護框弛,它只需直接從內(nèi)存中訪問到當前內(nèi)存地址中能用到的數(shù)據(jù)即可(可以理解為getter方法一直可以返回數(shù)值辛辨,盡管這個數(shù)值在cpu中可能正在修改中)
4. 不要誤認為多線程下加atomic是安全的,這樣理解是不正確的,說明理解的不夠深入斗搞。atomic的安全只是在getter和setter方法的時候是原子操作指攒,是安全的。但是其他方面是不在atomic管理范圍之內(nèi)的僻焚,例如變量cnt的++運算允悦。這個時候不能保證安全。

@property  int cnt;
    @synthesize cnt = _cnt;
    self.cnt = 0;
    for (i = 0; i < n; i++) {
      self.cnt ++;
    }

這里線程就不是安全的虑啤,想要線程安全就得加鎖隙弛,加鎖的技術以后會專門寫一篇文章。


致謝

文章雖然很簡單狞山,但是時間倉促難免有所紕漏全闷,有錯誤的地方敬請指正,希望可以相互學習铣墨,共同進步室埋,同時謝謝朋友和同事的關心。

參考資料和相關博客

  1. Objective-C——retain/copy/assign/atomic/nonatomic/strong/weak/readonly/readwrite詳解

  2. 整理一下OC中的那些屬性修飾符 --iOS小孟和小夢

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末伊约,一起剝皮案震驚了整個濱河市姚淆,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌屡律,老刑警劉巖腌逢,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異超埋,居然都是意外死亡搏讶,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進店門霍殴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來媒惕,“玉大人,你說我怎么就攤上這事来庭《饰担” “怎么了?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵月弛,是天一觀的道長肴盏。 經(jīng)常有香客問我,道長帽衙,這世上最難降的妖魔是什么菜皂? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮厉萝,結果婚禮上恍飘,老公的妹妹穿的比我還像新娘榨崩。我一直安慰自己,他們只是感情好常侣,可當我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布蜡饵。 她就那樣靜靜地躺著,像睡著了一般胳施。 火紅的嫁衣襯著肌膚如雪溯祸。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天舞肆,我揣著相機與錄音焦辅,去河邊找鬼。 笑死椿胯,一個胖子當著我的面吹牛筷登,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播哩盲,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼前方,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了廉油?” 一聲冷哼從身側響起惠险,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎抒线,沒想到半個月后班巩,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡嘶炭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年抱慌,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片眨猎。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡抑进,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出睡陪,到底是詐尸還是另有隱情单匣,我是刑警寧澤,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布宝穗,位于F島的核電站,受9級特大地震影響码秉,放射性物質發(fā)生泄漏逮矛。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一转砖、第九天 我趴在偏房一處隱蔽的房頂上張望须鼎。 院中可真熱鬧鲸伴,春花似錦、人聲如沸晋控。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽赡译。三九已至仲吏,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蝌焚,已是汗流浹背裹唆。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留只洒,地道東北人许帐。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像毕谴,于是被迫代替她去往敵國和親成畦。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,877評論 2 345

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