【问题标题】:Application crashes while saving core data in iOS11在 iOS11 中保存核心数据时应用程序崩溃
【发布时间】:2017-09-25 05:07:13
【问题描述】:

在 iOS 10 中完美运行。在我将 iOS 更新到 iOS11 后,应用程序在将数据保存到核心数据时崩溃,但出现异常。 我已经为 coredata 使用了 RZVinyl 框架

BOOL isSaved = [currentContext save:&saveErr];

断言失败:(moreParameters->mostRecentEntry == CFArrayGetValueAtIndex(stack, stackCount - 1)), 函数 NSKeyValuePopPendingNotificationPerThread,文件 /BuildRoot/Library/Caches/com.apple.xbs/Sources/Foundation_Sim/Foundation-1444.12/EO.subproj/NSKeyValueObserving.m,第 933 行。

0   libsystem_kernel.dylib            0x00000001826fd348 __pthread_kill + 8
1   libsystem_pthread.dylib           0x0000000182811354 pthread_kill$VARIANT$mp + 396
2   libsystem_c.dylib                 0x000000018266cfd8 abort + 140
3   libsystem_c.dylib                 0x0000000182640abc basename_r + 0
4   Foundation                        0x00000001834f1a9c -[NSRunLoop+ 178844 (NSRunLoop) runUntilDate:] + 0
5   Foundation                        0x00000001834df538 NSKeyValueDidChange + 436
6   Foundation                        0x0000000183597ae4 NSKeyValueDidChangeWithPerThreadPendingNotifications + 140
7   CoreData                          0x00000001854107c8 -[NSManagedObject didChangeValueForKey:] + 120
8   CoreData                          0x0000000185416358 -[NSManagedObject+ 844632 (_NSInternalMethods) _updateFromRefreshSnapshot:includingTransients:] + 692
9   CoreData                          0x000000018542e054 -[NSManagedObjectContext+ 942164 (_NestedContextSupport) _copyChildObject:toParentObject:fromChildContext:] + 652
10  CoreData                          0x000000018542e4bc -[NSManagedObjectContext+ 943292 (_NestedContextSupport) _parentProcessSaveRequest:inContext:error:] + 804
11  CoreData                          0x000000018542f3f0 __82-[NSManagedObjectContext+ 947184 (_NestedContextSupport) executeRequest:withContext:error:]_block_invoke + 580
12  CoreData                          0x0000000185431644 internalBlockToNSManagedObjectContextPerform + 92
13  libdispatch.dylib                 0x0000000182569048 _dispatch_client_callout + 16
14  libdispatch.dylib                 0x0000000182571ae8 _dispatch_queue_barrier_sync_invoke_and_complete + 56
15  CoreData                          0x000000018541dd10 _perform + 232
16  CoreData                          0x000000018542f0e4 -[NSManagedObjectContext+ 946404 (_NestedContextSupport) executeRequest:withContext:error:] + 172
17  CoreData                          0x0000000185387ff8 -[NSManagedObjectContext save:] + 2580
NSManagedObjectContext *currentContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[[currentContext userInfo] setObject:self forKey:kRZCoreDataStackParentStackKey];

[self performBlock:^{
    BOOL hasChanges = [currentContext hasChanges];
    if ( !hasChanges) {
        RZVLogInfo(@"Managed object context %@ does not have changes, not saving", self);
        rzv_performSaveCompletionAsync(completion, nil);
        return;
    }

    NSError *saveErr = nil;
    BOOL isSaved = [currentContext save:&saveErr];
    if ( !isSaved) {
        RZVLogError(@"Error saving managed object context context %@: %@", self, saveErr);
        rzv_performSaveCompletionAsync(completion, saveErr);

    }      
}];

