在iOS11中保存核心数据时应用程序崩溃

时间:2017-09-25 05:07:14

标签: objective-c ios11

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

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

    }      
}];

1 个答案:

答案 0 :(得分:0)

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

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

事实证明,对象的一个​​关系是观察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

后者会导致调用willChangeValue上的didChangeValueb(因为我们设置了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")
}

这可以防止每个设置关系后更新另一个(这是多余的,因为一旦设置了其中一个属性,每个都已经通知),从而打破了循环。

同样,这就是我的结果,这就是解决它的问题。 由于同样的原因,不知道你是否遇到了这个问题,但希望它能让你知道在哪里看。

希望现在更容易理解。

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