核心数据多线程违规

Posted

技术标签:

【中文标题】核心数据多线程违规【英文标题】:Core Data Multithreading violation 【发布时间】:2016-06-09 08:47:33 【问题描述】:

我遇到了 Core Data 多线程违规问题。即使我使用performBlockAndWait。我有一个NSOperation 子类来执行云套件的 BG 提取。下面是代码。它在所有执行完成后崩溃。

override public func main() 
 self.localStoreMOC?.performBlockAndWait( () -> Void in 
            do
            
                try self.fetchTest()
                self.syncCompletionBlock!(syncError: nil)
            
            catch let error as NSError
            
                let userInfo:Dictionary<String, AnyObject> = [CKSIncrementalStoreError: error];

                let error1 = NSError(domain: CKSIncrementalStoreSyncOperationErrorDomain, code: CKSErrorCode.CKSErrorDatabaseError.rawValue, userInfo: userInfo)
                self.syncCompletionBlock!(syncError: error)

            
   )


func fetchTest() throws

    let predicate = NSPredicate(format: "%K != %@", CKSIncrementalStoreLocalStoreChangeTypeAttributeName, NSNumber(short: CKSLocalStoreRecordChangeType.RecordNoChange.rawValue))

    var deletedManagedObjects:Array<AnyObject> = Array<AnyObject>()
    var insertedOrUpdatedManagedObjects:Array<AnyObject> = Array<AnyObject>()

    let fetchRequest = NSFetchRequest(entityName: self.entityNames1.objectAtIndex(self.tableIndex) as! String)
    fetchRequest.sortDescriptors = [NSSortDescriptor(key: "modifiedDateL", ascending: false)]
    fetchRequest.predicate = predicate
    fetchRequest.fetchOffset = self.fetchOffset
    fetchRequest.fetchLimit = self.batchSize

    var results: [AnyObject]?
    do
    

        results = try self.localStoreMOC?.executeFetchRequest(fetchRequest)

        if results != nil && results?.count > 0
        
            insertedOrUpdatedManagedObjects += (results!.filter((object)->Bool in

                let managedObject:NSManagedObject = object as! NSManagedObject

                if (managedObject.valueForKey(CKSIncrementalStoreLocalStoreChangeTypeAttributeName)) as! NSNumber == NSNumber(short: CKSLocalStoreRecordChangeType.RecordUpdated.rawValue)
                
                    return true
                
                if (managedObject.valueForKey(CKSIncrementalStoreLocalStoreChangeTypeAttributeName)) as! NSNumber == NSNumber(short: CKSLocalStoreRecordChangeType.RecordInserted.rawValue)
                
                    return true
                
                return false
            ))

            deletedManagedObjects += (results!.filter((object)->Bool in

                let managedObject:NSManagedObject = object as! NSManagedObject
                if (managedObject.valueForKey(CKSIncrementalStoreLocalStoreChangeTypeAttributeName)) as! NSNumber == NSNumber(short: CKSLocalStoreRecordChangeType.RecordDeleted.rawValue)
                

                    return true
                
                return false
            ))


            self.totalItems = insertedOrUpdatedManagedObjects.count + deletedManagedObjects.count
            self.fetchOffset = self.fetchOffset + self.batchSize

            print("totalItems : \(self.totalItems) fetchOffset : \(self.fetchOffset) results \(results)")
            if self.totalItems < self.defaultBatchSize
            
                self.batchSize = self.defaultBatchSize - self.totalItems
            

        
        else
        
            self.tableIndex++
            self.fetchOffset = 0
        

    
    catch let error1 as NSError
    
        insertedOrUpdatedManagedObjects.removeAll()
        deletedManagedObjects.removeAll()
        results = nil
        throw error1
    

编辑1:

我缩小了崩溃的范围,但我仍然无法找出崩溃的原因。如果我不将结果存储在deletedManagedObjects、insertedOrUpdatedManagedObjects 中,则代码可以正常工作。但是如果我这样做,它会在 NSoperation 完成后崩溃。

编辑 2: 已添加崩溃行和线程跟踪的屏幕截图。

【问题讨论】:

确保您已通读核心数据和并发中的以下内容:developer.apple.com/library/content/documentation/Cocoa/… 【参考方案1】:

在调试器中为“所有异常”设置断点并再次运行测试。断点在哪里触发?

从阅读您的问题来看,您似乎在假设问题就在这里。

究竟是哪一行代码引发了异常?

更新 1

根据您更新的问题,问题是您在创建它们的队列之外触摸NSManagedObject 的实例,这违反了规则。 NSOperation 完成后,您将如何处理这些对象?

【讨论】:

All Exception 断点根本不会触发。它只是为我提供了 CoreDataViolation。已附加线程跟踪。 我不使用 NSoperation 之外的对象。完成块仅显示操作成功的警报。已从完成块中删除了所有代码,但仍显示相同的违规警告。断点用于触发“executeFetchRequest”,所以我隔离了代码以检查我做错了什么。 我观察到的是,如果我在上面的代码中执行 fetch 请求之后注释代码,它可以正常工作而没有任何警告,如果我确实使用该代码,那么它会显示多线程违规,即使我不返回方法中的对象。操作完成后会出现违规警告。设备为 ios 8.3 和 Xcode 7.2 再一次,在不知道违规触发时断点所在的代码行的情况下,您只是在猜测。显示断点触发的行。 已经用上面的代码添加了带有崩溃行的截图。

以上是关于核心数据多线程违规的主要内容,如果未能解决你的问题,请参考以下文章

核心数据多线程获取记录

iPhone 核心数据和多线程

核心数据多线程[关闭]

核心数据多线程:代码示例

核心数据多线程问题

多线程核心数据 - NSManagedObject 无效