copy/strong/weak/__weak/__strong/assign的使用總結(jié)

ARC在編譯期間,根據(jù)Objective-C對象的存活周期绳匀,在適當(dāng)?shù)奈恢锰砑觬etain和release代碼芋忿。從概念上講,ARC與MRC內(nèi)存管理遵循同樣的內(nèi)存管理規(guī)則疾棵,區(qū)別MRC, ARC工作是編譯器完成的, 但是ARC也無法防止循環(huán)強引用戈钢。

ARC還引入了新的修飾符來修飾變量和聲明屬性。

聲明變量的修飾符:__strong, __weak, __unsafe_unretained, __autoreleasing;

聲明屬性的修飾符:strong, weak, unsafe_unretained是尔。

對于線程的安全殉了,有nonatomic,這樣效率就更高了拟枚,但是不是線程的薪铜。如果要線程安全,可以使用atomic恩溅,這樣在訪問是就會有線程鎖痕囱。

記住內(nèi)存管理法則(最重要的一點):誰使對象的引用計數(shù)+1,不再引用時暴匠,誰就負責(zé)將該對象的引用計數(shù)-1(誰引用誰釋放)鞍恢。

下面我們來聲明一個Person類來學(xué)習(xí):

@interface Person : NSObject

// 注意:蘋果有命名規(guī)范的,命名屬性時,不能以copy開頭帮掉。

// 如果下面的屬性聲明為copyString弦悉,會編譯不通過。

@property (nonatomic, copy) NSString *copiedString;

// 默認會是什么呢蟆炊?

@property (nonatomic) NSString *name;

// 默認是strong類型

@property (nonatomic) NSArray *array;

@end

如果屬性沒有指定類型稽莉,默認是strong。如果證明呢涩搓?驗證方法:分別將array屬性的類型分別設(shè)置為weak, assign,strong,不設(shè)置污秆,這四種情況的結(jié)果分別是:第一種打印為空,第二種直接直接崩潰昧甘,第三種和最后一種是可以正常使用良拼。如下面的驗證代碼:

Person *lili = [[Person alloc] init];

lili.name = @"LiLi";

lili.copiedString = @"LiLi\' father is LLL";

lili.array = @[@"謝謝", @"感謝"];

NSArray *otherArray = lili.array;

lili = nil;

NSLog(@"%@", otherArray);

再繼續(xù)添加下面的代碼。默認聲明變量的類型為__strong類型充边,因此上面的NSArray *otherArray = lili.array;與__strong NSArray *otherArray = lili.array;是一樣的庸推。如果我們要使用弱引用,特別是在解決循環(huán)強引用時就特別重要了浇冰。我們可以使用__weak聲明變量為弱引用贬媒,這樣就不會增加引用計數(shù)值。

__strong NSArray *strongArray = otherArray;

otherArray = nil;

// 打印出來正常的結(jié)果肘习。

NSLog(@"strongArray = %@", strongArray);

__weak NSArray * weakArray = strongArray;

strongArray = nil;

// 打印出來:null

NSLog(@"weakArray: %@", weakArray);

xib/storybard連接的對象為什么可以使用weak

@property (nonatomic, weak) IBOutlet UIButton *button;

像上面這行代碼一樣际乘,在連接時自動生成為weak。因為這個button已經(jīng)放到view上了漂佩,因此只要這個View不被釋放脖含,這個button的引用計數(shù)都不會為0,因此這里可以使用weak引用仅仆。

如果我們不使用xib/storyboard器赞,而是使用純代碼創(chuàng)建呢?

@property (nonatomic, weak) UIButton *button;

使用weak時墓拜,由于button在創(chuàng)建時港柜,沒有任何強引用,因此就有可能提前釋放咳榜。Xcode編譯器會告訴我們夏醉,這里不能使用weak。因此我們需要記住涌韩,只要我們在創(chuàng)建以后需要使用它畔柔,我們必須保證至少有一個強引用,否則引用計數(shù)為0臣樱,就會被釋放掉靶擦。對于上面的代碼腮考,就是由于在創(chuàng)建時使用了weak引用,因此button的引用計數(shù)仍然為0玄捕,也就是會被釋放踩蔚,編譯器在編譯時會檢測出來的。

這樣寫枚粘,在創(chuàng)建時通過self.button = ...就是出現(xiàn)錯誤馅闽,因為這是弱引用。所以我們需要聲明為強引用馍迄,也就是這樣:

@property (nonatomic, strong) UIButton *button;

block聲明使用copy

在使用block時福也,盡量使用typedef來起一個別名,這樣更容易閱讀攀圈。使block作為屬性時暴凑,使用copy。

