Exporting CoreData to JSON for Simulator Usage

Problem

While preparing iPad support and taking App Store screenshots I found an annoying issue. My app has many calendar records but I haven’t implemented device sync yet. This means I had to manually input all my iPhone data into the iPad simulator every time.

Solution: CoreData Export Using JSON

You cannot directly export/import CoreData between real device and simulator. Instead I solved this by converting CoreData to JSON format and using JSON instead of CoreData in the simulator environment.

Step 1: Export CoreData to JSON

First I wrote a function to convert all CoreData to JSON format on the real device:

import CoreData

func exportCoreDataToJSON() {
    let fetchRequest: NSFetchRequest<YourEntity> = YourEntity.fetchRequest()

    do {
        let objects = try context.fetch(fetchRequest)

        let jsonArray = objects.map { object in
            return [
                // Map according to your CoreData Attributes
            ]
        }

        let jsonData = try JSONSerialization.data(withJSONObject: jsonArray, options: .prettyPrinted)

        // Print JSON to console
        if let jsonString = String(data: jsonData, encoding: .utf8) {
            print(jsonString)
        }

    } catch {
        print("Export failed: \(error)")
    }
}

I considered saving the JSON file directly but finding the target folder on the device was also troublesome. Instead I decided to print the JSON to console and copy it manually. Then I created the JSON file directly in the project root and included it in the Bundle.

Step 2: Environment-based Branching

In the ViewModel I implemented different data sources based on the execution environment:

private func fetchData(for date: Date) {
    #if targetEnvironment(simulator)
        loadDataFromJSON(for: date)
    #else
        fetchDataFromCoreData(for: date)
    #endif
}

Using the #if targetEnvironment(simulator) compiler directive I distinguished the execution environment at build time. The simulator loads data from JSON while the real device loads from CoreData.

Step 3: JSON Data Loading and Mapping

I implemented logic to read JSON files included in the Bundle and convert them to Swift objects:

private func loadDataFromJSON(for date: Date) {
    // Load JSON file from Bundle, exported_data = json filename
    guard let fileURL = Bundle.main.url(forResource: "exported_data", withExtension: "json") else {
        print("Cannot find JSON file")
        self.entries = []
        return
    }

    do {
        let jsonData = try Data(contentsOf: fileURL)
        let jsonArray = try JSONSerialization.jsonObject(with: jsonData) as? [[String: Any]]

        // Convert JSON to Swift objects
        let filteredEntries = jsonArray?.compactMap { dict -> YourEntry? in
            guard //...
                // Data mapping
            else {
                return nil
            }

            return YourEntry(
                // Mapped data
            )
        } ?? []

        self.entries = filteredEntries.sorted { $0.date < $1.date }

    } catch {
        print("Failed to load JSON: \(error)")
        self.entries = []
    }
}

Conclusion

Using this method of converting real device CoreData to JSON for simulator usage greatly improved my App Store submission preparation process.

Later I created language-specific JSON files which reduced the hassle of writing and deleting diary entries for different languages and saved time preparing previews. Additionally since I store Color data the content between previews became more consistent.

This approach helped me streamline the development workflow and create better App Store screenshots with realistic data.