我想初始化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 导入CoreData
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)")
}
}
非常感谢您的帮助!
答案 0 :(得分: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
}
关于哪个是更好的设计模式,意见不一。