iOS 多线程安全数组

 iOS-SDK只提供了非线程安全的数组。如果要多线程并发的使用一个数组对象就必须要加锁,平凡的加锁使得代码的调用非常的麻烦。

我们需要多线程的读写锁在类的内部实现,所以需要对NSMutableArray进行封装封装后的对象负责接受所有事件并将其转发给真正的NSMutableArray对象,并通过合理的调度使得其支持多线程并发。


1、新建一个对象来对NSMutableArray 数组进行封装,包含dispatch_queue_t 调度队列对象一个NSObject 具体操作对象作为成员变量

@interface JXMultiThreadObject : NSObject 
{ 
    dispatch_queue_t _dispatchQueue; 
    NSObject *_container; 
} 
@property (nonatomic, strong) NSObject *container; 
@end 


2、再新建JXMutableArray类继承自JXMultiThreadObject并为其声明简单接口来支持其作为Array使用

@protocol JXMutableArrayProtocol  
@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 JXMutableArray : JXMultiThreadObject  
{ 
} 

并且初始化操作对象

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

3、回到JXMultiThreadObject类中 利用下面方法对一个对象无法实现的方法进行拦截和派发

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

该方法当你调用了一个对象没有实现的方法时,forwardInvocation方法将会响应,在这之前需要先实现

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

才能激活forwardInvocation


4、利用GCD的调度机制对对象和对象的行为进行调度

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

这里使用了同步的阻塞调度,属于效率比较低的一种调度方式,可以简单地作一下优化

- (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指定不同的调度规则以确保在逻辑正常的情况下拥有最高的性能。


总结:在多线程下使数组安全,就是通过给数组的访问和修改添加同步限制,使数组多线程安全。

同理,字典,集合等多线程安全实现类似。


参考:

http://blog.csdn.net/u010958446/article/details/62227615

http://blog.csdn.net/idaretobe/article/details/22191103

DEMO:https://github.com/joexi/JXMultiThreadObject.git

你可能感兴趣的:(iOS开发进阶篇,Object-C)