Objective c 域在更新时失效时崩溃
当我在其他线程中运行更新事件时,试图删除数据库时,我的领域经常崩溃 坠机原因是:Objective c 域在更新时失效时崩溃,objective-c,crash,realm,Objective C,Crash,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 beginW
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);
}
}
}
+(void)deleteRealm
{
@自动释放池{
[[RLMRealm defaultRealm]invalidate];
//黑客迫使领域清除缓存,因为配置被缓存,并最终崩溃,因为它检测到加密密钥已更改
禁止显示未声明的选择器警告([[RLMRealm class]性能选择器:@SELECTOR(resetRealmState)];
}
NSFileManager*manager=[NSFileManager defaultManager];
RLMRealmConfiguration*config=[RLMRealmConfiguration defaultConfiguration];
NSArray*realmFileURLs=@[
config.fileURL,
[config.fileURL URLByAppendingPathExtension:@“lock”],
[config.fileURL URLByAppendingPathExtension:@“log_a”],
[config.fileURL URLByAppendingPathExtension:@“log_b”],
[config.fileURL URLByAppendingPathExtension:@“注意”],
[[config.fileURL URLByDeletingLastPathComponent]URLByAppendingPathComponent:[NSString stringWithFormat:@“%@.realm.management”,[[config.fileURL URLByDeletingPathExtension]lastPathComponent]]
];
for(realmFileURLs中的NSURL*URL){
n错误*错误=nil;
[管理员删除属性:URL错误:&错误];
如果(错误){
//处理错误
DDLogError(@“删除域文件时出错-%@”,错误);
}
}
}
我的问题是:在运行此代码之前,是否有方法停止所有领域操作。来自以下领域的文档: 由于Realm避免将数据复制到内存中(绝对需要时除外),因此由Realm管理的所有对象都包含对磁盘上文件的引用,并且必须先解除分配,然后才能安全删除该文件。这包括从域读取(或添加到)的所有对象、所有
RLMArray
、RLMResults
、和rlmthreadsafeference
对象以及RLMRealm
本身
在实践中,这意味着删除领域文件应该在应用程序启动时在打开领域之前完成,或者在显式自动释放池中仅打开领域之后完成,这将确保所有领域对象都已解除分配
在另一个线程上访问文件时删除该文件将导致各种问题。调用Realm的私有方法,例如+[RLMRealm resetRealmState]
,也会导致错误。我强烈建议不要做这两件事
根据从磁盘中删除领域文件的动机,您可能会以稍微不同的方式来处理这个问题。如果你能分享更多关于用例的信息,我可能会提供一个更具体的建议
例如,您可以跟踪您的后台线程是否正在积极处理域,并且只在空闲时删除它。您需要非常小心,以确保在删除文件时删除了对领域的所有引用,否则您可能会通过已打开的文件句柄继续访问现在已删除的文件
或者,您可以为新的领域文件生成一个新的、唯一的路径,而不是立即删除该领域文件。然后,当您确定应用程序的其余部分未使用时,您将删除未使用的领域文件(下一次启动是实现这一点的非常可靠的方法,或者将其与应用程序生命周期中您知道旧状态无法再访问的点绑定)。这将是我的首选,因为在使用文件时不可能删除该文件。它也非常适合于许多具有注销用户概念的应用程序,因为每个用户的不同领域路径相对容易掌握。当用户结束会话时,出于符合HIPAA的原因,我们会删除该领域。我们以前是用加密的核心数据来做这件事的,但现在我们要做的是向领域的大规模迁移,为了通过审核,我们必须删除数据库的所有痕迹。使用加密领域,在会话结束时丢弃加密密钥,然后在以后清理文件,这能满足要求吗?我会尝试出售它。现在,我可以通过在删除领域文件之前运行此命令来避免崩溃。[[RLMRealm defaultRealm]beginWriteTransaction];[[RLMRealm defaultRealm]deleteAllObjects];[[RLMRealm defaultRealm]commitWriteTransaction];