简体   繁体   中英

swift3 CoreData fetch returns nil

Please see update below:

There are a number of questions similar to this, but none seem to be answered adequately for me, so any help will be appreciated.

I have a preloaded database that I created in a separate app. If this is a first time run, the database is copied into the documents directory. I can see from the log that the database is in the expected location:

AppDelegate urls:  [file:///Volumes/HD1%20-%20DATA/Users/david/Library/Developer/CoreSimulator/Devices/8B0E16F5-B739-4299-9B4D-E6A3C8C92E55/data/Containers/Data/Application/B8A87853-6FEB-4532-83EF-AB08985F2B43/Documents/]

By using SQLiteManager, I can verify that the database holds the data as expected.

在此处输入图片说明

My CoreData Object graph is:

在此处输入图片说明

However, when I execute a fetch request, the result is nil.

This is the fetch request:

func testLetters() {
        print(#function)

        let moc = coreDataStack.persistentContainer.viewContext
        let letterFetch = NSFetchRequest<NSFetchRequestResult>(entityName: "LetterEntity")

        do {
            let fetchedLetters = try moc.fetch(letterFetch) as! [LetterEntity]
            print(#function, "letter: ", fetchedLetters)
        } catch {
            fatalError("Failed to fetch employees: \(error)")
        }
}

I have a Core Data stack outside of my App Delegate that looks as follows:

import UIKit
import CoreData
class CoreDataStack {

    static let instance = CoreDataStack()

    lazy var persistentContainer: NSPersistentContainer = {
        let container = NSPersistentContainer(name: "GuessGreek")

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

        let applicationDocumentDirectory = directoryUrls[0]

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

        container.loadPersistentStores(completionHandler: { (storeUrl, error) in
            if let error = error as NSError? {

                fatalError("Unresolved error \(error), \(error.userInfo)")
            }
        })
        return container
    }()



    func saveContext() {
        let context = persistentContainer.viewContext
        if context.hasChanges {
            do {
                try context.save()
            } catch let error as NSError {
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }
        }
    }
}

Again, any help would be welcome.

UPDATE: I've changed the copy of the database as follows:

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

let applicationDocumentDirectory = directoryUrls[0]

let managedContext = coreDataStack.persistentContainer.viewContext

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

print("AppDelegate", #function, "StoreURL", storeUrl)


if !FileManager.default.fileExists(atPath: (storeUrl.path)) {
    print("Copying databases...")

    let sourceSqliteURLs = [
        Bundle.main.url(forResource: "GuessGreekDatabase", withExtension: "sqlite")!,
        Bundle.main.url(forResource: "GuessGreekDatabase", withExtension: "sqlite-wal")!,
        Bundle.main.url(forResource: "GuessGreekDatabase", withExtension: "sqlite-shm")!]

    let destSqliteURLs = [
        applicationDocumentDirectory.appendingPathComponent("GuessGreek.sqlite"),
        applicationDocumentDirectory.appendingPathComponent("GuessGreek.sqlite-wal"),
        applicationDocumentDirectory.appendingPathComponent("GuessGreek.sqlite-shm")]

    for index in 0..<sourceSqliteURLs.count {
        do {
            try FileManager.default.copyItem(at: sourceSqliteURLs[index], to: destSqliteURLs[index])
            print(#function, "Done copying")
        } catch {
            print(error)
        }


        do {
            try managedContext.save()
        } catch let error as NSError  {
            print("Error While Saving Data: \(error.userInfo)")
        }
    }
}

I remove the app from the Sim, and clean. When I run, I'm getting errors that the file cant be copied as it already exists... I'm missing something here.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM