无法使NSManagedObject.automaticallyMergesChangesFromParent工作

时间:2016-10-16 00:19:11

标签: ios core-data

我已经重写了我们的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
}

2 个答案:

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