美文网首页
iOS23-线程安全之NSMutableDictionary和N

iOS23-线程安全之NSMutableDictionary和N

作者: echo海猫 | 来源:发表于2020-09-16 15:29 被阅读0次

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

    那为什么会造成这一问题呢?那就要说到咱们的多线程了。多线程并发的本意就是充分使用系统资源去提升性能。但是当我们使用多线程去操作一个对象的属性(对象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 <Foundation/Foundation.h>
    
    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 <NSCopying>)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 <NSCopying>)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和N

          本文链接:https://www.haomeiwen.com/subject/vrjcyktx.html