Swift Magic with In-Memory Core Data

Shayan Ali
2 min readNov 20, 2023

--

Welcome to a swift journey through the enchanted realm of Core Data! In this short guide, we’ll focus on the magic of in-memory storage for swift SwiftUI previews and lightning-fast unit tests.

Normally, Core-data saves data on a physical disk, like a computer’s memory. But this takes extra time for tests because you have to reset it each time. Plus, it’s slow, especially for SwiftUI previews.

To speed things up, let’s imagine Core Data using a special kind of memory called “in-memory store.” It’s like a magical space where data is instantly remembered and doesn’t need a reset. This makes tests and previews much quicker and smoother! 🚀

Spoiler Alert

The trick is to set the URL of the persistent store description to /dev/null before loading the store:

storeDescription.url = URL(fileURLWithPath: "/dev/null")

In-Memory Core Data: The Speed Elixir

Now, let’s add a dash of speed to our magic with OfflineCacheStorage. This sorcerer relies on an in-memory store, making SwiftUI previews and unit tests quicker than ever.

final class OfflineCacheStorage {
static let standard = OfflineCacheStorage()

#if DEBUG
static var test: OfflineCacheStorage { .init(inMemory: true) }
#endif

/// The persistent container providing access to different contexts, such as the `viewContext` or creating a `newBackgroundContext()`.
private let container: NSPersistentContainer

/// The default managed object Core Data context to be used. Returns a `viewContext` of the persistent container.
var context: NSManagedObjectContext {
container.viewContext
}

private init(
inMemory: Bool = false
) {
container = NSPersistentContainer(name: "MagicalStore")

if inMemory {
container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null")
}

container.loadPersistentStores { _, error in
if let error = error as NSError? {
fatalError("Could not load Core Data persistent stores. Error \(error), \(error.userInfo)")
}
}
}

/// Saves the default managed object Core Data context if it has any changes. Use this, whenever you want to persist changes to the database.
func save() {
if context.hasChanges {
do {
try context.save()
}
catch {
if let error = error as NSError? {
fatalError("Could not save context to Core Data. Error \(error), \(error.userInfo)")
}
}
}
}
}

For unit tests:

final class OfflineCacheStorageTests: XCTestCase {
func testStoringAndFetchingUsers() throws {
let testStorage = OfflineCacheStorage.test
XCTAssertEqual(try testStorage.context.count(for: CachedUser.fetchRequest()), 0)
let newUser = CachedUser(context: testStorage.context)
newUser.id = "1"
newUser.name = "Shayan"
newUser.lastname = "Ali"
newUser.email = "test@demo.com"

testStorage.save()
XCTAssertEqual(try testStorage.context.count(for: CachedUser.fetchRequest()), 1)
}
}

Conclusion

Unleash the full potential of Core Data with in-memory magic! Swift SwiftUI previews and unit tests have never been more enchanting. May your code be swift, magical, and always in-memory! ✨🏰

--

--

Shayan Ali

An iOS developer by profession but curious about everything including Web 3.0