問題
視頻What's New in LLVM
中,從12:05的時(shí)間開始有個(gè)關(guān)于NSMutableArray可變數(shù)組屬性的使用問題裕便。
運(yùn)行后報(bào)錯(cuò)圖如下:
分析
self.photos的實(shí)際類型是 __NSMutable0,也就NSArray類型。沒有addObject的方法餐抢。
進(jìn)一步探討
OC是門動(dòng)態(tài)型語言,在編譯階段不會(huì)做類型檢測低匙。OC的內(nèi)存管理是引用計(jì)數(shù)旷痕,在ARC環(huán)境下,屬性@property的內(nèi)存管理語義關(guān)鍵字有copy,weak,strong,asssin顽冶。在編譯階段欺抗,默認(rèn)情況下編譯器會(huì)生成一個(gè)成員變量、一個(gè)setter方法强重、一個(gè)getter方法绞呈。而在setter方法中贸人,會(huì)根據(jù)內(nèi)存管理語義做相應(yīng)的引用計(jì)數(shù)相關(guān)的操作。當(dāng)使用copy修飾屬性時(shí)佃声,在setter中實(shí)際操作是拷貝了一份不可變的類型對象艺智。這樣的話,即使是其是可變類型圾亏,在被賦值后十拣,我們得到的是卻是不可變類型的對象。
OC具有多態(tài)性志鹃,父類可以指向子類夭问。對象最終類型會(huì)在運(yùn)行期根據(jù)實(shí)例化對象確認(rèn)。在運(yùn)行時(shí)階段其isa指向的是[NSArray Class]曹铃。那么當(dāng)向self.photos發(fā)送一個(gè)addObject消息時(shí)缰趋,self.photos對象是接收不到這個(gè)消息的。因?yàn)閍ddObject是NSArray的子類NSMutbleArray的方法陕见。
屬性語義多種:
- 原子性(Atomicity):原子性(atomic)埠胖、非原子性(nonatomic)
- Setter語義(Setter Semantics):strong,weak,copy,asssin
- 讀寫屬性(Writability): readwrite/readonly
原子性是具有線程安全的,會(huì)在屬性的setter方法內(nèi)部加個(gè)一個(gè)自旋鎖淳玩、而非原子性是不會(huì)在setter方法中加鎖的,是非線程安全的非竿。在小型設(shè)備的上蜕着,內(nèi)存空間是有限的。給屬性加自旋鎖是非常消耗資源的红柱。并且不一定說使用了原子性就能保證該屬性線程安全承匣。這個(gè)僅僅是在setter方法中是安全的,這也是atomic該做的事锤悄。如果繞開setter方法使用其他的方式給屬性賦值韧骗,依然是不安全的,比如使用KVC零聚。
- ARC下袍暴,屬性的默認(rèn)語義是:
- 基本數(shù)據(jù):atomic、assgin隶症、readwrite
- 普通的OC對象:atomic政模、strong、readwrite
在此情況下蚂会,實(shí)際編譯器添加setter方法如下:
// ARC
- (void)setPhotos:(NSMutableArray<UIImage *> *)photos{
// 1. 開始加鎖淋样,非自然語言,這里不寫代碼了
_photos = [photos copy];
// 2. 加鎖結(jié)束
}
那么得到的是個(gè)self.photos實(shí)際是NSArray類胁住。
從上就發(fā)現(xiàn)了2個(gè)問題:屬性就是使用了關(guān)鍵字atomic趁猴、copy修飾刊咳。那么這里會(huì)加鎖并且得到NSArray類的self.photos。
相關(guān)概念:
- 自旋鎖:當(dāng)上一個(gè)線程的任務(wù)沒有執(zhí)行完畢的時(shí)候(被鎖桌芩尽)娱挨,那么下一個(gè)線程會(huì)一直等待(不會(huì)睡眠),當(dāng)上一個(gè)線程的任務(wù)執(zhí)行完畢枫慷,下一個(gè)線程會(huì)立即執(zhí)行让蕾。
- 自旋鎖應(yīng)用場景:
比較適合做一些不耗時(shí)的操作
解決
1、修改copy語義在setter中默認(rèn)內(nèi)容:
方式一:
手動(dòng)重寫setter方法或听,使用賦值前mutableCopy探孝。如下,這樣獲取到的就是NSMutableArray類型的對象誉裆。
- (void)setPhotos:(NSMutableArray<UIImage *> *)photos{
_photos = [photos mutableCopy];
}
方式二:
使用關(guān)鍵字strong
修飾屬性顿颅。我們得到的依然是可變類型。
- (void)setPhotos:(NSMutableArray<UIImage *> *)photos{
_photos = photos;
}
2足丢、原子性修改:
使用:nonatomic粱腻,減少小型設(shè)備中性能消耗。