iOS技术交流iOS开发iOS面试

NSMutableArray线程安全

2017-03-20  本文已影响68人  打不死的小怪兽

数组线程安全的思考

NSMutableArray是线程不安全的,当有多个线程同时对数组进行操作的时候可能导致崩溃或数据错误,下面是我对线程安全的几个思路,希望由此能给你带来一些思路,如果有错误的地方还希望大家能够指出

数组线程安全的实现

下面咱们来看一下NSMutableArray线程安全的实现

1、 继承 NSMutableArray创建NSKSafeMutableArray在这个地方遇到了一些坑通过查阅文档发现问题所在:
在 Cocoa 中有一种奇葩的类存在 Class Clusters。面向对象的编程告诉我们:“类可以继承,子类具有父类的方法”。而 Cocoa 中的 Class Clusters 虽然平时表现的像普通类一样,但子类却没法继承父类的方法。 NSMutableArray就是这样的存在。为什么会这样呢?因为 Class Clusters 内部其实是由多个私有的类和方法组成。虽然它有这样的弊端,但是好处还是不言而喻的。例如,NSNumber 其实也是这种类,这样一个类可以把各种不同的原始类型封装到一个类下面,提供统一的接口。这正设计模式中的抽象工厂模式。

查看Apple的文档,要继承这样的类需要必须实现其primitive methods方法,实现了这些方法,其它方法便都能通过这些方法组合而成。比如需要继承NSMutableArray就需要实现它的以下primitive methods:

- (void)addObject:(id)anObject;
- (void)insertObject:(id)anObject atIndex:(NSUInteger)index;
- (void)removeLastObject;
- (void)removeObjectAtIndex:(NSUInteger)index;
- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject;
和NSArray的primitive methods:
- (NSUInteger)count;
- (id)objectAtIndex:(NSUInteger)index;
2 、NSKSafeMutableArray.h 的实现如下
#import "NSKSafeMutableArray.h"


@interface NSKSafeMutableArray()
{
    CFMutableArrayRef _array;
}
@end

@implementation NSKSafeMutableArray

- (id)init
{
    return [self initWithCapacity:10];
}

- (id)initWithCapacity:(NSUInteger)numItems
{
    self = [super init];
    if (self)
    {
        _array = CFArrayCreateMutable(kCFAllocatorDefault, numItems,  &kCFTypeArrayCallBacks);
    }
    return self;
}
- (NSUInteger)count {

    __block NSUInteger result;
    dispatch_sync(self.syncQueue, ^{
        result = CFArrayGetCount(_array);
    });
    return result;
}

- (id)objectAtIndex:(NSUInteger)index {

    __block id result;
    dispatch_sync(self.syncQueue, ^{
        NSUInteger count = CFArrayGetCount(_array);
        result = index<count ? CFArrayGetValueAtIndex(_array, index) : nil;
    });

    return result;
}

- (void)insertObject:(id)anObject atIndex:(NSUInteger)index
{
    __block NSUInteger blockindex = index;
    dispatch_barrier_async(self.syncQueue, ^{

        if (!anObject)
            return;

        NSUInteger count = CFArrayGetCount(_array);
        if (blockindex > count) {
            blockindex = count;
        }
        CFArrayInsertValueAtIndex(_array, index, (__bridge const void *)anObject);

    });

}

- (void)removeObjectAtIndex:(NSUInteger)index
{

    dispatch_barrier_async(self.syncQueue, ^{

        NSUInteger count = CFArrayGetCount(_array);
        NSLog(@"count:%lu,index:%lu",(unsigned long)count,(unsigned long)index);
        if (index < count) {
            CFArrayRemoveValueAtIndex(_array, index);
        }
    });
}

- (void)addObject:(id)anObject
{
    dispatch_barrier_async(self.syncQueue, ^{

        if (!anObject)
            return;

        CFArrayAppendValue(_array, (__bridge const void *)anObject);

    });
}

- (void)removeLastObject {
    dispatch_barrier_async(self.syncQueue, ^{

        NSUInteger count = CFArrayGetCount(_array);
        if (count > 0) {
            CFArrayRemoveValueAtIndex(_array, count-1);
        }

    });
}

- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject {


    dispatch_barrier_async(self.syncQueue, ^{

        if (!anObject)
            return;

        NSUInteger count = CFArrayGetCount(_array);
        CFArraySetValueAtIndex(_array, index, (__bridge const void*)anObject);
    });
}

#pragma mark Optional

- (void)removeAllObjects
{

    dispatch_barrier_async(self.syncQueue, ^{
        CFArrayRemoveAllValues(_array);
    });
}

- (NSUInteger)indexOfObject:(id)anObject{

    if (!anObject)
        return NSNotFound;

    __block NSUInteger result;
    dispatch_sync(self.syncQueue, ^{
        NSUInteger count = CFArrayGetCount(_array);
        result = CFArrayGetFirstIndexOfValue(_array, CFRangeMake(0, count), (__bridge const void *)(anObject));
    });
    return result;


    return result;
}
#pragma mark - Private
- (dispatch_queue_t)syncQueue {
    static dispatch_queue_t queue = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        queue = dispatch_queue_create("com.kong.NSKSafeMutableArray", DISPATCH_QUEUE_CONCURRENT);
    });
     return queue;

}
@end

3、调用
- (void)viewDidLoad {
    [super viewDidLoad];
    NSKSafeMutableArray *safeArr = [[NSKSafeMutableArray alloc] init];

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    for ( int i = 0; i < 5; i ++) {
        dispatch_async(queue, ^{

            NSLog(@"添加第%d个",i);
            [safeArr addObject:[NSString stringWithFormat:@"%d",i]];

        });

        dispatch_async(queue, ^{

            NSLog(@"删除第%d个",i);
            [safeArr removeObjectAtIndex:i];

        });
    }

    // Do any additional setup after loading the view, typically from a nib.
}

支持作者原创http://blog.csdn.net/kongdeqin/article/details/53171189

上一篇 下一篇

猜你喜欢

热点阅读