iOS23-线程安全之NSMutableDictionary和NSMutableArray

“线程安全”:即多条线程可以安全的访问同一数据,不会引起崩溃和数据错误

那为什么会造成这一问题呢?那就要说到咱们的多线程了。多线程并发的本意就是充分使用系统资源去提升性能。但是当我们使用多线程去操作一个对象的属性(对象Person中有一个age属性)时,由于线程和线程之间默认是没有进行通信的,这就导致,A线程去操作属性age“++”,但是此时B线程并不知道,然后B线程就去操作属性age“--”,然后等到A线程再去使用age“++”后的数据进行操作,发现数据已经出错了。这就是多线程并发带来的问题

但其实NSMutableDictionaryNSMutableArray并没有做到这一点,它们在iOS开发当中都不是线程安全的,在处理多线程下操作NSMutableDictionaryNSMutableArray,都需要我们自己去设计线程安全的保护机制,让我们在进行数据读写操作时,保证线程安全,也让我们的代码可以更健壮

首先我们就要知道,设计线程安全的保护机制有几种?该用什么?效率怎么样?

  • 在iOS当前技术下,处理线程安全的机制有两种:同步锁、派发队列。
  • 派发队列中包含了两种方式:同步串行队列,同步并发队列+GCD的栅栏块(dispatch_barrier_async/dispatch_barrier_sync)结合

不同方式对比:

  • 锁:主要是同步锁,会让每一个线程都进行等待,效率会比较低,极端情况还可能造成死锁的情况
  • 同步串行队列:将数据读取操作及写入操作都放在了同一个串行队列当中,这样顺序执行读写操作,可以保证数据安全
  • 同步并发队列+GCD的栅栏块:同步并发保证了

目前我采用的方式都是同步方式,如果说在操作数据的任务中比较耗时建议使用异步方式(不是特别耗时的任务,同步效率是要高于异步的)

通过以上思路,相信代码已经不难写出,建立一个安全dictionary类,命名为:EGSafeMutableDict
代码如下:
EGSafeMutableDict.h 文件

#import 

NS_ASSUME_NONNULL_BEGIN

@interface EGSafeMutableDict : NSMutableDictionary
//单例
+(instancetype)shareSafeMutableDict;

//NSMutableDictionary中key值为KeyType类型,除了nil、可变对象外,均可以做key,这里设置为id类型
- (nullable id)objectForKey:(_Nonnull id)aKey;

- (void)setObject:(nullable id)anObject forKey:(_Nonnull id )aKey;

- (void)removeObjectForKey:(_Nonnull id)aKey;

- (NSMutableDictionary *_Nonnull)getDictionary;

@end

NS_ASSUME_NONNULL_END

EGSafeMutableDict.m文件

#import "EGSafeMutableDict.h"

@interface EGSafeMutableDict()
@property(nonatomic, strong) NSMutableDictionary *dictionary;
@property(nonatomic, strong) dispatch_queue_t dispatchQueue;

@end

@implementation EGSafeMutableDict

//单例
+(instancetype)shareSafeMutableDict{
    static EGSafeMutableDict *_safeMutableDict = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _safeMutableDict = [[super allocWithZone:NULL]init];
    });
    return _safeMutableDict;
}

+(instancetype)allocWithZone:(struct _NSZone *)zone{
    return [EGSafeMutableDict shareSafeMutableDict];
}

-(id)copyWithZone:(struct _NSZone *)zone{
    return [EGSafeMutableDict shareSafeMutableDict];
}

- (instancetype)init
{
    self = [super init];
    if (self) {
        _dictionary = [[NSMutableDictionary alloc]init];
        _dispatchQueue = dispatch_queue_create("com.echo.equal.20200916safequeue", DISPATCH_QUEUE_CONCURRENT);
    }
    return self;
}

- (nullable id)objectForKey:(_Nonnull id)aKey{
    __block id object = nil;
    if (!aKey) return object;
    dispatch_sync(_dispatchQueue, ^{
        object = _dictionary[aKey];
    });
    return object;
}

- (void)setObject:(nullable id)anObject forKey:(_Nonnull id )aKey{
    if (!aKey) return;
    dispatch_barrier_async(_dispatchQueue, ^{
        [self->_dictionary setObject:anObject forKey:aKey];
    });
}

- (void)removeObjectForKey:(_Nonnull id)aKey{
    if(!aKey) return;
    dispatch_sync(_dispatchQueue, ^{
        [_dictionary removeObjectForKey:aKey];
    });
}

- (NSMutableDictionary *_Nonnull)getDictionary{
    __block NSMutableDictionary *_safeDict;
    dispatch_sync(_dispatchQueue, ^{
        _safeDict = _dictionary;
    });
    return _safeDict;
}

@end

暂时先写了两三个方法,后续会完善该类,并集成到EGuoLibs库中去,并增加NSMutableArray的安全可变对象的方法编写。

如果上述有不对的或者不完善的,敬请指出,共同进步!!!
<启文行书>

你可能感兴趣的:(iOS23-线程安全之NSMutableDictionary和NSMutableArray)