Swift Core Data preload persistentStoreCoordinator: - core-data

What needs to be modified to preload my sqlite file? I added the file to the project so that makes me think I have to make a change in this code.
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.URLByAppendingPathComponent("junkapp.sqlite")
var error: NSError? = nil
var failureReason = "There was an error creating or loading the application's saved data."
if coordinator!.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: nil, error: &error) == nil {
coordinator = nil
// Report any error we got.
let dict = NSMutableDictionary()
dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data"
dict[NSLocalizedFailureReasonErrorKey] = failureReason
dict[NSUnderlyingErrorKey] = error
//error = NSError.errorWithDomain("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 \(error), \(error!.userInfo)")
abort()
}
return coordinator
}()

Just change the file url to point to your SQLite file.
You need to
copy the SQLite file from the bundle to the documents directory.
reference this file url in addPersistentStore....
e.g.
// Copying
let path = NSBundle.mainBundle().pathForResource("sqlitefile", ofType:"sqlite")!
let destinationPath =
self.applicationDocumentsDirectory.URLByAppendingPathComponent("junkapp.sqlite")!.path
NSFileManager.defaultManager().copyItemAtPath(
path, toPath: destinationPath, error:nil)
// Using
coordinator!.addPersistentStoreWithType(NSSQLiteStoreType,
configuration: nil, URL: NSURL.fileURLWithPath(destinationPath),
options: nil, error: &error)

This is the final code that worked for me. Note the section //Copying and keep in mind that you will have to delete the app off device or simulator first before running this.
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.URLByAppendingPathComponent("junkapp.sqlite")
var error: NSError? = nil
var failureReason = "There was an error creating or loading the application's saved data."
// Copying
let path = NSBundle.mainBundle().pathForResource("junkapp", ofType:"sqlite")!
NSFileManager.defaultManager().copyItemAtPath(path, toPath: url.path!, error:nil)
//end copy
if coordinator!.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: NSURL.fileURLWithPath(url.path!), options: nil, error: &error) == nil {
coordinator = nil
// Report any error we got.
let dict = NSMutableDictionary()
dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data"
dict[NSLocalizedFailureReasonErrorKey] = failureReason
dict[NSUnderlyingErrorKey] = error
//error = NSError.errorWithDomain("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 \(error), \(error!.userInfo)")
abort()
}
return coordinator
}()

Related

Xcode 13 Warning - [NSKeyedUnarchiver validateAllowedClass:forKey:]

I am using File Storage system for saving some data models confirming to Codable Protocol.
My Save function is as below:
func save<T: Encodable>(value: T, for key: String, on path: URL) throws {
let url = path.appendingPathComponent(key, isDirectory: false)
do {
try ANFileManager.createDirectoryAtPath(path: url.deletingLastPathComponent())
let archiver = NSKeyedArchiver(requiringSecureCoding: true)
archiver.outputFormat = .binary
try archiver.encodeEncodable(value, forKey: NSKeyedArchiveRootObjectKey)
archiver.finishEncoding()
// then you can use encoded data
try archiver.encodedData.write(to: url)
} catch {
throw StorageError.cantWrite(error)
}
}
My fetch function is as below:
func fetchValue<T: Decodable>(for key: String, from path: URL) throws -> T {
let url = path.appendingPathComponent(key)
let data = try Data(contentsOf: url)
let unarchiver = try NSKeyedUnarchiver(forReadingFrom: data)
unarchiver.decodingFailurePolicy = .setErrorAndReturn
guard let decoded = unarchiver.decodeDecodable(T.self, forKey:
NSKeyedArchiveRootObjectKey) else {
throw StorageError.notFound
}
unarchiver.finishDecoding()
if let error = unarchiver.error {
throw StorageError.cantRead(error)
}
else {
return decoded
}
}
Save and fetch are working fine but at runtime seeing some below warning in xcode console.
*** -[NSKeyedUnarchiver validateAllowedClass:forKey:] allowed unarchiving safe plist type ''NSString' (0x7fff863014d0) [/Applications/Xcode_13.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/Frameworks/Foundation.framework]' for key 'NS.keys', even though it was not explicitly included in the client allowed classes set: '{(
"'NSDictionary' (0x7fff862db9a0) [/Applications/Xcode_13.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/Frameworks/CoreFoundation.framework]",
"'NSDate' (0x7fff862db798) [/Applications/Xcode_13.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/Frameworks/CoreFoundation.framework]"
)}'. This will be disallowed in the future.
What should be done to suppress the warning ?
The problem is the failure to require secure coding on the unarchiver:
https://developer.apple.com/documentation/foundation/nskeyedunarchiver/1410824-requiressecurecoding
But more broadly it is very odd to pass through a keyed archiver when Codable is already saveable directly.

