如何正确设置Core Data Stack到iOS和Swift中的第一个视图控制器?

时间:2014-09-29 22:14:22

标签: ios core-data swift nsmanagedobjectcontext

我想在我的iOS应用中使用Core Data,它使用UINavigationController和故事板上的第一个视图控制器。然后我想将NSManagedObjectContext中的NSPersistentStoreCoordinatorAppDelegate.h传递给UINavigationController内的第一个视图控制器。所以我首先编写了以下代码(请注意,我也使用UISplitViewController):

var splitViewController = self.window!.rootViewController as UISplitViewController
var navigationController: UINavigationController!
if splitViewController.viewControllers.count == 2 {
    navigationController = splitViewController.viewControllers[1] as UINavigationController
} else {
    navigationController = splitViewController.viewControllers[0] as UINavigationController
}
var firstViewController = navigationController.topViewController
firstViewController.managedObjectContext = managedObjectContext

但是,编译器说UIViewController没有managedObjectContext这样的属性。但奇怪的是,当我尝试通过println(firstViewController)进行记录时,它说它是FirstViewController的一个实例,而不是UIViewController ......但无论如何,我通过向下转换它来改变它:

var firstViewController = navigationController.topViewController as FirstViewController

然而,构建工作正常,但它会立即被运行时中的错误"Swift dynamic cast failed"崩溃。

那么如何将NSManagedObjectContext(和NSPersistentStoreCoordinator)传递给第一个视图控制器呢?

我在iOS(iPad)应用程序中使用Xcode 6.1 Beta 2和Swift。

3 个答案:

答案 0 :(得分:2)

您可以查看https://github.com/Alecrim/AlecrimCoreData中核心数据的使用方式。它看起来好像是一个经过深思熟虑的Swift核心数据库。

答案 1 :(得分:1)

您应该为Core Data定义一个单独的类,并将其用于核心数据。这是一个示例类:

class CoreDataHelper {

// MARK: - Properties

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

    lazy var managedObjectModel: NSManagedObjectModel? = {
        if let modelURL = NSBundle.mainBundle().URLForResource("YOUR_MODEL_NAME", withExtension: "momd") {
            return NSManagedObjectModel(contentsOfURL: modelURL)
        } else {
            println("Error: can't create managed object model")
            return nil
        }
    }()

    lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator? = {
        if let managedObjectModel = self.managedObjectModel {
            let coordinator = NSPersistentStoreCoordinator(managedObjectModel: managedObjectModel)
            let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("YOUR_MODEL_NAME.sqlite")

            var error: NSError? = nil

            let options = [NSMigratePersistentStoresAutomaticallyOption: true, NSInferMappingModelAutomaticallyOption: true]
            coordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: options, error: &error)


            if let error = error {
                println("Error: Can't add persistent store type to persistent store coordinate")
                return nil
            } else {
                return coordinator
            }
        } else {
            println("Error: Can't create persistant store coordinator. Because managed object model is not valid.")
            return nil
        }
    }()

    lazy var managedObjectContext: NSManagedObjectContext? = {
        if let coordinator = self.persistentStoreCoordinator {
            let managedObjectContext = NSManagedObjectContext()
            managedObjectContext.persistentStoreCoordinator = coordinator

            return managedObjectContext
        } else {
            println("Error: Can't create managed object context. Persistent store coordinator is not valid")
            return nil
        }
    }()

}

答案 2 :(得分:1)

我刚刚在Xcode 6.0中创建了一个Master-Detail应用程序,并检查了包含CoreData框。模板中的代码完全符合您的要求......

您的第一段代码:

var firstViewController = navigationController.topViewController
firstViewController.managedObjectContext = managedObjectContext

不能正常工作,因为在编译时,topViewController是一个UIViewController,即使它在运行时更具体。这就是你需要演员的原因。

至于为什么你的堕落者没有工作...... navigationController为空,或者topViewController为空。前者比后者更可能。

尝试将最后几行包裹在某些if let中,看看会发生什么:

if let nav = navigationController {
    if let firstViewController = navigationController.topViewController as? FirstViewController {
        firstViewController.managedObjectContext = managedObjectContext
    }
    else {
        println("navigationController.topViewController is not a FirstViewController")
    }
}
else {
    println("navigationController is empty")
}