2017-07-25 63 views
0

有时它给这个Coredata随机崩溃1560年,1550

2017-07-25 11:57:51.839 Test[14097:17556837] CoreData: error: Serious application error. Exception was caught during Core Data change processing. This is usually a bug within an observer of NSManagedObjectContextObjectsDidChangeNotification. -[__NSCFSet addObject:]: attempt to insert nil with userInfo (null) 
2017-07-25 11:57:51.852 Test[14097:17556837] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFSet addObject:]: attempt to insert nil' 
*** First throw call stack: 
(
    0 CoreFoundation      0x01573a94 __exceptionPreprocess + 180 
    1 libobjc.A.dylib      0x00c9be02 objc_exception_throw + 50 
    2 CoreFoundation      0x015739bd +[NSException raise:format:] + 141 
    3 CoreFoundation      0x01449d69 -[__NSCFSet addObject:] + 185 
    4 CoreData       0x010c8e00 -[NSManagedObjectContext(_NSInternalChangeProcessing) _processPendingInsertions:withDeletions:withUpdates:] + 560 
    5 CoreData       0x010c3a1c -[NSManagedObjectContext(_NSInternalChangeProcessing) _processRecentChanges:] + 2204 
    6 CoreData       0x010c3166 -[NSManagedObjectContext processPendingChanges] + 54 
    7 CoreData       0x01096355 _performRunLoopAction + 357 
    8 CoreFoundation      0x0148d77e __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 30 
    9 CoreFoundation      0x0148d6de __CFRunLoopDoObservers + 398 
    10 CoreFoundation      0x0148305c __CFRunLoopRun + 1340 
    11 CoreFoundation      0x01482866 CFRunLoopRunSpecific + 470 
    12 CoreFoundation      0x0148267b CFRunLoopRunInMode + 123 
    13 GraphicsServices     0x0801e664 GSEventRunModal + 192 
    14 GraphicsServices     0x0801e4a1 GSEventRun + 104 
    15 UIKit        0x01e5dcc1 UIApplicationMain + 160 
    16 Test        0x000f3a2b main + 75 
    17 libdyld.dylib      0x0496fa21 start + 1 
) 
libc++abi.dylib: terminating with uncaught exception of type NSException 

有时是给我这个

fatal error: Failure to save context: Error Domain=NSCocoaErrorDomain Code=1550 “The operation couldn’t be completed. (Cocoa error 1550.)” UserInfo={NSLocalizedDescription=The operation couldn’t be completed. (Cocoa error 1550.), Dangling reference to an invalid object.=null, NSValidationErrorObject=<Test.Article: 0x7c191030> (entity: Article; id: 0x7c1927d0 <x-coredata:///Article/t8BA04531-EB12-479D-9C0E-FF22ADE34A62201> ; data: { 
    category = “0x7aeecc30 <x-coredata://5095458E-7D52-4717-A948-E58E1C13176D/Category/p27>“; 
    categoryID = 5; 
    content =  (
     “0x7c457250 <x-coredata:///Content/t8BA04531-EB12-479D-9C0E-FF22ADE34A62202>“, 
     “0x7c18b890 <x-coredata:///Content/t8BA04531-EB12-479D-9C0E-FF22ADE34A62203>“, 
     “0x7c454840 <x-coredata:///Content/t8BA04531-EB12-479D-9C0E-FF22ADE34A62204>” 
    ); 
    featuredImage = “600x600(19).jpg”; 
    id = 1; 
    issueID = 1; 
    mainImage = “1.jpg”; 
    state = downloaded; 
    title = “New Title”; 
    version = “1.0”; 
}), NSAffectedObjectsErrorKey=(
    “<Test.Content: 0x7c454880> (entity: Content; id: 0x7c454840 <x-coredata:///Content/t8BA04531-EB12-479D-9C0E-FF22ADE34A62204> ; data: {\n article = nil;\n content = \“<p>New Content For Testing</p>\“;\n imageID = nil;\n ordering = 3;\n typeID = Paragraphs;\n})” 
), NSValidationErrorKey=content, NSValidationErrorValue=Relationship ‘content’ on managed object (0x7c191030) <Test.Article: 0x7c191030> (entity: Article; id: 0x7c1927d0 <x-coredata:///Article/t8BA04531-EB12-479D-9C0E-FF22ADE34A62201> ; data: { 
    category = “0x7aeecc30 <x-coredata://5095458E-7D52-4717-A948-E58E1C13176D/Category/p27>“; 
    categoryID = 5; 
    content =  (
     “0x7c457250 <x-coredata:///Content/t8BA04531-EB12-479D-9C0E-FF22ADE34A62202>“, 
     “0x7c18b890 <x-coredata:///Content/t8BA04531-EB12-479D-9C0E-FF22ADE34A62203>“, 
     “0x7c454840 <x-coredata:///Content/t8BA04531-EB12-479D-9C0E-FF22ADE34A62204>” 
    ); 
    featuredImage = “600x600(19).jpg”; 
    id = 1; 
    issueID = 1; 
    mainImage = “1.jpg”; 
    state = downloaded; 
    title = “New Title”; 
    version = “1.0”; 
}) with objects {(
    <Test.Content: 0x7c459270> (entity: Content; id: 0x7c457250 <x-coredata:///Content/t8BA04531-EB12-479D-9C0E-FF22ADE34A62202> ; data: { 
    article = nil; 
    content = “<p>Another Content with &lt;p&gt; Tag</p>“; 
    imageID = nil; 
    ordering = 1; 
    typeID = Introduction; 
}), 
    <Test.Content: 0x7c190cf0> (entity: Content; id: 0x7c18b890 <x-coredata:///Content/t8BA04531-EB12-479D-9C0E-FF22ADE34A62203> ; data: { 
    article = nil; 
    content = “Last Content”; 
    imageID = nil; 
    ordering = 2; 
    typeID = Illustration; 
}), 
    <Test.Content: 0x7c454880> (entity: Content; id: 0x7c454840 <x-coredata:///Content/t8BA04531-EB12-479D-9C0E-FF22ADE34A62204> ; data: { 
    article = nil; 
    content = “<p>New Content For Testing</p>“; 
    imageID = nil; 
    ordering = 3; 
    typeID = Paragraphs; 
}) 
)}, NSValidationErrorShouldAttemptRecoveryKey=true}: file /Users/user/Documents/Development/Test/Test/Issues/IssuesViewController.swift, line 322 

