2017-09-25 182 views
1

在iOS 10中完美运行。在将iOS更新为iOS11后,应用程序崩溃时将数据保存到核心数据中,但有一个例外。 为coredata我已经使用RZVinyl框架在iOS11中保存核心数据时应用程序崩溃

BOOL isSaved = [currentContext save:&saveErr]; 

断言失败:(moreParameters-> mostRecentEntry == CFArrayGetValueAtIndex(堆栈,stackCount - 1)),函数 NSKeyValuePopPendingNotificationPerThread,文件 /buildroot的/库/高速缓存/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); 

    }  
}]; 

回答

0

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

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

事实证明,一个对象的关系是观察KV的变化,更新对象的变化值,它也更新了关系值的变化。

这引发且物体,造成与变化更新的关系更新,等等等等......

这递归在志愿导致崩溃。

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

这对你有意义吗?

让我知道如果是这种情况,你需要一个代码示例来理解这个非常令人困惑的答案。

UPDATE:

我知道我的答案是相当混乱和模糊,所以我加入了一个例子。

请考虑以下情况。 我们拥有彼此之间的关系(即反向关系)两个示例类:

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

以后将会导致willChangeValuedidChangeValue被调用(因为我们设置了a)。然后a将接收更新并通知b

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

这几乎发生在我身上,发生了一些细微的不同。

我覆盖了这些功能,因为我使用的是NSFetchedResultsController,我需要选择关系中的更改来更新我的用户界面。

它把我扔进了一个导致崩溃的循环。

最后,修复很简单。 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") 
} 

这防止每个从更新一次的关系本身被设定在其它(这是多余的,因为每当其中一个属性被设置时,每个都已经被通知),从而打破了这个循环。

同样,这是我的情况,这是什么修复它。 不知道是否由于相同的原因而遇到问题,但希望它能让您知道在哪里寻找。

希望现在更容易理解。

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

+0

这与项目非常接近。在很多地方使用它们。我可以有一些解决你的错误的示例代码。 – Joe

+0

这与项目非常接近。在很多地方使用它们。我是否可以提供一些修正错误的示例代码,并且还可以改为“确保如果您通过willChangeValue和didChangeValue观察更改以更新关于此更改的关系,请不要更新,如果观察者是正在设置的观察者“。它有点混乱。 – Joe

+0

非常感谢Oren。你的例子很清楚,解决了我的问题。 – Joe