Value of type 'FileManager' has no member 'urlsForDirectory' - AppDelegate Swift 3 Error

Since I recently updated to XCode 8 Beta 5 I have been trying to solve this error in my appDelegate Core Data Stack.
In these lines of code I get the following error:
// 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 "fitness.paceapp.Pace" in the application's documents Application Support directory.
let urls = FileManager.default.urlsForDirectory(.documentDirectory, inDomains: .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.urlForResource("Dominos", withExtension: "momd")!
return NSManagedObjectModel(contentsOf: modelURL)!
}()
Any Ideas on what I could be missing. I am quite lost and there are not many answers out there. Thanks in advance.
Here you go,
lazy var applicationDocumentsDirectory: URL = {
// The directory the application uses to store the Core Data store file. This code uses a directory named "fitness.paceapp.Pace" in the application's documents Application Support directory.
let urls = FileManager.default.urls(for: FileManager.SearchPathDirectory.documentDirectory, in: FileManager.SearchPathDomainMask.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: "Dominos", withExtension: "momd")!
return NSManagedObjectModel(contentsOf: modelURL)!
}()
It is:
let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
return urls.last!
Or
return try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)

core data crashed when save it to a directory created by myself in LibraryDirectory

here is my code thar return a directory to save core data files.
lazy var applicationDocumentsDirectory: NSString = {
// The directory the application uses to store the Core Data store file. This code uses a directory named "com.triplec.WKCC" in the application's documents Application Support directory.
var libP = NSSearchPathForDirectoriesInDomains(.LibraryDirectory, NSSearchPathDomainMask.UserDomainMask, true).first! as NSString
let path = libP.stringByAppendingPathComponent("coredata") as String
let fileManager = NSFileManager.defaultManager()
if fileManager.fileExistsAtPath(path) {
do {
try fileManager.createDirectoryAtPath(path, withIntermediateDirectories: true, attributes: nil)
} catch { }
}
print(path)
return path as NSString
}()
when I called function below, it crashed. The crash log says that the file couldn’t be saved.
let url = NSURL.fileURLWithPath(self.applicationDocumentsDirectory.stringByAppendingPathComponent("SingleViewCoreData.sqlite"))
do {
try coordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: nil)
} catch {
abort()
}
And when I did't append string to libP, it did work。
Anyone knows how to save core data files in a diretory created by myself?
You haven't even tested your code that's supposed to create the directory to see if it works. This code:
if fileManager.fileExistsAtPath(path) {
do {
try fileManager.createDirectoryAtPath(path, withIntermediateDirectories: true, attributes: nil)
} catch { }
}
...says that if the directory already exists then create it. But if the directory doesn't exist, do nothing.

Can't read back SQLite file written using -migratePersistentStore withType:NSInMemoryStoreType