我相信这是由于并发性,而且是不确定的关系 以下是文章和内容模型

enter image description here enter image description here

这里是主要的API。我是否正确使用执行块?我应该使用它吗?我是否过度使用它?

func getArticleDetailsForArticleId(whereArticleId articleId: String, andCategoryObj categoryObj: Category) 
    { 
     //let issue = (Array(categoryObj.issue!) as! [Issue])[0] 
     let group = /*issue.articleDispatchGroup*/categoryObj.issue!.articleDispatchGroup 
     let queue = /*issue.articleQueue*/categoryObj.issue!.articleQueue 
     var errors = /*issue.articleErrors*/categoryObj.issue!.articleErrors 

     group.enter() 
     let privateMOC = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType) 
     privateMOC.parent = (UIApplication.shared.delegate as! AppDelegate).managedObjectContext 

     group.enter() 
     privateMOC.perform { 

     categoryObj.state = State.downloading.rawValue 
     do { 
      try privateMOC.save() 
      privateMOC.parent!.perform { 
       do { 
        try privateMOC.parent!.save() 
       } catch { 
        fatalError("Failure to save context: \(error)") 
       } 
      } 
     } catch { 
      fatalError("Failure to save context: \(error)") 
     } 
     } 

     print("saved category is downloading") 
     DataManager.sharedInstance.getArticleDetails(whereArticleId: articleId, andCompletionHandler: { (success, response) in 

      let privateMOC = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType) 
      privateMOC.parent = (UIApplication.shared.delegate as! AppDelegate).managedObjectContext 
      print("I am articleId \(articleId)") 
      // SVProgressHUD.dismiss() 
      //self.apiInProgress = false 
      if success 
      { 
       privateMOC.perform/* queue.async*/{ 

       let articleDetail = response.responseData as! Article 
       articleDetail.state = State.downloaded.rawValue 

       //queue.async { 

       //categoryObj.addToArticles(articleDetail) 
       //categoryObj. 


        //categoryObj.addToArticles(articleDetail) 
        let articles = NSMutableOrderedSet(orderedSet: categoryObj.articles!) 
        for content in Array(articleDetail.content!) 
        { 
         (content as! Content).article = articleDetail // should I add this line or the inverse relatioship is enough to set this 
         //privateMOC.parent?.insert(content as! Content) 
        } 
        // privateMOC.parent?.insert(articleDetail) 

        //articleDetail.content = NSOrderedSet(array: articleDetail.contents!) 
        articles.add(articleDetail) 
        categoryObj.articles = articles 

        //articleDetail.category = categoryObj 
        //categoryObj.theArticles.append(articleDetail) 

        categoryObj.issue!.articlesDownloaded += 1//categoryObj.issue?.articlesDownloaded += 1 
        let progress = CGFloat(categoryObj.issue!.articlesDownloaded)/CGFloat(categoryObj.issue!.articlesCount) 
        OperationQueue.main.addOperation({ 
         self.issuesToProgressDictionary[categoryObj.issue!]?.pathFromProgress(whereProgress: progress,andFillColor: UIColor(red: 64/1255.0, green: 121/255.0, blue: 117/255.0, alpha: 0.4),andStrokeColor: UIColor.clear) 
         categoryObj.state = State.downloaded.rawValue 

         //(UIApplication.shared.delegate as! AppDelegate).saveContext() 
        }) 
        do { 
         try privateMOC.save() 
         privateMOC.parent!.perform { 
          do { 
           try privateMOC.parent!.save() 
          } catch { 
           let categoryObjec = categoryObj 
           let articDet = articleDetail 
           fatalError("Failure to save context: \(error)") 
          } 
         } 
        } catch { 
         fatalError("Failure to save context: \(error)") 
        } 
       } 
      } 
    else 
    { 
    queue.async { 
    errors.append(response.responseError!.errorMessage!) 
    } 
    let alert = UIAlertController(title: "OOPS", message: response.responseError?.errorMessage, preferredStyle: .alert) 
    alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: nil)) 
    alert.addAction(UIAlertAction(title: "Try Again", style: .default, handler: { (action) in 
    self.getIssues() 
    })) 
    self.present(alert, animated: true, completion: nil) 
    } 
    group.leave() 
}) 

} 

