undo interface

This commit is contained in:
John Rommel Estropia
2015-12-05 18:21:21 +09:00
parent dec9757dc2
commit 4ce3d5de3c
7 changed files with 82 additions and 55 deletions

View File

@@ -1268,6 +1268,7 @@
2F03A54719C5C6DA005002A5 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
EMBEDDED_CONTENT_CONTAINS_SWIFT = YES;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
@@ -1277,12 +1278,14 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.johnestropia.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = CoreStoreTests;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
2F03A54819C5C6DA005002A5 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
EMBEDDED_CONTENT_CONTAINS_SWIFT = YES;
INFOPLIST_FILE = CoreStoreTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
@@ -1343,6 +1346,7 @@
B52DD1871BE1F8CD00949AFE /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "-";
COMBINE_HIDPI_IMAGES = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
@@ -1353,12 +1357,14 @@
PRODUCT_BUNDLE_IDENTIFIER = com.johnestropia.CoreStore;
PRODUCT_NAME = CoreStoreTests;
SDKROOT = macosx;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
B52DD1881BE1F8CD00949AFE /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "-";
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;

View File

@@ -216,8 +216,7 @@ public final class AsynchronousDataTransaction: BaseDataTransaction {
self.closure = closure
super.init(mainContext: mainContext, queue: queue)
self.context.undoManager = nil
super.init(mainContext: mainContext, queue: queue, supportsUndo: false, bypassesQueueing: false)
}
internal func perform() {

View File

@@ -194,26 +194,33 @@ public /*abstract*/ class BaseDataTransaction {
internal let context: NSManagedObjectContext
internal let transactionQueue: GCDQueue
internal let childTransactionQueue: GCDQueue = .createSerial("com.corestore.datastack.childtransactionqueue")
internal let supportsUndo: Bool
internal let bypassesQueueing: Bool
internal var isCommitted = false
internal var result: SaveResult?
internal init(mainContext: NSManagedObjectContext, queue: GCDQueue) {
self.transactionQueue = queue
internal init(mainContext: NSManagedObjectContext, queue: GCDQueue, supportsUndo: Bool, bypassesQueueing: Bool) {
let context = mainContext.temporaryContextInTransactionWithConcurrencyType(
queue == .Main
? .MainQueueConcurrencyType
: .PrivateQueueConcurrencyType
)
self.transactionQueue = queue
self.context = context
self.supportsUndo = supportsUndo
self.bypassesQueueing = bypassesQueueing
context.parentTransaction = self
}
internal var bypassesQueueing: Bool {
return false
if !supportsUndo {
context.undoManager = nil
}
else if context.undoManager == nil {
context.undoManager = NSUndoManager()
}
}
}

View File

@@ -43,25 +43,26 @@ public extension CoreStore {
}
/**
Using the `defaultStack`, begins a transaction asynchronously 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 `SaveResult` value indicating success or failure, or `nil` if the transaction was not comitted synchronously
*/
Using the `defaultStack`, begins a transaction asynchronously 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 `SaveResult` value indicating success or failure, or `nil` if the transaction was not comitted synchronously
*/
public static func beginSynchronous(closure: (transaction: SynchronousDataTransaction) -> Void) -> SaveResult? {
return self.defaultStack.beginSynchronous(closure)
}
/**
Using the `defaultStack`, begins a non-contiguous transaction where `NSManagedObject` creates, updates, and deletes can be made. This is useful for making temporary changes, such as partially filled forms. An unsafe transaction object should typically be only used from the main queue.
- returns: a `UnsafeDataTransaction` instance where creates, updates, and deletes can be made.
*/
Using the `defaultStack`, begins a non-contiguous transaction where `NSManagedObject` creates, updates, and deletes can be made. This is useful for making temporary changes, such as partially filled forms. An unsafe transaction object should typically be only used from the main queue.
- prameter supportsUndo: `undo()`, `redo()`, and `rollback()` methods are only available when this parameter is `true`, otherwise those method will raise an exception. Defaults to `false`. Note that turning on Undo support may heavily impact performance especially on iOS or watchOS where memory is limited.
- returns: a `UnsafeDataTransaction` instance where creates, updates, and deletes can be made.
*/
@warn_unused_result
public static func beginUnsafe() -> UnsafeDataTransaction {
public static func beginUnsafe(supportsUndo supportsUndo: Bool = false) -> UnsafeDataTransaction {
return self.defaultStack.beginUnsafe()
return self.defaultStack.beginUnsafe(supportsUndo: supportsUndo)
}
@available(*, deprecated=1.3.1, renamed="beginUnsafe")

View File

@@ -50,11 +50,11 @@ public extension DataStack {
}
/**
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 `SaveResult` value indicating success or failure, or `nil` if the transaction was not comitted synchronously
*/
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 `SaveResult` value indicating success or failure, or `nil` if the transaction was not comitted synchronously
*/
public func beginSynchronous(closure: (transaction: SynchronousDataTransaction) -> Void) -> SaveResult? {
return SynchronousDataTransaction(
@@ -64,19 +64,21 @@ public extension DataStack {
}
/**
Begins a non-contiguous transaction where `NSManagedObject` creates, updates, and deletes can be made. This is useful for making temporary changes, such as partially filled forms.
- returns: a `UnsafeDataTransaction` instance where creates, updates, and deletes can be made.
*/
Begins a non-contiguous transaction where `NSManagedObject` creates, updates, and deletes can be made. This is useful for making temporary changes, such as partially filled forms.
- prameter supportsUndo: `undo()`, `redo()`, and `rollback()` methods are only available when this parameter is `true`, otherwise those method will raise an exception. Defaults to `false`. Note that turning on Undo support may heavily impact performance especially on iOS or watchOS where memory is limited.
- returns: a `UnsafeDataTransaction` instance where creates, updates, and deletes can be made.
*/
@warn_unused_result
public func beginUnsafe() -> UnsafeDataTransaction {
public func beginUnsafe(supportsUndo supportsUndo: Bool = false) -> UnsafeDataTransaction {
return UnsafeDataTransaction(
mainContext: self.rootSavingContext,
queue: .createSerial(
"com.coreStore.dataStack.unsafeTransactionQueue",
targetQueue: .UserInitiated
)
),
supportsUndo: supportsUndo
)
}

View File

@@ -202,6 +202,13 @@ public final class SynchronousDataTransaction: BaseDataTransaction {
// MARK: Internal
internal init(mainContext: NSManagedObjectContext, queue: GCDQueue, closure: (transaction: SynchronousDataTransaction) -> Void) {
self.closure = closure
super.init(mainContext: mainContext, queue: queue, supportsUndo: false, bypassesQueueing: false)
}
internal func performAndWait() -> SaveResult? {
self.transactionQueue.sync {
@@ -219,14 +226,6 @@ public final class SynchronousDataTransaction: BaseDataTransaction {
return self.result
}
internal init(mainContext: NSManagedObjectContext, queue: GCDQueue, closure: (transaction: SynchronousDataTransaction) -> Void) {
self.closure = closure
super.init(mainContext: mainContext, queue: queue)
self.context.undoManager = nil
}
// MARK: Private

View File

@@ -62,6 +62,10 @@ public final class UnsafeDataTransaction: BaseDataTransaction {
*/
public func rollback() {
CoreStore.assert(
self.supportsUndo,
"Attempted to rollback a \(typeName(self)) with Undo support disabled."
)
self.context.rollback()
}
@@ -70,6 +74,10 @@ public final class UnsafeDataTransaction: BaseDataTransaction {
*/
public func undo() {
CoreStore.assert(
self.supportsUndo,
"Attempted to undo a \(typeName(self)) with Undo support disabled."
)
self.context.undo()
}
@@ -78,30 +86,36 @@ public final class UnsafeDataTransaction: BaseDataTransaction {
*/
public func redo() {
CoreStore.assert(
self.supportsUndo,
"Attempted to redo a \(typeName(self)) with Undo support disabled."
)
self.context.redo()
}
/**
Begins a child transaction where `NSManagedObject` creates, updates, and deletes can be made. This is useful for making temporary changes, such as partially filled forms.
- returns: a `UnsafeDataTransaction` instance where creates, updates, and deletes can be made.
*/
Begins a child transaction where `NSManagedObject` creates, updates, and deletes can be made. This is useful for making temporary changes, such as partially filled forms.
- prameter supportsUndo: `undo()`, `redo()`, and `rollback()` methods are only available when this parameter is `true`, otherwise those method will raise an exception. Defaults to `false`. Note that turning on Undo support may heavily impact performance especially on iOS or watchOS where memory is limited.
- returns: a `UnsafeDataTransaction` instance where creates, updates, and deletes can be made.
*/
@warn_unused_result
public func beginUnsafe() -> UnsafeDataTransaction {
public func beginUnsafe(supportsUndo supportsUndo: Bool = false) -> UnsafeDataTransaction {
return UnsafeDataTransaction(
mainContext: self.context,
queue: self.transactionQueue
queue: self.transactionQueue,
supportsUndo: supportsUndo
)
}
/**
Returns the `NSManagedObjectContext` for this unsafe transaction. Use only for cases where external frameworks need an `NSManagedObjectContext` instance to work with.
Note that it is the developer's responsibility to ensure the following:
- that the `UnsafeDataTransaction` that owns this context should be strongly referenced and prevented from being deallocated during the context's lifetime
- that all saves will be done either through the `UnsafeDataTransaction`'s `commit(...)` method, or by calling `save()` manually on the context, its parent, and all other ancestor contexts if there are any.
*/
Returns the `NSManagedObjectContext` for this unsafe transaction. Use only for cases where external frameworks need an `NSManagedObjectContext` instance to work with.
Note that it is the developer's responsibility to ensure the following:
- that the `UnsafeDataTransaction` that owns this context should be strongly referenced and prevented from being deallocated during the context's lifetime
- that all saves will be done either through the `UnsafeDataTransaction`'s `commit(...)` method, or by calling `save()` manually on the context, its parent, and all other ancestor contexts if there are any.
*/
public var internalContext: NSManagedObjectContext {
return self.context
@@ -117,9 +131,8 @@ public final class UnsafeDataTransaction: BaseDataTransaction {
// MARK: Internal
internal override var bypassesQueueing: Bool {
internal init(mainContext: NSManagedObjectContext, queue: GCDQueue, supportsUndo: Bool) {
return true
super.init(mainContext: mainContext, queue: queue, supportsUndo: supportsUndo, bypassesQueueing: true)
}
}