iOS只提供了非執行緒安全的陣列。 如果要多執行緒併發的使用一個陣列物件就必須要加鎖,頻繁加鎖使程式碼的呼叫非常的麻煩。
我們需要多執行緒的讀寫鎖在類的內部實現,所以需要對NSMutableArray進行封裝,封裝後的物件負責接受所有事件並將其轉發給真正的NSMutableArray物件,並通過合理的排程使得其支援多執行緒併發。
新建一個物件來對NSMutableArray 陣列進行封裝,包含 dispatch_queue_t 排程佇列物件 和一個 NSObject 具體操作物件作為成員變數
@implementation MultiThreadSafeObject
- (id)init
{
self = [super init];
if (self)
{
_mtsDispatchQueue = dispatch_queue_create("COM.MTS.MultiThreadSafeObject", NULL);
}
return self;
}
- (void)dealloc
{
_mtsDispatchQueue = nil;
_mtsContainer = nil;
}
複製程式碼
我們再新建mtsMutableArray類繼承自MultiThreadSafeObject併為其宣告簡單介面來支援其作為Array使用
#import "MultiThreadSafeObject.h"
@protocol mtsMutableArrayProtocol
@optional
- (id)lastObject;
- (id)objectAtIndex:(NSUInteger)index;
- (NSUInteger)count;
- (void)addObject:(id)anObject;
- (void)insertObject:(id)anObject atIndex:(NSUInteger)index;
- (void)removeLastObject;
- (void)removeObjectAtIndex:(NSUInteger)index;
- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject;
@end
@interface mtsMutableArray : MultiThreadSafeObject<mtsMutableArrayProtocol>
@end
複製程式碼
使用訊息轉發
#pragma mark - public method
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
return [[_mtsContainer class] instanceMethodSignatureForSelector:aSelector];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
NSMethodSignature *sig = [anInvocation valueForKey:@"_signature"];
const char *returnType = sig.methodReturnType;
//NSLog(@"%@ = > %@",anInvocation.target, NSStringFromSelector(anInvocation.selector));
//NSLog(@"%s",returnType);
if (!strcmp(returnType, "v"))
{
//沒有返回值 setter方法 非同步barrier
/** the setter method just use async dispatch
remove the barrier to make it faster when u r sure that invacations will not affect each other
*/
dispatch_barrier_async(_mtsDispatchQueue, ^{
[anInvocation invokeWithTarget:_mtsContainer];
});
}
else
{
//有返回值 getter方法 同步barrier
/** all getter method need sync dispatch
barrier make sure the result is correct
getter method need barrier in most ways unless u dont except this */
dispatch_barrier_sync(_mtsDispatchQueue, ^{
[anInvocation invokeWithTarget:_mtsContainer];
});
}
}
複製程式碼
獲取排程方法的返回值,如果是void型方法則使用非同步排程,如果是getter型別的則使用同步排程,可以略微的提升效能。
可以通過繼承等方法為不同型別的container指定不同的排程規則以確保在邏輯正常的情況下擁有最高的效能。