Coredata随机崩溃1560,1550

时间:2017-07-25 09:12:01

标签: ios core-data objectmapper

有时它会给出这个

    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
    }

}

2 个答案:

答案 0 :(得分: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实例。

答案 1 :(得分:0)

正如已经解释的那样,主要问题是您将对象从一个上下文传递到另一个上下文。您似乎有许多方法可以假设要使用的上下文而不是作为参数传递的上下文。

例如:

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

您假设所有对象创建都将在主要上下文中进行。任何使用不同上下文创建对象的尝试都将崩溃。您似乎总是通过获取主上下文来使对象创建更简单,更方便。那是一个错误。通过不知道您正在使用的上下文,您正在使代码FAR变得更加复杂。

同样,方法DataManager.sharedInstance.getArticleDetails似乎进行获取并在块中返回结果。它使用哪种上下文?它返回什么线程?如果它使用主上下文,那么它必须在主线程上运行还是在内部执行dispatch_async?很难用你的代码知道,因为fetch的上下文被隐藏了。如果您无法跟踪您使用的上下文,那么在任何地方添加performBlock都无法解决您的问题。相反,使用getArticleDetails(whereArticleId:, inContext:)的方法更容易理解和使用。

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

如果您有一个传递给托管对象的方法,那么它应该只使用它传递的对象的上下文并返回。传递托管对象然后使用不同的上下文是灾难的一个方法。

我建议使用NSPersistentContainer。使用viewContext完成所有阅读,并使用performBackgroundTask:进行所有阅读。不要使用在块外的performBackgroundTask:中创建的任何对象。