在 AppDelegate 中为其他 Viewcontroller 初始化 managedContect

Posted

技术标签:

【中文标题】在 AppDelegate 中为其他 Viewcontroller 初始化 managedContect【英文标题】:Initialize managedContect in AppDelegate for other Viewcontroller 【发布时间】:2017-12-11 08:58:53 【问题描述】:

我想初始化 managedObject,但总是报这个错:

线程 1:致命错误:打开包装时意外发现 nil 可选值

我想使用 Core Data / managedObject 的 ViewController 不是我启动的 ViewController,而是我正在通过启动 ViewController 访问的另一个 (PortfolioVC)。

这是我的代码:

import Foundation
import CoreData

class DatabaseController 
    private let modelName: String

    init(modelName: String) 
        self.modelName = modelName
    

    lazy var managedContext: NSManagedObjectContext = 
        return self.storeContainer.viewContext
    ()

    private lazy var storeContainer: NSPersistentContainer = 
        let container = NSPersistentContainer(name: self.modelName)
        container.loadPersistentStores  (storeDescription, error) in
            if let error = error as NSError? 
                print("Unresolved error \(error), \(error.userInfo)")
            
        
        return container
    ()

    func saveContext () 
        guard managedContext.hasChanges else  return 

        do 
            try managedContext.save()
         catch let error as NSError 
            print("Unresolved error \(error), \(error.userInfo)")
        
    

这是我的 AppDelegate:

import UIKit
import CoreData

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate 

    var window: UIWindow?
    lazy var coreDataStack = DatabaseController(modelName: "Portfolio")

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool 

        guard let navController = window?.rootViewController as? UINavigationController,
            let viewController = navController.topViewController as? PortfolioVC else 
                return true
        
        viewController.managedContext = coreDataStack.managedContext
        return true
    

    func applicationWillResignActive(_ application: UIApplication) 

    

    func applicationDidEnterBackground(_ application: UIApplication) 

        coreDataStack.saveContext()
    

    func applicationWillEnterForeground(_ application: UIApplication) 

    

    func applicationDidBecomeActive(_ application: UIApplication) 

    

    func applicationWillTerminate(_ application: UIApplication) 

        coreDataStack.saveContext()
    



这是 PortfolioVC 中的代码:

导入 UIKit 导入核心数据

class PortfolioVC: UIViewController 


    var managedContext: NSManagedObjectContext!
    var namePortfolio: NamePortfolio?

override func viewDidLoad() 
        super.viewDidLoad()
        tableViewPortfolio.dataSource = self

        let standardPortfolio = "Watchlist"
        let fetchRequest: NSFetchRequest<NamePortfolio> = NamePortfolio.fetchRequest()
        fetchRequest.predicate = NSPredicate(format: "%K == %@", #keyPath(NamePortfolio.name), standardPortfolio)

        do 
            let results = try managedContext.fetch(fetchRequest) // here I get the error (managedContext = nil)
            if results.count > 0 
                // Portfolio already created
                namePortfolio = results.first

             else 
                // no Portfolio
                namePortfolio = NamePortfolio(context: managedContext)
                namePortfolio?.name = standardPortfolio
                try managedContext.save()
            
          catch let error as NSError 

            print("Could not fetch \(error), \(error.userInfo)")
        

    

非常感谢您的帮助!

【问题讨论】:

如何从“启动视图控制器”访问 PortfolioVC? 使用这样的 UIButton:“@IBAction func portfolio(_ sender: Any) performSegue(withIdentifier: "segueToPortfolio", sender: self) " 谢谢! 【参考方案1】:

didFinishLaunchingWithOptions 中的代码运行时,PortfolioVC 还没有被添加到导航控制器堆栈中(甚至还没有被实例化),所以守卫失败了。有两种方法可以将 managedContext 获取到 PortfolioVC:

a) 在 didFinishLaunchingWithOptions 中将其传递给您的启动视图控制器,然后使用 prepareForSegue 将其从那里传递给 PortfolioVC。您需要向启动的 VC 添加 managedContext 属性,即使您只需要将其传递给 Portfolio VC。

b) 在 PortfolioVC 中,获取对 AppDelegate 的引用,然后从那里获取 managedContext。

    if let appDelegate = UIApplication.shared.delegate as? AppDelegate 
        managedContext = appDelegate.coreDataStack.managedContext
    

对于哪种设计模式更好,意见不一。

【讨论】:

以上是关于在 AppDelegate 中为其他 Viewcontroller 初始化 managedContect的主要内容,如果未能解决你的问题,请参考以下文章

在 AppDelegate 中为两个视图控制器使用和更新 NSMutableString

有没有办法在 appdelegate 中为整个项目的所有 UIImage 属性使用`UIImageRenderingModeAlwaysOriginal`

使用 Appdelegate 在 IOS Swift 中为所有视图控制器创建 Firebase CRUD 方法

更新 appDelegate 中的变量

“AppDelegate”类型的值没有成员“manageObjectContext”

试图在 AppDelegate 中隐藏所有其他应用程序