这周最大的收获是稍稍通透了 多线程安全字典的重要性。 
诱因是,发现了有字典坏地址错误 
 
 
果断以为是 value 或者 key 是可能出现了空值,补充了潜在的判断,虽然有的位置已经预判断的,但是真正赋值的时候并没判断呀,补充上了。
这种问题线下时候,我们基本0复现,所以迭代一个版本用户检验的时候还是报这个错误,不是那种坑坑一直报错势不可挡的bug,但是是很有生命力的bug,不多 还能定位到具体的一行代码。
 
这就让我很困惑了,怎么回事?? key,value 都保证是合法的了,怎么还是会报错,难道还存在字典也会不合法?
当我把我的疑惑在技术群里抛出,马上就能看出
 
哪些是酱油水平:“value key你判断了吗 blabla的”。 内心:我代码都粘出去了,为什么还问这个
哪些就是乱支招:“ runtime 进行方法交换呀” 。       内心:我是想解决问题,不是故意屏蔽问题呀,不是你们的项目是不是通通想搞坏的节奏。
哪些是牛逼指点:“数据源放在串行队列,可以保证没问题 ” 内心:竟然看出了,我这个字典保存的对象是网络请求对象。果真透过现象看本质的人。
 
我也是马上反应过来,这个错误的原因是 多个请求冲突了导致坏地址,需要通过串行队列保证 每次只有一个value key 加入字典 就不会发生野指针。
我也是把我被点得通透的想法问了一下对方,对方也给了肯定的回答。
 
于是我进一步整理了需要处理的逻辑:
我需要有一个串行请求队列,然后保证在加入字典和移除字典时候 在同一个队列,保证线程的一致。。。
并且迅速查找网上相关资源,如参考1中 中第5和第6部分,
正想根据思路写着,那个小哥哥给我发了一份多线程安全字典文件。
 
正对着我当前理解的情况,自己写可能得测试调试,这份有份量的文件值得一提的是,小哥哥说是来自于阿里。。。get
 
以上的工作还是不能够保证字典是线程安全的。。。怎讲?
因为这个字典保存的对象是网络请求对象,除了当前我们设置的串行队列里面持有,网络请求的串行队列里面也会持有这个对象啊,这就是当前问题:资源竞争造成的死锁,野指针也见怪不怪了。
 
所以还要在字典写入和删除的操作上加锁,保证当前独占资源。
这个加锁的逻辑 学习 参考2
 
 我自己是这么用的 安全锁:

- (void)setOperationDicValue:(id)operation forKey:(NSString *)key
{
NSCondition *mylock = [[NSCondition alloc]init];//创建锁对象
[mylock lock];//创建锁对象
[self.operationDict setObject:operation forKey:key];//对共享抢占资源进行操作的代码
[mylock unlock];//操作完数据,马上释放锁,给其他的线程调用操作
} - (void)removeOperationObjectForKey:(NSString *)key
{
NSCondition *mylock = [[NSCondition alloc]init];
[mylock lock];
[self.operationDict removeObjectForKey:key];
[mylock unlock];
} - (void)removeAllOperationObjects
{
NSCondition *mylock = [[NSCondition alloc]init];
[mylock lock];
[self.operationDict removeAllObjects];
[mylock unlock];
} - (id)getOperationObjectValueForKey:(NSString *)key
{
return [self.operationDict objectForKey:key];
}

关键怎么让线程不安全的字典变安全:(好东西要分享呀)

