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

Posted

技术标签:

【中文标题】如何正确设置 Core Data Stack 到 iOS 和 Swift 中的第一个视图控制器?【英文标题】:How to correctly set up Core Data Stack to the first view controller in iOS and Swift? 【发布时间】:2014-09-29 22:14:22 【问题描述】:

我想在我的 ios 应用程序中使用 Core Data,它使用 UINavigationController 和故事板上的第一个视图控制器。然后我想将AppDelegate.h 中的NSManagedObjectContextNSPersistentStoreCoordinator 传递给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。

【问题讨论】:

【参考方案1】:

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

【讨论】:

【参考方案2】:

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

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
        
    ()

【讨论】:

【参考方案3】:

我刚刚在 Xcode 6.0 中创建了一个主从应用程序并选中了包含 CoreData 框。模板中的代码完全符合您的要求...

你的第一个代码块:

var firstViewController = navigationController.topViewController
firstViewController.managedObjectContext = managedObjectContext

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

至于为什么你的沮丧不工作......要么navigationController 是空的,要么它的topViewController 是空的。前者比后者更有可能。

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

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")

【讨论】:

navigationControllertopViewController 都不为空,但它返回了 navigationController.topViewController is not a FirstViewController。所以它未能将topViewController 向下转换为FirstViewController,但我不知道为什么。

以上是关于如何正确设置 Core Data Stack 到 iOS 和 Swift 中的第一个视图控制器?的主要内容,如果未能解决你的问题,请参考以下文章

ios Core Data 获取特定值

CoreData学习:Core Data Stack(Swift)

刷新Core Data数据库的正确方法

ios 如何正确使用 NSPredicate 来匹配 Core Data 的 NSString?

如何使用 Core Data 设置 NSArrayController?

如何正确使用 Core Data 验证和错误框架?