typedef void (^HYBTestBlock)(NSString *name);

@property (nonatomic, copy) HYBTestBlock testBlock;

字符串

對于字符串量承,通常都是使用copy的方式搬设。雖然使用strong似乎也沒有沒有問題穴店,但是事實上在開發(fā)中都會使用copy撕捍。為什么這么做?因為對于字符串泣洞,我們希望是一次內(nèi)容的拷貝忧风,外部修改也不會影響我們的原來的值,而且NSString類遵守了NSCopying, NSMutableCopying, NSSecureCoding協(xié)議球凰。

下面時使用copy的方式狮腿,驗證如下:

NSString *hahaString = @"哈哈";

NSString *heheString = [hahaString copy];

// 哈哈, 哈哈

NSLog(@"%@, %@", hahaString, heheString);

heheString = @"呵呵";

// 哈哈, 呵呵

NSLog(@"%@, %@", hahaString, heheString);

我們修改了heheString,并不會影響到原來的hahaString呕诉。copy一個對象變成新的對象(新內(nèi)存地址) 引用計數(shù)為1 原來對象計數(shù)不變缘厢。

屬性聲明修飾符

屬性聲明修飾符有:strong, weak, unsafe_unretained, readWrite,默認strong, readWrite的甩挫。

strong:strong和retain相似,只要有一個strong指針指向?qū)ο筇颍搶ο缶筒粫讳N毀

weak:聲明為weak的指針,weak指針指向的對象一旦被釋放伊者,weak的指針都將被賦值為nil英遭;

unsafe_unretained:用unsafe_unretained聲明的指針,指針指向的對象一旦被釋放亦渗,這些指針將成為野指針挖诸。

@property (nonatomic, copy) NSString *name;

// 一旦所指向的對象被釋放,就會成為野指針

@property (nonatomic, unsafe_unretained) NSString *unsafeName;

lili.name = @"Lili";

lili.unsafeName = lili.name;

lili.name = nil;

// unsafeName就變成了野指針法精。這里不會崩潰多律,因為為nil.

NSLog(@"%@", lili.unsafeName);

深拷貝與淺拷貝

關(guān)于淺拷貝痴突,簡單來說,就像是人與人的影子一樣狼荞。而深拷貝就像是夢幻西游中的龍宮有很多個長得一樣的龍宮苞也,但是他們都是不同的精靈,因此他們各自都是獨立的粘秆。

我相信還有不少朋友有這樣一種誤解:淺拷貝就是用copy如迟,深拷貝就是用mutableCopy。如果有這樣的誤解攻走,一定要更正過來殷勘。copy只是不可變拷貝,而mutableCopy是可變拷貝昔搂。比如玲销,NSArray *arr = [modelsArray copy],那么arr是不可變的摘符。而NSMutableArray *ma = [modelsArray mutableCopy]贤斜,那么ma是可變的。

lili.array = [@[@"謝謝", @"感謝"] mutableCopy];

NSMutableArray *otherArray = [lili.array copy];

lili.array[0] = @"修改了謝謝";

NSLog(@"%@ %@", otherArray[0], lili.array[0]);

// 打庸淇恪: 謝謝 修改了謝謝

// 說明數(shù)組里面是字符串時瘩绒,直接使用copy是相當(dāng)于深拷貝的。

NSLog(@"%@ %@", otherArray[0], lili.array[0]);

這里就是淺拷貝带族,但是由于數(shù)組中的元素都是字符串锁荔,因此不會影響原來的值。

數(shù)組中是對象時:

NSMutableArray *personArray = [[NSMutableArray alloc] init];

Person *person1 = [[Person alloc] init];

person1.name = @"lili";

[personArray addObject:person1];

Person *person2 = [[Person alloc] init];

person2.name = @"lisa";

[personArray addObject:person2];

// 淺拷貝

NSArray *newArray = [personArray copy];

Person *p = newArray[0];

p.name = @"lili的名字被修改了";

// 打印結(jié)果:lili的名字被修改了

// 說明這邊修改了蝙砌,原來的數(shù)組對象的值也被修改了阳堕。雖然newArray和personArray不是同一個數(shù)組,不是同一塊內(nèi)存择克,

// 但是實際上兩個數(shù)組的元素都是指向同一塊內(nèi)存恬总。

NSLog(@"%@", ((Person *)(personArray[0])).name);

深拷貝,其實就是對數(shù)組中的所有對象都創(chuàng)建一個新的對象:

NSMutableArray *personArray = [[NSMutableArray alloc] init];

Person *person1 = [[Person alloc] init];

person1.name = @"lili";

