使用CoreData和NSFetchedResultsController在可选的managedObject中查找nil

时间:2016-03-03 04:26:22

标签: swift core-data nsfetchedresultscontroller nsmanagedobjectcontext

我正在尝试用一些CoreData填充collectionView。我在Swift中进行编程并且使用的是iOS 9.我已经将大部分内容正确连接(据我所知),但由于一行代码而导致崩溃。

这是我的viewController中的代码。与nil一起出错的行是" managedObjectContext:coreDataStack.context":

override func viewDidLoad() {
    super.viewDidLoad()

    //1
    let fetchRequest = NSFetchRequest(entityName: "Family")

    let firstNameSort =
    NSSortDescriptor(key: "firstName", ascending: true)

    fetchRequest.sortDescriptors = [firstNameSort]

    //2
    fetchedResultsController =
        NSFetchedResultsController(fetchRequest: fetchRequest,
            managedObjectContext: coreDataStack.context,
            sectionNameKeyPath: nil,
            cacheName: nil)

    fetchedResultsController.delegate = CollectionViewFetchedResultsControllerDelegate(collectionView: familyCollectionView)

    //3
    do {
        try fetchedResultsController.performFetch()
    } catch let error as NSError {
        print("Error: \(error.localizedDescription)")
    }
}

以下是" CoreDataStack"我引用的对象:

import Foundation
import CoreData

class CoreDataStack {
let modelName = "CoreDataModel"

lazy var context: NSManagedObjectContext = {

    var managedObjectContext = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)

    managedObjectContext.persistentStoreCoordinator = self.psc

    return managedObjectContext
}()

private lazy var psc: NSPersistentStoreCoordinator = {

    let coordinator = NSPersistentStoreCoordinator(
        managedObjectModel: self.managedObjectModel)

    let url = self.applicationDocumentsDirectory
        .URLByAppendingPathComponent(self.modelName)

    do {
        let options =
        [NSMigratePersistentStoresAutomaticallyOption : true]

        try coordinator.addPersistentStoreWithType(
            NSSQLiteStoreType, configuration: nil, URL: url,
            options: options)
    } catch  {
                print("Error adding persistent store.")
    }

    return coordinator
}()

private lazy var managedObjectModel: NSManagedObjectModel = {

    let modelURL = NSBundle.mainBundle()
        .URLForResource(self.modelName,
        withExtension: "momd")!
    return NSManagedObjectModel(contentsOfURL: modelURL)!
}()

private lazy var applicationDocumentsDirectory: NSURL = {
    let urls = NSFileManager.defaultManager().URLsForDirectory(
    .DocumentDirectory, inDomains: .UserDomainMask)
    return urls[urls.count-1]
}()

func saveContext () {
    if context.hasChanges {
    do {
        try context.save()
    } catch let error as NSError {
            print("Error: \(error.localizedDescription)")
            abort()
    }
    }
}

}

当我打电话给那条线路时,为什么我会选择nil的任何想法?

1 个答案:

答案 0 :(得分:0)

问题的存在是因为从未分配过self.coreDataStack,但是在定义了fetchedResultsController时访问了它。

要简单地解决问题,请在访问视图控制器的coreDataStack属性之前创建并分配为CoreDataStuck的实例:

self.coreDataStack = CoreDataStack()

我想强调管理NSManagedObjectContext的重要性。我相信创建CoreDataStack实例并在需要时传递对它的引用是一种更常见的模式。例如,您可以在Application Delegate中创建它的实例,并将引用分配给您的第一个视图控制器,如下所示:

lazy var cds = CoreDataStack()

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSOBject: AnyObject?]?) -> Bool {

// Obtain a reference to your root view controller, this may have to be different if you use different types of controllers. This would be the View controller where you use the core data stack in your question though.
let vc = window!.rootViewController as! ViewController
vc.coreDataStack = self.cds // This will now ensure the property on your view controller is assigned and can be accessed.
return true
}

稍后在您的应用中,我会建议传递相同的参考。你可以通过访问app delegate来做到这一点,我个人认为通过准备segue方法传递引用更简洁。我只想象你的应用程序中存在一个SecondViewController类,你正在从你的问题中的ViewController过渡到它:

class SecondViewController: UIViewController {

    var cds: CoreDataStack!

}

我假设ViewController和SecondViewController之间有一个名为“next”的segue。在ViewController文件中,定义prepareForSegue方法:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {

    if segue.identifier == "next" {

        let secondVc = segue.destinationViewController as! SecondViewController
        secondVc.cds = self.coreDataStack 

    }

}

我试图强调保留对最初创建的核心数据堆栈实例的引用的想法,我认为随着你的进展,你会发现它更有益。