2017-09-25 175 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

相關問題