RestKit核心数据NSError dealloc崩溃 [英] RestKit Core Data NSError dealloc Crash

查看:187
本文介绍了RestKit核心数据NSError dealloc崩溃的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

试图找到一个问题的底部,我在生产构建中看到,并且最终能够在测试期间重现它。使用RestKit v0.23.1,当使用下面的代码(当插入仪器)进行RKManagedObjectRequest操作时,我得到一个Objective-C消息被发送到一个释放的'NSError'对象(zombie)和应用程序崩溃每次有对象响应JSON - 如果响应是像objects =();没有崩溃 - 所以我猜它是在RestKit / Core数据映射或存储中的某个地方?

Trying to get to the bottom of an issue I've been seeing in production builds and FINALLY was able to reproduce it while testing. Using RestKit v0.23.1, when doing an RKManagedObjectRequestOperation using the following code (while plugged into instruments) I get "An Objective-C message was sent to a deallocated 'NSError' object (zombie)" and the app crashes every time there's objects in the response JSON - if the response is something like "objects = ();" there's no crash - so I'm guessing it's somewhere in the RestKit/Core Data mapping or storage?

    RKManagedObjectRequestOperation *objectRequestOperation = [_objectManager managedObjectRequestOperationWithRequest:request managedObjectContext:_objectManager.managedObjectStore.mainQueueManagedObjectContext success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
        DDLogInfo(@"INSIDE SUCCESS BLOCK");
    } failure:^(RKObjectRequestOperation *operation, NSError *error) {
        DDLogInfo(@"INSIDE ERROR BLOCK");
    }];

    [objectRequestOperation setWillMapDeserializedResponseBlock:^id(id deserializedResponseBody) {
        DDLogInfo(@"Response JSON: %@", deserializedResponseBody);

        return deserializedResponseBody;
    }];

    objectRequestOperation.savesToPersistentStore = YES;
    [objectRequestOperation start];

原始JSON正确记录在setWillMapDeserializedResponseBlock内,但成功和错误块中的日志永远不会到达。这是我从crashlytics回来的堆栈跟踪:

The raw JSON is properly logged inside the setWillMapDeserializedResponseBlock, but the logs inside the success and error block are never reached. Here is the stack trace I get back from crashlytics:

Thread : Crashed: NSOperationQueue Serial Queue
0  libobjc.A.dylib                0x37dd4626 objc_msgSend + 5
1  Foundation                     0x2df5802d -[NSError dealloc] + 60
2  libobjc.A.dylib                0x37dd9b6b objc_object::sidetable_release(bool) + 174
3  libobjc.A.dylib                0x37dda0d3 (anonymous namespace)::AutoreleasePoolPage::pop(void*) + 358
4  CoreFoundation                 0x2d569501 _CFAutoreleasePoolPop + 16
5  Foundation                     0x2df69999 -[__NSOperationInternal _start:] + 1064
6  Foundation                     0x2e00d745 __NSOQSchedule_f + 60
7  libdispatch.dylib              0x382b8cbd _dispatch_queue_drain + 488
8  libdispatch.dylib              0x382b5c6f _dispatch_queue_invoke + 42
9  libdispatch.dylib              0x382b95f1 _dispatch_root_queue_drain + 76
10 libdispatch.dylib              0x382b98dd _dispatch_worker_thread2 + 56
11 libsystem_pthread.dylib        0x383e4c17 _pthread_wqthread + 298


推荐答案

这不是RestKit的问题。我经常看到这个问题,它实际上看起来像过度释放实际上发生在苹果的代码。当您尝试保存到Core Data存储并且失败时,会发生此问题。核心数据报告错误,因为它应该,但该错误处理错误。

This isn't a problem with RestKit. I've seen this problem frequently and it actually looks like the over-release actually happens in Apple's code. The problem happens when you try to save to a Core Data store and it fails. Core Data reports an error as it should, but that error is mishandled.

我有一些情况导致保存失败,这是我如何修复他们:

I had a few scenarios causing the save failures and this is how I fixed them:

由于数据保护API,无法访问数据存储。

让您的应用程式无法启动,如下所示:

Either busy wait and let your app fail to launch like this:

while(![[UIApplication sharedApplication] isProtectedDataAvailable]) {
        [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.5f]];
   }

或禁用保护,如果您的商店中的数据不敏感,

Or disable protection if the data in your store isn't sensitive like this:

[_coordinator addPersistentStoreWithType:NSSQLiteStoreType
                               configuration:nil
                                         URL:url
            options:@{NSPersistentStoreFileProtectionKey:NSFileProtectionNone}
                                       error:&error];

重要的是,您不能尝试保存,直到您可以访问该文件。如果你可以重新构造你的代码,以防止访问数据库时,它是不可访问的,这也是好的。您可以使用Data Protection API应用程序委托方法来触发该机制。

The important thing is that you don't try to save until you can access the file. If you can re-structure you code to prevent accessing the database when it is inaccessible that is good too. You can use the Data Protection API application delegate methods to trigger that mechanism.

数据存储已损坏 - 最好的做法是删除存储并重新开始。这是一种使用sqlite库直接检测损坏的商店的好方法。

    #import <sqlite3.h>

    sqlite3 *dbConnection;
    if (sqlite3_open([[url absoluteString] UTF8String], &dbConnection) != SQLITE_OK) {
        NSLog(@"[SQLITE] Unable to open database!");
    }
    sqlite3_stmt *statement = nil;
    sqlite3_prepare_v2(dbConnection, "PRAGMA quick_check;", -1, &statement, NULL);
    NSString *result = nil;
    while (sqlite3_step(statement) == SQLITE_ROW) {
        for (int i=0; i<sqlite3_column_count(statement); i++) {
            int colType = sqlite3_column_type(statement, i);
            if (colType == SQLITE_TEXT) {
                const unsigned char *col = sqlite3_column_text(statement, i);
                result = [NSString stringWithFormat:@"%s", col];
            } else {
                NSLog(@"[SQLITE] UNKNOWN DATATYPE");
            }
        }
    }
    sqlite3_close(dbConnection);

这将运行sqlite PRAGMA查询以执行完整性检查。我使用quick_check,但你也可以使用integrity_check如果你愿意等待额外的时间。你可以告诉事情是好的使用[result isEqualToString:@ok]

This runs a sqlite PRAGMA query to perform an integrity check. I use quick_check, but you could also use integrity_check if you are willing to wait the extra time. You can tell things are good using [result isEqualToString:@"ok"]

这篇关于RestKit核心数据NSError dealloc崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