//main thread
self.arr = @[@1, @2, @3].mutableCopy;
for (int i = 0; i < _arr.count; i ++) {
NSLog(@"element: %@", _arr[i]);
}
//thread 2
NSMutableArray* localArr = self.arr;
//get result from server
NSArray* results = @[@8, @9, @10];
//refresh local arr
[localArr removeAllObjects];
[localArr addObjectsFromArray:results];
arr初始化之后,以64位系統為例,其實際的內存布局分為三塊:第一塊是指針NSMutableArray* arr所處的位置,為8個字節。第二塊是數組實際的內存區域所處的位置,為連續3個指針地址,各占8個字節一共24個字節。第三塊才是@1,@2,@3這些NSNumber對象真正的內存空間。當我們調用不同的API對arr進行操作的時候,要分清楚實際是在操作哪部分內存。
thread 2這行代碼實際上只是新生成了8個字節的第一類內存空間給localArr,localArr實際上還是和arr共享第二塊和第三塊內存區域,當在thread 2執行[localArr removeAllObjects];清理第二塊內存區域的時候,如果主線程正在同時訪問第二塊內存區域_arr[1],就會導致crash了。這類問題的根本原因,還是在對于同一塊內存區域的同時讀寫。
Swift有COW機制,當賦值時,會新生成一個數組實際的內存區域所處的位置,同時讀寫就不會出現問題
OC沒有COW機制就需要我們自己copy,比如:
NSMutableArray* iterateArr = [self.arr copy];
self.arr = @[@1, @2, @3].mutableCopy;
只要是針對共享數組的操作,時刻記得copy一份新的內存區域,就可以實現手動COW的效果,這樣Objective C也能在維護狀態的時候,是多線程安全的。