PreloadedPersistentContainer

A Framework to extend NSPersistentContainer with preloaded SQLite data. This supports both macOS for build phase and iOS for runtime.

MIT License

Stars
5

PreloadedPersistentContainer

A Framework to extend NSPersistentContainer with preloaded SQLite data. This supports both macOS for build phase and iOS for runtime.

Use cases

  • Preload multple records at build phase, then provide search experience to customers

Install

Using Carthage:

$ cat Cartfile
github "riywo/PreloadedPersistentContainer"

$ carthage update
*** Fetching PreloadedPersistentContainer
*** Checking out PreloadedPersistentContainer at "v0.1.0"
*** xcodebuild output can be found in /var/folders/29/mmyrpb0d5g39glgdcv9x4z780000gn/T/carthage-xcodebuild.PBBnLr.log
*** Building scheme "PreloadedPersistentContainer iOS" in PreloadedPersistentContainer.xcodeproj
*** Building scheme "PreloadedPersistentContainer macOS" in PreloadedPersistentContainer.xcodeproj

Now, you can use Framework:

./Carthage/Build
 Mac
  PreloadedPersistentContainer.framework
  PreloadedPersistentContainer.framework.dSYM
 iOS
     PreloadedPersistentContainer.framework
     PreloadedPersistentContainer.framework.dSYM

Usage

1. Create a macOS CLI target.

File -> New -> Target -> macOS Command Line Tool

2. Associate each Framework to iOS App and macOS CLI.

Add to Linked Frameworks and Libraries

3. Add macOS CLI to target memberships of your Core Data model, related classes, etc.

Open file -> Show the File inspector (right pane) -> Check macOS CLI in Target Membership

4. Edit scheme of iOS App to add macOS CLI into its build targets before iOS App. Uncheck Parallelize Build.

Product -> Scheme -> Manage Schemes -> Edit Your iOS scheme -> Build -> Add macOS CLI -> Move it before iOS App -> Uncheck Parallelize Build

5. Add run script phase to iOS App build phases.

Open Buid Phases of your iOS App target -> Add Run script -> Move it after Compile Sources -> Paste command below

${BUILT_PRODUCTS_DIR}/../${CONFIGURATION}/YourMacOSCLI

6. Edit macOS CLI's Build Settings to link libraries

Framework with CLI is tricky. It requires additional steps to load Framework. See How to add a dynamic Swift framework to a Command Line Tool

In summary, because Swift stdlibs are already embedded in macOS Framework, you only need to do the steps below:

  • Add Runpath Search Paths
    • $(PROJECT_DIR)/Carthage/Build/Mac/ (to find Framework itself)
    • $(PROJECT_DIR)/Carthage/Build/Mac/PreloadedPersistentContainer.framework/Versions/Current/Frameworks (to find Swift stdlibs)
  • Add User-Defined to dynamically link Swift stdlibs
    • SWIFT_FORCE_DYNAMIC_LINK_STDLIB = YES
    • SWIFT_FORCE_STATIC_LINK_STDLIB = NO

7. Write preload functions in macOS CLI.

If this CLI runs on build phase of iOS App, it preloads SQLite files in you iOS App main bundle (Your.app/YourModel.sqlite*).

import CoreData
import PreloadedPersistentContainer

let container = NSPersistentContainer(name: "YourModel")
container.loadPersistentStoresWithPreload { (storeDescription, error) in
    if let error = error {
        fatalError("Failed to load store: \(error)")
    }
}

let entity = YourEntity(context: container.viewContext)
entity.id = 1
try! container.viewContext.save()

8. Use loadPersistentStoresWithPreload() in your iOS App.

Maybe in AppDelegate.swift, replace loadPersistentStores() with loadPersistentStoresWithPreload().

Then, the bundled SQLite files (Your.app/YourModel.sqlite*) will be automatically read.

import CoreData
import PreloadedPersistentContainer

lazy var persistentContainer: NSPersistentContainer = {
    let modelName = "YourModel"
    let container = NSPersistentContainer(name: modelName)
    container.loadPersistentStoresWithPreload(completionHandler: { (storeDescription, error) in
        if let error = error as NSError? {
            fatalError("Unresolved error \(error), \(error.userInfo)")
        }
    })
    return container
}()

9. Build iOS App.

Have fun!

References