文章目录
  1. 1. 前言
  2. 2. 一. 多线程常见崩溃
    1. 2.1. MRC下:
    2. 2.2. 修改方案:
  3. 3. 二. 最终修改方案
    1. 3.1. MRC下
    2. 3.2. ARC下:
  4. 4. 三. 异步读写
  5. 5. demo下载

前言

在介绍异步读写之前,先介绍一下多线程下崩溃的容易崩溃的原因,以及如何进行同步读,异步写

一. 多线程常见崩溃

MRC下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
-(id) getSafeObjectForKey:(NSString *) bindingKey
{
@synchronized(self.dic) {
if(bindingKey){
return [self.dic objectForKey:bindingKey];
}
}
return nil;
}

-(void) setSafeObject:(id) object forKey:(NSString*) bindingKey
{
@synchronized(self.dic) {
if(bindingKey && object){
[self.dic setObject:object forKey:bindingKey];
}
}
}

-(void) testSyncizedDictionary
{
for (int i = 0; i < 1000000; i++) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//多线程写
[self setSafeObject:[NSString stringWithFormat:@"86+111111111 %i", i] forKey:KEY];
});
//主线程读
NSString *result = [self getSafeObjectForKey:KEY];
NSLog(@"get string: %@, length : %lu", result, result.length);
}
}

"NSDictionary"

原因分析:程序还没执行到NSLog那一行的时候,get出来的一个值,在多线程中执行了set方法执行导致key对应的result对释放掉了。此时执行到NSLog,导致了崩溃.

修改方案:

1
2
3
4
//主线程读
NSString *result = [[self getSafeObjectForKey:KEY] retain];
NSLog(@"get string: %@, length : %lu", result, result.length);
[result release];

在读取的时候retain一下,后续在release,还是会崩溃。因为在retain之前很可能野掉了,此时retain也只是对野掉的的指针

二. 最终修改方案

MRC下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#pragma mark- 用GCD的方式去实现
-(id) getRightObjectForKey:(NSString *) bindingKey
{
if (!bindingKey) {
return nil;
}
__block id result = nil;
dispatch_sync(self.ioQueue, ^{
result = [[_dic objectForKey:bindingKey] retain]; //关键点1
});

return [result autorelease]; //关键点2

}

-(void) setRightObject:(id) object forKey:(NSString*) bindingKey
{
bindingKey = [bindingKey copy];
dispatch_barrier_async(self.ioQueue, ^{
if(bindingKey && object){
[_dic setObject:object forKey:bindingKey];
}
});
}

-(void) testSyncizedDictionaryRight
{

for (int i = 0; i < 1000000; i++) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//多线程写
[self setRightObject:[NSString stringWithFormat:@"86+111111111 %i", i] forKey:KEY];
});
//主线程读
NSString *result = [[self getRightObjectForKey:KEY] retain];
NSLog(@"get string: %@, length : %lu", result, result.length);
[result release];
}
}

请看关键点1和关键点2,如果没有retainautorelease,还是会崩溃。原因同上。

ARC下:

怎么操作都不崩溃。不过还是建议写法

@property(nonatomic,strong) NSMutableDictionary *dic;  
@property(nonatomic,strong) dispatch_queue_t ioQueue;

self.ioQueue = dispatch_queue_create("ioQueue", DISPATCH_QUEUE_CONCURRENT);  
self.dic = [NSMutableDictionary dictionaryWithCapacity:1];

#pragma mark- 用GCD的方式去实现
-(id) getRightObjectForKey:(NSString *) bindingKey
{
    if (!bindingKey) {
        return nil;
    }
    __block id result = nil;
    dispatch_sync(self.ioQueue, ^{
        result = [_dic objectForKey:bindingKey];             });

    return result;
}

-(void) setRightObject:(id) object forKey:(NSString*) bindingKey
{
    bindingKey = [bindingKey copy];
    dispatch_barrier_async(self.ioQueue, ^{
        if(bindingKey && object){
            [_dic setObject:object forKey:bindingKey];
        }
    });
}

-(void) testSyncizedDictionaryRight
{        
    for (int i = 0; i < 1000000; i++) {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            //多线程写
            [self setRightObject:[NSString stringWithFormat:@"86+111111111   %i", i] forKey:KEY];
        });
        //主线程读
        NSString *result = [self getRightObjectForKey:KEY];
        NSLog(@"get string: %@, length : %lu", result, result.length);
    }
}

三. 异步读写

创建一个串行队列。然后gcd结合锁去执行

@property(nonatomic,strong) dispatch_queue_t asynModelQueue;

self.asynModelQueue = dispatch_queue_create("AsynModelQueue", DISPATCH_QUEUE_SERIAL);

#pragma mark- 用GCD去异步读写
-(void) getAsyncRightObjectForKey:(NSString *) bindingKey block:(void(^)(NSMutableDictionary* modelDicCache)) modelCallBack
{
    if (!bindingKey && modelCallBack) {
        modelCallBack(nil);
        return;
    }
    __block id result = nil;
    dispatch_async(self.asynModelQueue, ^{
        @synchronized(self) {//@synchronized是为了多一层保护
            result = [_dic objectForKey:bindingKey];     //由于self.bindingInfo重写过,此处不能用self.bindingInfo,否则造成死锁
            modelCallBack(result);
        }
    });
}

-(void) setAsyncRightObject:(id) object forKey:(NSString*) bindingKey
{
    bindingKey = [bindingKey copy];
    dispatch_barrier_async(self.asynModelQueue, ^{
        @synchronized(self) {//@synchronized是为了多一层保护
            if(bindingKey && object){
                [_dic setObject:object forKey:bindingKey];
            }
        }
    });
}

-(void) testAsyncSyncizedDictionaryRight
{
    for (int i = 0; i < 1000000; i++) {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            //多线程写
            [self setRightObject:[NSString stringWithFormat:@"86+111111111   %i", i] forKey:KEY];
        });
        //主线程读
        NSString *result = [self getRightObjectForKey:KEY];
        NSLog(@"get string: %@, length : %lu", result, result.length);
    }
}

demo下载

demo

文章目录
  1. 1. 前言
  2. 2. 一. 多线程常见崩溃
    1. 2.1. MRC下:
    2. 2.2. 修改方案:
  3. 3. 二. 最终修改方案
    1. 3.1. MRC下
    2. 3.2. ARC下:
  4. 4. 三. 异步读写
  5. 5. demo下载