2016-12-30 125 views
0

我正在使用核心數據功能在XCode 8中開發一個項目。 Xcode中8不支持的核心數據功能,適用於iOS 10只及以上,但是當我嘗試實施它的iOS 8和9,它與消息越來越managedContext崩潰時:Swift 3中iOS 9的核心數據無法正常工作

fatal error: unexpectedly found nil while unwrapping an Optional value

的代碼:

let managedContext = appDelegate.managedObjectContext

應用代表:

// MARK: - Core Data stack 

@available(iOS 10.0, *) 
lazy var persistentContainer: NSPersistentContainer = { 
    /* 
    The persistent container for the application. This implementation 
    creates and returns a container, having loaded 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. 
    */ 
    let container = NSPersistentContainer(name: "Feel") 
    container.loadPersistentStores(completionHandler: { (storeDescription, error) in 
     if let error = error as NSError? { 
      // Replace this implementation with code to handle the error appropriately. 
      // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. 

      /* 
      Typical reasons for an error here include: 
      * The parent directory does not exist, cannot be created, or disallows writing. 
      * The persistent store is not accessible, due to permissions or data protection when the device is locked. 
      * The device is out of space. 
      * The store could not be migrated to the current model version. 
      Check the error message to determine what the actual problem was. 
      */ 
      fatalError("Unresolved error \(error), \(error.userInfo)") 
     } 
    }) 
    return container 
}() 


lazy var applicationDocumentsDirectory: URL = { 

    let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask) 
    return urls[urls.count-1] 
}() 

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: "coreDataTemplate", withExtension: "momd")! 
    return NSManagedObjectModel(contentsOf: modelURL)! 
}() 

lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = { 
    // The persistent store coordinator for the application. This implementation creates and returns 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 
    let coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel) 
    let url = self.applicationDocumentsDirectory.appendingPathComponent("SingleViewCoreData.sqlite") 
    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 { 
     // Report any error we got. 
     var dict = [String: AnyObject]() 
     dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data" as AnyObject? 
     dict[NSLocalizedFailureReasonErrorKey] = failureReason as AnyObject? 

     dict[NSUnderlyingErrorKey] = error as NSError 
     let wrappedError = NSError(domain: "YOUR_ERROR_DOMAIN", code: 9999, userInfo: dict) 
     // Replace this with code to handle the error appropriately. 
     // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. 
     NSLog("Unresolved error \(wrappedError), \(wrappedError.userInfo)") 
     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 
    var managedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType) 
    managedObjectContext.persistentStoreCoordinator = coordinator 
    return managedObjectContext 
}() 


// MARK: - Core Data Saving support 

func saveContext() { 
    if #available(iOS 10.0, *) { 

     let context = persistentContainer.viewContext 
     if context.hasChanges { 
      do { 
       try context.save() 
      } catch { 
       // Replace this implementation with code to handle the error appropriately. 
       // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. 
       let nserror = error as NSError 
       fatalError("Unresolved error \(nserror), \(nserror.userInfo)") 
      } 
     } 
    } else { 
     if managedObjectContext.hasChanges { 
      do { 
       try managedObjectContext.save() 
      } catch { 
       // Replace this implementation with code to handle the error appropriately. 
       // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. 
       let nserror = error as NSError 
       NSLog("Unresolved error \(nserror), \(nserror.userInfo)") 
       abort() 
      } 
     } 
    } 
} 

取代碼:

guard let appDelegate = 
     UIApplication.shared.delegate as? AppDelegate else { 
      return 
    } 

    if #available(iOS 10.0, *) { 
     let managedContext = 
      appDelegate.persistentContainer.viewContext 

     let fetchRequest = 
      NSFetchRequest<NSManagedObject>(entityName: "Test") 

     do { 
      tests = try managedContext.fetch(fetchRequest) 
     } catch let error as NSError { 
      print("Could not fetch. \(error), \(error.userInfo)") 
     } 
    } else { 
     let appDelegate = UIApplication.shared.delegate as! AppDelegate 
     let managedContext = appDelegate.managedObjectContext 

     let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Test") 

     do { 
      let results = 
       try managedContext.fetch(fetchRequest) 
      tests = results as! [NSManagedObject] 
     } catch let error as NSError { 
      print("Could not fetch \(error), \(error.userInfo)") 
     } 
    } 

如何使用Swift 3在XCode 8中爲部署版本爲iOS 8.2的iOS項目實現Core Data?

+0

您確定發生錯誤的行是?你可以在它之前打印(appDelegate)嗎? – jtbandes

+0

@jtbandes是的,我打印了'appDelegate',它返回了我的AppDelegate實例。 – nothingwhatsoever

回答

3

您是否在iOS 8/9代碼中使用不同的型號名稱?你可以嘗試在你的AppDelegate的managedObjectModel財產與"Feel"更換"coreDataTemplate"這樣的:

let modelURL = Bundle.main.url(forResource: "Feel", withExtension: "momd")! 
0

我不知道爲什麼它拋出此特定錯誤,但省去了下面的行可能會解決它:

let appDelegate = UIApplication.shared.delegate as! AppDelegate 

請注意,您已經從上面的guard語句中獲得了appDelegate,並且您在此處所做的只是在較低的上下文中創建一個具有相同名稱的新常量。所以,你可以很容易地消除這條線。 (實際上,我應該認爲這種向下轉換會失敗併產生不同的錯誤。)

還有一些其他建議我會提出。

  • 首先,最重要的是,切出所有與持久化存儲 協調員的代碼。這是多餘的。相反,請始終使用應用程序代理的managedObjectContext屬性 。這仍然會在iOS的10

    (工作通過使用持久存儲協調和預iOS的10 碼兩種,你只是創建雙爲自己的工作。而且, 你可能會得到很多更多的錯誤,就像你在這裏所做的那樣)。

  • 其他的建議只是一個優選實踐的問題。您可以在每個視圖控制器中創建一個managedObjectContext屬性。 然後,在應用程序委託中,將它們全部設置爲應用程序委託的 managedObjectContext。作爲首選的做法,控制器通常不應該引用應用程序 委託人。