Realm实战--多线程踩坑(二)

接Realm实战--多线程踩坑(一):

www.jianshu.com/p/f77b28d7b6c7

错误案例二:

创建一个单例 RealmManagerFail2,实现数据库相关操作:

1、创建数据库:

@property(nonatomic,strong) dispatch_queue_t realmQueue;

- (void)createDataBase {

_realmQueue=dispatch_queue_create("realmQueue",NULL);

dispatch_async(_realmQueue, ^{

NSLog(@"createDataBase------当前线程是%@", [NSThread currentThread]);

NSArray*docPath =NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);

NSString*path = [docPath objectAtIndex:0];

NSString*filePath = [path stringByAppendingPathComponent:@"test.realm"];

NSLog(@"realm22222 ====数据库目录======= %@", filePath);

RLMRealmConfiguration*config = [RLMRealmConfiguration defaultConfiguration];

config.fileURL= [NSURL URLWithString:filePath];

config.readOnly=NO;

config.schemaVersion=1.0;

[RLMRealmConfiguration setDefaultConfiguration:config];

});

}

2、添加对象

- (void)addPerson:(Person*)person {

dispatch_async(_realmQueue, ^{

NSLog(@"addPerson-----当前线程是%@", [NSThread currentThread]);

RLMRealm*realm = [RLMRealm realmWithConfiguration:[RLMRealmConfiguration defaultConfiguration] error:nil];

[realm transactionWithBlock:^{

[realm addOrUpdateObject:person];

}];

NSLog(@"Tony来了");

});

}

3、操作数据库,狗狗长大

- (void)dogsGrowUpForMaster:(Person*)person {

dispatch_async(_realmQueue, ^{

NSLog(@"dogsGrowUpForMaster-----当前线程是%@", [NSThread currentThread]);

RLMRealm*realm = [RLMRealm realmWithConfiguration:[RLMRealmConfiguration defaultConfiguration]error:nil];

for(inti =0; i < person.dogs.count; i++) {

Dog*dog = person.dogs[i];

dispatch_async(_realmQueue, ^{

NSLog(@"某一只小狗长大了--------当前线程是%@", [NSThread currentThread]);

[self doSomeThingsCompleteBlock:^{

[realm transactionWithBlock:^{

dog.age=3;

}];

}];

});

}

});

}

- (void)doSomeThingsCompleteBlock:(void(^)(void))complete {

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{

NSIntegerdelay =arc4random() %3;

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay *NSEC_PER_SEC)),dispatch_get_main_queue(), ^{

complete();

});

});

}

4、外部调用

- (void)testFunc2 {

[[RealmManagerFail2sharedInstance]createDataBase];

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1*NSEC_PER_SEC)),dispatch_get_main_queue(), ^{

[[RealmManagerFail2sharedInstance]addPerson:_person];

});

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2*NSEC_PER_SEC)),dispatch_get_main_queue(), ^{

[[RealmManagerFail2sharedInstance]dogsGrowUpForMaster:_person];

});

}

5、运行,奔溃。打印结果如下:

createDataBase------当前线程是 <NSThread: 0x608000268b00> {number = 3, name = (null)}

addPerson-----当前线程是 <NSThread: 0x608000268b00> {number = 3, name = (null)}

dogsGrowUpForMaster-----当前线程是 <NSThread: 0x60800026f2c0> {number = 5, name = (null)}

*** Terminating app due to uncaught exception 'RLMException', reason: 'Realm accessed from incorrect thread.'

6、解释说明

与单例一(见上一篇)类似,该单例也实现了以下方法:创建数据库、添加对象、操作数据库。

唯一不同的是,这个单例中为了将数据库相关的操作放在同一个线程中,使用的方法是定义了一个线程队列的成员变量。所有的数据库操作均放在该队列分配的子线程中,如下

dispatch_async(_realmQueue, ^{

xxxxx

});

然而事与愿违的是,addPerson、dogsGrowUp方法中,确实保证了在同一个子线程中,而在doSomeThingsCompleteBlock: 方法中,因为嵌套了一层dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{}),出现了不同的子线程。

从而可以得出的猜测是,该队列在同一个线程中,会随机分类一个子线程供执行代码。嵌套子线程后,分配的子线程也随之改变。因此通过同一个队列,来实现所有操作均放在同一个线程中的方法,是不对的。


待续...

推荐阅读更多精彩内容