Compare commits

...

4 Commits
2.0.5 ... 2.0.6

Author SHA1 Message Date
John Rommel Estropia
0dbd05b172 version bump 2016-09-11 14:30:32 +09:00
John Rommel Estropia
243c4044ab fix bridging producing base abstract class instead of subclass concrete class 2016-09-11 14:30:25 +09:00
John Rommel Estropia
df835114cb ignore errors when deleting wal files 2016-09-10 22:57:45 +09:00
John Rommel Estropia
f99d3cc21a fix RecreateStoreOnModelMismatch option not working when an existing xcdatamodel gets updated without adding a new version 2016-09-10 22:51:33 +09:00
17 changed files with 130 additions and 47 deletions

View File

@@ -1,6 +1,6 @@
Pod::Spec.new do |s| Pod::Spec.new do |s|
s.name = "CoreStore" s.name = "CoreStore"
s.version = "2.0.5" s.version = "2.0.6"
s.license = "MIT" s.license = "MIT"
s.summary = "Unleashing the real power of Core Data with the elegance and safety of Swift" s.summary = "Unleashing the real power of Core Data with the elegance and safety of Swift"
s.homepage = "https://github.com/JohnEstropia/CoreStore" s.homepage = "https://github.com/JohnEstropia/CoreStore"

View File

@@ -197,4 +197,41 @@
XCTAssertNil(sqliteError); XCTAssertNil(sqliteError);
} }
- (void)test_ThatTransactions_BridgeCorrectly {
[CSCoreStore
setDefaultStack:[[CSDataStack alloc]
initWithModelName:@"Model"
bundle:[NSBundle bundleForClass:[self class]]
versionChain:nil]];
[CSCoreStore
addInMemoryStorageAndWait:[CSInMemoryStore new]
error:nil];
{
CSUnsafeDataTransaction *transaction = [CSCoreStore beginUnsafe];
XCTAssertNotNil(transaction);
XCTAssert([transaction isKindOfClass:[CSUnsafeDataTransaction class]]);
}
{
XCTestExpectation *expectation = [self expectationWithDescription:@"sync"];
[CSCoreStore beginSynchronous:^(CSSynchronousDataTransaction * _Nonnull transaction) {
XCTAssertNotNil(transaction);
XCTAssert([transaction isKindOfClass:[CSSynchronousDataTransaction class]]);
[expectation fulfill];
}];
}
{
XCTestExpectation *expectation = [self expectationWithDescription:@"async"];
[CSCoreStore beginAsynchronous:^(CSAsynchronousDataTransaction * _Nonnull transaction) {
XCTAssertNotNil(transaction);
XCTAssert([transaction isKindOfClass:[CSAsynchronousDataTransaction class]]);
[expectation fulfill];
}];
}
[self waitForExpectationsWithTimeout:10 handler:nil];
}
@end @end

View File

@@ -308,7 +308,7 @@ public protocol LocalStorage: StorageInterface {
var mappingModelBundles: [NSBundle] { get } var mappingModelBundles: [NSBundle] { get }
var localStorageOptions: LocalStorageOptions { get } var localStorageOptions: LocalStorageOptions { get }
func storeOptionsForOptions(options: LocalStorageOptions) -> [String: AnyObject]? func storeOptionsForOptions(options: LocalStorageOptions) -> [String: AnyObject]?
func eraseStorageAndWait(soureModel soureModel: NSManagedObjectModel) throws func eraseStorageAndWait(soureModel soureModel: NSManagedObjectModel?) throws
} }
``` ```
If you have custom `NSIncrementalStore` or `NSAtomicStore` subclasses, you can implement this protocol and use it similarly to `SQLiteStore`. If you have custom `NSIncrementalStore` or `NSAtomicStore` subclasses, you can implement this protocol and use it similarly to `SQLiteStore`.

View File

@@ -15,7 +15,7 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>FMWK</string> <string>FMWK</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>2.0.5</string> <string>2.0.6</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>

View File

