Actually I have some experience in coreData with iOS 10.
But I now create an app thats tartget is #version 8.0 and above.
First I create an app including coreData. So they auto generate me a code in AppDelegate as iOS 10 standard. When I change the target 10 to 8.0 the AppDelegate shows some errors.
Error in AppDelegate
How to solve this? I want to use coreData in ios 8.0 and above.
// MARK: - Core Data stack
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: "coreDataTestForPreOS")
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
}()
// MARK: - Core Data Saving support
func saveContext () {
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)")
}
}
}
}
let ad = UIApplication.shared.delegate as! AppDelegate
let context = ad.persistentContainer.viewContext
var context: NSManagedObjectContext?
if #available(iOS 10.0, *) {
context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
} else {
// iOS 9.0 and below - however you were previously handling it
guard let modelURL = Bundle.main.url(forResource: "Model", withExtension:"momd") else {
fatalError("Error loading model from bundle")
}
guard let mom = NSManagedObjectModel(contentsOf: modelURL) else {
fatalError("Error initializing mom from: \(modelURL)")
}
let psc = NSPersistentStoreCoordinator(managedObjectModel: mom)
context = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let docURL = urls[urls.endIndex-1]
let storeURL = docURL.appendingPathComponent("Model.sqlite")
do {
try psc.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: storeURL, options: nil)
} catch {
fatalError("Error migrating store: \(error)")
}
}`
Before the convenience of NSPersistentContainer there was NSPersistentStoreCoordinator. You'll need to create one of those:
if
let modelURL = Bundle.main.url(forResource: "Model", withExtension: "momd"),
let model = NSManagedObjectModel(contentsOf: modelURL),
let psc = NSPersistentStoreCoordinator(managedObjectModel: model) {
...
}
and then create and add one or more NSPersistentStores to it via .addPersistentStore(ofType:configurationName:at:options).
Related
I have tableview which display list of animals.Tapping on each cell (or animal) it navigates to detail of animal and it has save button.
Whenever I save the information using core data, all the records in the core data gets over-write with last updated data.
I'm not sure what could be the reason. Reference for the code is taken form this post:
Swift 3 IOS 9 And IOS 10 Core Data
Below is the code
class CoreDataStack {
static var applicationDocumentsDirectory: URL = {
let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
return urls[urls.count-1]
}()
static 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(for: CoreDataStack.self).url(forResource: "DatabaseTest", withExtension: "momd")! // type your database name here..
return NSManagedObjectModel(contentsOf: modelURL)!
}()
static 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: managedObjectModel)
let url = applicationDocumentsDirectory.appendingPathComponent("DatabaseTest.sqlite") // type your database name here...
var failureReason = "There was an error creating or loading the application's saved data."
let options = [NSMigratePersistentStoresAutomaticallyOption: NSNumber(value: true as Bool), NSInferMappingModelAutomaticallyOption: NSNumber(value: true as Bool)]
do {
try coordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: url, options: options)
} 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
}()
static 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 = persistentStoreCoordinator
var managedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
managedObjectContext.persistentStoreCoordinator = coordinator
return managedObjectContext
}()
static func getEntity<T: NSManagedObject>() -> T {
if #available(iOS 10, *) {
let obj = T(context: CoreDataStack.context)
return obj
} else {
guard let entityDescription = NSEntityDescription.entity(forEntityName: NSStringFromClass(T.self), in: CoreDataStack.context) else {
fatalError("Core Data entity name doesn't match.")
}
let obj = T(entity: entityDescription, insertInto: CoreDataStack.context)
return obj
}
}
// MARK: - Core Data Saving support
static func saveContext () {
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()
}
}
}
}
On tapping save button, I call this code
let animalObj: animalTable = CoreDataStack.getEntity()
animalObj.Name = animalModel.Name
animalObj.Type = animalModel.Type
CoreDataStack.saveContext()
Not sure, where is the problem that it over-write all data in core data with last data saved.
I created a project that support iOS 8.0 and above. So I slightly change the code in AppDelegate.
AppDelegate
// 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: "coreDataTestForPreOS")
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
}()
// iOS 9 and below
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: "coreDataTestForPreOS", 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 {
// iOS 9.0 and below - however you were previously handling it
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()
}
}
}
}
}
}
let ad = UIApplication.shared.delegate as! AppDelegate
#available(iOS 10.0, *)
let contextAbove = ad.persistentContainer.viewContext
let contextBelow = ad.managedObjectContext
Now I want to generate data to db. I use a custom function to it.
Function
func generateData() {
if #available(iOS 10.0, *) {
let item1 = Item(context: contextAbove)
item1.name = "Alwin"
} else {
// Fallback on earlier versions
}
// to save data
ad.saveContext()
}
the above code is not completed please help me to complete it.
In iOS 10 I use the below function to achieve that
func generateData() {
let item1 = Item(context: contextAbove)
item1.name = "Alwin"
// to save data
ad.saveContext()
}
You can use code like below
func generateData() {
if #available(iOS 10.0, *) {
let item1 = Item(context: contextAbove)
item1.name = "Alwin"
} else {
// Fallback on earlier versions
let managedObjectContext = contextBelow
let entityDesc = NSEntityDescription.entity(forEntityName: "Item", in: managedObjectContext)
let item1 = Item(entity: entityDesc!, insertInto: managedObjectContext)
item1.name = "Alwin"
}
// to save data
ad.saveContext()
}
I get a problem actually, I am using Xcode 8, iOS 10 but in my run target I give it 9.1, the problem happens I include CoreData but I need to be functional enter image description here with both iOS 9 and iOS 10
I put the image here
And in this part of the code
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: "delete")
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
}()
// MARK: - Core Data Saving support
func saveContext () {
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)")
}
}
}
And in this part are my functions
func saveData(){
let appDelegate = UIApplication.shared.delegate as! AppDelegate
if #available(iOS 10.0, *) {
let context = appDelegate.persistentContainer.viewContext
let newToken = NSEntityDescription.insertNewObject(forEntityName: "Token_entity", into: context)
newToken.setValue("85724985724897247ifeifjhadjkfhsauq89r8479138941874193874", forKey: "accessToken" )
do
{
try context.save()
print("SAVED")
}
catch
{
///PROCESS ERROR
}
} else {
// Fallback on earlier versions
}
}
func requestCoreData (){
let appDel = UIApplication.shared.delegate as! AppDelegate
if #available(iOS 10.0, *) {
let contex = appDel.persistentContainer.viewContext
let requests = NSFetchRequest<NSFetchRequestResult>(entityName: "Token_entity")
requests.returnsObjectsAsFaults = false
do
{
let results = try contex.fetch(requests)
if results.count > 0
{
for result in results as! [NSManagedObject]{
if let tokenrequest = result.value(forKey: "accessToken") as? String
{
print(tokenrequest)
}
}
}
}
catch
{
///PROCESS ERROR
}
} else {
// Fallback on earlier versions
}
}
The main difference between the iOS 9 and earlier versions of the Core Data code that defaults into the app delegate when you create a project with that option selected is the way the app accesses the ManagedObjectContext. In iOS 10, the context is reached via a new singleton object called the NSPersistentContainer (see the code below from the app delegate in an iOS 10 project created with Core Data). You need to delete any references to persistent container if you're targeting < iOS 10. Here's the iOS 10 variable persistentContainer inside of the app delegate that you need to delete:
class AppDelegate: UIResponder, UIApplicationDelegate {
...
lazy var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "CustomNumericKeypad")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
}
Here's the code necessary to retrieve the context for iOS 9:
lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator =
{
let coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
let url = self.applicationDocumentsDirectory.appendingPathComponent("SingleViewCoreData.sqlite")
do {
try coordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: url, options: nil)
} catch {
let dict : [String : Any] = [NSLocalizedDescriptionKey : "Failed to initialize the application's saved data" as NSString,
NSLocalizedFailureReasonErrorKey : "There was an error creating or loading the application's saved data." as NSString,
NSUnderlyingErrorKey : error as NSError]
let wrappedError = NSError(domain: "YOUR_ERROR_DOMAIN", code: 9999, userInfo: dict)
print("Unresolved error \(wrappedError), \(wrappedError.userInfo)")
abort()
}
return coordinator
}()
lazy var managedObjectContext: NSManagedObjectContext = {
let coordinator = self.persistentStoreCoordinator
var managedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
managedObjectContext.persistentStoreCoordinator = coordinator
return managedObjectContext
}()
The only other thing you have to change is the way you reference the context when saveContext() method in the app delegate when it gets called:
iOS 10 func saveContext () {
let context = persistentContainer.viewContext
...
iOS 9 func saveContext () {
let context = managedObjectContext
...
There is a somewhat straightforward way to implement both ways of obtaining the context so that your code is OS neutral in case you don't want to worry about it if you're switching you're target back and forth between OS 9 and 10 during development. See this blog post for instructions / sample code on how to do this.
My answer may be rather late. I've created a stack (singleton) that supports iOS versions 8.0 through 10.0. From iOS 10.0 onwards NSPersistentContainer is obviously supported. Please have a look here for more information.
In you app you can access the read-only and writable contexts irregardless of whether the targets are iOS 8, 9, or 10 like so
//Read
let stack = CoreDataStack.shared
stack.viewContext
//fetch operations...
//Write
let stack = CoreDataStack.shared
stack.backgroundContext
//write operations...
Facing issue "Value of type 'AppDelegate' has no member 'managedObjectContext' In new Xcode 8 (using Swift 3, iOS 10) when trying to create new context in View Controller
let context = (UIApplication.shared().delegate as! AppDelegate).managedObjectContext
In Xcode 8 there is no code for managedObjectContext inside AppDelegate.swift file. Core Data stack code inside AppDelegate.swift presented only with: lazy var persistentContainer: NSPersistentContainer property and func saveContext () . There is no managedObjectContext property.
How to create managedObjectContext using Swift 3 in Xcode 8) or maybe there is no need to do it using Swift 3 ?
In Swift3, you can access the managedObjectContext via the viewContext as
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
This option is available if Core data was enabled when creating the project. However, for existing project that you want to include core data, go through the normal process of adding the core data and add the following code which will allow you to get the
lazy var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "you_model_file_name")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
You will need to import the CoreData.
Note: For Swift3, the ManagedObject Subclass are generated automatically.
See more from WWDC 2016
Moved all the core data stack code to a single file and added iOS 10 and below iOS10. below is my try (not sure its fully up to the mark)
import Foundation
import CoreData
class CoreDataManager {
// MARK: - Core Data stack
static let sharedInstance = CoreDataManager()
private lazy var applicationDocumentsDirectory: URL = {
// The directory the application uses to store the Core Data store file. This code uses a directory named in the application's documents Application Support directory.
let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
return urls[urls.count-1]
}()
private 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: "CoreDataSwift", withExtension: "momd")!
return NSManagedObjectModel(contentsOf: modelURL)!
}()
private 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("CoreDataSwift.sqlite")
var failureReason = "There was an error creating or loading the application's saved data."
do {
// Configure automatic migration.
let options = [ NSMigratePersistentStoresAutomaticallyOption : true, NSInferMappingModelAutomaticallyOption : true ]
try coordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: url, options: options)
} 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 = {
var managedObjectContext: NSManagedObjectContext?
if #available(iOS 10.0, *){
managedObjectContext = self.persistentContainer.viewContext
}
else{
// 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
managedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
managedObjectContext?.persistentStoreCoordinator = coordinator
}
return managedObjectContext!
}()
// iOS-10
#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: "CoreDataSwift")
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)")
}
})
print("\(self.applicationDocumentsDirectory)")
return container
}()
// MARK: - Core Data Saving support
func saveContext () {
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()
}
}
}
}
The solution by James Amo gets you most of the way there for iOS 10.0, but doesn't address iOS 9.0 and below, which can't access that method and needs to manually build the NSManagedObjectModel. Here is the solution that worked for me:
var context: NSManagedObjectContext?
if #available(iOS 10.0, *) {
context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
} else {
// iOS 9.0 and below - however you were previously handling it
guard let modelURL = Bundle.main.url(forResource: "Model", withExtension:"momd") else {
fatalError("Error loading model from bundle")
}
guard let mom = NSManagedObjectModel(contentsOf: modelURL) else {
fatalError("Error initializing mom from: \(modelURL)")
}
let psc = NSPersistentStoreCoordinator(managedObjectModel: mom)
context = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let docURL = urls[urls.endIndex-1]
let storeURL = docURL.appendingPathComponent("Model.sqlite")
do {
try psc.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: storeURL, options: nil)
} catch {
fatalError("Error migrating store: \(error)")
}
}
It's clear that the change to 10.0 makes CoreData significantly simpler, but it's unfortunate that it's so painful for existing developers to make the jump...
To implement the above, just make sure to throw the persistentContainer into your AppDelegate.swift, defined in James Amo's answer.
NSPersistentContainer has a viewContext property that is an NSManagedObjectContext type.
As a side note, if you create a Master-Detail application in Xcode 8, Apple's sample code puts the managedObjectContext property in the MasterViewController.swift file and sets it by using said viewContext property in AppDelegate.
First, get AppDelegate object:-
let appDelegateObject = UIApplication.shared.delegate as! AppDelegate
And now, we can get managed object as:
let managedObject = appDelegateObject.persistentContainer.viewContext
Facing issue "Value of type 'AppDelegate' has no member 'managedObjectContext' In new Xcode 8 (using Swift 3, iOS 10) when trying to create new context in View Controller
let context = (UIApplication.shared().delegate as! AppDelegate).managedObjectContext
In Xcode 8 there is no code for managedObjectContext inside AppDelegate.swift file. Core Data stack code inside AppDelegate.swift presented only with: lazy var persistentContainer: NSPersistentContainer property and func saveContext () . There is no managedObjectContext property.
How to create managedObjectContext using Swift 3 in Xcode 8) or maybe there is no need to do it using Swift 3 ?
In Swift3, you can access the managedObjectContext via the viewContext as
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
This option is available if Core data was enabled when creating the project. However, for existing project that you want to include core data, go through the normal process of adding the core data and add the following code which will allow you to get the
lazy var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "you_model_file_name")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
You will need to import the CoreData.
Note: For Swift3, the ManagedObject Subclass are generated automatically.
See more from WWDC 2016
Moved all the core data stack code to a single file and added iOS 10 and below iOS10. below is my try (not sure its fully up to the mark)
import Foundation
import CoreData
class CoreDataManager {
// MARK: - Core Data stack
static let sharedInstance = CoreDataManager()
private lazy var applicationDocumentsDirectory: URL = {
// The directory the application uses to store the Core Data store file. This code uses a directory named in the application's documents Application Support directory.
let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
return urls[urls.count-1]
}()
private 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: "CoreDataSwift", withExtension: "momd")!
return NSManagedObjectModel(contentsOf: modelURL)!
}()
private 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("CoreDataSwift.sqlite")
var failureReason = "There was an error creating or loading the application's saved data."
do {
// Configure automatic migration.
let options = [ NSMigratePersistentStoresAutomaticallyOption : true, NSInferMappingModelAutomaticallyOption : true ]
try coordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: url, options: options)
} 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 = {
var managedObjectContext: NSManagedObjectContext?
if #available(iOS 10.0, *){
managedObjectContext = self.persistentContainer.viewContext
}
else{
// 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
managedObjectContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
managedObjectContext?.persistentStoreCoordinator = coordinator
}
return managedObjectContext!
}()
// iOS-10
#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: "CoreDataSwift")
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)")
}
})
print("\(self.applicationDocumentsDirectory)")
return container
}()
// MARK: - Core Data Saving support
func saveContext () {
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()
}
}
}
}
The solution by James Amo gets you most of the way there for iOS 10.0, but doesn't address iOS 9.0 and below, which can't access that method and needs to manually build the NSManagedObjectModel. Here is the solution that worked for me:
var context: NSManagedObjectContext?
if #available(iOS 10.0, *) {
context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
} else {
// iOS 9.0 and below - however you were previously handling it
guard let modelURL = Bundle.main.url(forResource: "Model", withExtension:"momd") else {
fatalError("Error loading model from bundle")
}
guard let mom = NSManagedObjectModel(contentsOf: modelURL) else {
fatalError("Error initializing mom from: \(modelURL)")
}
let psc = NSPersistentStoreCoordinator(managedObjectModel: mom)
context = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let docURL = urls[urls.endIndex-1]
let storeURL = docURL.appendingPathComponent("Model.sqlite")
do {
try psc.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: storeURL, options: nil)
} catch {
fatalError("Error migrating store: \(error)")
}
}
It's clear that the change to 10.0 makes CoreData significantly simpler, but it's unfortunate that it's so painful for existing developers to make the jump...
To implement the above, just make sure to throw the persistentContainer into your AppDelegate.swift, defined in James Amo's answer.
NSPersistentContainer has a viewContext property that is an NSManagedObjectContext type.
As a side note, if you create a Master-Detail application in Xcode 8, Apple's sample code puts the managedObjectContext property in the MasterViewController.swift file and sets it by using said viewContext property in AppDelegate.
First, get AppDelegate object:-
let appDelegateObject = UIApplication.shared.delegate as! AppDelegate
And now, we can get managed object as:
let managedObject = appDelegateObject.persistentContainer.viewContext