Preload Data Functionality #118

Closed
opened 2025-12-29 15:24:54 +01:00 by adam · 2 comments
Owner

Originally created by @ghost on GitHub (Jan 12, 2017).

Hi,

In my app I have to populate my database with external data. I'm doing that during the app launch. This could take a lot of time, because there are thousands of records returned from the server. To avoid bad UX, making user to wait, I'm preloading data like this:

class AppDelegate: UIResponder, UIApplicationDelegate {

...

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
      
        ...

        // Preload SQLite, for better UX
        preloadData()
        
        // Setup Core Data
        let dataStack = DataStack(modelName: "Compare")
        CoreStore.defaultStack = dataStack
        try! CoreStore.addStorageAndWait()

        ...

        return true
    }

...

}

...

extension AppDelegate {
    
    //MARK: - Helpers
    
    fileprivate lazy var applicationSupportDirectory: URL = {
        let urls = FileManager.default.urls(for: .applicationSupportDirectory,
                                            in: .userDomainMask)
        return urls.first!
    }()
    
    // same as defaultRootDirectory in SQLiteStore
    fileprivate lazy var sqliteStoreDefaultRootDirectory: URL = {
        let urls = FileManager.default.urls(for: .applicationSupportDirectory,
                                            in: .userDomainMask)
        let defaultSystemDirectory = self.applicationSupportDirectory
        return defaultSystemDirectory.appendingPathComponent(
            Bundle.main.bundleIdentifier ?? "com.CoreStore.DataStack",
            isDirectory: true
        )
    
    //MARK: - Preload CoreData
    
    func preloadData() {
        let fileManager = FileManager.default
        // Exception Means that is already created - we don't cate
        try! fileManager.createDirectory(at: sqliteStoreDefaultRootDirectory,
                                         withIntermediateDirectories: true,
                                         attributes: nil)
        
        let url = sqliteStoreDefaultRootDirectory.appendingPathComponent("Compare.sqlite")
        
        if !fileManager.fileExists(atPath: url.path) {
            // !!! Add wal and shm if needed
            let sourceSqliteURLs = [Bundle.main.url(forResource: "Compare",
                                                    withExtension: "sqlite")!]
            let destSqliteURLs = [url]
            
            do {
                for index in 0..<sourceSqliteURLs.count {
                    try fileManager.copyItem(at: sourceSqliteURLs[index],
                                             to: destSqliteURLs[index])
                }
            } catch {
                print("Preload Data Error: \(error)")
            }
        }
    }
    
}

As you can see I'm repeating the part of your code responsible for getting the default root directory (see: sqliteStoreDefaultRootDirectory). Is it possible for you to make those methods accessible? Or even better, how about implementing a method which will copy bundled database (.wal and .shm also) to store.

Originally created by @ghost on GitHub (Jan 12, 2017). Hi, In my app I have to populate my database with external data. I'm doing that during the app launch. This could take a lot of time, because there are thousands of records returned from the server. To avoid bad UX, making user to wait, I'm preloading data like this: ``` class AppDelegate: UIResponder, UIApplicationDelegate { ... func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { ... // Preload SQLite, for better UX preloadData() // Setup Core Data let dataStack = DataStack(modelName: "Compare") CoreStore.defaultStack = dataStack try! CoreStore.addStorageAndWait() ... return true } ... } ... extension AppDelegate { //MARK: - Helpers fileprivate lazy var applicationSupportDirectory: URL = { let urls = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask) return urls.first! }() // same as defaultRootDirectory in SQLiteStore fileprivate lazy var sqliteStoreDefaultRootDirectory: URL = { let urls = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask) let defaultSystemDirectory = self.applicationSupportDirectory return defaultSystemDirectory.appendingPathComponent( Bundle.main.bundleIdentifier ?? "com.CoreStore.DataStack", isDirectory: true ) //MARK: - Preload CoreData func preloadData() { let fileManager = FileManager.default // Exception Means that is already created - we don't cate try! fileManager.createDirectory(at: sqliteStoreDefaultRootDirectory, withIntermediateDirectories: true, attributes: nil) let url = sqliteStoreDefaultRootDirectory.appendingPathComponent("Compare.sqlite") if !fileManager.fileExists(atPath: url.path) { // !!! Add wal and shm if needed let sourceSqliteURLs = [Bundle.main.url(forResource: "Compare", withExtension: "sqlite")!] let destSqliteURLs = [url] do { for index in 0..<sourceSqliteURLs.count { try fileManager.copyItem(at: sourceSqliteURLs[index], to: destSqliteURLs[index]) } } catch { print("Preload Data Error: \(error)") } } } } ``` As you can see I'm repeating the part of your code responsible for getting the default root directory (see: `sqliteStoreDefaultRootDirectory`). Is it possible for you to make those methods accessible? Or even better, how about implementing a method which will copy bundled database (.wal and .shm also) to store.
adam added the question label 2025-12-29 15:24:54 +01:00
adam closed this issue 2025-12-29 15:24:54 +01:00
Author
Owner

@JohnEstropia commented on GitHub (Jan 13, 2017):

Hi, thanks for the feedback!

If you trace the contents of addStorageAndWait(), you'll find that it just passes a default-initialized SQLiteStore. You can get the actual path from that instance:

let storage = SQLiteStore()
let sqliteStoreDefaultRootDirectory = storage.fileURL
// ... preloadData(sqliteStoreDefaultRootDirectory)
try! CoreStore.addStorageAndWait(storage)

You can also do it the other way: specify your own path and assign it to SQLiteStore()

let sqliteStoreDefaultRootDirector: URL = // ...
let storage = SQLiteStore(fileURL: sqliteStoreDefaultRootDirector)
// ... preloadData(sqliteStoreDefaultRootDirectory)
try! CoreStore.addStorageAndWait(storage)
@JohnEstropia commented on GitHub (Jan 13, 2017): Hi, thanks for the feedback! If you trace the contents of `addStorageAndWait()`, you'll find that it just passes a default-initialized `SQLiteStore`. You can get the actual path from that instance: ```swift let storage = SQLiteStore() let sqliteStoreDefaultRootDirectory = storage.fileURL // ... preloadData(sqliteStoreDefaultRootDirectory) try! CoreStore.addStorageAndWait(storage) ``` You can also do it the other way: specify your own path and assign it to `SQLiteStore()` ```swift let sqliteStoreDefaultRootDirector: URL = // ... let storage = SQLiteStore(fileURL: sqliteStoreDefaultRootDirector) // ... preloadData(sqliteStoreDefaultRootDirectory) try! CoreStore.addStorageAndWait(storage) ```
Author
Owner

@ghost commented on GitHub (Jan 13, 2017):

Thank you very much, I totally missed that!

@ghost commented on GitHub (Jan 13, 2017): Thank you very much, I totally missed that!
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/CoreStore#118