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
我们再新建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 <JXMutableArrayProtocol>
- {
- }
并且初始化操作对象
- - (id)init
- {
- self = [super init];
- if (self) {
- self.container = [NSMutableArray array];
- }
- return self;
- }
2.回到JXMultiThreadObject类中 利用下面方法对一个对象无法实现的方法进行拦截和派发
- - (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];
- });
- }
这里使用了同步的阻塞调度,属于效率比较低的一种调度方式,可以简单地作一下优化
- - (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指定不同的调度规则以确保在逻辑正常的情况下拥有最高的性能。 最后附个DEMO的例子https://github.com/joexi/JXMultiThreadObject.git
|