-[NSError retain]: 发送到释放实例的消息

-[NSError retain]: message sent to deallocated instance

启用 Zombies 后,我在以下 saveToURL 调用中收到标题错误(消息发送到已解除分配的 NSError 实例):

[aDocument saveToURL:aDocument.fileURL
forSaveOperation:UIDocumentSaveForOverwriting
completionHandler:^(BOOL success) { ...

堆栈跟踪如下所示:

aDocument 是 UIManagedDocument 子类的实例。我打开并发调试,查看是否有任何线程冲突,但还没有找到。我该如何调试?

编辑:还尝试了以下发生相同崩溃的代码

__weak typeof(self) weakSelf = self;

    [aDocument saveToURL:aDocument.fileURL forSaveOperation:UIDocumentSaveForOverwriting completionHandler:^(BOOL success) {
        if (success) {
            dispatch_async(dispatch_get_main_queue(), ^{
                [weakSelf documentSaved:aDocument forRestoredAssessment:patientAssessment];
            });
        }
    }];

编辑:增加赏金

看来调用完成块代码的对象当时可能不存在,所以你需要一些方法来保持它的存活。

试试这个代码:

__weak typeof(self) weakSelf = self;

dispatch_async(dispatch_get_main_queue(), ^{
    [weakSelf documentSaved:aDocument forRestoredAssessment:patientAssessment]; 
});

如果您还有问题,请告诉我。

我相信我知道是什么原因造成的,因为我进行了以下更改,然后错误消失了。该错误很难解决,因为它没有直接指出这是原因。

我正在使用 UIDocumentSaveForOverwriting,但我发现有时该文件已被另一个进程删除。

因此,为了解决这个问题,我测试了文件是否存在,然后基于此使用了 UIDocumentSaveForOverwriting 或 UIDocumentSaveForCreating。

我们发现当父上下文有合并冲突时会出现这个僵尸。如果您在子类中覆盖 [UIManagedDocument writeContents:toURL:forSaveOperation:originalContentsURL:error] 方法,请使用:NSManagedObjectContext *context = [(NSDictionary *)contents objectForKey:@"parentContext"]; 访问父上下文。如果使用以下标准代码存在更改,请保存父上下文。如果通过设置合并策略或重置上下文来解决冲突,则不会发生僵尸。

- (BOOL)writeContents:(id)contents
                toURL:(NSURL *)url
     forSaveOperation:(UIDocumentSaveOperation)saveOperation
  originalContentsURL:(NSURL *)originalContentsURL
                error:(NSError * _Nullable __autoreleasing *)outError {

    NSError *error = nil;

    NSManagedObjectContext *context = self.managedObjectContext.parentContext;

    if (context.hasChanges) {
        [context performBlockAndWait:^{

            NSError *saveError = nil;
            if (![context save:&saveError]) {
                NSLog(@"Document Writing: error saving context %@", saveError);
                [context reset];
            }
        }];
    }
    return [super writeContents:contents
                          toURL:url
               forSaveOperation:saveOperation
            originalContentsURL:originalContentsURL
                          error:outError];
}