当我在其他线程中运行更新事件的同时尝试删除数据库时,我在Realm上一直崩溃。
崩溃是:
2017-08-14 18:07:56.289 App Staging[28264:7828070] *** Terminating app due to uncaught exception 'RLMException', reason: 'Can only add, remove, or create objects in a Realm in a write transaction - call beginWriteTransaction on an RLMRealm instance first.'
*** First throw call stack:
(
0 CoreFoundation 0x000000010c67fb0b __exceptionPreprocess + 171
1 libobjc.A.dylib 0x000000010c0e4141 objc_exception_throw + 48
2 Realm 0x0000000108095f96 _ZL27RLMVerifyInWriteTransactionP8RLMRealm + 86
3 Realm 0x000000010809710a RLMCreateObjectInRealmWithValue + 138
4 Realm 0x00000001080820af +[RLMObject createOrUpdateInRealm:withValue:] + 607
5 App Staging 0x0000000107497ae0 +[RealmRoundable createOrUpdateInRealm:withMemberResponse:] + 400
6 App Staging 0x0000000107497916 +[RealmRoundable createOrUpdateWithMemberResponse:] + 118
7 App Staging 0x000000010742a0a0 +[RealmStaff createOrUpdateInRealm:withResponse:inCareProvider:] + 352
8 App Staging 0x000000010742ab92 +[RealmStaff createOrUpdateInRealm:withStaff:inCareProvider:] + 514
9 App Staging 0x000000010742a94b +[RealmStaff createOrUpdateStaff:inCareProvider:] + 139
10 App Staging 0x000000010733b803 -[StaffRoundableTableViewController updateRoundables:fromDataLoader:inCareProvider:] + 131
11 App Staging 0x000000010747ae3a __54-[RoundableTableViewController dataLoaderDidLoadData:]_block_invoke.324 + 122
12 Realm 0x00000001081d01a6 -[RLMRealm transactionWithBlock:error:] + 86
13 Realm 0x00000001081d010e -[RLMRealm transactionWithBlock:] + 62
14 App Staging 0x000000010747ab0d __54-[RoundableTableViewController dataLoaderDidLoadData:]_block_invoke + 765
15 libdispatch.dylib 0x000000010e15c4a6 _dispatch_call_block_and_release + 12
16 libdispatch.dylib 0x000000010e18505c _dispatch_client_callout + 8
17 libdispatch.dylib 0x000000010e164dcd _dispatch_queue_override_invoke + 1321
18 libdispatch.dylib 0x000000010e166ec4 _dispatch_root_queue_drain + 634
19 libdispatch.dylib 0x000000010e166bef _dispatch_worker_thread3 + 123
20 libsystem_pthread.dylib 0x000000010e51c5a2 _pthread_wqthread + 1299
21 libsystem_pthread.dylib 0x000000010e51c07d start_wqthread + 13
)
libc++abi.dylib: terminating with uncaught exception of type NSException
当我打电话时会发生这种情况:
[RealmManager deleteRealm];
实现方式如下:
+ (void)deleteRealm
{
@autoreleasepool {
[[RLMRealm defaultRealm] invalidate];
// Hack to force Realm to clear cache because config is cached and crashes eventually because it detects encryption key has changed
SUPPRESS_UNDECLARED_SELECTOR_WARNING([[RLMRealm class] performSelector:@selector(resetRealmState)]);
}
NSFileManager *manager = [NSFileManager defaultManager];
RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
NSArray<NSURL *> *realmFileURLs = @[
config.fileURL,
[config.fileURL URLByAppendingPathExtension:@"lock"],
[config.fileURL URLByAppendingPathExtension:@"log_a"],
[config.fileURL URLByAppendingPathExtension:@"log_b"],
[config.fileURL URLByAppendingPathExtension:@"note"],
[[config.fileURL URLByDeletingLastPathComponent] URLByAppendingPathComponent:[NSString stringWithFormat:@"%@.realm.management", [[config.fileURL URLByDeletingPathExtension] lastPathComponent]]]
];
for (NSURL *URL in realmFileURLs) {
NSError *error = nil;
[manager removeItemAtURL:URL error:&error];
if (error) {
// handle error
DDLogError(@"Error deleting realm file - %@", error);
}
}
}
我的问题是:在运行此代码之前,有没有办法停止所有Realm操作。
答案 0 :(得分:4)
来自Realm关于Deleting Realm Files的文档:
因为Realm避免将数据复制到内存中,除非绝对需要,所以Realm管理的所有对象都包含对磁盘上文件的引用,并且必须先释放它才能安全删除文件。这包括从Realm,所有
RLMArray
,RLMResults
和RLMThreadSafeReference
对象以及RLMRealm
本身读取(或添加到)的所有对象。实际上,这意味着删除Realm文件应该在应用程序启动之前在打开Realm之前完成,或者仅在显式自动释放池中打开Realm之后完成,这样可以确保所有Realm对象都已经存在解除分配。
在另一个线程上仍然访问文件时删除文件会导致各种问题。调用Realm的私有方法,例如+[RLMRealm resetRealmState]
,也是如此。我强烈建议不做这两件事。
您可能会以稍微不同的方式处理此问题,具体取决于从磁盘中删除Realm文件的动机。如果您可以分享有关您的用例的更多信息,我可能会提供更具体的建议。
例如,您可以跟踪您的后台线程是否正在使用Realm,并且只有在它们空闲时才将其删除。您需要非常小心以确保在删除文件时删除了对Realm的所有引用,否则您最终可能会通过已打开的文件句柄继续访问现在删除的文件。
或者,您可以改为为Realm文件生成新的唯一路径,而不是立即删除Realm文件。然后,当您确定应用程序的其余部分未使用它们时,您将删除未使用的Realm文件(下次启动是实现此目的的一种非常可靠的方式,或者将其绑定到应用程序生命周期中的点数你知道无法再访问旧状态了。这是我的偏好,因为在使用文件时没有机会删除它。它也非常适合许多具有记录用户概念的应用程序,因为每个用户不同的Realm路径是一个相对容易理解的概念。