//
// SyncMutableDictionary.h
// banggood
//
// Created by Artillery on 2017/10/16.
// Copyright © 2017年 banggood. All rights reserved.
// #import <Foundation/Foundation.h>
/*
多线程下的安全字典 来自阿里
*/
@interface SyncMutableDictionary : NSObject - (nullable id)objectForKey:(_Nonnull id)aKey; - (nullable id)valueForKey:(_Nonnull id)aKey; - (NSArray * _Nonnull)allKeys; - (void)setObject:(nullable id)anObject forKey:(_Nonnull id <NSCopying>)aKey; - (void)removeObjectForKey:(_Nonnull id)aKey; - (void)removeAllObjects; - (NSMutableDictionary *_Nonnull)getDictionary; @end //
// SyncMutableDictionary.m
// banggood
//
// Created by Artillery on 2017/10/16.
// Copyright © 2017年 banggood. All rights reserved.
// #import "SyncMutableDictionary.h" @interface SyncMutableDictionary () @property(nonatomic, strong) NSMutableDictionary *dictionary;
@property(nonatomic, strong) dispatch_queue_t dispatchQueue; @end @implementation SyncMutableDictionary - (instancetype)init {
if (self = [super init]) {
_dictionary = [NSMutableDictionary new];
_dispatchQueue = dispatch_queue_create("com.banggood.banggoodSycmutableDictionary", DISPATCH_QUEUE_SERIAL);
}
return self;
} - (NSArray * _Nonnull)allKeys{
__block NSArray *allKeys = [NSArray array];
dispatch_sync(_dispatchQueue, ^{
allKeys = [_dictionary allKeys];
});
return allKeys;
} - (nullable id)objectForKey:(_Nonnull id)aKey{
__block id returnObject = nil;
if(!aKey) return returnObject;
dispatch_sync(_dispatchQueue, ^{
returnObject = _dictionary[aKey];
});
return returnObject;
} - (void)setValue:(nullable id)value forKey:(NSString *)key {
if(!key) return;
dispatch_barrier_async(_dispatchQueue, ^{
[_dictionary setValue:value forKey:key];
});
} - (nullable id)valueForKey:(_Nonnull id)aKey{
__block id returnObject = nil;
dispatch_sync(_dispatchQueue, ^{
returnObject = [_dictionary valueForKey:aKey];
});
return returnObject;
} - (void)setObject:(nullable id)anObject forKey:(_Nonnull id <NSCopying>)aKey{
dispatch_barrier_async(_dispatchQueue, ^{
if (anObject == nil) return;
self.dictionary[aKey] = anObject;
});
} - (void)removeObjectForKey:(_Nonnull id)aKey{
if(!aKey) return;
dispatch_sync(_dispatchQueue, ^{
[_dictionary removeObjectForKey:aKey];
});
} - (void)removeAllObjects {
dispatch_sync(_dispatchQueue, ^{
[_dictionary removeAllObjects];
});
} - (NSMutableDictionary *)getDictionary {
__block NSMutableDictionary *temp;
dispatch_sync(_dispatchQueue, ^{
temp = _dictionary;
});
return temp;
} -(NSString *)description{
return [NSString stringWithFormat:@"%@",self.dictionary];
} @end

至此总结:

可变字典,(同理可变数组等)是线程不安全的,以后尽量减少在多线程的情况下 处理数据源的情况。

如像我这次这样需要使用的话,处理成多线程安全字典和加安全锁。

参考 
1.https://www.cnblogs.com/alunchen/p/5607821.html
2.https://www.cnblogs.com/XYQ-208910/p/4857470.html

