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];