new auto-commit transaction methods

This commit is contained in:
John Estropia
2017-03-31 19:44:18 +09:00
parent d72d1afe8b
commit 97d7a276fe
39 changed files with 3739 additions and 3232 deletions

View File

@@ -43,29 +43,22 @@ public final class CSAsynchronousDataTransaction: CSBaseDataTransaction {
- parameter completion: the block executed after the save completes. Success or failure is reported by the `CSSaveResult` argument of the block.
*/
@objc
public func commitWithCompletion(_ completion: ((_ result: CSSaveResult) -> Void)?) {
public func commitWithSuccess(_ success: (() -> Void)?, failure: ((CSError) -> Void)?) {
self.bridgeToSwift.commit { (result) in
CoreStore.assert(
self.bridgeToSwift.transactionQueue.cs_isCurrentExecutionContext(),
"Attempted to commit a \(cs_typeName(self)) outside its designated queue."
)
CoreStore.assert(
!self.bridgeToSwift.isCommitted,
"Attempted to commit a \(cs_typeName(self)) more than once."
)
self.bridgeToSwift.autoCommit { (result) in
completion?(result.bridgeToObjectiveC)
}
}
/**
Begins a child transaction synchronously where `NSManagedObject` creates, updates, and deletes can be made. This method should not be used after the `-commitWithCompletion:` method was already called once.
- parameter closure: the block where creates, updates, and deletes can be made to the transaction. Transaction blocks are executed serially in a background queue, and all changes are made from a concurrent `NSManagedObjectContext`.
- returns: a `CSSaveResult` value indicating success or failure, or `nil` if the transaction was not comitted synchronously
*/
@objc
@discardableResult
public func beginSynchronous(_ closure: @escaping (_ transaction: CSSynchronousDataTransaction) -> Void) -> CSSaveResult? {
return bridge {
self.bridgeToSwift.beginSynchronous { (transaction) in
switch result {
closure(transaction.bridgeToObjectiveC)
case (_, nil): success?()
case (_, let error?): failure?(error.bridgeToObjectiveC)
}
}
}
@@ -159,6 +152,52 @@ public final class CSAsynchronousDataTransaction: CSBaseDataTransaction {
super.init(swiftValue as! AsynchronousDataTransaction)
}
// MARK: Deprecated
/**
Saves the transaction changes. This method should not be used after the `-commitWithCompletion:` method was already called once.
- parameter completion: the block executed after the save completes. Success or failure is reported by the `CSSaveResult` argument of the block.
*/
@available(*, deprecated: 4.0.0, message: "Use the new -[CSAsynchronousDataTransaction commitWithSuccess:failure:] method.")
@objc
public func commitWithCompletion(_ completion: ((_ result: CSSaveResult) -> Void)?) {
CoreStore.assert(
self.bridgeToSwift.transactionQueue.cs_isCurrentExecutionContext(),
"Attempted to commit a \(cs_typeName(self)) outside its designated queue."
)
CoreStore.assert(
!self.bridgeToSwift.isCommitted,
"Attempted to commit a \(cs_typeName(self)) more than once."
)
self.bridgeToSwift.commit { (result) in
completion?(result.bridgeToObjectiveC)
}
}
/**
Begins a child transaction synchronously where `NSManagedObject` creates, updates, and deletes can be made. This method should not be used after the `-commitWithCompletion:` method was already called once.
- parameter closure: the block where creates, updates, and deletes can be made to the transaction. Transaction blocks are executed serially in a background queue, and all changes are made from a concurrent `NSManagedObjectContext`.
- returns: a `CSSaveResult` value indicating success or failure, or `nil` if the transaction was not comitted synchronously
*/
@available(*, deprecated: 4.0.0, message: "Secondary tasks spawned from CSAsynchronousDataTransactions and CSSynchronousDataTransactions are no longer supported. ")
@objc
@discardableResult
public func beginSynchronous(_ closure: @escaping (_ transaction: CSSynchronousDataTransaction) -> Void) -> CSSaveResult? {
return bridge {
self.bridgeToSwift.beginSynchronous { (transaction) in
closure(transaction.bridgeToObjectiveC)
}
}
}
}

View File

@@ -38,10 +38,7 @@ public extension CSCoreStore {
@objc
public static func beginAsynchronous(_ closure: @escaping (_ transaction: CSAsynchronousDataTransaction) -> Void) {
return CoreStore.beginAsynchronous { (transaction) in
closure(transaction.bridgeToObjectiveC)
}
self.defaultStack.beginAsynchronous(closure)
}
/**
@@ -51,16 +48,9 @@ public extension CSCoreStore {
- returns: a `CSSaveResult` value indicating success or failure, or `nil` if the transaction was not comitted synchronously
*/
@objc
@discardableResult
public static func beginSynchronous(_ closure: @escaping (_ transaction: CSSynchronousDataTransaction) -> Void) -> CSSaveResult? {
public static func beginSynchronous(_ closure: @escaping (_ transaction: CSSynchronousDataTransaction) -> Void, error: NSErrorPointer) -> Bool {
return bridge {
CoreStore.beginSynchronous { (transaction) in
closure(transaction.bridgeToObjectiveC)
}
}
return self.defaultStack.beginSynchronous(closure, error: error)
}
/**
@@ -101,4 +91,21 @@ public extension CSCoreStore {
CoreStore.refreshAndMergeAllObjects()
}
// MARK: Deprecated
/**
Using the `defaultStack`, begins a transaction synchronously where `NSManagedObject` creates, updates, and deletes can be made.
- parameter closure: the block where creates, updates, and deletes can be made to the transaction. Transaction blocks are executed serially in a background queue, and all changes are made from a concurrent `NSManagedObjectContext`.
- returns: a `CSSaveResult` value indicating success or failure, or `nil` if the transaction was not comitted synchronously
*/
@available(*, deprecated: 4.0.0, message: "Use the new +[CSCoreStore beginSynchronous:error:] API that reports failure using an error instance.")
@objc
@discardableResult
public static func beginSynchronous(_ closure: @escaping (_ transaction: CSSynchronousDataTransaction) -> Void) -> CSSaveResult? {
return self.defaultStack.beginSynchronous(closure)
}
}

View File

@@ -38,27 +38,57 @@ public extension CSDataStack {
@objc
public func beginAsynchronous(_ closure: @escaping (_ transaction: CSAsynchronousDataTransaction) -> Void) {
return self.bridgeToSwift.beginAsynchronous { (transaction) in
closure(transaction.bridgeToObjectiveC)
}
self.bridgeToSwift.perform(
asynchronous: { (transaction) in
let csTransaction = transaction.bridgeToObjectiveC
closure(csTransaction)
if !transaction.isCommitted && transaction.hasChanges {
CoreStore.log(
.warning,
message: "The closure for the \(cs_typeName(csTransaction)) completed without being committed. All changes made within the transaction were discarded."
)
}
try transaction.cancel()
},
completion: { _ in }
)
}
/**
Begins a transaction synchronously where `NSManagedObject` creates, updates, and deletes can be made.
- parameter closure: the block where creates, updates, and deletes can be made to the transaction. Transaction blocks are executed serially in a background queue, and all changes are made from a concurrent `NSManagedObjectContext`.
- returns: a `CSSaveResult` value indicating success or failure, or `nil` if the transaction was not comitted synchronously
- parameter error: the `CSError` pointer that indicates the reason in case of an failure
- returns: `YES` if the commit succeeded, `NO` if the commit failed. If `NO`, the `error` argument will hold error information.
*/
@objc
@discardableResult
public func beginSynchronous(_ closure: @escaping (_ transaction: CSSynchronousDataTransaction) -> Void) -> CSSaveResult? {
public func beginSynchronous(_ closure: @escaping (_ transaction: CSSynchronousDataTransaction) -> Void, error: NSErrorPointer) -> Bool {
return bridge {
return bridge(error) {
self.bridgeToSwift.beginSynchronous { (transaction) in
do {
closure(transaction.bridgeToObjectiveC)
try self.bridgeToSwift.perform(
synchronous: { (transaction) in
let csTransaction = transaction.bridgeToObjectiveC
closure(csTransaction)
if !transaction.isCommitted && transaction.hasChanges {
CoreStore.log(
.warning,
message: "The closure for the \(cs_typeName(csTransaction)) completed without being committed. All changes made within the transaction were discarded."
)
}
try transaction.cancel()
}
)
}
catch CoreStoreError.userCancelled {
return
}
}
}
@@ -101,4 +131,27 @@ public extension CSDataStack {
self.bridgeToSwift.refreshAndMergeAllObjects()
}
// MARK: Deprecated
/**
Begins a transaction synchronously where `NSManagedObject` creates, updates, and deletes can be made.
- parameter closure: the block where creates, updates, and deletes can be made to the transaction. Transaction blocks are executed serially in a background queue, and all changes are made from a concurrent `NSManagedObjectContext`.
- returns: a `CSSaveResult` value indicating success or failure, or `nil` if the transaction was not comitted synchronously
*/
@available(*, deprecated: 4.0.0, message: "Use the new -[CSDataStack beginSynchronous:error:] API that reports failure using an error instance.")
@objc
@discardableResult
public func beginSynchronous(_ closure: @escaping (_ transaction: CSSynchronousDataTransaction) -> Void) -> CSSaveResult? {
return bridge {
self.bridgeToSwift.beginSynchronous { (transaction) in
closure(transaction.bridgeToObjectiveC)
}
}
}
}

View File

@@ -34,6 +34,7 @@ import CoreData
- SeeAlso: `SaveResult`
*/
@available(*, deprecated: 4.0.0, message: "Use APIs that report failures with `CSError`s instead.")
@objc
public final class CSSaveResult: NSObject, CoreStoreObjectiveCType {
@@ -173,6 +174,7 @@ public final class CSSaveResult: NSObject, CoreStoreObjectiveCType {
// MARK: - SaveResult
@available(*, deprecated: 4.0.0, message: "Use the new DataStack.perform(asynchronous:...) and DataStack.perform(synchronous:...) family of APIs")
extension SaveResult: CoreStoreSwiftType {
// MARK: CoreStoreSwiftType

View File

@@ -38,34 +38,19 @@ import CoreData
public final class CSSynchronousDataTransaction: CSBaseDataTransaction {
/**
Saves the transaction changes and waits for completion synchronously. This method should not be used after the `-commitAndWait` method was already called once.
Saves the transaction changes and waits for completion synchronously. This method should not be used after the `-commitAndWaitWithError:` method was already called once.
- returns: a `CSSaveResult` containing the success or failure information
- parameter error: the `CSError` pointer that indicates the reason in case of an failure
- returns: `YES` if the commit succeeded, `NO` if the commit failed. If `NO`, the `error` argument will hold error information.
*/
@objc
public func commitAndWait() -> CSSaveResult {
public func commitAndWait(error: NSErrorPointer) -> Bool {
return bridge {
return bridge(error) {
self.bridgeToSwift.commitAndWait()
}
}
/**
Begins a child transaction synchronously where `NSManagedObject` creates, updates, and deletes can be made. This method should not be used after the `-commitAndWait` method was already called once.
- parameter closure: the block where creates, updates, and deletes can be made to the transaction. Transaction blocks are executed serially in a background queue, and all changes are made from a concurrent `NSManagedObjectContext`.
- returns: a `CSSaveResult` value indicating success or failure, or `nil` if the transaction was not comitted synchronously
*/
@objc
@discardableResult
public func beginSynchronous(_ closure: @escaping (_ transaction: CSSynchronousDataTransaction) -> Void) -> CSSaveResult? {
return bridge {
self.bridgeToSwift.beginSynchronous { (transaction) in
if case (_, let error?) = self.bridgeToSwift.context.saveSynchronously(waitForMerge: true) {
closure(transaction.bridgeToObjectiveC)
throw error
}
}
}
@@ -158,6 +143,44 @@ public final class CSSynchronousDataTransaction: CSBaseDataTransaction {
super.init(swiftValue as! SynchronousDataTransaction)
}
// MARK: Deprecated
/**
Saves the transaction changes and waits for completion synchronously. This method should not be used after the `-commitAndWait` method was already called once.
- returns: a `CSSaveResult` containing the success or failure information
*/
@available(*, deprecated: 4.0.0, message: "Use the new -[CSSynchronousDataTransaction commitAndWaitWithError:] method")
@objc
public func commitAndWait() -> CSSaveResult {
return bridge {
self.bridgeToSwift.commitAndWait()
}
}
/**
Begins a child transaction synchronously where `NSManagedObject` creates, updates, and deletes can be made. This method should not be used after the `-commitAndWait` method was already called once.
- parameter closure: the block where creates, updates, and deletes can be made to the transaction. Transaction blocks are executed serially in a background queue, and all changes are made from a concurrent `NSManagedObjectContext`.
- returns: a `CSSaveResult` value indicating success or failure, or `nil` if the transaction was not comitted synchronously
*/
@available(*, deprecated: 4.0.0, message: "Secondary tasks spawned from CSAsynchronousDataTransactions and CSSynchronousDataTransactions are no longer supported. ")
@objc
@discardableResult
public func beginSynchronous(_ closure: @escaping (_ transaction: CSSynchronousDataTransaction) -> Void) -> CSSaveResult? {
return bridge {
self.bridgeToSwift.beginSynchronous { (transaction) in
closure(transaction.bridgeToObjectiveC)
}
}
}
}

View File

@@ -36,32 +36,43 @@ import CoreData
*/
@objc
public final class CSUnsafeDataTransaction: CSBaseDataTransaction {
/**
Saves the transaction changes asynchronously. For a `CSUnsafeDataTransaction`, multiple commits are allowed, although it is the developer's responsibility to ensure a reasonable leeway to prevent blocking the main thread.
- parameter completion: the block executed after the save completes. Success or failure is reported by the `CSSaveResult` argument of the block.
- parameter completion: the block executed after the save completes. Success or failure is reported by the `error` argument of the block.
*/
@objc
public func commit(_ completion: ((_ result: CSSaveResult) -> Void)?) {
public func commitWithSuccess(_ success: (() -> Void)?, _ failure: ((CSError) -> Void)?) {
self.bridgeToSwift.commit { (result) in
self.bridgeToSwift.context.saveAsynchronouslyWithCompletion { (_, error) in
completion?(result.bridgeToObjectiveC)
if let error = error {
failure?(error.bridgeToObjectiveC)
}
else {
success?()
}
withExtendedLifetime(self, {})
}
}
/**
Saves the transaction changes and waits for completion synchronously. For a `CSUnsafeDataTransaction`, multiple commits are allowed, although it is the developer's responsibility to ensure a reasonable leeway to prevent blocking the main thread.
- returns: a `CSSaveResult` containing the success or failure information
- parameter error: the `CSError` pointer that indicates the reason in case of an failure
- returns: `YES` if the commit succeeded, `NO` if the commit failed. If `NO`, the `error` argument will hold error information.
*/
@objc
public func commitAndWait() -> CSSaveResult {
public func commitAndWait(error: NSErrorPointer) -> Bool {
return bridge {
return bridge(error) {
self.bridgeToSwift.commitAndWait()
if case (_, let error?) = self.bridgeToSwift.context.saveSynchronously(waitForMerge: true) {
throw error
}
}
}
@@ -156,7 +167,7 @@ public final class CSUnsafeDataTransaction: CSBaseDataTransaction {
- that all saves will be done either through the `CSUnsafeDataTransaction`'s `-commit:` or `-commitAndWait` method, or by calling `-save:` manually on the context, its parent, and all other ancestor contexts if there are any.
*/
@objc
public var internalContext: NSManagedObjectContext {
public func unsafeContext() -> NSManagedObjectContext {
return self.bridgeToSwift.context
}
@@ -188,6 +199,58 @@ public final class CSUnsafeDataTransaction: CSBaseDataTransaction {
super.init(swiftValue as! UnsafeDataTransaction)
}
// MARK: Deprecated
@available(*, deprecated: 4.0.0, renamed: "unsafeContext()")
@objc
public var internalContext: NSManagedObjectContext {
return self.bridgeToSwift.context
}
/**
Saves the transaction changes asynchronously. For a `CSUnsafeDataTransaction`, multiple commits are allowed, although it is the developer's responsibility to ensure a reasonable leeway to prevent blocking the main thread.
- parameter completion: the block executed after the save completes. Success or failure is reported by the `CSSaveResult` argument of the block.
*/
@available(*, deprecated: 4.0.0, message: "Use the new -[CSUnsafeDataTransaction commitWithSuccess:failure:] method")
@objc
public func commit(_ completion: ((_ result: CSSaveResult) -> Void)?) {
self.bridgeToSwift.context.saveAsynchronouslyWithCompletion { (hasChanges, error) in
if let error = error {
completion?(SaveResult(error).bridgeToObjectiveC)
}
else {
completion?(SaveResult(hasChanges: hasChanges).bridgeToObjectiveC)
}
withExtendedLifetime(self, {})
}
}
/**
Saves the transaction changes and waits for completion synchronously. For a `CSUnsafeDataTransaction`, multiple commits are allowed, although it is the developer's responsibility to ensure a reasonable leeway to prevent blocking the main thread.
- returns: a `CSSaveResult` containing the success or failure information
*/
@available(*, deprecated: 4.0.0, message: "Use the new -[CSUnsafeDataTransaction commitAndWaitWithError:] method")
@objc
public func commitAndWait() -> CSSaveResult {
return bridge { () -> SaveResult in
switch self.bridgeToSwift.context.saveSynchronously(waitForMerge: true) {
case (let hasChanges, nil): return SaveResult(hasChanges: hasChanges)
case (_, let error?): return SaveResult(error)
}
}
}
}