@@ -223,7 +223,7 @@ public extension DataStack {
do { do {
try _ = self.model[metadata].flatMap(storage.eraseStorageAndWait) _ = try storage.eraseStorageAndWait(soureModel: self.model[metadata])
try self.addStorageAndWait(storage) try self.addStorageAndWait(storage)
GCDQueue.Main.async { GCDQueue.Main.async {
@@ -388,7 +388,7 @@ public extension DataStack {
URL: cacheFileURL, URL: cacheFileURL,
options: storeOptions options: storeOptions
) )
try _ = self.model[metadata].flatMap(storage.eraseStorageAndWait) _ = try storage.eraseStorageAndWait(soureModel: self.model[metadata])
try self.createPersistentStoreFromStorage( try self.createPersistentStoreFromStorage(
storage, storage,

View File

@@ -144,7 +144,7 @@ public final class CSAsynchronousDataTransaction: CSBaseDataTransaction {
// MARK: CoreStoreObjectiveCType // MARK: CoreStoreObjectiveCType
internal typealias SwiftType = AsynchronousDataTransaction public typealias SwiftType = AsynchronousDataTransaction
public override var bridgeToSwift: AsynchronousDataTransaction { public override var bridgeToSwift: AsynchronousDataTransaction {
@@ -153,21 +153,21 @@ public final class CSAsynchronousDataTransaction: CSBaseDataTransaction {
public required init(_ swiftValue: AsynchronousDataTransaction) { public required init(_ swiftValue: AsynchronousDataTransaction) {
super.init(swiftValue) super.init(swiftValue as BaseDataTransaction)
} }
public required init(_ swiftValue: BaseDataTransaction) { public required init(_ swiftValue: BaseDataTransaction) {
fatalError("init(_:) requires an AsynchronousDataTransaction instance") super.init(swiftValue as! AsynchronousDataTransaction)
} }
} }
// MARK: - AsynchronousDataTransaction // MARK: - AsynchronousDataTransaction
extension AsynchronousDataTransaction { extension AsynchronousDataTransaction: CoreStoreSwiftType {
// MARK: CoreStoreSwiftType // MARK: CoreStoreSwiftType
internal typealias ObjectiveCType = CSAsynchronousDataTransaction public typealias ObjectiveCType = CSAsynchronousDataTransaction
} }

View File

@@ -292,8 +292,6 @@ public class CSBaseDataTransaction: NSObject, CoreStoreObjectiveCType {
// MARK: CoreStoreObjectiveCType // MARK: CoreStoreObjectiveCType
public typealias SwiftType = BaseDataTransaction
public required init(_ swiftValue: BaseDataTransaction) { public required init(_ swiftValue: BaseDataTransaction) {
self.swiftTransaction = swiftValue self.swiftTransaction = swiftValue
@@ -312,11 +310,11 @@ public class CSBaseDataTransaction: NSObject, CoreStoreObjectiveCType {
} }
// MARK: - BaseDataTransaction //// MARK: - BaseDataTransaction
//
extension BaseDataTransaction: CoreStoreSwiftType { //extension BaseDataTransaction: CoreStoreSwiftType {
//
// MARK: CoreStoreSwiftType // // MARK: CoreStoreSwiftType
//
public typealias ObjectiveCType = CSBaseDataTransaction // public typealias ObjectiveCType = CSBaseDataTransaction
} //}

View File

@@ -154,7 +154,7 @@ public final class CSSQLiteStore: NSObject, CSLocalStorage, CoreStoreObjectiveCT
Called by the `CSDataStack` to perform actual deletion of the store file from disk. Do not call directly! The `sourceModel` argument is a hint for the existing store's model version. For `CSSQLiteStore`, this converts the database's WAL journaling mode to DELETE before deleting the file. Called by the `CSDataStack` to perform actual deletion of the store file from disk. Do not call directly! The `sourceModel` argument is a hint for the existing store's model version. For `CSSQLiteStore`, this converts the database's WAL journaling mode to DELETE before deleting the file.
*/ */
@objc @objc
public func eraseStorageAndWait(soureModel soureModel: NSManagedObjectModel, error: NSErrorPointer) -> Bool { public func eraseStorageAndWait(soureModel soureModel: NSManagedObjectModel?, error: NSErrorPointer) -> Bool {
return bridge(error) { return bridge(error) {

View File

@@ -121,5 +121,5 @@ public protocol CSLocalStorage: CSStorageInterface {
Called by the `CSDataStack` to perform actual deletion of the store file from disk. Do not call directly! The `sourceModel` argument is a hint for the existing store's model version. Implementers can use the `sourceModel` to perform necessary store operations. (SQLite stores for example, can convert WAL journaling mode to DELETE before deleting) Called by the `CSDataStack` to perform actual deletion of the store file from disk. Do not call directly! The `sourceModel` argument is a hint for the existing store's model version. Implementers can use the `sourceModel` to perform necessary store operations. (SQLite stores for example, can convert WAL journaling mode to DELETE before deleting)
*/ */
@objc @objc
func eraseStorageAndWait(soureModel soureModel: NSManagedObjectModel, error: NSErrorPointer) -> Bool func eraseStorageAndWait(soureModel soureModel: NSManagedObjectModel?, error: NSErrorPointer) -> Bool
} }

View File

@@ -143,7 +143,7 @@ public final class CSSynchronousDataTransaction: CSBaseDataTransaction {
// MARK: CoreStoreObjectiveCType // MARK: CoreStoreObjectiveCType
internal typealias SwiftType = SynchronousDataTransaction public typealias SwiftType = SynchronousDataTransaction
public override var bridgeToSwift: SynchronousDataTransaction { public override var bridgeToSwift: SynchronousDataTransaction {
@@ -152,21 +152,21 @@ public final class CSSynchronousDataTransaction: CSBaseDataTransaction {
public required init(_ swiftValue: SynchronousDataTransaction) { public required init(_ swiftValue: SynchronousDataTransaction) {
super.init(swiftValue) super.init(swiftValue as BaseDataTransaction)
} }
public required init(_ swiftValue: BaseDataTransaction) { public required init(_ swiftValue: BaseDataTransaction) {
fatalError("init(_:) requires a BaseDataTransaction instance") super.init(swiftValue as! SynchronousDataTransaction)
} }
} }
// MARK: - SynchronousDataTransaction // MARK: - SynchronousDataTransaction
extension SynchronousDataTransaction { extension SynchronousDataTransaction: CoreStoreSwiftType {
// MARK: CoreStoreSwiftType // MARK: CoreStoreSwiftType
internal typealias ObjectiveCType = CSSynchronousDataTransaction public typealias ObjectiveCType = CSSynchronousDataTransaction
} }

View File

@@ -174,7 +174,7 @@ public final class CSUnsafeDataTransaction: CSBaseDataTransaction {
// MARK: CoreStoreObjectiveCType // MARK: CoreStoreObjectiveCType
internal typealias SwiftType = UnsafeDataTransaction public typealias SwiftType = UnsafeDataTransaction
public override var bridgeToSwift: UnsafeDataTransaction { public override var bridgeToSwift: UnsafeDataTransaction {
@@ -183,21 +183,21 @@ public final class CSUnsafeDataTransaction: CSBaseDataTransaction {
public required init(_ swiftValue: UnsafeDataTransaction) { public required init(_ swiftValue: UnsafeDataTransaction) {
super.init(swiftValue) super.init(swiftValue as BaseDataTransaction)
} }
public required init(_ swiftValue: BaseDataTransaction) { public required init(_ swiftValue: BaseDataTransaction) {
fatalError("init(_:) requires an UnsafeDataTransaction instance") super.init(swiftValue as! UnsafeDataTransaction)
} }
} }
// MARK: - UnsafeDataTransaction // MARK: - UnsafeDataTransaction
extension UnsafeDataTransaction { extension UnsafeDataTransaction: CoreStoreSwiftType {
// MARK: CoreStoreSwiftType // MARK: CoreStoreSwiftType
internal typealias ObjectiveCType = CSUnsafeDataTransaction public typealias ObjectiveCType = CSUnsafeDataTransaction
} }

View File

@@ -118,12 +118,18 @@ internal func bridge<T: CoreStoreSwiftType>(error: NSErrorPointer, @noescape _ c
do { do {
let result = try closure() let result = try closure()
error.memory = nil if error != nil {
error.memory = nil
}
return result.bridgeToObjectiveC return result.bridgeToObjectiveC
} }
catch let swiftError { catch let swiftError {
error.memory = swiftError.bridgeToObjectiveC if error != nil {
error.memory = swiftError.bridgeToObjectiveC
}
return nil return nil
} }
} }
@@ -133,12 +139,18 @@ internal func bridge(error: NSErrorPointer, @noescape _ closure: () throws -> Vo
do { do {
try closure() try closure()
error.memory = nil if error != nil {
error.memory = nil
}
return true return true
} }
catch let swiftError { catch let swiftError {
error.memory = swiftError.bridgeToObjectiveC if error != nil {
error.memory = swiftError.bridgeToObjectiveC
}
return false return false
} }
} }
@@ -148,12 +160,18 @@ internal func bridge<T>(error: NSErrorPointer, @noescape _ closure: () throws ->
do { do {
let result = try closure() let result = try closure()
error.memory = nil if error != nil {
error.memory = nil
}
return result return result
} }
catch let swiftError { catch let swiftError {
error.memory = swiftError.bridgeToObjectiveC if error != nil {
error.memory = swiftError.bridgeToObjectiveC
}
return nil return nil
} }
} }
@@ -163,12 +181,18 @@ internal func bridge<T: CoreStoreSwiftType>(error: NSErrorPointer, @noescape _ c
do { do {
let result = try closure() let result = try closure()
error.memory = nil if error != nil {
error.memory = nil
}
return result.map { $0.bridgeToObjectiveC } return result.map { $0.bridgeToObjectiveC }
} }
catch let swiftError { catch let swiftError {
error.memory = swiftError.bridgeToObjectiveC if error != nil {
error.memory = swiftError.bridgeToObjectiveC
}
return nil return nil
} }
} }

View File

@@ -263,7 +263,7 @@ public final class DataStack {
URL: fileURL, URL: fileURL,
options: storeOptions options: storeOptions
) )
try _ = self.model[metadata].flatMap(storage.eraseStorageAndWait) _ = try storage.eraseStorageAndWait(soureModel: self.model[metadata])
try self.createPersistentStoreFromStorage( try self.createPersistentStoreFromStorage(
storage, storage,
@@ -359,7 +359,7 @@ public final class DataStack {
URL: cacheFileURL, URL: cacheFileURL,
options: storeOptions options: storeOptions
) )
try _ = self.model[metadata].flatMap(storage.eraseStorageAndWait) _ = try storage.eraseStorageAndWait(soureModel: self.model[metadata])
try self.createPersistentStoreFromStorage( try self.createPersistentStoreFromStorage(
storage, storage,

View File

@@ -424,11 +424,19 @@ public class ICloudStore: CloudStorage {
/** /**
Called by the `DataStack` to perform actual deletion of the store file from disk. Do not call directly! The `sourceModel` argument is a hint for the existing store's model version. For `SQLiteStore`, this converts the database's WAL journaling mode to DELETE before deleting the file. Called by the `DataStack` to perform actual deletion of the store file from disk. Do not call directly! The `sourceModel` argument is a hint for the existing store's model version. For `SQLiteStore`, this converts the database's WAL journaling mode to DELETE before deleting the file.
*/ */
public func eraseStorageAndWait(soureModel soureModel: NSManagedObjectModel) throws { public func eraseStorageAndWait(soureModel soureModel: NSManagedObjectModel?) throws {
// TODO: check if attached to persistent store // TODO: check if attached to persistent store
let cacheFileURL = self.cacheFileURL let cacheFileURL = self.cacheFileURL
guard let soureModel = soureModel else {
let fileManager = NSFileManager.defaultManager()
try fileManager.removeItemAtURL(cacheFileURL)
_ = try? fileManager.removeItemAtPath("\(cacheFileURL.absoluteString)-wal")
_ = try? fileManager.removeItemAtPath("\(cacheFileURL.absoluteString)-shm")
return
}
try cs_autoreleasepool { try cs_autoreleasepool {
let journalUpdatingCoordinator = NSPersistentStoreCoordinator(managedObjectModel: soureModel) let journalUpdatingCoordinator = NSPersistentStoreCoordinator(managedObjectModel: soureModel)

View File

@@ -165,11 +165,19 @@ public final class LegacySQLiteStore: LocalStorage, DefaultInitializableStore {
/** /**
Called by the `DataStack` to perform actual deletion of the store file from disk. Do not call directly! The `sourceModel` argument is a hint for the existing store's model version. For `SQLiteStore`, this converts the database's WAL journaling mode to DELETE before deleting the file. Called by the `DataStack` to perform actual deletion of the store file from disk. Do not call directly! The `sourceModel` argument is a hint for the existing store's model version. For `SQLiteStore`, this converts the database's WAL journaling mode to DELETE before deleting the file.
*/ */
public func eraseStorageAndWait(soureModel soureModel: NSManagedObjectModel) throws { public func eraseStorageAndWait(soureModel soureModel: NSManagedObjectModel?) throws {
// TODO: check if attached to persistent store // TODO: check if attached to persistent store
let fileURL = self.fileURL let fileURL = self.fileURL
guard let soureModel = soureModel else {
let fileManager = NSFileManager.defaultManager()
try fileManager.removeItemAtURL(fileURL)
_ = try? fileManager.removeItemAtPath("\(fileURL.absoluteString)-wal")
_ = try? fileManager.removeItemAtPath("\(fileURL.absoluteString)-shm")
return
}
try cs_autoreleasepool { try cs_autoreleasepool {
let journalUpdatingCoordinator = NSPersistentStoreCoordinator(managedObjectModel: soureModel) let journalUpdatingCoordinator = NSPersistentStoreCoordinator(managedObjectModel: soureModel)

View File

@@ -162,11 +162,19 @@ public final class SQLiteStore: LocalStorage, DefaultInitializableStore {
/** /**
Called by the `DataStack` to perform actual deletion of the store file from disk. Do not call directly! The `sourceModel` argument is a hint for the existing store's model version. For `SQLiteStore`, this converts the database's WAL journaling mode to DELETE before deleting the file. Called by the `DataStack` to perform actual deletion of the store file from disk. Do not call directly! The `sourceModel` argument is a hint for the existing store's model version. For `SQLiteStore`, this converts the database's WAL journaling mode to DELETE before deleting the file.
*/ */
public func eraseStorageAndWait(soureModel soureModel: NSManagedObjectModel) throws { public func eraseStorageAndWait(soureModel soureModel: NSManagedObjectModel?) throws {
// TODO: check if attached to persistent store // TODO: check if attached to persistent store
let fileURL = self.fileURL let fileURL = self.fileURL
guard let soureModel = soureModel else {
let fileManager = NSFileManager.defaultManager()
try fileManager.removeItemAtURL(fileURL)
_ = try? fileManager.removeItemAtPath("\(fileURL.absoluteString)-wal")
_ = try? fileManager.removeItemAtPath("\(fileURL.absoluteString)-shm")
return
}
try cs_autoreleasepool { try cs_autoreleasepool {
let journalUpdatingCoordinator = NSPersistentStoreCoordinator(managedObjectModel: soureModel) let journalUpdatingCoordinator = NSPersistentStoreCoordinator(managedObjectModel: soureModel)

View File

@@ -158,7 +158,7 @@ public protocol LocalStorage: StorageInterface {
/** /**
Called by the `DataStack` to perform actual deletion of the store file from disk. **Do not call directly!** The `sourceModel` argument is a hint for the existing store's model version. Implementers can use the `sourceModel` to perform necessary store operations. (SQLite stores for example, can convert WAL journaling mode to DELETE before deleting) Called by the `DataStack` to perform actual deletion of the store file from disk. **Do not call directly!** The `sourceModel` argument is a hint for the existing store's model version. Implementers can use the `sourceModel` to perform necessary store operations. (SQLite stores for example, can convert WAL journaling mode to DELETE before deleting)
*/ */
func eraseStorageAndWait(soureModel soureModel: NSManagedObjectModel) throws func eraseStorageAndWait(soureModel soureModel: NSManagedObjectModel?) throws
} }
internal extension LocalStorage { internal extension LocalStorage {
@@ -242,7 +242,7 @@ public protocol CloudStorage: StorageInterface {
/** /**
Called by the `DataStack` to perform actual deletion of the store file from disk. **Do not call directly!** The `sourceModel` argument is a hint for the existing store's model version. Implementers can use the `sourceModel` to perform necessary store operations. (Cloud stores for example, can set the NSPersistentStoreRemoveUbiquitousMetadataOption option before deleting) Called by the `DataStack` to perform actual deletion of the store file from disk. **Do not call directly!** The `sourceModel` argument is a hint for the existing store's model version. Implementers can use the `sourceModel` to perform necessary store operations. (Cloud stores for example, can set the NSPersistentStoreRemoveUbiquitousMetadataOption option before deleting)
*/ */
func eraseStorageAndWait(soureModel soureModel: NSManagedObjectModel) throws func eraseStorageAndWait(soureModel soureModel: NSManagedObjectModel?) throws
} }
internal extension CloudStorage { internal extension CloudStorage {