Core Data with Pre-Filled .Sqlite (Swift3)

Core Data with pre-filled .sqlite (Swift3)

This is how I do it:

lazy var persistentContainer: NSPersistentContainer = {

let container = NSPersistentContainer(name: "app_name")

let seededData: String = "app_name"
var persistentStoreDescriptions: NSPersistentStoreDescription

let storeUrl = self.applicationDocumentsDirectory.appendingPathComponent("app_name.sqlite")

if !FileManager.default.fileExists(atPath: (storeUrl.path)) {
let seededDataUrl = Bundle.main.url(forResource: seededData, withExtension: "sqlite")
try! FileManager.default.copyItem(at: seededDataUrl!, to: storeUrl)

}

print(storeUrl)

container.persistentStoreDescriptions = [NSPersistentStoreDescription(url: storeUrl)]
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error {

fatalError("Unresolved error \(error),")
}
})

return container

}()

How to pre-load Core Data with a SQLite file that have references to images that were saved using external storage?

Step 1: Create "MyAppSeedData" dir and paste MyApp.sqlite, the MyApp_SUPPORT, the MyApp.sqilte-smh, MyApp.sqilte-wal files inside.

Step 2: Drag MyAppSeedData to the bundle under AppDelegate and tick the box add target.

Step 3: These functions must be in AppDelegate file:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool
{
//If first launch condition == true {
seedData()
//}
return true
}


func seedData() {
let fm = FileManager.default

//Destination URL: Application Folder
let libURL = fm.urls(for: .libraryDirectory, in: .userDomainMask).first!
let destFolder = libURL.appendingPathComponent("Application Support").path
//Or
//let l1 = NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, .userDomainMask, true).last!
//

//Starting URL: MyAppSeedData dir
let folderPath = Bundle.main.resourceURL!.appendingPathComponent("MyAppSeedData").path

let fileManager = FileManager.default
let urls = fileManager.urls(for: .applicationSupportDirectory, in: .userDomainMask)
if let applicationSupportURL = urls.last {
do{
try fileManager.createDirectory(at: applicationSupportURL, withIntermediateDirectories: true, attributes: nil)
}
catch{
print(error)
}
}
copyFiles(pathFromBundle: folderPath, pathDestDocs: destFolder)
}

func copyFiles(pathFromBundle : String, pathDestDocs: String) {
let fm = FileManager.default
do {
let filelist = try fm.contentsOfDirectory(atPath: pathFromBundle)
let fileDestList = try fm.contentsOfDirectory(atPath: pathDestDocs)

for filename in fileDestList {
try FileManager.default.removeItem(atPath: "\(pathDestDocs)/\(filename)")
}

for filename in filelist {
try? fm.copyItem(atPath: "\(pathFromBundle)/\(filename)", toPath: "\(pathDestDocs)/\(filename)")
}
} catch {
print("Error info: \(error)")
}
}

// MARK: - Core Data stack

lazy var persistentContainer: NSPersistentContainer = {
let modelName = "MyApp"

var container: NSPersistentContainer!

container = NSPersistentContainer(name: modelName)

container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()

SQLite to Core Data Migration

I think @SaintThread hit the main issue here. The reason for it is that Core Data is not a wrapper around SQLite-- it's a different API with different assumptions that just happens to use SQLite internally. Core Data doesn't attempt to be compatible with how you'd use SQLite if you were using SQLite on its own.

That said, if you still want to migrate, you'll have to design a Core Data model and then write fully custom code to migrate from your existing SQLite file to Core Data. Your code would need to read everything from SQLite, convert it to the new Core Data representation, save the changes, and then remove the existing SQLite files.

When removing the existing SQLite file, make sure to also remove the SQLite journal files (if any).

Pre-fill SQLite database with Core Data using Django

You might want to have a look at the Active Record port for cocoa/cocoa touch. I've done an app like this before, and what we (the client and i), choose to do was to import the data from an XML file on the first app launch. The idea being that as the parser was built into the app, we could do OVA updates if we choose to at a later date. The data did have fairly complex relationships, but i decided Core Data was still the way forward.

I've only used raw SQLite once, and that was before we had CoreData on the iPhone. Also you should consider what your solution is for doing schema migrations which are handled by CoreData.

A Hybrid solution is to load the data into Core Data in the simulator, and then ship that SQLite database with the app, and copy it into the app's document directory, on the initial load. Best of both worlds.

Good luck

swift3 CoreData fetch returns nil

NSPersistentContainer uses the Application Support directory by default, not the documents directory.

If you print out the value of storeURL in your loadPersistentStores completion block, you'll see that it is pointing to Application support. What's happening is that it is creating a blank database based on your model, ignoring the copy you've made.

Either copy into application support instead, or pass in an NSPersistentStoreDescription object with a URL pointing to the documents directory if you want to control where NSPersistentContainer does its thing.

It's worth noting that these lines:

let directoryUrls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)

let applicationDocumentDirectory = directoryUrls[0]

let storeUrl = applicationDocumentDirectory.appendingPathComponent("GuessGreek.sqlite")

Are doing absolutely nothing in your current code.

Also worthy of note - your SQLiteManager screenshot suggests the file is called GuessGreekDatabase.sqlite, yet your NSPersistentContainer will default to a store name of GuessGreek.sqlite, so may also need fixing unless you're doing that during the copy.

Swift Core Data is saving to /dev/null so it is in memory only

When you instantiate your NSPersistentStoreDescription you have the option of passing in a URL. Here's a link to the documentation, and here's a well explained post on the topic

let container = NSPersistentContainer(name: "NameOfDataModel")

let storeURL = try! FileManager
.default
.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
.appendingPathComponent("NameOfDataModel.sqlite")

let storeDescription = NSPersistentStoreDescription(url: storeURL)
container.persistentStoreDescriptions = [storeDescription]


Related Topics



Leave a reply



Submit