致命错误:意外地发现零,而展开一个可选值 - 核心数据(斯威夫特)
我得到这个包装错误,当我实现我提取的托管对象的核心数据代码。目前得到fatal error: unexpectedly found nil while unwrapping an Optional value
。我究竟做错了什么?致命错误:意外地发现零,而展开一个可选值 - 核心数据(斯威夫特)
的ViewController:
func saveRun() {
// 1
let savedRun = NSEntityDescription.insertNewObject(forEntityName: "Run", into: managedObjectContext!) as! Run
savedRun.distance = NSNumber(value: distance)
savedRun.duration = (NSNumber(value: seconds))
savedRun.timestamp = NSDate() as Date
// 2
var savedLocations = [Location]()
for location in locations {
let savedLocation = NSEntityDescription.insertNewObject(forEntityName: "Location",
into: managedObjectContext!) as! Location
savedLocation.timestamp = (location.timestamp as NSDate) as Date
savedLocation.latitude = NSNumber(value: location.coordinate.latitude)
savedLocation.longitude = NSNumber(value: location.coordinate.longitude)
savedLocations.append(savedLocation)
}
savedRun.locations = NSOrderedSet(array: savedLocations)
run = savedRun
do{
try managedObjectContext!.save()
}catch{
print("Could not save the run!")
}
}
应用代表:
// MARK: - Core Data stack
lazy var applicationDocumentsDirectory: URL = {
// The directory the application uses to store the Core Data store file. This code uses a directory named "com.zedenem.MarathonRun" in the application's documents Application Support directory.
let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
return urls.last!
}()
lazy var managedObjectModel: NSManagedObjectModel = {
// The managed object model for the application. This property is not optional. It is a fatal error for the application not to be able to find and load its model.
let modelURL = Bundle.main.url(forResource: "MarathonRun", withExtension: "momd")!
return NSManagedObjectModel(contentsOf: modelURL)!
}()
lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator? = {
// The persistent store coordinator for the application. This implementation creates and return a coordinator, having added the store for the application to it. This property is optional since there are legitimate error conditions that could cause the creation of the store to fail.
// Create the coordinator and store
var coordinator: NSPersistentStoreCoordinator? = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
let url = self.applicationDocumentsDirectory.appendingPathComponent("MarathonRun")
var error: NSError? = nil
var failureReason = "There was an error creating or loading the application's saved data."
do {
try coordinator!.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: url, options: nil)
}catch let error as NSError {
coordinator = nil
// Report any error we got.
var dict = [AnyHashable: Any]()
dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data"
dict[NSLocalizedFailureReasonErrorKey] = failureReason
dict[NSUnderlyingErrorKey] = error
print("Error: \(error.domain)")
abort()
}
return coordinator
}()
lazy var managedObjectContext: NSManagedObjectContext? = {
// Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.) This property is optional since there are legitimate error conditions that could cause the creation of the context to fail.
let coordinator = self.persistentStoreCoordinator
if coordinator == nil {
return nil
}
var managedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)//NSManagedObjectContext()
managedObjectContext.persistentStoreCoordinator = coordinator
return managedObjectContext
}()
// MARK: - Core Data Saving support
func saveContext() {
if let moc = self.managedObjectContext {
if moc.hasChanges{
do{
try moc.save()
}catch let error as NSError{
print("Error: \(error.domain)")
}
}
}
你managedObjectContext
对象是nil
,你已经用!
将它包裹起来,这会导致崩溃。
你这样做,所以才:
let savedRun = NSEntityDescription.insertNewObject(forEntityName: "Run", into: managedObjectContext!) as! Run
确保你有一个价值managedObjectContext
:
if let managedObjectContext = [get the managedObjectContext object here] {
// If you succeed with getting the managedObjectContext, then you can use it without the ! in here
let savedRun = NSEntityDescription.insertNewObject(forEntityName: "Run", into: managedObjectContext) as! Run
}
你能解释一下这是如何工作的吗? –
@ faig-huseynov:我相信上面的答案是正确的,因此现在根据你的问题,为什么我可以知道你如何访问你的VC中的managedObject上下文 –
你问这个问题吗? 'var managedObjectContext:NSManagedObjectContext?' –
如果让你可以使用,所以你的应用程序不会崩溃。
if let savedRun = NSEntityDescription.insertNewObject(forEntityName: "Run", into: managedObjectContext!) as! Run {
}
但是对于永久性修复,请重新检查Run Entity类。
通过阅读注释做了一些调查后坠毁的原因是最有可能的,你是唯一的声明被管理对象上下文
var managedObjectContext: NSManagedObjectContext?
但不初始化它在视图控制器。所以它仍然是nil
并导致崩溃。
合适的方式来获得AppDelegate中的背景是一个懒惰的实例属性
lazy var managedObjectContext : NSManagedObjectContext = {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
return appDelegate.managedObjectContext
}()
现在你saveRun()
方法应该工作。
顺便说一句:不要初始化的AppDelegate persistentStoreCoordinator
和managedObjectContext
可选。这是无稽之谈。该应用程序是不可行的,如果无法创建协调程序,它将终止。
lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = {
// Create the coordinator and store
let coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
let url = self.applicationDocumentsDirectory.appendingPathComponent("MarathonRun")
do {
try coordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: url, options: nil)
} catch let error as NSError {
// Report any error we got.
var dict = [AnyHashable: Any]()
dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data"
dict[NSLocalizedFailureReasonErrorKey] = "There was an error creating or loading the application's saved data."
dict[NSUnderlyingErrorKey] = error
print("Error: ", error)
abort()
}
return coordinator
}()
lazy var managedObjectContext: NSManagedObjectContext = {
let coordinator = self.persistentStoreCoordinator
var managedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)//NSManagedObjectContext()
managedObjectContext.persistentStoreCoordinator = coordinator
return managedObjectContext
}()
另一个繁琐的代码转换Double
到NSNumber
,反之亦然舞蹈。在NSManagedObject
子类中声明latitude
和longitude
为Double
是完全合法的。同样的事情是date
属性。声明它们为Date
以避免大量类型转换。
你认为你需要删除persistentStoreCoordinator和managedObjectContext吗? –
不,不删除。对象是必需的(在AppDelegate中)。但不要声明它们是可选的。 – vadian
哪里声明它们是可选的? 我想我错过了东西,所以它崩溃了 –
为什么'NSPersistentStoreCoordinator'和'NSManagedObjectContext'是可选的?如果创建协调程序失败,则会发生致命错误('abort()'),并且应用程序终止。这两个实例都应该是**非可选**。而init方法'NSPersistentStoreCoordinator'的init(managedObjectModel)也会返回一个非可选实例。为什么你注释类型是可选的,并且变得更糟? – vadian
但是这里有什么问题? –
也许编译器会告诉你。 – vadian