知識點:可變陣列的屬性使用copy修飾的後果
阿新 • • 發佈:2018-11-16
問題
視訊What's New in LLVM 中,從12:05的時間開始有個關於NSMutableArray可變陣列屬性的使用問題。
執行後報錯圖如下:
分析
self.photos的實際型別是 __NSMutable0,也就NSArray型別。沒有addObject的方法。
進一步探討
OC是門動態型語言,在編譯階段不會做型別檢測。OC的記憶體管理是引用計數,在ARC環境下,屬性@property的記憶體管理語義關鍵字有copy,weak,strong,asssin。在編譯階段,預設情況下編譯器會生成一個成員變數、一個setter方法、一個getter方法。而在setter方法中,會根據記憶體管理語義做相應的引用計數相關的操作。當使用copy修飾屬性時,在setter中實際操作是拷貝了一份不可變的型別物件。這樣的話,即使是其是可變型別,在被賦值後,我們得到的是卻是不可變型別的物件。
OC具有多型性,父類可以指向子類。物件最終型別會在執行期根據例項化物件確認。在執行時階段其isa指向的是[NSArray Class]。那麼當向self.photos傳送一個addObject訊息時,self.photos物件是接收不到這個訊息的。因為addObject是NSArray的子類NSMutbleArray的方法。
實際編譯器新增setter方法如下:
// ARC
- (void)setPhotos:(NSMutableArray<UIImage *> *)photos{
_photos = [photos copy];
}
那麼得到的是個self.Photos實際是NSArray類。
解決
方式一:
手動重寫setter方法,使用賦值前mutableCopy。如下,這樣獲取到的就是NSMutableArray型別的物件。
- (void)setPhotos:(NSMutableArray<UIImage *> *)photos{
_photos = [photos mutableCopy];
}
方式二:
使用關鍵字strong
修飾屬性。我們得到的依然是可變型別。
- (void)setPhotos:(NSMutableArray<UIImage *> *)photos{
_photos = photos;
}