iOS 多线程安全 与 可变字典的更多相关文章

  1. iOS 多线程安全 与可变数组

    完全来自于iOS 多线程安全与可变字典 的学习 基本相同,举一反三 直接上样例代码 是我参照网上,根据当前业务需求改的. 其实好多人在这里喜欢用类别处理.我个人觉得用类别 极其容易和普通方法混淆,所以 ...

  2. NSDictionary字典创建,获取,遍历,可变字典的删除 - iOS

    字典是以键值对的形式来存储数据 key value 1 NSDictionary 字典 1.1 创建字典,不可变的 NSDictionary * dic = [NSDictionary diction ...

  3. iOS多线程开发之GCD(中篇)

    前文回顾: 上篇博客讲到GCD的实现是由队列和任务两部分组成,其中获取队列的方式有两种,第一种是通过GCD的API的dispatch_queue_create函数生成Dispatch Queue:第二 ...

  4. iOS多线程编程指南

    iOS多线程编程指南(拓展篇)(1) 一.Cocoa 在Cocoa上面使用多线程的指南包括以下这些: (1)不可改变的对象一般是线程安全的.一旦你创建了它们,你可以把这些对象在线程间安全的传递.另一方 ...

  5. iOS 多线程的使用

    iOS 多线程 先看一篇阮一峰写关于进程和线程的文章,快速了解线程的相关概念. 随着现在计算机硬件的发展,多核心.高频率的cpu越来越普及,为了充分发挥cpu的性能,在不通的环境下实现cpu的利用最大 ...

  6. iOS 多线程 GCD part3:API

    https://www.jianshu.com/p/072111f5889d 2017.03.05 22:54* 字数 1667 阅读 88评论 0喜欢 1 0. 预备知识 GCD对时间的描述有些新奇 ...

  7. iOS多线程开发之GCD(中级篇)

    前文回顾: 上篇博客讲到GCD的实现是由队列和任务两部分组成,其中获取队列的方式有两种,第一种是通过GCD的API的dispatch_queue_create函数生成Dispatch Queue:第二 ...

  8. iOS多线程主题

    下面是:2个并发进程.和2个并发线程的示意图: 下面介绍三种多线程技术(Thread.Cocoa Operation.Grand Central Dispatch): 1.最轻量级Thread(需要自 ...

  9. iOS多线程技术方案

    iOS多线程技术方案 目录 一.多线程简介 1.多线程的由来 2.耗时操作的模拟试验 3.进程和线程 4.多线程的概念及原理 5.多线程的优缺点和一个Tip 6.主线程 7.技术方案 二.Pthrea ...

随机推荐

  1. 如何用redis/memcache做Mysql缓存层

    方法一:直接用MysqlMysql有缓存,实现了类似的功能,如果需要缓存的东西很多,可以把缓存的内存设置大一点.这样的好处就是不用去控制缓存的失效,确保数据一致性. 方法二:启用用DAO框架的缓存比如 ...

  2. 微软公布带外安全更新MS14-068

     11月19日,微软公布了带外更新MS14-068以解决Windows 系统中的一个安全漏洞,该补丁安全等级为"严重". MS14-068 | Kerberos 中的漏洞可能同 ...

  3. Java序列化(转载)

    引用自:http://developer.51cto.com/art/201506/479979_all.htm 关于 Java 对象序列化您不知道的 5 件事 数年前,当和一个软件团队一起用 Jav ...

  4. 【IOS】 readonly IOS下实战入门

    当非常多XXX.h 文件属性YY设计中,对外的设计是 YY(readonly) 时.外界便不能改动该属性, 同一时候问题也来了,该XXX类的内部也不能改动改YY属性了.你瞬间凌乱过么. ..Y_Y 然 ...

  5. 客户端用JavaScript填充DropDownList控件 服务器端读不到值

    填充没有任何问题,但是在服务器端却取不出来下拉表中的内容.页面代码如下. <form id="form1" runat="server"> < ...

  6. WebApi接口传参不再困惑:传参详解

    http://www.cnblogs.com/landeanfen/p/5337072.html

  7. AWS系列-根设备类型

    1.AWS根设备类型分为两类 实例存储(本地存储) EBS存储(网络存储) 2.实例存储 系统和磁盘在同一主机上 3.EBS存储 Elastic Block Storage EBS可能与云主机不在一台 ...

  8. Android中的&lt;include&gt;标签和&lt;merge&gt;标签

    android开发中经常会碰到某一个布局的复用:直接拷贝粘贴并不是是有效的策略,这时候就能够借助<include>标签和<merge>标签来完毕. 官方文档: http://d ...

  9. 【LeetCode】Copy List with Random Pointer

    A linked list is given such that each node contains an additional random pointer which could point t ...

  10. IE的文档模式, 及Textarea呈现bug一例

    做了个非常简单的页面, 仅有几行html代码, 内容如下: <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtm ...