这周最大的收获是稍稍通透了 多线程安全字典的重要性。 
诱因是,发现了有字典坏地址错误 
 
 
果断以为是 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. 20140710文安c++面试总结

    这次去文安面试并未是我想象中的那个样子,可能有如下原因: 1.招聘旺季已过,仅剩下c++这个职位 2.并未做过面试前大公司的面试技巧-做面试题 面试过程基本就是先做面试题: 1.试题分布式-逻辑题.分 ...

  2. WPF 开源项目 【watcher】 守望者,一款监控,统计,分析你每天在自己电脑上究竟干了什么的软件

    时隔多年(两年),天天沉迷写PHP的我在连续加薪了逐渐发现自己不怎么写代码了. 甚至有一天我发现我连IDE 都没有打开,实在是太堕落了 为了及时悬崖勒马,回头是岸.为了鼓励自己专心写代码,我决定写一款 ...

  3. [LintCode] 正则表达式匹配

    class Solution { public: /** * @param s: A string * @param p: A string includes "." and &q ...

  4. PAT 1014 Waiting in Line (模拟)

    1014. Waiting in Line (30) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue Suppo ...

  5. 《挑战程序设计竞赛》2.2 贪心法-其它 POJ3617 3069 3253 2393 1017 3040 1862 3262

    POJ3617 Best Cow Line 题意 给定长度为N的字符串S,要构造一个长度为N的字符串T.起初,T是一个空串,随后反复进行下列任意操作: 从S的头部(或尾部)删除一个字符,加到T的尾部 ...

  6. 墨菲定律(Murphy's Law)

    https://baike.baidu.com/item/墨菲定律/746284?fr=aladdin 墨菲定律是一种心理学效应,是由 爱德华·墨菲(Edward A. Murphy)提出的. 主要内 ...

  7. 深入理解Java内存模型之系列篇

    深入理解Java内存模型(一)——基础 并发编程模型的分类 在并发编程中,我们需要处理两个关键问题:线程之间如何通信及线程之间如何同步(这里的线程是指并发执行的活动实体).通信是指线程之间以何种机制来 ...

  8. IO 流的操作基本规律

    想要知道开发时,使用哪个流对象, 只要通过四个明确即可. 明确源和目的(数据汇) 源: InputStream 或 Reader 目的: OutPutStream 或 Writer 明确数据是否是纯文 ...

  9. Making the Grade---poj3666(类似离散化+dp)

    题目链接:http://poj.org/problem?id=3666 题意是给出一组数,每个数代表当前位置的地面高度,问把路径修成非递增或者非递减,需要花费的最小代价? ///用dp[i][j]表示 ...

  10. 我的Android进阶之旅------>解决:debug-stripped.ap_' specified for property 'resourceFile' does not exist.

    1.错误描述 更新Android Studio到2.0版本后,出现了编译失败的问题,我clean project然后重新编译还是出现抑郁的问题,问题具体描述如下所示: Error:A problem ...