致命错误:意外地发现零,而展开一个可选值 - 核心数据(斯威夫特)

问题描述:

我得到这个包装错误,当我实现我提取的托管对象的核心数据代码。目前得到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)") 
       } 
      } 
     } 

请检查截图enter image description here enter image description here

+1

为什么'NSPersistentStoreCoordinator'和'NSManagedObjectContext'是可选的?如果创建协调程序失败,则会发生致命错误('abort()'),并且应用程序终止。这两个实例都应该是**非可选**。而init方法'NSPersistentStoreCoordinator'的init(managedObjectModel)也会返回一个非可选实例。为什么你注释类型是可选的,并且变得更糟? – vadian

+0

但是这里有什么问题? –

+0

也许编译器会告诉你。 – vadian

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 
} 
+0

你能解释一下这是如何工作的吗? –

+0

@ faig-huseynov:我相信上面的答案是正确的,因此现在根据你的问题,为什么我可以知道你如何访问你的VC中的managedObject上下文 –

+0

你问这个问题吗? '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 persistentStoreCoordinatormanagedObjectContext可选。这是无稽之谈。该应用程序是不可行的,如果无法创建协调程序,它将终止。

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

另一个繁琐的代码转换DoubleNSNumber,反之亦然舞蹈。在NSManagedObject子类中声明latitudelongitudeDouble是完全合法的。同样的事情是date属性。声明它们为Date以避免大量类型转换。

+0

你认为你需要删除persistentStoreCoordinator和managedObjectContext吗? –

+0

不,不删除。对象是必需的(在AppDelegate中)。但不要声明它们是可选的。 – vadian

+0

哪里声明它们是可选的? 我想我错过了东西,所以它崩溃了 –