線程安全的NSMutableArray
NSMutableArray本身是線程不安全的生均。多線程訪問(wèn)NSMutableArray 會(huì)出現(xiàn)異常和Crash
一、不能使用atomic 修飾屬性
原因:atomic 的內(nèi)存管理語(yǔ)義是原子性的,僅保證了屬性的setter和getter方法是原子性的感昼,是線程安全的赡矢,但是屬性的其他方法,不能保證線程安全饱须。同時(shí)atomic 效率低域醇,編程時(shí)慎用。
二蓉媳、打造線程安全的NSMutableArray
1譬挚、讀寫(xiě)數(shù)組時(shí)加鎖
2、讀寫(xiě)數(shù)組放到串行隊(duì)列中酪呻。
3减宣、使用并發(fā)隊(duì)列,結(jié)合GCD的攔珊塊(barrier)來(lái)實(shí)現(xiàn)線程同步玩荠。
第三種實(shí)現(xiàn)方式:
@interface QSThreadSafeMutableArray : NSMutableArray
@end
//QSThreadSafeMutableArray.m
#import "QSThreadSafeMutableArray.h"
@interface QSThreadSafeMutableArray()
@property (nonatomic, strong) dispatch_queue_t syncQueue;
@property (nonatomic, strong) NSMutableArray* array;
@end
@implementation QSThreadSafeMutableArray
#pragma mark - init 方法
- (instancetype)initCommon{
self = [super init];
if (self) {
//%p 以16進(jìn)制的形式輸出內(nèi)存地址漆腌,附加前綴0x
NSString* uuid = [NSString stringWithFormat:@"com.jzp.array_%p", self];
//注意:_syncQueue是并行隊(duì)列
_syncQueue = dispatch_queue_create([uuid UTF8String], DISPATCH_QUEUE_CONCURRENT);
}
return self;
}
- (instancetype)init{
self = [self initCommon];
if (self) {
_array = [NSMutableArray array];
}
return self;
}
//其他init方法略
#pragma mark - 數(shù)據(jù)操作方法 (凡涉及更改數(shù)組中元素的操作,使用異步派發(fā)+柵欄塊阶冈;讀取數(shù)據(jù)使用 同步派發(fā)+并行隊(duì)列)
- (NSUInteger)count{
__block NSUInteger count;
dispatch_sync(_syncQueue, ^{
count = _array.count;
});
return count;
}
- (id)objectAtIndex:(NSUInteger)index{
__block id obj;
dispatch_sync(_syncQueue, ^{
if (index < [_array count]) {
obj = _array[index];
}
});
return obj;
}
- (NSEnumerator *)objectEnumerator{
__block NSEnumerator *enu;
dispatch_sync(_syncQueue, ^{
enu = [_array objectEnumerator];
});
return enu;
}
- (void)insertObject:(id)anObject atIndex:(NSUInteger)index{
dispatch_barrier_async(_syncQueue, ^{
if (anObject && index < [_array count]) {
[_array insertObject:anObject atIndex:index];
}
});
}
- (void)addObject:(id)anObject{
dispatch_barrier_async(_syncQueue, ^{
if(anObject){
[_array addObject:anObject];
}
});
}
- (void)removeObjectAtIndex:(NSUInteger)index{
dispatch_barrier_async(_syncQueue, ^{
if (index < [_array count]) {
[_array removeObjectAtIndex:index];
}
});
}
- (void)removeLastObject{
dispatch_barrier_async(_syncQueue, ^{
[_array removeLastObject];
});
}
- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject{
dispatch_barrier_async(_syncQueue, ^{
if (anObject && index < [_array count]) {
[_array replaceObjectAtIndex:index withObject:anObject];
}
});
}
- (NSUInteger)indexOfObject:(id)anObject{
__block NSUInteger index = NSNotFound;
dispatch_sync(_syncQueue, ^{
for (int i = 0; i < [_array count]; i ++) {
if ([_array objectAtIndex:i] == anObject) {
index = i;
break;
}
}
});
return index;
}
- (void)dealloc{
if (_syncQueue) {
_syncQueue = NULL;
}
}
@end
參考:
NSMutableArray使用中忽視的問(wèn)題
dispatch_async與dispatch_sync區(qū)別
GCD有關(guān)問(wèn)題:dispatch_sync(dispatch_get_main_queue(), ^{NSLog(@"Hello ?");}); 死鎖的原因
dispatch_barrier_sync 和dispatch_barrier_async的區(qū)別
iOS多線程-GCD之串行隊(duì)列和并行隊(duì)列