【问题讨论】:

    标签: objective-c ios11


    【解决方案1】:

    我现在也有同样的事情,当我遇到你的问题时正在寻找答案。

    在没有找到任何答案的情况下,我做了一些深入的调查并找到了原因(至少在我的情况下)。

    事实证明,对象的关系之一是观察 KV 变化以更新对象的值变化,同时它也在更新关系值的变化。

    触发并更新对象,导致关系随着变化而更新,依此类推......

    KVO 中的这种递归导致了崩溃。

    确保如果您通过willChangeValuedidChangeValue 观察更改以更新您与此更改的关系,如果观察者是被设置的,请不要更新。

    这对你有意义吗?

    如果是这种情况,请告诉我,您需要一个代码示例来理解这个非常令人困惑的答案。

    更新:

    我知道我的回答很混乱和含糊,所以我将添加一个示例。

    考虑以下问题。 我们有两个相互关联的示例类(即反向关系):

    class A: NSManagedObject {
    
        @NSManaged var id: NSNumber!
        @NSManaged var title: String?
        @NSManaged var b: B!
    
        override func willChangeValue(forKey key: String) {
            super.willChangeValue(forKey: key)
            b?.willChangeValue(forKey: "a")
        }
    
        override func didChangeValue(forKey key: String) {
            super.didChangeValue(forKey: key)
            b?.didChangeValue(forKey: "a")
        }
    }
    
    class B: NSManagedObject {
    
        @NSManaged var id: NSNumber!
        @NSManaged var name: String?
        @NSManaged var date: Date?
        @NSManaged var a: A!
    
        override func willChangeValue(forKey key: String) {
            super.willChangeValue(forKey: key)
            a?.willChangeValue(forKey: "b")
        }
    
        override func didChangeValue(forKey key: String) {
            super.didChangeValue(forKey: key)
            a?.didChangeValue(forKey: "b")
        }
    
        func setNewA(_ newA: A) {
            newA.b = self
            a = newA
        }
    }
    

    我们在每个类中使用willChangeValuedidChangeValue 来通知它关于自身变化的关系。

    现在考虑以下代码:

    let b = B(context: context)
    let a = A(context: context)
    b.setNewA(a)
    

    我们使用setNewA 函数来设置反向引用。 在该函数中,首先将b 分配给a.b 用于反向引用,然后设置self.a 引用。 此时,a 已经知道b

    后者将导致b 上的willChangeValuedidChangeValue 被调用(正如我们设置的a)。然后a 将接收更新并通知b

    从这里开始,试着猜猜它会如何继续。

    这几乎就是发生在我身上的事情,只是有一些细微的差别。

    我覆盖了这些函数,因为我使用的是 NSFetchedResultsController,并且我需要了解关系的变化来更新我的 UI。

    它让我陷入了导致崩溃的循环。

    最后,修复相当简单。 A修改为:

    override func willChangeValue(forKey key: String) {
        super.willChangeValue(forKey: key)
        guard key != "b" else { return }
        b?.willChangeValue(forKey: "a")
    }
    
    override func didChangeValue(forKey key: String) {
        super.didChangeValue(forKey: key)
        guard key != "b" else { return }
        b?.didChangeValue(forKey: "a")
    }
    

    B 修改方式相同,为:

    override func willChangeValue(forKey key: String) {
        super.willChangeValue(forKey: key)
        guard key != "a" else { return }
        a?.willChangeValue(forKey: "b")
    }
    
    override func didChangeValue(forKey key: String) {
        super.didChangeValue(forKey: key)
        guard key != "a" else { return }
        a?.didChangeValue(forKey: "b")
    }
    

    一旦设置了关系本身,这会阻止每个人更新另一个人(这是多余的,因为一旦设置了它的一个属性,每个人都已经收到通知),从而打破了循环。

    同样,这就是我的情况,这就是解决它的原因。 不知道您是否因为同样的原因遇到了这个问题,但希望它能让您知道在哪里寻找。

    希望现在更容易理解。

    如果您仍然无法理解,请分享一些代码或直接与我联系,我会尽力提供帮助。

    【讨论】:

    • 这与项目非常接近。在很多地方使用它们。我可以提供一些修复您的错误的示例代码吗?
    • 这与项目非常接近。在很多地方使用它们。我可以提供一些修复您的错误的示例代码吗?您是否可以重新表述“确保如果您通过 willChangeValue 和 didChangeValue 观察更改以更新您与此更改的关系,如果观察者是被设置的人,请不要更新。”有点混乱。
    • 非常感谢奥伦。你的例子很清楚,解决了我的问题。
    • 没问题,很高兴它有帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-24
    • 2011-01-10
    • 2011-10-06
    • 1970-01-01
    相关资源
    最近更新 更多