iOS如何實現一個線程安全的 NSMutableArray?

NSMutableArray是線程不安全的,當有多個線程同時對數組進行操作的時候可能導致崩潰或數據錯誤

線程鎖:使用線程鎖對數組讀寫時進行加鎖

派發(fā)隊列:在《Effective Objective-C 2.0..》書中第41條:多用派發(fā)隊列,少用同步鎖中指出:使用“串行同步隊列”(serial synchronization queue),將讀取操作及寫入操作都安排在同一個隊列里,即可保證數據同步。而通過并發(fā)隊列,結合GCD的柵欄塊(barrier)來不僅實現數據同步線程安全,還比串行同步隊列方式更高效。

方案二
iOS-SDK只提供了非線程安全的數組。如果要多線程并發(fā)的使用一個數組對象就必須要加鎖,頻繁的加鎖使得代碼的調用非常的麻煩。

我們需要多線程的讀寫鎖在類的內部實現,所以需要對NSMutableArray進行封裝,封裝后的對象負責接受所有事件并將其轉發(fā)給真正的NSMutableArray對象,并通過合理的調度使得其支持多線程并發(fā)。

1 新建一個對象來對NSMutableArray 數組進行封裝,包含

dispatch_queue_t 調度隊列對象 和一個

NSObject 具體操作對象作為成員變量

并且初始化操作對象

- (id)init {
  self = [super init];
  if (self) {
    self.container = [NSMutableArray array];
   }
   return self;
}

2.回到JXMultiThreadObject類中 利用下面方法對一個對象無法實現的方法進行攔截和派發(fā)

- (void)forwardInvocation:(NSInvocation *)anInvocation {
}

該方法當你調用了一個對象沒有實現的方法時,forwardInvocation方法將會響應,并讓你覺得這個方法的處理方式,

在這之前你需要先實現

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
   return [[_container class] instanceMethodSignatureForSelector:aSelector];
}

才能激活forwardInvocation

3.這里利用到G-C-D的調度機制對對象和對象的行為進行調度

- (void)forwardInvocation:(NSInvocation *)anInvocation {
    dispatch_barrier_sync(_dispatchQueue, ^{
        [anInvocation invokeWithTarget:_container];
    });
}

這里使用了同步的阻塞調度,屬于效率比較低的一種調度方式,可以簡單地作一下優(yōu)化

- (void)forwardInvocation:(NSInvocation *)anInvocation {
NSMethodSignature *sig = [anInvocation valueForKey:@"_signature"];
const char *returnType = sig.methodReturnType;
if (!strcmp(returnType, "v")) {
    dispatch_barrier_async(_dispatchQueue, ^{
        [anInvocation invokeWithTarget:_container];
    });
}
else {
    dispatch_barrier_sync(_dispatchQueue, ^{
        [anInvocation invokeWithTarget:_container];
    });
}

}
獲取調度方法的返回值,如果是void型方法則使用異步調度,如果是getter類型的則使用同步調度,可以略微的提升性能。

你可以通過繼承等方法為不同類型的container指定不同的調度規(guī)則以確保在邏輯正常的情況下擁有最高的性能。

?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容