下面是一个示例NSManagedObject:第

// 
// Article+CoreDataClass.swift 
// 
// 
// Created by User on 7/12/17. 
// 
// 

import Foundation 
import CoreData 
import ObjectMapper 

//@objc(Article) 
public class Article: NSManagedObject, Mappable { 

    var contents : [Content]? 
    //var content: NSOrderedSet? 
    required public init?(map: Map) { 
     let context = (UIApplication.shared.delegate as! AppDelegate).managedObjectContext 
     let entity = NSEntityDescription.entity(forEntityName: "Article", in: context) 

     super.init(entity: entity!, insertInto: context) 
     self.mapping(map: map) 
     self.content = NSOrderedSet(array: self.contents!) 
      } 
     //  } 

    } 

    override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) { 
     super.init(entity: entity, insertInto: (UIApplication.shared.delegate as! AppDelegate).managedObjectContext) 
    } 


    //private override init(){} 

    public func mapping(map: Map) 
    { 

     featuredImage <- map["FeaturedImage"] 
     issueID <- map["IssueID"] 
     mainImage <- map["MainImage"] 
     title <- map["Title"] 
     version <- map["Version"] 
     categoryID <- map["categoryID"] 
     id <- map["ArticleID"] 
     contents <- map["Content"] 
     //content = NSOrderedSet(array: map["Content"] as! [Content]) 
     state = State.nothing.rawValue 
    } 

} 

回答

0

看行:

DataManager.sharedInstance.getArticleDetails(whereArticleId: articleId, andCompletionHandler: { (success, response) in 

在这里,您从一个线程请求CoreData模型,并将其加工成其他线程:

privateMOC.perform/* queue.async*/{ 

let articleDetail = response.responseData as! Article 
articleDetail.state = State.downloaded.rawValue 
<....> 

您不应该在threads之间共享CoreData型号。

NSManagedObject实例不打算在 之间传递队列。否则可能导致应用程序的数据损坏并终止 。当需要将管理对象从一个队列切换到另一个时,必须通过 NSManagedObjectID实例完成。

+0

我试着添加这个 让categoryObj = privateMOC.parent!.object(with:categoryObj.objectID)as!类别 - 只是在DataManager.sharedInstance.getArticleDetails {} //里面没有区别 – thirdage

+0

你确定当前线程中的“categoryObj.objectID”?我认为方法getArticleDetails的complitionHandler在主线程上被调用,但请求在后台线程上执行。如果不是这样,可能是我错了。 –

+0

我想你应该从getArticleDetails方法返回complitionHandler UID数组(不是对象数组)。 –

0

如前所述,主要问题是您将对象从一个上下文传递到另一个上下文。您似乎有许多方法会假定要使用的上下文而不是作为参数传递的上下文。

例如:

override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) { 
    super.init(entity: entity, insertInto: (UIApplication.shared.delegate as! AppDelegate).managedObjectContext) 
} 

你是假设所有对象创建将发生在主背景。任何尝试创建具有不同上下文的对象都会崩溃。看起来您正在尝试通过始终获取主要上下文来使对象创建更简单,更方便。这是一个错误。由于您不容易知道您使用的是什么环境,因此您将使代码更加复杂。

同样,方法DataManager.sharedInstance.getArticleDetails似乎做了一个提取并将结果返回到一个块中。它使用哪种上下文?它返回什么线程?如果它使用主要上下文,那么它是否必须在主线程上运行,或者它是否在内部执行dispatch_async?由于取回的上下文隐藏起来,因此很难了解您的代码。如果无法追踪使用的上下文,则在任何地方添加performBlock都无法解决您的问题。取而代之的是,getArticleDetails(whereArticleId:, inContext:)的方法更易于理解和使用。

我不明白你的大部分代码。这似乎是一个大混乱。我看起来像你开始崩溃,所以你添加更多的performBlock和更多的线程,而不修复任何真正的问题。要理解的关键是,对于每个核心数据操作 - 读取,插入,更新 - 您必须知道上下文是什么,并且必须从正确的线程调用它。所以如果你有一个方法在核心数据中进行读取,你必须将它传递给一个上下文。如果你只是假设上下文是主要的上下文,你会搞砸了。

如果您有一个传递managedObject的方法,那么它应该只使用它传递和返回的对象的上下文。传递managedObjects然后使用不同的上下文是灾难的秘诀。

我建议使用NSPersistentContainer。用viewContext做所有的阅读,并用performBackgroundTask:来完成你所写的全部内容。请勿使用块外部performBackgroundTask:中创建的任何对象。

+0

我尝试在主队列上运行的东西,因为我使用的主要上下文。它仍然有时会崩溃。 – thirdage

+0

我希望我能帮到更多,但我真的不明白你的代码。 –