我已经重写了我们的iOS应用,以便在Core Data中使用新的iOS 10功能。特别是我已将Core Data堆栈创建切换到新的NSPersistentStore设置。
我们已经有了一个主队列上下文和一个后台上下文,所以我们直接使用NSPersistentStore对象。我还改变了使用通知将各种更改合并到在viewContext和backgroundContext中设置新的automaticMergesChangesFromParent。
不幸的是,我现在在NSFetchedResultsController中遇到了许多奇怪的崩溃,它们更新了UICollectionViewController和视图。
所以我设置了" -com.apple.CoreData.ConcurrencyDebug 1"启动参数以确保事情发生在正确的队列上,当后台线程尝试保存后台对象上下文时,我立即得到异常,即使堆栈跟踪显示正在"正确"后台队列:
#0 0x00000001948b89bc in +[NSManagedObjectContext __Multithreading_Violation_AllThatIsLeftToUsIsHonor__] ()
#1 0x0000000194853724 in -[_PFBatchFaultingArray managedObjectIDAtIndex:] ()
#2 0x0000000194853600 in -[_PFMutableProxyArray newArrayFromObjectIDs] ()
#3 0x0000000194853548 in -[_PFMutableProxyArray arrayFromObjectIDs] ()
#4 0x0000000194852638 in -[NSFetchedResultsController(PrivateMethods) _managedObjectContextDidSave:] ()
#5 0x00000001924e622c in __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ ()
#6 0x00000001924e5930 in _CFXRegistrationPost ()
#7 0x00000001924e56ac in ___CFXNotificationPost_block_invoke ()
#8 0x0000000192554b9c in -[_CFXNotificationRegistrar find:object:observer:enumerator:] ()
#9 0x0000000192427bf4 in _CFXNotificationPost ()
#10 0x0000000192f2e6bc in -[NSNotificationCenter postNotificationName:object:userInfo:] ()
#11 0x00000001948c5b48 in -[NSManagedObjectContext(_NSInternalNotificationHandling) _postContextDidSaveNotificationWithUserInfo:] ()
#12 0x0000000194850350 in -[NSManagedObjectContext(_NSInternalAdditions) _didSaveChanges] ()
#13 0x000000019483ca0c in -[NSManagedObjectContext save:] ()
关于我可能做错的任何想法?以下是一些相关代码:
var initializationError: NSError?
// The persistent container (local database) for the application.
lazy var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: self.storeName)
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
self.initializationError = error // This will be displayed by the AppDelegate
}
})
return container
}()
// The managed object context for the main thread of the application.
lazy var mainObjectContext: NSManagedObjectContext? = {
// Get the main thread context.
let context = self.persistentContainer.viewContext
context.mergePolicy = NSOverwriteMergePolicy // In-memory properties overwrite datastore properties
context.automaticallyMergesChangesFromParent = true // Merge all changes.
return context
}()
// Return a managed object for background threads to create and modify objects without affecting the main thread until necessary.
lazy var backgroundObjectContext: NSManagedObjectContext? = {
// Get a background thread context.
let context = self.persistentContainer.newBackgroundContext()
context.mergePolicy = NSOverwriteMergePolicy // In-memory properties overwrite datastore properties
context.automaticallyMergesChangesFromParent = true // Merge all changes.
return context
}()
// Synchronously save any pending object changes in a managed object context to the database persistent store.
class func saveAnyChangesSync(_ context: NSManagedObjectContext) -> NSError? {
var error: NSError?
// If the context has changes, save them.
if context.hasChanges {
do {
try context.save()
} catch let saveError as NSError {
error = saveError
NSLog("CoreData error saving context \(saveError)")
}
}
return error
}
答案 0 :(得分:1)
如果您正在管理Swift中的核心数据而没有看到在后台保存和主要上下文之间传播的更改,那么您(像我一样)可能会缺少autoreleasepool部分(pfffbt!objective-c)。我在做这个改变之前看到了一堆错误,虽然我的一切都是关于NSSet被改变的。
您可能还想查看合并策略 - 我认为两种情境都不应该具有相同的策略。主要应该屈服于文件存储和背景shoudl坚持当前对象的变化。
缩写示例:
Create FUNCTION Trim
(
@Original varchar(max), @letter char(1)
)
RETURNS varchar(max)
AS
BEGIN
DECLARE @rtrim varchar(max)
SELECT @rtrim = iif(right(@original, 1) = @letter, left(@original,datalength(@original)-1), @original)
return iif( left(@rtrim,1) = @letter, right(@rtrim,datalength(@rtrim)-1),@rtrim)
END
答案 1 :(得分:0)
我猜想saveAnyChangesSync
是从具有后台上下文的主线程中调用的,在这种情况下,您将需要使用上下文的perform方法。
/* asynchronously performs the block on the context's queue. Encapsulates an autorelease pool and a call to processPendingChanges */
- (void)performBlock:(void (^)(void))block API_AVAILABLE(macosx(10.7),ios(5.0));
/* synchronously performs the block on the context's queue. May safely be called reentrantly. */
- (void)performBlockAndWait:(void (NS_NOESCAPE ^)(void))block API_AVAILABLE(macosx(10.7),ios(5.0));