核心数据崩溃尝试使用userInfo插入nil(null)

时间:2016-04-04 12:15:42

标签: ios swift core-data asynchronous

当我的代码尝试从API下载该系列时,它随机崩溃并显示以下错误消息:

  

(entity:Series; id:   0x7b181002016-04-04 14:01:33.868 Postzegel Catalogus [1816:39059]   CoreData:错误:严重的应用程序错误。抓住了例外   在核心数据更改处理期间。这通常是一个bug   NSManagedObjectContextObjectsDidChangeNotification的观察者。    - [ NSCFSet addObject:]:尝试使用userInfo(null)插入nil 0(entity:Series; id:   0x7b00c450    ;    2016-04-04 14:01:33.871 Postzegel目录[1816:39059] ***终止app到期   未被捕获的异常' NSInvalidArgumentException',原因:   ' - [__ NSCFSet addObject:]:尝试插入nil'   ***第一次抛出调用堆栈:(0 CoreFoundation 0x0083d494 __exceptionPreprocess + 180 1 libobjc.A.dylib
  0x02551e02 objc_exception_throw + 50 2 CoreFoundation
  0x0083d3bd + [NSException raise:format:] + 141 3 CoreFoundation
  0x0070c959 - [__ NSCFSet addObject:] + 185 4 CoreData
  0x0038a010 - [NSManagedObjectContext(_NSInternalChangeProcessing)   _processPendingInsertions:withDeletions:withUpdates:] + 560 5 CoreData 0x003846da    - [NSManagedObjectContext(_NSInternalChangeProcessing)_processRecentChanges:] + 2410 6 CoreData 0x00383d56 - [NSManagedObjectContext processPendingChanges] + 54 7
  CoreData 0x003ae5e4    - [NSManagedObjectContext(_NestedContextSupport)_parentProcessSaveRequest:inContext:error:] + 116 8 CoreData 0x00433bec __82- [NSManagedObjectContext(_NestedContextSupport)   executeRequest:withContext:error:] _ block_invoke + 412 9 CoreData
  0x003a924c internalBlockToNSManagedObjectContextPerform + 76 10   libdispatch.dylib 0x03c8f9cd   _dispatch_client_callout + 14 11 libdispatch.dylib 0x03c76d90 _dispatch_barrier_sync_f_slow_invoke + 133 12   libdispatch.dylib 0x03c8f9cd   _dispatch_client_callout + 14 13 libdispatch.dylib 0x03c74f7c _dispatch_main_queue_callback_4CF + 910 14 CoreFoundation   0x007871be __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE
+ 14 15   CoreFoundation 0x00745434 __CFRunLoopRun + 2356     16 CoreFoundation 0x00744846   CFRunLoopRunSpecific + 470 17 CoreFoundation
  0x0074465b CFRunLoopRunInMode + 123 18 GraphicsServices
  0x07a8d664 GSEventRunModal + 192 19 GraphicsServices
  0x07a8d4a1 GSEventRun + 104 20 UIKit
  0x0102beb9 UIApplicationMain + 160 21 Postzegel目录
  0x000f63b1 main + 145 22 libdyld.dylib
  0x03cb9a25 start + 1)(entity:Series; id:0x7b25bc40    ;

我只是不知道为什么?我使用了私有托管上下文选项,以便使用。我甚至将.xcdatamodeld中的字段设置为可选。所以它不应该是一个问题,它是否为零?它只会随机崩溃,甚至不会在同一个对象上。我该如何解决这个问题?

我包含了我的代码,希望对您有所帮助。我删除了我的API密钥,因此您无法尝试使用它。如果您对我的代码有任何其他评论,请告诉我,我是Core Data和Alamofire的新用户,因此我有租用来制作意大利面代码'。

提前致谢

import Foundation
import CoreData
import Alamofire
import SwiftyJSON

//CoreData Init
let appDelegate: AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext: NSManagedObjectContext = appDelegate.managedObjectContext

let queue = dispatch_queue_create("com.GJ-Computers.Postzegel-Catalogus.responseJSON-Manager", DISPATCH_QUEUE_CONCURRENT)

//Colnect API
let LANG: String = NSLocale.preferredLanguages()[0].substringToIndex(NSLocale.preferredLanguages()[0].startIndex.advancedBy(2))
let DATE = NSCalendar.currentCalendar().component([.Day, .Month, .Year], fromDate: NSDate())
let API_KEY: String = "----" //Private API KEY
let CAT_STAMPS: String = ("cat/stamps/")
var BASE_URL: String{
    return ("http://api.colnect.net/" + LANG + "/api/" + API_KEY + "/")
}

//Ghetto Delegate
var didGetCountires: Bool = false
var didGetYears: Bool = false
var didGetSeries: Bool = false

//MARK: - First Time setup Database
func setupDatabase(){
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)){


        getYears() //Download Years per country from database        
}
    }


//get Series
func getSeries(){
    //Retrieve Countries from Coredata
    let countryFetchRequest = NSFetchRequest(entityName: "Countries")
    var results: [Countries]?
    do {
        results = try managedContext.executeFetchRequest(countryFetchRequest) as? [Countries]
    } catch let error as NSError {
        print("Could not fetch \(error), \(error.userInfo)")
    }

    let resultCount = results!.count
    var completedRequestCount: Int = 0
    var requestedRequests = 0


    for result in results!{
        let countryID = result.countryID
        Alamofire.request(.GET, (BASE_URL + "series/"+CAT_STAMPS+"producer/\(countryID)")).responseJSON(queue: queue, completionHandler:{ response in
            if let json = response.result.value{
                let privateMOC = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)
                privateMOC.parentContext = managedContext

                let rawData = JSON(json)
                for data in rawData {
                    //Setup let
                    let seriesID = Int(data.1.array![0].string!)
                    let seriesName = data.1.array![1].string
                    let itemCount = Int(data.1.array![2].string!)

                    if seriesID != 0 && itemCount != 0 && seriesName != nil{
                        privateMOC.performBlock{
                            let series = NSEntityDescription.insertNewObjectForEntityForName("Series", inManagedObjectContext: managedContext) as! Series
                            series.countryID = countryID
                            series.seriesID = seriesID
                            series.seriesName = seriesName
                            series.itemCount = itemCount

                            print(completedRequestCount)

                            do {
                                try privateMOC.save()
                            } catch let error as NSError  {
                                print("Could not save \(error), \(error.userInfo)")
                            }
                        }

                    }else{
                        print("ERROR")
                    }

                }
            }
            completedRequestCount += 1
            print(completedRequestCount)
        })
        requestedRequests += 1
        if(requestedRequests == resultCount){
            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)){
                while(true){
                    if(completedRequestCount == resultCount){
                        didGetSeries = true
                        sleep(3)
                        print("DEBUG - Series Done")
                        break
                    }
                }
            }
        }
    }
}

2 个答案:

答案 0 :(得分:2)

解决了我自己。我制作了一个私人MOC,但是当你制作一个MOC时,你必须在代码中不断添加它,否则它将无法工作。我忘了用privateMOC替换managedContext。我的不好

let series = NSEntityDescription.insertNewObjectForEntityForName("Series", inManagedObjectContext: managedContext) as! Series

应该是

let series = NSEntityDescription.insertNewObjectForEntityForName("Series", inManagedObjectContext: privateMOC) as! Series

答案 1 :(得分:2)

实际上,使用私有MOC解决问题的原因是因为你在后台线程中执行操作,而当你在后台线程中执行coredata操作时你必须确保

  • 托管对象上下文绑定到它们所在的线程(队列) 与初始化相关联
  • 从上下文中检索的托管对象绑定到同一队列 上下文绑定到

仅供参考,因为(“我制作了一个私人MOC,但是当你创建一个私有MOC时,你必须在代码中不断添加它,否则它将无效。我忘了用privateMOC替换managedContext”)