Skip to content

Commit 2392762

Browse files
committed
Ensure bad files get cleared out regardless (#30)
1 parent 62d602c commit 2392762

File tree

3 files changed

+51
-11
lines changed

3 files changed

+51
-11
lines changed

Flapjack.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Pod::Spec.new do |s|
22
s.name = 'Flapjack'
3-
s.version = '0.4.0'
3+
s.version = '0.5.0'
44
s.summary = 'A Swift data persistence API with support for Core Data.'
55
s.description = <<-DESC
66
Flapjack is an iOS/macOS/tvOS framework with 2 primary goals.

Flapjack/CoreData/CoreDataAccess.swift

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,18 @@ public final class CoreDataAccess: DataAccess {
168168
- parameter completion: A closure to be called upon completion.
169169
*/
170170
public func deleteDatabase(rebuild: Bool, completion: @escaping (DataAccessError?) -> Void) {
171+
let fileExistsAtPath = storeType.url.map { FileManager.default.fileExists(atPath: $0.path, isDirectory: nil) } ?? false
172+
173+
// If we've never attached any store, delete any stale file that may be there and add them
174+
// anew with `addDefaultPersistentStores(async:completion:)`.
171175
guard !persistentStores.isEmpty else {
176+
if let storeURL = storeType.url, fileExistsAtPath {
177+
do {
178+
try FileManager.default.removeItem(atPath: storeURL.path)
179+
} catch let error {
180+
Logger.error("Error destroying persistent store at \(storeURL): \(error)")
181+
}
182+
}
172183
if rebuild {
173184
addDefaultPersistentStores(async: shouldLoadAsynchronously, completion: completion)
174185
} else {
@@ -177,8 +188,8 @@ public final class CoreDataAccess: DataAccess {
177188
return
178189
}
179190

191+
// Let listeners know we're about to detach our store from our coordinator, and then do it.
180192
NotificationCenter.default.post(name: type(of: self).willDestroyMainContextNotification, object: mainContext)
181-
182193
let localPersistentStores = persistentStores
183194
localPersistentStores.enumerated().forEach { idx, persistentStore in
184195
do {
@@ -188,12 +199,11 @@ public final class CoreDataAccess: DataAccess {
188199
}
189200
}
190201

191-
if let storeURL = storeType.url {
202+
// Now that we've detached the store from the coordinator,
203+
if let storeURL = storeType.url, fileExistsAtPath {
192204
do {
193-
if FileManager.default.fileExists(atPath: storeURL.path, isDirectory: nil) {
194-
try persistentStoreCoordinator.destroyPersistentStore(at: storeURL, ofType: storeType.coreDataType, options: nil)
195-
try FileManager.default.removeItem(atPath: storeURL.path)
196-
}
205+
try persistentStoreCoordinator.destroyPersistentStore(at: storeURL, ofType: storeType.coreDataType, options: nil)
206+
try FileManager.default.removeItem(atPath: storeURL.path)
197207
} catch let error {
198208
Logger.error("Error destroying persistent store at \(storeURL): \(error)")
199209
}

Tests/CoreData/CoreDataAccessTests.swift

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,8 @@ class CoreDataAccessWithSQLFileTests: XCTestCase {
238238
XCTAssertTrue(FileManager.default.fileExists(atPath: storeURL.path, isDirectory: nil))
239239

240240
let expect = expectation(description: "completion")
241-
dataAccess.deleteDatabase(rebuild: false) { _ in
241+
dataAccess.deleteDatabase(rebuild: false) { error in
242+
XCTAssertNil(error)
242243
XCTAssertFalse(FileManager.default.fileExists(atPath: self.storeURL.path, isDirectory: nil))
243244
expect.fulfill()
244245
}
@@ -250,7 +251,8 @@ class CoreDataAccessWithSQLFileTests: XCTestCase {
250251
XCTAssertTrue(FileManager.default.fileExists(atPath: storeURL.path, isDirectory: nil))
251252

252253
let expect = expectation(description: "completion")
253-
dataAccess.deleteDatabase(rebuild: true) { _ in
254+
dataAccess.deleteDatabase(rebuild: true) { error in
255+
XCTAssertNil(error)
254256
XCTAssertTrue(FileManager.default.fileExists(atPath: self.storeURL.path, isDirectory: nil))
255257
expect.fulfill()
256258
}
@@ -259,7 +261,8 @@ class CoreDataAccessWithSQLFileTests: XCTestCase {
259261

260262
func testDeleteDatabaseWithoutPersistentStoresNoRebuild() {
261263
let expect = expectation(description: "completion")
262-
dataAccess.deleteDatabase(rebuild: false) { _ in
264+
dataAccess.deleteDatabase(rebuild: false) { error in
265+
XCTAssertNil(error)
263266
XCTAssertFalse(FileManager.default.fileExists(atPath: self.storeURL.path, isDirectory: nil))
264267
expect.fulfill()
265268
}
@@ -268,7 +271,34 @@ class CoreDataAccessWithSQLFileTests: XCTestCase {
268271

269272
func testDeleteDatabaseWithoutPersistentStoresWithRebuild() {
270273
let expect = expectation(description: "completion")
271-
dataAccess.deleteDatabase(rebuild: true) { _ in
274+
dataAccess.deleteDatabase(rebuild: true) { error in
275+
XCTAssertNil(error)
276+
XCTAssertTrue(FileManager.default.fileExists(atPath: self.storeURL.path, isDirectory: nil))
277+
expect.fulfill()
278+
}
279+
waitForExpectations(timeout: 1.0) { XCTAssertNil($0) }
280+
}
281+
282+
func testDeleteDatabaseWithoutPersistentStoresJunkSQLNoRebuild() throws {
283+
try "junk".write(to: storeURL, atomically: true, encoding: .utf8)
284+
XCTAssertTrue(FileManager.default.fileExists(atPath: storeURL.path, isDirectory: nil))
285+
286+
let expect = expectation(description: "completion")
287+
dataAccess.deleteDatabase(rebuild: false) { error in
288+
XCTAssertNil(error)
289+
XCTAssertFalse(FileManager.default.fileExists(atPath: self.storeURL.path, isDirectory: nil))
290+
expect.fulfill()
291+
}
292+
waitForExpectations(timeout: 1.0) { XCTAssertNil($0) }
293+
}
294+
295+
func testDeleteDatabaseWithoutPersistentStoresJunkSQLWithRebuild() throws {
296+
try "junk".write(to: storeURL, atomically: true, encoding: .utf8)
297+
XCTAssertTrue(FileManager.default.fileExists(atPath: storeURL.path, isDirectory: nil))
298+
299+
let expect = expectation(description: "completion")
300+
dataAccess.deleteDatabase(rebuild: true) { error in
301+
XCTAssertNil(error)
272302
XCTAssertTrue(FileManager.default.fileExists(atPath: self.storeURL.path, isDirectory: nil))
273303
expect.fulfill()
274304
}

0 commit comments

Comments
 (0)