(My problem is somewhat similar to this one, except I'm not using an UndoManager, and the proposed solution doesn't work for me.)
My app imports data from a 3rd party app and stores it in memory until the user saves it. The import periodically save:'s to its own managedObjectContext on a background thread. This MOC uses the persistent store coordinator of it's parent NSPersistentDocument MOC. In order to avoid writing to a temp file on disk, a persistent store is added using the type NSInMemoryStoreType. When the user wants to actually save the data to a file on disk, migratePersistentStore withType:NSInMemoryStoreType is called in the writeToURL override in the NSPersistentDocument.
This all works fine as long as I use NSXMLStoreType for writing and reading (at //1 and //2 in the code below).
As soon as I switch to NSSQLiteStoreType, writing does produce a valid SQLite file with all the proper data in it, but reading back the file fails with the following error:
CoreData: error: Encountered exception I/O error for database at /a/b/c.dat. SQLite error code:14, 'unable to open database file' with userInfo {
NSFilePath = "/a/b/c.dat";
NSSQLiteErrorDomain = 14;
} while checking table name from store: <NSSQLiteConnection: 0x6080001e3300>
CoreData: error: -addPersistentStoreWithType:SQLite configuration:(null) URL:file:///a/b/c.dat options:{
NSMigratePersistentStoresAutomaticallyOption = 1;
NSReadOnlyPersistentStoreOption = 1;
} ... returned error Error Domain=NSCocoaErrorDomain Code=256 "The file couldn’t be opened." UserInfo=0x60800006df40 {NSSQLiteErrorDomain=14, NSUnderlyingException=I/O error for database at /a/b/c.dat. SQLite error code:14, 'unable to open database file'} with userInfo dictionary {
NSSQLiteErrorDomain = 14;
NSUnderlyingException = "I/O error for database at /a/b/c.dat. SQLite error code:14, 'unable to open database file'";
Here is the relevant simplified code:
// NSPersistentDocument.m
- (BOOL)readFromURL:(NSURL *)absoluteURL ofType:(NSString *)typeName error:(NSError *__autoreleasing *)error {
NSError *err;
NSDictionary *opts = #{
NSMigratePersistentStoresAutomaticallyOption : #YES,// it doesn't matter if these options are set or not
NSReadOnlyPersistentStoreOption : #YES,
};
if (![self.managedObjectContext.persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType //1
configuration:nil
URL:absoluteURL
options:opts
error:&err])
{
return NO;
} else {
return YES;
}
}
- (BOOL)writeToURL:(NSURL *)absoluteURL ofType:(NSString *)typeName forSaveOperation:(NSSaveOperationType)saveOperation originalContentsURL:(NSURL *)absoluteOriginalContentsURL error:(NSError *__autoreleasing *)error {
NSDictionary *opts = #{
NSMigratePersistentStoresAutomaticallyOption : #YES,// it doesn't matter if these options are set or not
NSReadOnlyPersistentStoreOption : #YES,
};
NSError *err;
[self.managedObjectContext.persistentStoreCoordinator migratePersistentStore:self.managedObjectContext.persistentStoreCoordinator.persistentStores[0]
toURL:absoluteURL
options:opts
withType:NSSQLiteStoreType //2
error:&err];
return YES;
}
// ====================================
// NSOperation.m
- (void)main
{
[...]
self.managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
self.managedObjectContext.persistentStoreCoordinator = self.myDoc.managedObjectContext.persistentStoreCoordinator;
self.managedObjectContext.undoManager = nil;
[self.managedObjectContext.persistentStoreCoordinator addPersistentStoreWithType:NSInMemoryStoreType
configuration:nil
URL:nil
options:nil
error:nil];
A typical database consists of 30k objects which takes ages to write and read when using XML so I do need to use the SQLite type.
Any suggestions are welcome.
I solved the problem by using the following dict in the -writeToUrl method:
NSDictionary *opts = #{NSSQLitePragmasOption: #{#"journal_mode":#"DELETE"}};

Swift crashing with two core data entities

I have an app set up with core data and one entity named "subject", when I try to add another entity to core data called "homework", my app crashes and I get this error
2014-10-04 12:41:05.302 HomeJournal[1050:20160] Unresolved error Optional(Error Domain=YOUR_ERROR_DOMAIN Code=9999 "Failed to initialize the application's saved data" UserInfo=0x7fe6bb60cac0 {NSLocalizedFailureReason=There was an error creating or loading the application's saved data., NSLocalizedDescription=Failed to initialize the application's saved data, NSUnderlyingError=0x7fe6bb524760 "The operation couldn’t be completed. (Cocoa error 134100.)"}), Optional([NSLocalizedFailureReason: There was an error creating or loading the application's saved data., NSLocalizedDescription: Failed to initialize the application's saved data, NSUnderlyingError: Error Domain=NSCocoaErrorDomain Code=134100 "The operation couldn’t be completed. (Cocoa error 134100.)" UserInfo=0x7fe6bb524720 {metadata={
NSPersistenceFrameworkVersion = 519;
NSStoreModelVersionHashes = {
Subject = <e90676da 933291ac ffe738ee ec80ba71 d2cc14a0 df80b9fe b69b358c 43d4cebc>;
};
NSStoreModelVersionHashesVersion = 3;
NSStoreModelVersionIdentifiers = (
""
);
NSStoreType = SQLite;
NSStoreUUID = "CB1FC120-99D2-4DB2-9C08-D6679CC6ECB7";
"_NSAutoVacuumLevel" = 2;
}, reason=The model used to open the store is incompatible with the one used to create the store}])
(lldb)
I'm not sure what I did wrong, I have it set up to get the data out of the entity called "subject" using this code
var appDel:AppDelegate = (UIApplication.sharedApplication().delegate as AppDelegate)
var context:NSManagedObjectContext = appDel.managedObjectContext!
var request = NSFetchRequest(entityName: "Subject")
request.returnsObjectsAsFaults = false;
Which works perfectly if there is only one entity.
Thanks in advanced
As someone suggested in comment, try deleting the app from simulator and re-install. If it still fails then match the NSManagedObject files you created for your data models to that in actual data models. It may be the case that you created files and then changed the models.

Resources