[personArray addObject:person1];

Person *person2 = [[Person alloc] init];

person2.name = @"lisa";

[personArray addObject:person2];

// 深拷貝

NSMutableArray *newArray = [[NSMutableArray alloc] init];

for (Person *p in personArray) {

Person *newPerson = [[Person alloc] init];

newPerson.name = p.name;

[newArray addObject:newPerson];

}

Person *p = newArray[0];

p.name = @"lili的名字被修改了";

// 打印結(jié)果:lili

NSLog(@"%@", ((Person *)(personArray[0])).name);

Getter/Setter

在ARC下肚邢,getter/setter的寫法與MRC的不同了壹堰。我面試過一些朋友,筆試這關(guān)就寫得很糟(不包括算法)道偷。通常在筆試時都會讓重寫一個屬性的Getter/Setter方法缀旁。

@property (nonatomic, strong) NSMutableArray *array;

- (void)setArray:(NSMutableArray *)array {

if (_array != array) {

_array = nil;

_array = array;

}

}

如果是要重寫getter就去呢?就得增加一個變量了勺鸦,如果同時重寫getter/setter方法并巍,就不會自動生成_array變量,因此我們可以聲明一個變量為_array:

- (void)setArray:(NSMutableArray *)array {

if (_array != array) {

_array = nil;

_array = array;

}

}

- (NSMutableArray *)array {

return _array;

}

總結(jié)

關(guān)于屬性的這些選項的學(xué)習(xí)换途,做一下總結(jié):

所有的屬性,都盡可能使用nonatomic,以提高效率录语,除非真的有必要考慮線程安全蜓萄。

NSString:通常都使用copy牙咏,以得到新的內(nèi)存分配,而不只是原來的引用。

strong:對于繼承于NSObject類型的對象,若要聲明為強使用摹恰,使用strong,若要使用弱引用怒见,使用__weak來引用俗慈,用于解決循環(huán)強引用的問題。

(對于數(shù)組, 字典, 集合, 字符串來說, 可變用strong修飾, 不可變用copy修飾)

weak:對于xib上的控件引用遣耍,可以使用weak闺阱,也可以使用strong。

__weak:對于變量的聲明舵变,如果要使用弱引用酣溃,可以使用__weak,如:__weak typeof(Model) weakModel = model;就可以直接使用weakModel了纪隙。

__strong:對于變量的聲明赊豌,如果要使用強引用,可以使用__strong瘫拣,默認就是__strong亿絮,因此不寫與寫__strong聲明都是一樣的告喊。

unsafe_unretained:這個是比較少用的麸拄,幾乎沒有使用到。在所引用的對象被釋放后黔姜,該指針就成了野指針拢切,不好控制。

__unsafe_unretained:也是很少使用秆吵。同上淮椰。

__autoreleasing:如果要在循環(huán)過程中就釋放,可以手動使用__autoreleasing來聲明將之放到自動釋放池纳寂。


參考資料

http://www.reibang.com/p/c16467bbedc1

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末主穗,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子毙芜,更是在濱河造成了極大的恐慌忽媒,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件腋粥,死亡現(xiàn)場離奇詭異晦雨,居然都是意外死亡架曹,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進店門闹瞧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來绑雄,“玉大人,你說我怎么就攤上這事奥邮⊥蛭” “怎么了?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵洽腺,是天一觀的道長杏愤。 經(jīng)常有香客問我,道長已脓,這世上最難降的妖魔是什么珊楼? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮度液,結(jié)果婚禮上厕宗,老公的妹妹穿的比我還像新娘。我一直安慰自己堕担,他們只是感情好已慢,可當(dāng)我...
    茶點故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著霹购,像睡著了一般佑惠。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上齐疙,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天膜楷,我揣著相機與錄音,去河邊找鬼贞奋。 笑死赌厅,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的轿塔。 我是一名探鬼主播特愿,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼勾缭!你這毒婦竟也來了揍障?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤俩由,失蹤者是張志新(化名)和其女友劉穎毒嫡,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體采驻,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡审胚,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年匈勋,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片膳叨。...
    茶點故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡洽洁,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出菲嘴,到底是詐尸還是另有隱情饿自,我是刑警寧澤,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布龄坪,位于F島的核電站昭雌,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏健田。R本人自食惡果不足惜烛卧,卻給世界環(huán)境...
    茶點故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望妓局。 院中可真熱鬧总放,春花似錦、人聲如沸好爬。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽存炮。三九已至炬搭,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間穆桂,已是汗流浹背宫盔。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留充尉,地道東北人飘言。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像驼侠,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子谆吴,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,044評論 2 355

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