1. 程式人生 > >知識點:可變陣列的屬性使用copy修飾的後果

知識點:可變陣列的屬性使用copy修飾的後果

問題

視訊What's New in LLVM 中,從12:05的時間開始有個關於NSMutableArray可變陣列屬性的使用問題。


執行後報錯圖如下:

分析

self.photos的實際型別是 __NSMutable0,也就NSArray型別。沒有addObject的方法。

進一步探討

  1. OC是門動態型語言,在編譯階段不會做型別檢測。OC的記憶體管理是引用計數,在ARC環境下,屬性@property的記憶體管理語義關鍵字有copy,weak,strong,asssin。在編譯階段,預設情況下編譯器會生成一個成員變數、一個setter方法、一個getter方法。而在setter方法中,會根據記憶體管理語義做相應的引用計數相關的操作。當使用copy修飾屬性時,在setter中實際操作是拷貝了一份不可變的型別物件。這樣的話,即使是其是可變型別,在被賦值後,我們得到的是卻是不可變型別的物件。

  2. 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;
}