mirror of
https://github.com/JohnEstropia/CoreStore.git
synced 2026-04-14 13:09:42 +02:00
new auto-commit transaction methods
This commit is contained in:
@@ -398,10 +398,6 @@
|
|||||||
B59FA0B11CCBACA7007C9BCA /* ICloudStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B59FA0AD1CCBAC95007C9BCA /* ICloudStore.swift */; };
|
B59FA0B11CCBACA7007C9BCA /* ICloudStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B59FA0AD1CCBAC95007C9BCA /* ICloudStore.swift */; };
|
||||||
B59FA0B21CCBACA8007C9BCA /* ICloudStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B59FA0AD1CCBAC95007C9BCA /* ICloudStore.swift */; };
|
B59FA0B21CCBACA8007C9BCA /* ICloudStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B59FA0AD1CCBAC95007C9BCA /* ICloudStore.swift */; };
|
||||||
B5A261211B64BFDB006EB6D3 /* MigrationType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A261201B64BFDB006EB6D3 /* MigrationType.swift */; };
|
B5A261211B64BFDB006EB6D3 /* MigrationType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A261201B64BFDB006EB6D3 /* MigrationType.swift */; };
|
||||||
B5A27F861E857C5300203C3E /* TransactionResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A27F851E857C5300203C3E /* TransactionResult.swift */; };
|
|
||||||
B5A27F871E857C5300203C3E /* TransactionResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A27F851E857C5300203C3E /* TransactionResult.swift */; };
|
|
||||||
B5A27F881E857C5300203C3E /* TransactionResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A27F851E857C5300203C3E /* TransactionResult.swift */; };
|
|
||||||
B5A27F891E857C5300203C3E /* TransactionResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A27F851E857C5300203C3E /* TransactionResult.swift */; };
|
|
||||||
B5A5F2661CAEC50F004AB9AF /* CSSelect.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A5F2651CAEC50F004AB9AF /* CSSelect.swift */; };
|
B5A5F2661CAEC50F004AB9AF /* CSSelect.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A5F2651CAEC50F004AB9AF /* CSSelect.swift */; };
|
||||||
B5A5F2681CAEC50F004AB9AF /* CSSelect.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A5F2651CAEC50F004AB9AF /* CSSelect.swift */; };
|
B5A5F2681CAEC50F004AB9AF /* CSSelect.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A5F2651CAEC50F004AB9AF /* CSSelect.swift */; };
|
||||||
B5A5F2691CAEC50F004AB9AF /* CSSelect.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A5F2651CAEC50F004AB9AF /* CSSelect.swift */; };
|
B5A5F2691CAEC50F004AB9AF /* CSSelect.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A5F2651CAEC50F004AB9AF /* CSSelect.swift */; };
|
||||||
@@ -689,7 +685,6 @@
|
|||||||
B59AFF401C6593E400C0ABE2 /* NSPersistentStoreCoordinator+Setup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSPersistentStoreCoordinator+Setup.swift"; sourceTree = "<group>"; };
|
B59AFF401C6593E400C0ABE2 /* NSPersistentStoreCoordinator+Setup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSPersistentStoreCoordinator+Setup.swift"; sourceTree = "<group>"; };
|
||||||
B59FA0AD1CCBAC95007C9BCA /* ICloudStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ICloudStore.swift; sourceTree = "<group>"; };
|
B59FA0AD1CCBAC95007C9BCA /* ICloudStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ICloudStore.swift; sourceTree = "<group>"; };
|
||||||
B5A261201B64BFDB006EB6D3 /* MigrationType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MigrationType.swift; sourceTree = "<group>"; };
|
B5A261201B64BFDB006EB6D3 /* MigrationType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MigrationType.swift; sourceTree = "<group>"; };
|
||||||
B5A27F851E857C5300203C3E /* TransactionResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransactionResult.swift; sourceTree = "<group>"; };
|
|
||||||
B5A5F2651CAEC50F004AB9AF /* CSSelect.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSSelect.swift; sourceTree = "<group>"; };
|
B5A5F2651CAEC50F004AB9AF /* CSSelect.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CSSelect.swift; sourceTree = "<group>"; };
|
||||||
B5AD60CD1C90141E00F2B2E8 /* Package.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = SOURCE_ROOT; };
|
B5AD60CD1C90141E00F2B2E8 /* Package.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = SOURCE_ROOT; };
|
||||||
B5AEFAB41C9962AE00AD137F /* CoreStoreBridge.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreStoreBridge.swift; sourceTree = "<group>"; };
|
B5AEFAB41C9962AE00AD137F /* CoreStoreBridge.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreStoreBridge.swift; sourceTree = "<group>"; };
|
||||||
@@ -1165,7 +1160,6 @@
|
|||||||
B5E84EEE1AFF846E0064E85B /* CoreStore+Transaction.swift */,
|
B5E84EEE1AFF846E0064E85B /* CoreStore+Transaction.swift */,
|
||||||
B50392F81C478FF3009900CA /* NSManagedObject+Transaction.swift */,
|
B50392F81C478FF3009900CA /* NSManagedObject+Transaction.swift */,
|
||||||
B5E84EF21AFF846E0064E85B /* SaveResult.swift */,
|
B5E84EF21AFF846E0064E85B /* SaveResult.swift */,
|
||||||
B5A27F851E857C5300203C3E /* TransactionResult.swift */,
|
|
||||||
);
|
);
|
||||||
path = Transactions;
|
path = Transactions;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -1609,7 +1603,6 @@
|
|||||||
B549F6731E56A92800FBAB2D /* CoreDataNativeType.swift in Sources */,
|
B549F6731E56A92800FBAB2D /* CoreDataNativeType.swift in Sources */,
|
||||||
B509C7F41E54511B0061C547 /* ImportableAttributeType.swift in Sources */,
|
B509C7F41E54511B0061C547 /* ImportableAttributeType.swift in Sources */,
|
||||||
B5E84F0E1AFF847B0064E85B /* Tweak.swift in Sources */,
|
B5E84F0E1AFF847B0064E85B /* Tweak.swift in Sources */,
|
||||||
B5A27F861E857C5300203C3E /* TransactionResult.swift in Sources */,
|
|
||||||
B5E1B5931CAA0C15007FD580 /* CSObjectMonitor.swift in Sources */,
|
B5E1B5931CAA0C15007FD580 /* CSObjectMonitor.swift in Sources */,
|
||||||
B5ECDC291CA81CC700C7F112 /* CSDataStack+Transaction.swift in Sources */,
|
B5ECDC291CA81CC700C7F112 /* CSDataStack+Transaction.swift in Sources */,
|
||||||
B5E84F121AFF847B0064E85B /* OrderBy.swift in Sources */,
|
B5E84F121AFF847B0064E85B /* OrderBy.swift in Sources */,
|
||||||
@@ -1766,7 +1759,6 @@
|
|||||||
B549F6741E56A92800FBAB2D /* CoreDataNativeType.swift in Sources */,
|
B549F6741E56A92800FBAB2D /* CoreDataNativeType.swift in Sources */,
|
||||||
B509C7F51E54511B0061C547 /* ImportableAttributeType.swift in Sources */,
|
B509C7F51E54511B0061C547 /* ImportableAttributeType.swift in Sources */,
|
||||||
82BA18B31C4BBD3900A0916E /* ImportableUniqueObject.swift in Sources */,
|
82BA18B31C4BBD3900A0916E /* ImportableUniqueObject.swift in Sources */,
|
||||||
B5A27F871E857C5300203C3E /* TransactionResult.swift in Sources */,
|
|
||||||
B5E1B5951CAA0C15007FD580 /* CSObjectMonitor.swift in Sources */,
|
B5E1B5951CAA0C15007FD580 /* CSObjectMonitor.swift in Sources */,
|
||||||
B5ECDC2B1CA81CC700C7F112 /* CSDataStack+Transaction.swift in Sources */,
|
B5ECDC2B1CA81CC700C7F112 /* CSDataStack+Transaction.swift in Sources */,
|
||||||
82BA18A11C4BBD1D00A0916E /* CoreStore.swift in Sources */,
|
82BA18A11C4BBD1D00A0916E /* CoreStore.swift in Sources */,
|
||||||
@@ -1923,7 +1915,6 @@
|
|||||||
B549F6761E56A92800FBAB2D /* CoreDataNativeType.swift in Sources */,
|
B549F6761E56A92800FBAB2D /* CoreDataNativeType.swift in Sources */,
|
||||||
B509C7F71E54511B0061C547 /* ImportableAttributeType.swift in Sources */,
|
B509C7F71E54511B0061C547 /* ImportableAttributeType.swift in Sources */,
|
||||||
B5220E1F1D130810009BC71E /* CSListObserver.swift in Sources */,
|
B5220E1F1D130810009BC71E /* CSListObserver.swift in Sources */,
|
||||||
B5A27F891E857C5300203C3E /* TransactionResult.swift in Sources */,
|
|
||||||
B52DD1941BE1F92500949AFE /* CoreStore.swift in Sources */,
|
B52DD1941BE1F92500949AFE /* CoreStore.swift in Sources */,
|
||||||
B52DD1A61BE1F92F00949AFE /* BaseDataTransaction+Importing.swift in Sources */,
|
B52DD1A61BE1F92F00949AFE /* BaseDataTransaction+Importing.swift in Sources */,
|
||||||
B5220E1D1D13080A009BC71E /* CSDataStack+Observing.swift in Sources */,
|
B5220E1D1D13080A009BC71E /* CSDataStack+Observing.swift in Sources */,
|
||||||
@@ -2080,7 +2071,6 @@
|
|||||||
B549F6751E56A92800FBAB2D /* CoreDataNativeType.swift in Sources */,
|
B549F6751E56A92800FBAB2D /* CoreDataNativeType.swift in Sources */,
|
||||||
B509C7F61E54511B0061C547 /* ImportableAttributeType.swift in Sources */,
|
B509C7F61E54511B0061C547 /* ImportableAttributeType.swift in Sources */,
|
||||||
B5E1B5961CAA0C15007FD580 /* CSObjectMonitor.swift in Sources */,
|
B5E1B5961CAA0C15007FD580 /* CSObjectMonitor.swift in Sources */,
|
||||||
B5A27F881E857C5300203C3E /* TransactionResult.swift in Sources */,
|
|
||||||
B5ECDC2C1CA81CC700C7F112 /* CSDataStack+Transaction.swift in Sources */,
|
B5ECDC2C1CA81CC700C7F112 /* CSDataStack+Transaction.swift in Sources */,
|
||||||
B56321911BD65216006C9394 /* BaseDataTransaction+Importing.swift in Sources */,
|
B56321911BD65216006C9394 /* BaseDataTransaction+Importing.swift in Sources */,
|
||||||
B546F95A1C99B17400D5AC55 /* CSCoreStore+Setup.swift in Sources */,
|
B546F95A1C99B17400D5AC55 /* CSCoreStore+Setup.swift in Sources */,
|
||||||
|
|||||||
@@ -30,47 +30,48 @@ class BaseTestDataTestCase: BaseTestCase {
|
|||||||
@nonobjc
|
@nonobjc
|
||||||
func prepareTestDataForStack(_ stack: DataStack, configurations: [String?] = [nil]) {
|
func prepareTestDataForStack(_ stack: DataStack, configurations: [String?] = [nil]) {
|
||||||
|
|
||||||
stack.beginSynchronous { (transaction) in
|
try! stack.perform(
|
||||||
|
synchronous: { (transaction) in
|
||||||
for (configurationIndex, configuration) in configurations.enumerated() {
|
|
||||||
|
|
||||||
let configurationOrdinal = configurationIndex + 1
|
for (configurationIndex, configuration) in configurations.enumerated() {
|
||||||
if configuration == nil || configuration == "Config1" {
|
|
||||||
|
|
||||||
for idIndex in 1 ... 5 {
|
let configurationOrdinal = configurationIndex + 1
|
||||||
|
if configuration == nil || configuration == "Config1" {
|
||||||
|
|
||||||
let object = transaction.create(Into<TestEntity1>(configuration))
|
for idIndex in 1 ... 5 {
|
||||||
object.testEntityID = NSNumber(value: (configurationOrdinal * 100) + idIndex)
|
|
||||||
|
let object = transaction.create(Into<TestEntity1>(configuration))
|
||||||
object.testNumber = NSNumber(value: idIndex)
|
object.testEntityID = NSNumber(value: (configurationOrdinal * 100) + idIndex)
|
||||||
object.testDate = self.dateFormatter.date(from: "2000-\(configurationOrdinal)-\(idIndex)T00:00:00Z")
|
|
||||||
object.testBoolean = NSNumber(value: (idIndex % 2) == 1)
|
object.testNumber = NSNumber(value: idIndex)
|
||||||
object.testDecimal = NSDecimalNumber(string: "\(idIndex)")
|
object.testDate = self.dateFormatter.date(from: "2000-\(configurationOrdinal)-\(idIndex)T00:00:00Z")
|
||||||
|
object.testBoolean = NSNumber(value: (idIndex % 2) == 1)
|
||||||
let string = "\(configuration ?? "nil"):TestEntity1:\(idIndex)"
|
object.testDecimal = NSDecimalNumber(string: "\(idIndex)")
|
||||||
object.testString = string
|
|
||||||
object.testData = (string as NSString).data(using: String.Encoding.utf8.rawValue)
|
let string = "\(configuration ?? "nil"):TestEntity1:\(idIndex)"
|
||||||
|
object.testString = string
|
||||||
|
object.testData = (string as NSString).data(using: String.Encoding.utf8.rawValue)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
if configuration == nil || configuration == "Config2" {
|
||||||
if configuration == nil || configuration == "Config2" {
|
|
||||||
|
|
||||||
for idIndex in 1 ... 5 {
|
|
||||||
|
|
||||||
let object = transaction.create(Into<TestEntity2>(configuration))
|
for idIndex in 1 ... 5 {
|
||||||
object.testEntityID = NSNumber(value: (configurationOrdinal * 200) + idIndex)
|
|
||||||
|
let object = transaction.create(Into<TestEntity2>(configuration))
|
||||||
object.testNumber = NSNumber(value: idIndex)
|
object.testEntityID = NSNumber(value: (configurationOrdinal * 200) + idIndex)
|
||||||
object.testDate = self.dateFormatter.date(from: "2000-\(configurationOrdinal)-\(idIndex)T00:00:00Z")
|
|
||||||
object.testBoolean = NSNumber(value: (idIndex % 2) == 1)
|
object.testNumber = NSNumber(value: idIndex)
|
||||||
object.testDecimal = NSDecimalNumber(string: "\(idIndex)")
|
object.testDate = self.dateFormatter.date(from: "2000-\(configurationOrdinal)-\(idIndex)T00:00:00Z")
|
||||||
|
object.testBoolean = NSNumber(value: (idIndex % 2) == 1)
|
||||||
let string = "\(configuration ?? "nil"):TestEntity2:\(idIndex)"
|
object.testDecimal = NSDecimalNumber(string: "\(idIndex)")
|
||||||
object.testString = string
|
|
||||||
object.testData = (string as NSString).data(using: String.Encoding.utf8.rawValue)
|
let string = "\(configuration ?? "nil"):TestEntity2:\(idIndex)"
|
||||||
|
object.testString = string
|
||||||
|
object.testData = (string as NSString).data(using: String.Encoding.utf8.rawValue)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ = transaction.commitAndWait()
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -212,6 +212,9 @@
|
|||||||
CSUnsafeDataTransaction *transaction = [CSCoreStore beginUnsafe];
|
CSUnsafeDataTransaction *transaction = [CSCoreStore beginUnsafe];
|
||||||
XCTAssertNotNil(transaction);
|
XCTAssertNotNil(transaction);
|
||||||
XCTAssert([transaction isKindOfClass:[CSUnsafeDataTransaction class]]);
|
XCTAssert([transaction isKindOfClass:[CSUnsafeDataTransaction class]]);
|
||||||
|
NSError *error;
|
||||||
|
XCTAssertTrue([transaction commitAndWaitWithError:&error]);
|
||||||
|
XCTAssertNil(error);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
XCTestExpectation *expectation = [self expectationWithDescription:@"sync"];
|
XCTestExpectation *expectation = [self expectationWithDescription:@"sync"];
|
||||||
@@ -219,6 +222,9 @@
|
|||||||
|
|
||||||
XCTAssertNotNil(transaction);
|
XCTAssertNotNil(transaction);
|
||||||
XCTAssert([transaction isKindOfClass:[CSSynchronousDataTransaction class]]);
|
XCTAssert([transaction isKindOfClass:[CSSynchronousDataTransaction class]]);
|
||||||
|
NSError *error;
|
||||||
|
XCTAssertTrue([transaction commitAndWaitWithError:&error]);
|
||||||
|
XCTAssertNil(error);
|
||||||
[expectation fulfill];
|
[expectation fulfill];
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
@@ -228,7 +234,15 @@
|
|||||||
|
|
||||||
XCTAssertNotNil(transaction);
|
XCTAssertNotNil(transaction);
|
||||||
XCTAssert([transaction isKindOfClass:[CSAsynchronousDataTransaction class]]);
|
XCTAssert([transaction isKindOfClass:[CSAsynchronousDataTransaction class]]);
|
||||||
[expectation fulfill];
|
[transaction
|
||||||
|
commitWithSuccess:^{
|
||||||
|
|
||||||
|
[expectation fulfill];
|
||||||
|
}
|
||||||
|
failure:^(CSError *error){
|
||||||
|
|
||||||
|
XCTFail();
|
||||||
|
}];
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
[self waitForExpectationsWithTimeout:10 handler:nil];
|
[self waitForExpectationsWithTimeout:10 handler:nil];
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -149,29 +149,29 @@ class ListObserverTests: BaseTestDataTestCase {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
let saveExpectation = self.expectation(description: "save")
|
let saveExpectation = self.expectation(description: "save")
|
||||||
stack.beginAsynchronous { (transaction) in
|
stack.perform(
|
||||||
|
asynchronous: { (transaction) -> Bool in
|
||||||
let object = transaction.create(Into<TestEntity1>())
|
|
||||||
object.testBoolean = NSNumber(value: true)
|
|
||||||
object.testNumber = NSNumber(value: 1)
|
|
||||||
object.testDecimal = NSDecimalNumber(string: "1")
|
|
||||||
object.testString = "nil:TestEntity1:1"
|
|
||||||
object.testData = ("nil:TestEntity1:1" as NSString).data(using: String.Encoding.utf8.rawValue)!
|
|
||||||
object.testDate = self.dateFormatter.date(from: "2000-01-01T00:00:00Z")!
|
|
||||||
|
|
||||||
transaction.commit { (result) in
|
|
||||||
|
|
||||||
switch result {
|
let object = transaction.create(Into<TestEntity1>())
|
||||||
|
object.testBoolean = NSNumber(value: true)
|
||||||
case .success(let hasChanges):
|
object.testNumber = NSNumber(value: 1)
|
||||||
XCTAssertTrue(hasChanges)
|
object.testDecimal = NSDecimalNumber(string: "1")
|
||||||
saveExpectation.fulfill()
|
object.testString = "nil:TestEntity1:1"
|
||||||
|
object.testData = ("nil:TestEntity1:1" as NSString).data(using: String.Encoding.utf8.rawValue)!
|
||||||
case .failure:
|
object.testDate = self.dateFormatter.date(from: "2000-01-01T00:00:00Z")!
|
||||||
XCTFail()
|
|
||||||
}
|
return transaction.hasChanges
|
||||||
|
},
|
||||||
|
success: { (hasChanges) in
|
||||||
|
|
||||||
|
XCTAssertTrue(hasChanges)
|
||||||
|
saveExpectation.fulfill()
|
||||||
|
},
|
||||||
|
failure: { _ in
|
||||||
|
|
||||||
|
XCTFail()
|
||||||
}
|
}
|
||||||
}
|
)
|
||||||
self.waitAndCheckExpectations()
|
self.waitAndCheckExpectations()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -283,49 +283,49 @@ class ListObserverTests: BaseTestDataTestCase {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
let saveExpectation = self.expectation(description: "save")
|
let saveExpectation = self.expectation(description: "save")
|
||||||
stack.beginAsynchronous { (transaction) in
|
stack.perform(
|
||||||
|
asynchronous: { (transaction) -> Bool in
|
||||||
if let object = transaction.fetchOne(
|
|
||||||
From<TestEntity1>(),
|
|
||||||
Where(#keyPath(TestEntity1.testEntityID), isEqualTo: 101)) {
|
|
||||||
|
|
||||||
object.testNumber = NSNumber(value: 11)
|
if let object = transaction.fetchOne(
|
||||||
object.testDecimal = NSDecimalNumber(string: "11")
|
From<TestEntity1>(),
|
||||||
object.testString = "nil:TestEntity1:11"
|
Where(#keyPath(TestEntity1.testEntityID), isEqualTo: 101)) {
|
||||||
object.testData = ("nil:TestEntity1:11" as NSString).data(using: String.Encoding.utf8.rawValue)!
|
|
||||||
object.testDate = self.dateFormatter.date(from: "2000-01-11T00:00:00Z")!
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
XCTFail()
|
|
||||||
}
|
|
||||||
if let object = transaction.fetchOne(
|
|
||||||
From<TestEntity1>(),
|
|
||||||
Where(#keyPath(TestEntity1.testEntityID), isEqualTo: 102)) {
|
|
||||||
|
|
||||||
object.testNumber = NSNumber(value: 22)
|
|
||||||
object.testDecimal = NSDecimalNumber(string: "22")
|
|
||||||
object.testString = "nil:TestEntity1:22"
|
|
||||||
object.testData = ("nil:TestEntity1:22" as NSString).data(using: String.Encoding.utf8.rawValue)!
|
|
||||||
object.testDate = self.dateFormatter.date(from: "2000-01-22T00:00:00Z")!
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
XCTFail()
|
|
||||||
}
|
|
||||||
transaction.commit { (result) in
|
|
||||||
|
|
||||||
switch result {
|
|
||||||
|
|
||||||
case .success(let hasChanges):
|
object.testNumber = NSNumber(value: 11)
|
||||||
XCTAssertTrue(hasChanges)
|
object.testDecimal = NSDecimalNumber(string: "11")
|
||||||
saveExpectation.fulfill()
|
object.testString = "nil:TestEntity1:11"
|
||||||
|
object.testData = ("nil:TestEntity1:11" as NSString).data(using: String.Encoding.utf8.rawValue)!
|
||||||
|
object.testDate = self.dateFormatter.date(from: "2000-01-11T00:00:00Z")!
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
case .failure:
|
|
||||||
XCTFail()
|
XCTFail()
|
||||||
}
|
}
|
||||||
|
if let object = transaction.fetchOne(
|
||||||
|
From<TestEntity1>(),
|
||||||
|
Where(#keyPath(TestEntity1.testEntityID), isEqualTo: 102)) {
|
||||||
|
|
||||||
|
object.testNumber = NSNumber(value: 22)
|
||||||
|
object.testDecimal = NSDecimalNumber(string: "22")
|
||||||
|
object.testString = "nil:TestEntity1:22"
|
||||||
|
object.testData = ("nil:TestEntity1:22" as NSString).data(using: String.Encoding.utf8.rawValue)!
|
||||||
|
object.testDate = self.dateFormatter.date(from: "2000-01-22T00:00:00Z")!
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
XCTFail()
|
||||||
|
}
|
||||||
|
return transaction.hasChanges
|
||||||
|
},
|
||||||
|
success: { (hasChanges) in
|
||||||
|
|
||||||
|
XCTAssertTrue(hasChanges)
|
||||||
|
saveExpectation.fulfill()
|
||||||
|
},
|
||||||
|
failure: { _ in
|
||||||
|
|
||||||
|
XCTFail()
|
||||||
}
|
}
|
||||||
}
|
)
|
||||||
self.waitAndCheckExpectations()
|
self.waitAndCheckExpectations()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -409,31 +409,31 @@ class ListObserverTests: BaseTestDataTestCase {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
let saveExpectation = self.expectation(description: "save")
|
let saveExpectation = self.expectation(description: "save")
|
||||||
stack.beginAsynchronous { (transaction) in
|
stack.perform(
|
||||||
|
asynchronous: { (transaction) -> Bool in
|
||||||
if let object = transaction.fetchOne(
|
|
||||||
From<TestEntity1>(),
|
|
||||||
Where(#keyPath(TestEntity1.testEntityID), isEqualTo: 102)) {
|
|
||||||
|
|
||||||
object.testBoolean = NSNumber(value: true)
|
if let object = transaction.fetchOne(
|
||||||
}
|
From<TestEntity1>(),
|
||||||
else {
|
Where(#keyPath(TestEntity1.testEntityID), isEqualTo: 102)) {
|
||||||
|
|
||||||
|
object.testBoolean = NSNumber(value: true)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
XCTFail()
|
||||||
|
}
|
||||||
|
return transaction.hasChanges
|
||||||
|
},
|
||||||
|
success: { (hasChanges) in
|
||||||
|
|
||||||
|
XCTAssertTrue(hasChanges)
|
||||||
|
saveExpectation.fulfill()
|
||||||
|
},
|
||||||
|
failure: { _ in
|
||||||
|
|
||||||
XCTFail()
|
XCTFail()
|
||||||
}
|
}
|
||||||
transaction.commit { (result) in
|
)
|
||||||
|
|
||||||
switch result {
|
|
||||||
|
|
||||||
case .success(let hasChanges):
|
|
||||||
XCTAssertTrue(hasChanges)
|
|
||||||
saveExpectation.fulfill()
|
|
||||||
|
|
||||||
case .failure:
|
|
||||||
XCTFail()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.waitAndCheckExpectations()
|
self.waitAndCheckExpectations()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -544,25 +544,25 @@ class ListObserverTests: BaseTestDataTestCase {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
let saveExpectation = self.expectation(description: "save")
|
let saveExpectation = self.expectation(description: "save")
|
||||||
stack.beginAsynchronous { (transaction) in
|
stack.perform(
|
||||||
|
asynchronous: { (transaction) -> Bool in
|
||||||
transaction.deleteAll(
|
|
||||||
From<TestEntity1>(),
|
|
||||||
Where(#keyPath(TestEntity1.testBoolean), isEqualTo: false)
|
|
||||||
)
|
|
||||||
transaction.commit { (result) in
|
|
||||||
|
|
||||||
switch result {
|
transaction.deleteAll(
|
||||||
|
From<TestEntity1>(),
|
||||||
case .success(let hasChanges):
|
Where(#keyPath(TestEntity1.testBoolean), isEqualTo: false)
|
||||||
XCTAssertTrue(hasChanges)
|
)
|
||||||
saveExpectation.fulfill()
|
return transaction.hasChanges
|
||||||
|
},
|
||||||
case .failure:
|
success: { (hasChanges) in
|
||||||
XCTFail()
|
|
||||||
}
|
XCTAssertTrue(hasChanges)
|
||||||
|
saveExpectation.fulfill()
|
||||||
|
},
|
||||||
|
failure: { _ in
|
||||||
|
|
||||||
|
XCTFail()
|
||||||
}
|
}
|
||||||
}
|
)
|
||||||
self.waitAndCheckExpectations()
|
self.waitAndCheckExpectations()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -125,29 +125,29 @@ import CoreStore
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
let saveExpectation = self.expectation(description: "save")
|
let saveExpectation = self.expectation(description: "save")
|
||||||
stack.beginAsynchronous { (transaction) in
|
stack.perform(
|
||||||
|
asynchronous: { (transaction) -> Bool in
|
||||||
guard let object = transaction.edit(object) else {
|
|
||||||
|
guard let object = transaction.edit(object) else {
|
||||||
|
|
||||||
|
XCTFail()
|
||||||
|
try transaction.cancel()
|
||||||
|
}
|
||||||
|
object.testNumber = NSNumber(value: 10)
|
||||||
|
object.testString = "nil:TestEntity1:10"
|
||||||
|
|
||||||
|
return transaction.hasChanges
|
||||||
|
},
|
||||||
|
success: { (hasChanges) in
|
||||||
|
|
||||||
|
XCTAssertTrue(hasChanges)
|
||||||
|
saveExpectation.fulfill()
|
||||||
|
},
|
||||||
|
failure: { _ in
|
||||||
|
|
||||||
XCTFail()
|
XCTFail()
|
||||||
return
|
|
||||||
}
|
}
|
||||||
object.testNumber = NSNumber(value: 10)
|
)
|
||||||
object.testString = "nil:TestEntity1:10"
|
|
||||||
|
|
||||||
transaction.commit { (result) in
|
|
||||||
|
|
||||||
switch result {
|
|
||||||
|
|
||||||
case .success(let hasChanges):
|
|
||||||
XCTAssertTrue(hasChanges)
|
|
||||||
saveExpectation.fulfill()
|
|
||||||
|
|
||||||
case .failure:
|
|
||||||
XCTFail()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.waitAndCheckExpectations()
|
self.waitAndCheckExpectations()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -193,29 +193,29 @@ import CoreStore
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
let saveExpectation = self.expectation(description: "save")
|
let saveExpectation = self.expectation(description: "save")
|
||||||
stack.beginAsynchronous { (transaction) in
|
stack.perform(
|
||||||
|
asynchronous: { (transaction) -> Bool in
|
||||||
guard let object = transaction.edit(object) else {
|
|
||||||
|
guard let object = transaction.edit(object) else {
|
||||||
|
|
||||||
|
XCTFail()
|
||||||
|
try transaction.cancel()
|
||||||
|
}
|
||||||
|
transaction.delete(object)
|
||||||
|
|
||||||
|
return transaction.hasChanges
|
||||||
|
},
|
||||||
|
success: { (hasChanges) in
|
||||||
|
|
||||||
|
XCTAssertTrue(hasChanges)
|
||||||
|
XCTAssertTrue(monitor.isObjectDeleted)
|
||||||
|
saveExpectation.fulfill()
|
||||||
|
},
|
||||||
|
failure: { _ in
|
||||||
|
|
||||||
XCTFail()
|
XCTFail()
|
||||||
return
|
|
||||||
}
|
}
|
||||||
transaction.delete(object)
|
)
|
||||||
|
|
||||||
transaction.commit { (result) in
|
|
||||||
|
|
||||||
switch result {
|
|
||||||
|
|
||||||
case .success(let hasChanges):
|
|
||||||
XCTAssertTrue(hasChanges)
|
|
||||||
XCTAssertTrue(monitor.isObjectDeleted)
|
|
||||||
saveExpectation.fulfill()
|
|
||||||
|
|
||||||
case .failure:
|
|
||||||
XCTFail()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.waitAndCheckExpectations()
|
self.waitAndCheckExpectations()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -33,7 +33,7 @@ public extension NSManagedObject {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
Exposes a `FetchableSource` that can fetch sibling objects of this `NSManagedObject` instance. This may be the `DataStack`, a `BaseDataTransaction`, the `NSManagedObjectContext` itself, or `nil` if the obejct's parent is already deallocated.
|
Exposes a `FetchableSource` that can fetch sibling objects of this `NSManagedObject` instance. This may be the `DataStack`, a `BaseDataTransaction`, the `NSManagedObjectContext` itself, or `nil` if the obejct's parent is already deallocated.
|
||||||
- Warning: Future implementations may change the instance returned by this method depending on the timing or condition that `fetchSource()` was called. Do not make assumptions that the instance will be a specific instance. If the `NSManagedObjectContext` instance is desired, use the `FetchableSource.internalContext()` method to get the correct instance. Also, do not assume that the `fetchSource()` and `querySource()` return the same instance all the time.
|
- Warning: Future implementations may change the instance returned by this method depending on the timing or condition that `fetchSource()` was called. Do not make assumptions that the instance will be a specific instance. If the `NSManagedObjectContext` instance is desired, use the `FetchableSource.unsafeContext()` method to get the correct instance. Also, do not assume that the `fetchSource()` and `querySource()` return the same instance all the time.
|
||||||
- returns: a `FetchableSource` that can fetch sibling objects of this `NSManagedObject` instance. This may be the `DataStack`, a `BaseDataTransaction`, the `NSManagedObjectContext` itself, or `nil` if the object's parent is already deallocated.
|
- returns: a `FetchableSource` that can fetch sibling objects of this `NSManagedObject` instance. This may be the `DataStack`, a `BaseDataTransaction`, the `NSManagedObjectContext` itself, or `nil` if the object's parent is already deallocated.
|
||||||
*/
|
*/
|
||||||
@nonobjc
|
@nonobjc
|
||||||
@@ -56,7 +56,7 @@ public extension NSManagedObject {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
Exposes a `QueryableSource` that can query attributes and aggregate values. This may be the `DataStack`, a `BaseDataTransaction`, the `NSManagedObjectContext` itself, or `nil` if the obejct's parent is already deallocated.
|
Exposes a `QueryableSource` that can query attributes and aggregate values. This may be the `DataStack`, a `BaseDataTransaction`, the `NSManagedObjectContext` itself, or `nil` if the obejct's parent is already deallocated.
|
||||||
- Warning: Future implementations may change the instance returned by this method depending on the timing or condition that `querySource()` was called. Do not make assumptions that the instance will be a specific instance. If the `NSManagedObjectContext` instance is desired, use the `QueryableSource.internalContext()` method to get the correct instance. Also, do not assume that the `fetchSource()` and `querySource()` return the same instance all the time.
|
- Warning: Future implementations may change the instance returned by this method depending on the timing or condition that `querySource()` was called. Do not make assumptions that the instance will be a specific instance. If the `NSManagedObjectContext` instance is desired, use the `QueryableSource.unsafeContext()` method to get the correct instance. Also, do not assume that the `fetchSource()` and `querySource()` return the same instance all the time.
|
||||||
- returns: a `QueryableSource` that can query attributes and aggregate values. This may be the `DataStack`, a `BaseDataTransaction`, the `NSManagedObjectContext` itself, or `nil` if the object's parent is already deallocated.
|
- returns: a `QueryableSource` that can query attributes and aggregate values. This may be the `DataStack`, a `BaseDataTransaction`, the `NSManagedObjectContext` itself, or `nil` if the object's parent is already deallocated.
|
||||||
*/
|
*/
|
||||||
@nonobjc
|
@nonobjc
|
||||||
|
|||||||
@@ -288,10 +288,19 @@ public extension NSError {
|
|||||||
|
|
||||||
internal var isCoreDataMigrationError: Bool {
|
internal var isCoreDataMigrationError: Bool {
|
||||||
|
|
||||||
let code = self.code
|
guard self.domain == CocoaError.errorDomain else {
|
||||||
return (code == NSPersistentStoreIncompatibleVersionHashError
|
|
||||||
|| code == NSMigrationMissingSourceModelError
|
return false
|
||||||
|| code == NSMigrationError)
|
}
|
||||||
&& self.domain == NSCocoaErrorDomain
|
switch CocoaError.Code(rawValue: self.code) {
|
||||||
|
|
||||||
|
case CocoaError.Code.persistentStoreIncompatibleVersionHash,
|
||||||
|
CocoaError.Code.migrationMissingSourceModel,
|
||||||
|
CocoaError.Code.migration:
|
||||||
|
return true
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -359,8 +359,17 @@ extension BaseDataTransaction: FetchableSource, QueryableSource {
|
|||||||
/**
|
/**
|
||||||
The internal `NSManagedObjectContext` managed by this instance. Using this context directly should typically be avoided, and is provided by CoreStore only for extremely specialized cases.
|
The internal `NSManagedObjectContext` managed by this instance. Using this context directly should typically be avoided, and is provided by CoreStore only for extremely specialized cases.
|
||||||
*/
|
*/
|
||||||
public func internalContext() -> NSManagedObjectContext {
|
public func unsafeContext() -> NSManagedObjectContext {
|
||||||
|
|
||||||
return self.context
|
return self.context
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: Deprecated
|
||||||
|
|
||||||
|
@available(*, deprecated: 4.0.0, renamed: "unsafeContext()")
|
||||||
|
public func internalContext() -> NSManagedObjectContext {
|
||||||
|
|
||||||
|
return self.unsafeContext()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -322,8 +322,17 @@ extension DataStack: FetchableSource, QueryableSource {
|
|||||||
/**
|
/**
|
||||||
The internal `NSManagedObjectContext` managed by this instance. Using this context directly should typically be avoided, and is provided by CoreStore only for extremely specialized cases.
|
The internal `NSManagedObjectContext` managed by this instance. Using this context directly should typically be avoided, and is provided by CoreStore only for extremely specialized cases.
|
||||||
*/
|
*/
|
||||||
public func internalContext() -> NSManagedObjectContext {
|
public func unsafeContext() -> NSManagedObjectContext {
|
||||||
|
|
||||||
return self.mainContext
|
return self.mainContext
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: Deprecated
|
||||||
|
|
||||||
|
@available(*, deprecated: 4.0.0, renamed: "unsafeContext()")
|
||||||
|
public func internalContext() -> NSManagedObjectContext {
|
||||||
|
|
||||||
|
return self.unsafeContext()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -159,5 +159,11 @@ public protocol FetchableSource: class {
|
|||||||
/**
|
/**
|
||||||
The internal `NSManagedObjectContext` managed by this `FetchableSource`. Using this context directly should typically be avoided, and is provided by CoreStore only for extremely specialized cases.
|
The internal `NSManagedObjectContext` managed by this `FetchableSource`. Using this context directly should typically be avoided, and is provided by CoreStore only for extremely specialized cases.
|
||||||
*/
|
*/
|
||||||
|
func unsafeContext() -> NSManagedObjectContext
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: Deprecated
|
||||||
|
|
||||||
|
@available(*, deprecated: 4.0.0, renamed: "unsafeContext()")
|
||||||
func internalContext() -> NSManagedObjectContext
|
func internalContext() -> NSManagedObjectContext
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,5 +85,11 @@ public protocol QueryableSource: class {
|
|||||||
/**
|
/**
|
||||||
The internal `NSManagedObjectContext` managed by this `QueryableSource`. Using this context directly should typically be avoided, and is provided by CoreStore only for extremely specialized cases.
|
The internal `NSManagedObjectContext` managed by this `QueryableSource`. Using this context directly should typically be avoided, and is provided by CoreStore only for extremely specialized cases.
|
||||||
*/
|
*/
|
||||||
|
func unsafeContext() -> NSManagedObjectContext
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: Deprecated
|
||||||
|
|
||||||
|
@available(*, deprecated: 4.0.0, renamed: "unsafeContext()")
|
||||||
func internalContext() -> NSManagedObjectContext
|
func internalContext() -> NSManagedObjectContext
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ public protocol ImportableObject: class, NSObjectProtocol, AnyObject {
|
|||||||
func didInsert(from source: ImportSource, in transaction: BaseDataTransaction) throws
|
func didInsert(from source: ImportSource, in transaction: BaseDataTransaction) throws
|
||||||
|
|
||||||
|
|
||||||
// MARK: Deprecated
|
// MARK: Obsolete (`deprecated` only for reference, please use new methods)
|
||||||
|
|
||||||
@available(*, deprecated: 3.0.0, renamed: "shouldInsert(from:in:)")
|
@available(*, deprecated: 3.0.0, renamed: "shouldInsert(from:in:)")
|
||||||
static func shouldInsertFromImportSource(_ source: ImportSource, inTransaction transaction: BaseDataTransaction) -> Bool
|
static func shouldInsertFromImportSource(_ source: ImportSource, inTransaction transaction: BaseDataTransaction) -> Bool
|
||||||
@@ -93,13 +93,15 @@ public extension ImportableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: Deprecated
|
// MARK: Obsolete
|
||||||
|
|
||||||
|
@available(*, obsoleted: 4.0.0, renamed: "shouldInsert(from:in:)")
|
||||||
static func shouldInsertFromImportSource(_ source: ImportSource, inTransaction transaction: BaseDataTransaction) -> Bool {
|
static func shouldInsertFromImportSource(_ source: ImportSource, inTransaction transaction: BaseDataTransaction) -> Bool {
|
||||||
|
|
||||||
return Self.shouldInsert(from: source, in: transaction)
|
return Self.shouldInsert(from: source, in: transaction)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@available(*, obsoleted: 4.0.0, renamed: "didInsert(from:in:)")
|
||||||
func didInsertFromImportSource(_ source: ImportSource, inTransaction transaction: BaseDataTransaction) throws {
|
func didInsertFromImportSource(_ source: ImportSource, inTransaction transaction: BaseDataTransaction) throws {
|
||||||
|
|
||||||
try self.didInsert(from: source, in: transaction)
|
try self.didInsert(from: source, in: transaction)
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ public protocol ImportableUniqueObject: ImportableObject {
|
|||||||
func update(from source: ImportSource, in transaction: BaseDataTransaction) throws
|
func update(from source: ImportSource, in transaction: BaseDataTransaction) throws
|
||||||
|
|
||||||
|
|
||||||
// MARK: Deprecated
|
// MARK: Obsolete (`deprecated` only for reference, please use new methods)
|
||||||
|
|
||||||
@available(*, deprecated: 3.0.0, renamed: "shouldInsert(from:in:)")
|
@available(*, deprecated: 3.0.0, renamed: "shouldInsert(from:in:)")
|
||||||
static func shouldInsertFromImportSource(_ source: ImportSource, inTransaction transaction: BaseDataTransaction) -> Bool
|
static func shouldInsertFromImportSource(_ source: ImportSource, inTransaction transaction: BaseDataTransaction) -> Bool
|
||||||
@@ -155,28 +155,33 @@ public extension ImportableUniqueObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: Deprecated
|
// MARK: Obsolete
|
||||||
|
|
||||||
|
@available(*, obsoleted: 4.0.0, renamed: "shouldInsert(from:in:)")
|
||||||
static func shouldInsertFromImportSource(_ source: ImportSource, inTransaction transaction: BaseDataTransaction) -> Bool {
|
static func shouldInsertFromImportSource(_ source: ImportSource, inTransaction transaction: BaseDataTransaction) -> Bool {
|
||||||
|
|
||||||
return Self.shouldInsert(from: source, in: transaction)
|
return Self.shouldInsert(from: source, in: transaction)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@available(*, obsoleted: 4.0.0, renamed: "shouldUpdate(from:in:)")
|
||||||
static func shouldUpdateFromImportSource(_ source: ImportSource, inTransaction transaction: BaseDataTransaction) -> Bool {
|
static func shouldUpdateFromImportSource(_ source: ImportSource, inTransaction transaction: BaseDataTransaction) -> Bool {
|
||||||
|
|
||||||
return Self.shouldUpdate(from: source, in: transaction)
|
return Self.shouldUpdate(from: source, in: transaction)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@available(*, obsoleted: 4.0.0, renamed: "uniqueID(from:in:)")
|
||||||
static func uniqueIDFromImportSource(_ source: ImportSource, inTransaction transaction: BaseDataTransaction) throws -> UniqueIDType? {
|
static func uniqueIDFromImportSource(_ source: ImportSource, inTransaction transaction: BaseDataTransaction) throws -> UniqueIDType? {
|
||||||
|
|
||||||
return try Self.uniqueID(from: source, in: transaction)
|
return try Self.uniqueID(from: source, in: transaction)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@available(*, obsoleted: 4.0.0, renamed: "didInsert(from:in:)")
|
||||||
func didInsertFromImportSource(_ source: ImportSource, inTransaction transaction: BaseDataTransaction) throws {
|
func didInsertFromImportSource(_ source: ImportSource, inTransaction transaction: BaseDataTransaction) throws {
|
||||||
|
|
||||||
try self.didInsert(from: source, in: transaction)
|
try self.didInsert(from: source, in: transaction)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@available(*, obsoleted: 4.0.0, renamed: "update(from:in:)")
|
||||||
func updateFromImportSource(_ source: ImportSource, inTransaction transaction: BaseDataTransaction) throws {
|
func updateFromImportSource(_ source: ImportSource, inTransaction transaction: BaseDataTransaction) throws {
|
||||||
|
|
||||||
try self.update(from: source, in: transaction)
|
try self.update(from: source, in: transaction)
|
||||||
|
|||||||
@@ -54,9 +54,14 @@ internal extension DispatchQueue {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@nonobjc @inline(__always)
|
@nonobjc
|
||||||
internal func cs_isCurrentExecutionContext() -> Bool {
|
internal func cs_isCurrentExecutionContext() -> Bool {
|
||||||
|
|
||||||
|
enum Static {
|
||||||
|
|
||||||
|
static let specificKey = DispatchSpecificKey<ObjectIdentifier>()
|
||||||
|
}
|
||||||
|
|
||||||
let specific = ObjectIdentifier(self)
|
let specific = ObjectIdentifier(self)
|
||||||
|
|
||||||
self.setSpecific(key: Static.specificKey, value: specific)
|
self.setSpecific(key: Static.specificKey, value: specific)
|
||||||
@@ -89,9 +94,4 @@ internal extension DispatchQueue {
|
|||||||
|
|
||||||
|
|
||||||
// MARK: Private
|
// MARK: Private
|
||||||
|
|
||||||
private enum Static {
|
|
||||||
|
|
||||||
static let specificKey = DispatchSpecificKey<ObjectIdentifier>()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -290,10 +290,19 @@ extension NSManagedObjectContext: FetchableSource, QueryableSource {
|
|||||||
// MARK: FetchableSource, QueryableSource
|
// MARK: FetchableSource, QueryableSource
|
||||||
|
|
||||||
@nonobjc
|
@nonobjc
|
||||||
public func internalContext() -> NSManagedObjectContext {
|
public func unsafeContext() -> NSManagedObjectContext {
|
||||||
|
|
||||||
return self
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: Deprecated
|
||||||
|
|
||||||
|
@available(*, deprecated: 4.0.0, renamed: "unsafeContext()")
|
||||||
|
public func internalContext() -> NSManagedObjectContext {
|
||||||
|
|
||||||
|
return self.unsafeContext()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ internal extension NSManagedObjectContext {
|
|||||||
|
|
||||||
for objectID in updatedObjectIDs {
|
for objectID in updatedObjectIDs {
|
||||||
|
|
||||||
context?.object(with: objectID).willAccessValue(forKey: nil)
|
context?.registeredObject(for: objectID)?.willAccessValue(forKey: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
context?.mergeChanges(fromContextDidSave: note)
|
context?.mergeChanges(fromContextDidSave: note)
|
||||||
|
|||||||
@@ -140,17 +140,15 @@ internal extension NSManagedObjectContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@nonobjc
|
@nonobjc
|
||||||
internal func saveSynchronously(waitForMerge: Bool) -> SaveResult {
|
internal func saveSynchronously(waitForMerge: Bool) -> (hasChanges: Bool, error: CoreStoreError?) {
|
||||||
|
|
||||||
var result = SaveResult(hasChanges: false)
|
var result: (hasChanges: Bool, error: CoreStoreError?) = (false, nil)
|
||||||
|
|
||||||
self.performAndWait {
|
self.performAndWait {
|
||||||
|
|
||||||
guard self.hasChanges else {
|
guard self.hasChanges else {
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
|
||||||
self.isSavingSynchronously = waitForMerge
|
self.isSavingSynchronously = waitForMerge
|
||||||
@@ -164,32 +162,24 @@ internal extension NSManagedObjectContext {
|
|||||||
saveError,
|
saveError,
|
||||||
"Failed to save \(cs_typeName(NSManagedObjectContext.self))."
|
"Failed to save \(cs_typeName(NSManagedObjectContext.self))."
|
||||||
)
|
)
|
||||||
result = SaveResult(saveError)
|
result = (true, saveError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if let parentContext = self.parent, self.shouldCascadeSavesToParent {
|
if let parentContext = self.parent, self.shouldCascadeSavesToParent {
|
||||||
|
|
||||||
switch parentContext.saveSynchronously(waitForMerge: waitForMerge) {
|
let (_, error) = parentContext.saveSynchronously(waitForMerge: waitForMerge)
|
||||||
|
result = (true, error)
|
||||||
case .success:
|
|
||||||
result = SaveResult(hasChanges: true)
|
|
||||||
|
|
||||||
case .failure(let error):
|
|
||||||
result = SaveResult(error)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
||||||
result = SaveResult(hasChanges: true)
|
result = (true, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
@nonobjc
|
@nonobjc
|
||||||
internal func saveAsynchronouslyWithCompletion(_ completion: @escaping ((_ result: SaveResult) -> Void) = { _ in }) {
|
internal func saveAsynchronouslyWithCompletion(_ completion: @escaping (_ hasChanges: Bool, _ error: CoreStoreError?) -> Void = { _ in }) {
|
||||||
|
|
||||||
self.perform {
|
self.perform {
|
||||||
|
|
||||||
@@ -197,11 +187,10 @@ internal extension NSManagedObjectContext {
|
|||||||
|
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
|
|
||||||
completion(SaveResult(hasChanges: false))
|
completion(false, nil)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
|
||||||
self.isSavingSynchronously = false
|
self.isSavingSynchronously = false
|
||||||
@@ -216,21 +205,23 @@ internal extension NSManagedObjectContext {
|
|||||||
"Failed to save \(cs_typeName(NSManagedObjectContext.self))."
|
"Failed to save \(cs_typeName(NSManagedObjectContext.self))."
|
||||||
)
|
)
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
|
|
||||||
completion(SaveResult(saveError))
|
completion(true, saveError)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.shouldCascadeSavesToParent, let parentContext = self.parent {
|
if self.shouldCascadeSavesToParent, let parentContext = self.parent {
|
||||||
|
|
||||||
parentContext.saveAsynchronouslyWithCompletion(completion)
|
parentContext.saveAsynchronouslyWithCompletion { (_, error) in
|
||||||
|
|
||||||
|
completion(true, error)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
|
|
||||||
completion(SaveResult(hasChanges: true))
|
completion(true, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,8 +48,7 @@ extension AsynchronousDataTransaction: CustomDebugStringConvertible, CoreStoreDe
|
|||||||
("context", self.context),
|
("context", self.context),
|
||||||
("supportsUndo", self.supportsUndo),
|
("supportsUndo", self.supportsUndo),
|
||||||
("bypassesQueueing", self.bypassesQueueing),
|
("bypassesQueueing", self.bypassesQueueing),
|
||||||
("isCommitted", self.isCommitted),
|
("isCommitted", self.isCommitted)
|
||||||
("result", self.result as Any)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -614,6 +613,7 @@ extension OrderBy: CustomDebugStringConvertible, CoreStoreDebugStringConvertible
|
|||||||
|
|
||||||
// MARK: - SaveResult
|
// MARK: - SaveResult
|
||||||
|
|
||||||
|
@available(*, deprecated: 4.0.0, message: "Use the new DataStack.perform(asynchronous:...) and DataStack.perform(synchronous:...) family of APIs")
|
||||||
extension SaveResult: CustomDebugStringConvertible, CoreStoreDebugStringConvertible {
|
extension SaveResult: CustomDebugStringConvertible, CoreStoreDebugStringConvertible {
|
||||||
|
|
||||||
// MARK: CustomDebugStringConvertible
|
// MARK: CustomDebugStringConvertible
|
||||||
@@ -824,8 +824,7 @@ extension SynchronousDataTransaction: CustomDebugStringConvertible, CoreStoreDeb
|
|||||||
("context", self.context),
|
("context", self.context),
|
||||||
("supportsUndo", self.supportsUndo),
|
("supportsUndo", self.supportsUndo),
|
||||||
("bypassesQueueing", self.bypassesQueueing),
|
("bypassesQueueing", self.bypassesQueueing),
|
||||||
("isCommitted", self.isCommitted),
|
("isCommitted", self.isCommitted)
|
||||||
("result", self.result as Any)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ public extension CoreStore {
|
|||||||
|
|
||||||
// MARK: Internal
|
// MARK: Internal
|
||||||
|
|
||||||
|
@inline(__always)
|
||||||
internal static func log(_ level: LogLevel, message: String, fileName: StaticString = #file, lineNumber: Int = #line, functionName: StaticString = #function) {
|
internal static func log(_ level: LogLevel, message: String, fileName: StaticString = #file, lineNumber: Int = #line, functionName: StaticString = #function) {
|
||||||
|
|
||||||
self.logger.log(
|
self.logger.log(
|
||||||
@@ -49,6 +50,7 @@ public extension CoreStore {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@inline(__always)
|
||||||
internal static func log(_ error: CoreStoreError, _ message: String, fileName: StaticString = #file, lineNumber: Int = #line, functionName: StaticString = #function) {
|
internal static func log(_ error: CoreStoreError, _ message: String, fileName: StaticString = #file, lineNumber: Int = #line, functionName: StaticString = #function) {
|
||||||
|
|
||||||
self.logger.log(
|
self.logger.log(
|
||||||
@@ -60,6 +62,7 @@ public extension CoreStore {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@inline(__always)
|
||||||
internal static func assert( _ condition: @autoclosure () -> Bool, _ message: String, fileName: StaticString = #file, lineNumber: Int = #line, functionName: StaticString = #function) {
|
internal static func assert( _ condition: @autoclosure () -> Bool, _ message: String, fileName: StaticString = #file, lineNumber: Int = #line, functionName: StaticString = #function) {
|
||||||
|
|
||||||
self.logger.assert(
|
self.logger.assert(
|
||||||
@@ -71,6 +74,7 @@ public extension CoreStore {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@inline(__always)
|
||||||
internal static func abort(_ message: String, fileName: StaticString = #file, lineNumber: Int = #line, functionName: StaticString = #function) -> Never {
|
internal static func abort(_ message: String, fileName: StaticString = #file, lineNumber: Int = #line, functionName: StaticString = #function) -> Never {
|
||||||
|
|
||||||
self.logger.abort(
|
self.logger.abort(
|
||||||
|
|||||||
@@ -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.
|
- parameter completion: the block executed after the save completes. Success or failure is reported by the `CSSaveResult` argument of the block.
|
||||||
*/
|
*/
|
||||||
@objc
|
@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)
|
switch result {
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
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
|
|
||||||
|
|
||||||
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)
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -38,10 +38,7 @@ public extension CSCoreStore {
|
|||||||
@objc
|
@objc
|
||||||
public static func beginAsynchronous(_ closure: @escaping (_ transaction: CSAsynchronousDataTransaction) -> Void) {
|
public static func beginAsynchronous(_ closure: @escaping (_ transaction: CSAsynchronousDataTransaction) -> Void) {
|
||||||
|
|
||||||
return CoreStore.beginAsynchronous { (transaction) in
|
self.defaultStack.beginAsynchronous(closure)
|
||||||
|
|
||||||
closure(transaction.bridgeToObjectiveC)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -51,16 +48,9 @@ public extension CSCoreStore {
|
|||||||
- returns: a `CSSaveResult` value indicating success or failure, or `nil` if the transaction was not comitted synchronously
|
- returns: a `CSSaveResult` value indicating success or failure, or `nil` if the transaction was not comitted synchronously
|
||||||
*/
|
*/
|
||||||
@objc
|
@objc
|
||||||
@discardableResult
|
public static func beginSynchronous(_ closure: @escaping (_ transaction: CSSynchronousDataTransaction) -> Void, error: NSErrorPointer) -> Bool {
|
||||||
public static func beginSynchronous(_ closure: @escaping (_ transaction: CSSynchronousDataTransaction) -> Void) -> CSSaveResult? {
|
|
||||||
|
|
||||||
return bridge {
|
return self.defaultStack.beginSynchronous(closure, error: error)
|
||||||
|
|
||||||
CoreStore.beginSynchronous { (transaction) in
|
|
||||||
|
|
||||||
closure(transaction.bridgeToObjectiveC)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -101,4 +91,21 @@ public extension CSCoreStore {
|
|||||||
|
|
||||||
CoreStore.refreshAndMergeAllObjects()
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,27 +38,57 @@ public extension CSDataStack {
|
|||||||
@objc
|
@objc
|
||||||
public func beginAsynchronous(_ closure: @escaping (_ transaction: CSAsynchronousDataTransaction) -> Void) {
|
public func beginAsynchronous(_ closure: @escaping (_ transaction: CSAsynchronousDataTransaction) -> Void) {
|
||||||
|
|
||||||
return self.bridgeToSwift.beginAsynchronous { (transaction) in
|
self.bridgeToSwift.perform(
|
||||||
|
asynchronous: { (transaction) in
|
||||||
closure(transaction.bridgeToObjectiveC)
|
|
||||||
}
|
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.
|
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`.
|
- 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
|
@objc
|
||||||
@discardableResult
|
public func beginSynchronous(_ closure: @escaping (_ transaction: CSSynchronousDataTransaction) -> Void, error: NSErrorPointer) -> Bool {
|
||||||
public func beginSynchronous(_ closure: @escaping (_ transaction: CSSynchronousDataTransaction) -> Void) -> CSSaveResult? {
|
|
||||||
|
|
||||||
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()
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import CoreData
|
|||||||
|
|
||||||
- SeeAlso: `SaveResult`
|
- SeeAlso: `SaveResult`
|
||||||
*/
|
*/
|
||||||
|
@available(*, deprecated: 4.0.0, message: "Use APIs that report failures with `CSError`s instead.")
|
||||||
@objc
|
@objc
|
||||||
public final class CSSaveResult: NSObject, CoreStoreObjectiveCType {
|
public final class CSSaveResult: NSObject, CoreStoreObjectiveCType {
|
||||||
|
|
||||||
@@ -173,6 +174,7 @@ public final class CSSaveResult: NSObject, CoreStoreObjectiveCType {
|
|||||||
|
|
||||||
// MARK: - SaveResult
|
// MARK: - SaveResult
|
||||||
|
|
||||||
|
@available(*, deprecated: 4.0.0, message: "Use the new DataStack.perform(asynchronous:...) and DataStack.perform(synchronous:...) family of APIs")
|
||||||
extension SaveResult: CoreStoreSwiftType {
|
extension SaveResult: CoreStoreSwiftType {
|
||||||
|
|
||||||
// MARK: CoreStoreSwiftType
|
// MARK: CoreStoreSwiftType
|
||||||
|
|||||||
@@ -38,34 +38,19 @@ import CoreData
|
|||||||
public final class CSSynchronousDataTransaction: CSBaseDataTransaction {
|
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
|
@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) {
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
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
|
|
||||||
|
|
||||||
closure(transaction.bridgeToObjectiveC)
|
throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -158,6 +143,44 @@ public final class CSSynchronousDataTransaction: CSBaseDataTransaction {
|
|||||||
|
|
||||||
super.init(swiftValue as! SynchronousDataTransaction)
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -36,32 +36,43 @@ import CoreData
|
|||||||
*/
|
*/
|
||||||
@objc
|
@objc
|
||||||
public final class CSUnsafeDataTransaction: CSBaseDataTransaction {
|
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.
|
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
|
@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.
|
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
|
@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.
|
- 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
|
@objc
|
||||||
public var internalContext: NSManagedObjectContext {
|
public func unsafeContext() -> NSManagedObjectContext {
|
||||||
|
|
||||||
return self.bridgeToSwift.context
|
return self.bridgeToSwift.context
|
||||||
}
|
}
|
||||||
@@ -188,6 +199,58 @@ public final class CSUnsafeDataTransaction: CSBaseDataTransaction {
|
|||||||
|
|
||||||
super.init(swiftValue as! UnsafeDataTransaction)
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -202,7 +202,7 @@ public final class ListMonitor<T: NSManagedObject>: Hashable {
|
|||||||
!self.isPendingRefetch || Thread.isMainThread,
|
!self.isPendingRefetch || Thread.isMainThread,
|
||||||
"Attempted to access a \(cs_typeName(self)) outside the main thread while a refetch is in progress."
|
"Attempted to access a \(cs_typeName(self)) outside the main thread while a refetch is in progress."
|
||||||
)
|
)
|
||||||
return self.fetchedResultsController.dynamicCast().fetchedObjects ?? []
|
return (self.fetchedResultsController.dynamicCast() as NSFetchedResultsController<T>).fetchedObjects ?? []
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -213,7 +213,7 @@ public final class ListMonitor<T: NSManagedObject>: Hashable {
|
|||||||
*/
|
*/
|
||||||
public func objectsInSection(_ section: Int) -> [T] {
|
public func objectsInSection(_ section: Int) -> [T] {
|
||||||
|
|
||||||
return (self.sectionInfoAtIndex(section).objects as? [T]) ?? []
|
return (self.sectionInfoAtIndex(section).objects as! [T]?) ?? []
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -224,7 +224,7 @@ public final class ListMonitor<T: NSManagedObject>: Hashable {
|
|||||||
*/
|
*/
|
||||||
public func objectsInSection(safeSectionIndex section: Int) -> [T]? {
|
public func objectsInSection(safeSectionIndex section: Int) -> [T]? {
|
||||||
|
|
||||||
return (self.sectionInfoAtIndex(safeSectionIndex: section)?.objects as? [T]) ?? []
|
return self.sectionInfoAtIndex(safeSectionIndex: section)?.objects as! [T]?
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -371,7 +371,7 @@ public final class ListMonitor<T: NSManagedObject>: Hashable {
|
|||||||
!self.isPendingRefetch || Thread.isMainThread,
|
!self.isPendingRefetch || Thread.isMainThread,
|
||||||
"Attempted to access a \(cs_typeName(self)) outside the main thread while a refetch is in progress."
|
"Attempted to access a \(cs_typeName(self)) outside the main thread while a refetch is in progress."
|
||||||
)
|
)
|
||||||
return (self.fetchedResultsController.dynamicCast().fetchedObjects ?? []).index(of: object)
|
return (self.fetchedResultsController.dynamicCast() as NSFetchedResultsController<T>).fetchedObjects?.index(of: object)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -155,12 +155,9 @@ public extension CoreStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: Deprecated
|
// MARK: Obsolete
|
||||||
|
|
||||||
/**
|
@available(*, obsoleted: 4.0.0, renamed: "entityDescription(for:)")
|
||||||
Returns the `NSEntityDescription` for the specified `NSManagedObject` subclass from `defaultStack`'s model.
|
|
||||||
*/
|
|
||||||
@available(*, deprecated: 3.0.0, renamed: "entityDescription(for:)")
|
|
||||||
public static func entityDescriptionForType(_ type: NSManagedObject.Type) -> NSEntityDescription? {
|
public static func entityDescriptionForType(_ type: NSManagedObject.Type) -> NSEntityDescription? {
|
||||||
|
|
||||||
return self.entityDescription(for: type)
|
return self.entityDescription(for: type)
|
||||||
|
|||||||
@@ -529,15 +529,15 @@ public final class DataStack: Equatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: Deprecated
|
// MARK: Obsolete
|
||||||
|
|
||||||
@available(*, deprecated: 3.0.0, renamed: "entityDescription(for:)")
|
@available(*, obsoleted: 4.0.0, renamed: "entityDescription(for:)")
|
||||||
public func entityDescriptionForType(_ type: NSManagedObject.Type) -> NSEntityDescription? {
|
public func entityDescriptionForType(_ type: NSManagedObject.Type) -> NSEntityDescription? {
|
||||||
|
|
||||||
return self.entityDescription(for: type)
|
return self.entityDescription(for: type)
|
||||||
}
|
}
|
||||||
|
|
||||||
@available(*, deprecated: 3.0.0, renamed: "objectID(forURIRepresentation:)")
|
@available(*, obsoleted: 4.0.0, renamed: "objectID(forURIRepresentation:)")
|
||||||
public func objectIDForURIRepresentation(_ url: URL) -> NSManagedObjectID? {
|
public func objectIDForURIRepresentation(_ url: URL) -> NSManagedObjectID? {
|
||||||
|
|
||||||
return self.objectID(forURIRepresentation: url)
|
return self.objectID(forURIRepresentation: url)
|
||||||
|
|||||||
@@ -34,63 +34,51 @@ import CoreData
|
|||||||
*/
|
*/
|
||||||
public final class AsynchronousDataTransaction: BaseDataTransaction {
|
public final class AsynchronousDataTransaction: BaseDataTransaction {
|
||||||
|
|
||||||
|
// MARK: - Result
|
||||||
|
|
||||||
|
public enum Result<T> {
|
||||||
|
|
||||||
|
case success(userInfo: T)
|
||||||
|
case failure(error: CoreStoreError)
|
||||||
|
|
||||||
|
public var boolValue: Bool {
|
||||||
|
|
||||||
|
switch self {
|
||||||
|
|
||||||
|
case .success: return true
|
||||||
|
case .failure: return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: Internal
|
||||||
|
|
||||||
|
internal init(userInfo: T) {
|
||||||
|
|
||||||
|
self = .success(userInfo: userInfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal init(error: CoreStoreError) {
|
||||||
|
|
||||||
|
self = .failure(error: error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: -
|
||||||
|
|
||||||
|
/**
|
||||||
|
Cancels a transaction by throwing `CoreStoreError.userCancelled`.
|
||||||
|
```
|
||||||
|
try transaction.cancel()
|
||||||
|
```
|
||||||
|
- Important: Never use `try?` or `try!` on a `cancel()` call. Always use `try`. Using `try?` will swallow the cancellation and the transaction will proceed to commit as normal. Using `try!` will crash the app as `cancel()` will *always* throw an error.
|
||||||
|
*/
|
||||||
public func cancel() throws -> Never {
|
public func cancel() throws -> Never {
|
||||||
|
|
||||||
throw CoreStoreError.userCancelled
|
throw CoreStoreError.userCancelled
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
Saves the transaction changes. This method should not be used after the `commit()` method was already called once.
|
|
||||||
|
|
||||||
- parameter completion: the block executed after the save completes. Success or failure is reported by the `SaveResult` argument of the block.
|
|
||||||
*/
|
|
||||||
public func commit(_ completion: @escaping (_ result: SaveResult) -> Void = { _ in }) {
|
|
||||||
|
|
||||||
CoreStore.assert(
|
|
||||||
self.transactionQueue.cs_isCurrentExecutionContext(),
|
|
||||||
"Attempted to commit a \(cs_typeName(self)) outside its designated queue."
|
|
||||||
)
|
|
||||||
CoreStore.assert(
|
|
||||||
!self.isCommitted,
|
|
||||||
"Attempted to commit a \(cs_typeName(self)) more than once."
|
|
||||||
)
|
|
||||||
|
|
||||||
self.isCommitted = true
|
|
||||||
let group = DispatchGroup()
|
|
||||||
group.enter()
|
|
||||||
self.context.saveAsynchronouslyWithCompletion { (result) -> Void in
|
|
||||||
|
|
||||||
self.result = result
|
|
||||||
completion(result)
|
|
||||||
group.leave()
|
|
||||||
}
|
|
||||||
group.wait()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Begins a child transaction synchronously where NSManagedObject creates, updates, and deletes can be made. This method should not be used after the `commit()` 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 `SaveResult` value indicating success or failure, or `nil` if the transaction was not comitted synchronously
|
|
||||||
*/
|
|
||||||
@discardableResult
|
|
||||||
public func beginSynchronous(_ closure: @escaping (_ transaction: SynchronousDataTransaction) -> Void) -> SaveResult? {
|
|
||||||
|
|
||||||
CoreStore.assert(
|
|
||||||
self.transactionQueue.cs_isCurrentExecutionContext(),
|
|
||||||
"Attempted to begin a child transaction from a \(cs_typeName(self)) outside its designated queue."
|
|
||||||
)
|
|
||||||
CoreStore.assert(
|
|
||||||
!self.isCommitted,
|
|
||||||
"Attempted to begin a child transaction from an already committed \(cs_typeName(self))."
|
|
||||||
)
|
|
||||||
|
|
||||||
return SynchronousDataTransaction(
|
|
||||||
mainContext: self.context,
|
|
||||||
queue: self.childTransactionQueue,
|
|
||||||
closure: closure).performAndWait()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: BaseDataTransaction
|
// MARK: BaseDataTransaction
|
||||||
|
|
||||||
@@ -193,47 +181,93 @@ public final class AsynchronousDataTransaction: BaseDataTransaction {
|
|||||||
|
|
||||||
// MARK: Internal
|
// MARK: Internal
|
||||||
|
|
||||||
internal init(mainContext: NSManagedObjectContext, queue: DispatchQueue, closure: @escaping (_ transaction: AsynchronousDataTransaction) -> Void) {
|
internal init(mainContext: NSManagedObjectContext, queue: DispatchQueue) {
|
||||||
|
|
||||||
self.closure = closure
|
|
||||||
|
|
||||||
super.init(mainContext: mainContext, queue: queue, supportsUndo: false, bypassesQueueing: false)
|
super.init(mainContext: mainContext, queue: queue, supportsUndo: false, bypassesQueueing: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal func perform() {
|
internal func autoCommit(_ completion: @escaping (_ hasChanges: Bool, _ error: CoreStoreError?) -> Void) {
|
||||||
|
|
||||||
self.transactionQueue.async {
|
self.isCommitted = true
|
||||||
|
let group = DispatchGroup()
|
||||||
|
group.enter()
|
||||||
|
self.context.saveAsynchronouslyWithCompletion { (result) -> Void in
|
||||||
|
|
||||||
self.closure(self)
|
completion(result.0, result.1)
|
||||||
if !self.isCommitted && self.hasChanges {
|
self.result = result
|
||||||
|
group.leave()
|
||||||
|
}
|
||||||
|
group.wait()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: Deprecated
|
||||||
|
|
||||||
|
/**
|
||||||
|
Saves the transaction changes. This method should not be used after the `commit()` method was already called once.
|
||||||
|
|
||||||
|
- parameter completion: the block executed after the save completes. Success or failure is reported by the `SaveResult` argument of the block.
|
||||||
|
*/
|
||||||
|
@available(*, deprecated: 4.0.0, message: "Use the new auto-commiting methods `DataStack.perform(asynchronous:completion:)` or `DataStack.perform(asynchronous:success:failure:)`. Please read the documentation on the behavior of the new methods.")
|
||||||
|
public func commit(_ completion: @escaping (_ result: SaveResult) -> Void = { _ in }) {
|
||||||
|
|
||||||
|
CoreStore.assert(
|
||||||
|
self.transactionQueue.cs_isCurrentExecutionContext(),
|
||||||
|
"Attempted to commit a \(cs_typeName(self)) outside its designated queue."
|
||||||
|
)
|
||||||
|
CoreStore.assert(
|
||||||
|
!self.isCommitted,
|
||||||
|
"Attempted to commit a \(cs_typeName(self)) more than once."
|
||||||
|
)
|
||||||
|
self.autoCommit { (result) in
|
||||||
|
|
||||||
|
switch result {
|
||||||
|
|
||||||
CoreStore.log(
|
case (let hasChanges, nil): completion(SaveResult(hasChanges: hasChanges))
|
||||||
.warning,
|
case (_, let error?): completion(SaveResult(error))
|
||||||
message: "The closure for the \(cs_typeName(self)) completed without being committed. All changes made within the transaction were discarded."
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal func performAndWait() -> SaveResult? {
|
/**
|
||||||
|
Begins a child transaction synchronously where NSManagedObject creates, updates, and deletes can be made. This method should not be used after the `commit()` 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 `SaveResult` value indicating success or failure, or `nil` if the transaction was not comitted synchronously
|
||||||
|
*/
|
||||||
|
@available(*, deprecated: 4.0.0, message: "Secondary tasks spawned from AsynchronousDataTransactions and SynchronousDataTransactions are no longer supported. ")
|
||||||
|
@discardableResult
|
||||||
|
public func beginSynchronous(_ closure: @escaping (_ transaction: SynchronousDataTransaction) -> Void) -> SaveResult? {
|
||||||
|
|
||||||
self.transactionQueue.sync {
|
CoreStore.assert(
|
||||||
|
self.transactionQueue.cs_isCurrentExecutionContext(),
|
||||||
|
"Attempted to begin a child transaction from a \(cs_typeName(self)) outside its designated queue."
|
||||||
|
)
|
||||||
|
CoreStore.assert(
|
||||||
|
!self.isCommitted,
|
||||||
|
"Attempted to begin a child transaction from an already committed \(cs_typeName(self))."
|
||||||
|
)
|
||||||
|
let childTransaction = SynchronousDataTransaction(
|
||||||
|
mainContext: self.context,
|
||||||
|
queue: self.childTransactionQueue
|
||||||
|
)
|
||||||
|
childTransaction.transactionQueue.cs_sync {
|
||||||
|
|
||||||
self.closure(self)
|
closure(childTransaction)
|
||||||
|
|
||||||
if !self.isCommitted && self.hasChanges {
|
if !childTransaction.isCommitted && childTransaction.hasChanges {
|
||||||
|
|
||||||
CoreStore.log(
|
CoreStore.log(
|
||||||
.warning,
|
.warning,
|
||||||
message: "The closure for the \(cs_typeName(self)) completed without being committed. All changes made within the transaction were discarded."
|
message: "The closure for the \(cs_typeName(childTransaction)) completed without being committed. All changes made within the transaction were discarded."
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return self.result
|
switch childTransaction.result {
|
||||||
|
|
||||||
|
case nil: return nil
|
||||||
|
case (let hasChanges, nil)?: return SaveResult(hasChanges: hasChanges)
|
||||||
|
case (_, let error?)?: return SaveResult(error)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: Private
|
|
||||||
|
|
||||||
private let closure: (_ transaction: AsynchronousDataTransaction) -> Void
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -455,7 +455,7 @@ public /*abstract*/ class BaseDataTransaction {
|
|||||||
internal let supportsUndo: Bool
|
internal let supportsUndo: Bool
|
||||||
internal let bypassesQueueing: Bool
|
internal let bypassesQueueing: Bool
|
||||||
internal var isCommitted = false
|
internal var isCommitted = false
|
||||||
internal var result: SaveResult?
|
internal var result: (hasChanges: Bool, error: CoreStoreError?)?
|
||||||
|
|
||||||
internal init(mainContext: NSManagedObjectContext, queue: DispatchQueue, supportsUndo: Bool, bypassesQueueing: Bool) {
|
internal init(mainContext: NSManagedObjectContext, queue: DispatchQueue, supportsUndo: Bool, bypassesQueueing: Bool) {
|
||||||
|
|
||||||
|
|||||||
@@ -31,25 +31,39 @@ import Foundation
|
|||||||
public extension CoreStore {
|
public extension CoreStore {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Using the `defaultStack`, begins a transaction asynchronously where `NSManagedObject` creates, updates, and deletes can be made.
|
Using the `defaultStack`, performs a transaction asynchronously where `NSManagedObject` creates, updates, and deletes can be made. The changes are commited automatically after the `task` closure returns. On success, the value returned from closure will be the wrapped as `TransactionResult.success(userInfo: T)` in the `completion`'s `TransactionResult<T>`. Any errors thrown from inside the `task` will be reported as `TransactionResult.failure(error: Error)`. To cancel/rollback changes, call `transaction.cancel()`, which throws a `CoreStoreError.userCancelled`.
|
||||||
|
|
||||||
- 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`.
|
- parameter task: the asynchronous closure 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`.
|
||||||
|
- parameter completion: the closure executed after the save completes. The `TransactionResult` argument of the closure will either wrap the return value of `task`, or any uncaught errors thrown from within `task`. Cancelled `task`s will be indicated by `CoreStoreError.userCancelled`. Custom errors thrown by the user will be wrapped in `CoreStoreError.userError(error: Error)`.
|
||||||
*/
|
*/
|
||||||
public static func beginAsynchronous(_ closure: @escaping (_ transaction: AsynchronousDataTransaction) -> Void) {
|
public static func perform<T>(asynchronous task: @escaping (_ transaction: AsynchronousDataTransaction) throws -> T, completion: @escaping (AsynchronousDataTransaction.Result<T>) -> Void) {
|
||||||
|
|
||||||
self.defaultStack.beginAsynchronous(closure)
|
self.defaultStack.perform(asynchronous: task, completion: completion)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Using the `defaultStack`, begins a transaction asynchronously where `NSManagedObject` creates, updates, and deletes can be made.
|
Using the `defaultStack`, performs a transaction asynchronously where `NSManagedObject` creates, updates, and deletes can be made. The changes are commited automatically after the `task` closure returns. On success, the value returned from closure will be the argument of the `success` closure. Any errors thrown from inside the `task` will be wrapped in a `CoreStoreError` and reported in the `failure` closure. To cancel/rollback changes, call `transaction.cancel()`, which throws a `CoreStoreError.userCancelled`.
|
||||||
|
|
||||||
- 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`.
|
- parameter task: the asynchronous closure 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
|
- parameter success: the closure executed after the save succeeds. The `T` argument of the closure will be the value returned from `task`.
|
||||||
|
- parameter failure: the closure executed if the save fails or if any errors are thrown within `task`. Cancelled `task`s will be indicated by `CoreStoreError.userCancelled`. Custom errors thrown by the user will be wrapped in `CoreStoreError.userError(error: Error)`.
|
||||||
*/
|
*/
|
||||||
@discardableResult
|
public static func perform<T>(asynchronous task: @escaping (_ transaction: AsynchronousDataTransaction) throws -> T, success: @escaping (T) -> Void, failure: @escaping (CoreStoreError) -> Void) {
|
||||||
public static func beginSynchronous(_ closure: @escaping (_ transaction: SynchronousDataTransaction) -> Void) -> SaveResult? {
|
|
||||||
|
|
||||||
return self.defaultStack.beginSynchronous(closure)
|
self.defaultStack.perform(asynchronous: task, success: success, failure: failure)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Using the `defaultStack`, performs a transaction synchronously where `NSManagedObject` creates, updates, and deletes can be made. The changes are commited automatically after the `task` closure returns. On success, the value returned from closure will be the return value of `perform(synchronous:)`. Any errors thrown from inside the `task` will be rethrown from `perform(synchronous:)`. To cancel/rollback changes, call `transaction.cancel()`, which throws a `CoreStoreError.userCancelled`.
|
||||||
|
|
||||||
|
- parameter task: the synchronous non-escaping closure 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`.
|
||||||
|
- parameter waitForAllObservers: When `true`, this method waits for all observers to be notified of the changes before returning. This results in more predictable data update order, but may risk triggering deadlocks. When `false`, this method does not wait for observers to be notified of the changes before returning. This results in lower risk for deadlocks, but the updated data may not have been propagated to the `DataStack` after returning. Defaults to `true`.
|
||||||
|
- throws: a `CoreStoreError` value indicating the failure. Cancelled `task`s will be indicated by `CoreStoreError.userCancelled`. Custom errors thrown by the user will be wrapped in `CoreStoreError.userError(error: Error)`.
|
||||||
|
- returns: the value returned from `task`
|
||||||
|
*/
|
||||||
|
public static func perform<T>(synchronous task: ((_ transaction: SynchronousDataTransaction) throws -> T), waitForAllObservers: Bool = true) throws -> T {
|
||||||
|
|
||||||
|
return try self.defaultStack.perform(synchronous: task, waitForAllObservers: waitForAllObservers)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -70,4 +84,31 @@ public extension CoreStore {
|
|||||||
|
|
||||||
self.defaultStack.refreshAndMergeAllObjects()
|
self.defaultStack.refreshAndMergeAllObjects()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: Deprecated
|
||||||
|
|
||||||
|
/**
|
||||||
|
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`.
|
||||||
|
*/
|
||||||
|
@available(*, deprecated: 4.0.0, message: "Use the new auto-commiting methods `perform(asynchronous:completion:)` or `perform(asynchronous:success:failure:)`. Please read the documentation on the behavior of the new methods.")
|
||||||
|
public static func beginAsynchronous(_ closure: @escaping (_ transaction: AsynchronousDataTransaction) -> Void) {
|
||||||
|
|
||||||
|
self.defaultStack.beginAsynchronous(closure)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
@available(*, deprecated: 4.0.0, message: "Use the new auto-commiting method `perform(synchronous:)`. Please read the documentation on the behavior of the new methods.")
|
||||||
|
@discardableResult
|
||||||
|
public static func beginSynchronous(_ closure: @escaping (_ transaction: SynchronousDataTransaction) -> Void) -> SaveResult? {
|
||||||
|
|
||||||
|
return self.defaultStack.beginSynchronous(closure)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,22 +31,33 @@ import CoreData
|
|||||||
|
|
||||||
public extension DataStack {
|
public extension DataStack {
|
||||||
|
|
||||||
|
/**
|
||||||
public func perform<T>(asynchronous task: @escaping (_ transaction: AsynchronousDataTransaction) throws -> T, completion: @escaping (TransactionResult<T>) -> Void) {
|
Performs a transaction asynchronously where `NSManagedObject` creates, updates, and deletes can be made. The changes are commited automatically after the `task` closure returns. On success, the value returned from closure will be the wrapped as `TransactionResult.success(userInfo: T)` in the `completion`'s `TransactionResult<T>`. Any errors thrown from inside the `task` will be reported as `TransactionResult.failure(error: Error)`. To cancel/rollback changes, call `transaction.cancel()`, which throws a `CoreStoreError.userCancelled`.
|
||||||
|
|
||||||
|
- parameter task: the asynchronous closure 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`.
|
||||||
|
- parameter completion: the closure executed after the save completes. The `TransactionResult` argument of the closure will either wrap the return value of `task`, or any uncaught errors thrown from within `task`. Cancelled `task`s will be indicated by `CoreStoreError.userCancelled`. Custom errors thrown by the user will be wrapped in `CoreStoreError.userError(error: Error)`.
|
||||||
|
*/
|
||||||
|
public func perform<T>(asynchronous task: @escaping (_ transaction: AsynchronousDataTransaction) throws -> T, completion: @escaping (AsynchronousDataTransaction.Result<T>) -> Void) {
|
||||||
|
|
||||||
self.perform(
|
self.perform(
|
||||||
asynchronous: task,
|
asynchronous: task,
|
||||||
success: { completion(TransactionResult(userInfo: $0)) },
|
success: { completion(.init(userInfo: $0)) },
|
||||||
failure: { completion(TransactionResult(error: $0)) }
|
failure: { completion(.init(error: $0)) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Performs a transaction asynchronously where `NSManagedObject` creates, updates, and deletes can be made. The changes are commited automatically after the `task` closure returns. On success, the value returned from closure will be the argument of the `success` closure. Any errors thrown from inside the `task` will be wrapped in a `CoreStoreError` and reported in the `failure` closure. To cancel/rollback changes, call `transaction.cancel()`, which throws a `CoreStoreError.userCancelled`.
|
||||||
|
|
||||||
|
- parameter task: the asynchronous closure 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`.
|
||||||
|
- parameter success: the closure executed after the save succeeds. The `T` argument of the closure will be the value returned from `task`.
|
||||||
|
- parameter failure: the closure executed if the save fails or if any errors are thrown within `task`. Cancelled `task`s will be indicated by `CoreStoreError.userCancelled`. Custom errors thrown by the user will be wrapped in `CoreStoreError.userError(error: Error)`.
|
||||||
|
*/
|
||||||
public func perform<T>(asynchronous task: @escaping (_ transaction: AsynchronousDataTransaction) throws -> T, success: @escaping (T) -> Void, failure: @escaping (CoreStoreError) -> Void) {
|
public func perform<T>(asynchronous task: @escaping (_ transaction: AsynchronousDataTransaction) throws -> T, success: @escaping (T) -> Void, failure: @escaping (CoreStoreError) -> Void) {
|
||||||
|
|
||||||
let transaction = AsynchronousDataTransaction(
|
let transaction = AsynchronousDataTransaction(
|
||||||
mainContext: self.rootSavingContext,
|
mainContext: self.rootSavingContext,
|
||||||
queue: self.childTransactionQueue,
|
queue: self.childTransactionQueue
|
||||||
closure: { _ in }
|
|
||||||
)
|
)
|
||||||
transaction.transactionQueue.cs_async {
|
transaction.transactionQueue.cs_async {
|
||||||
|
|
||||||
@@ -65,30 +76,40 @@ public extension DataStack {
|
|||||||
DispatchQueue.main.async { failure(.userError(error: error)) }
|
DispatchQueue.main.async { failure(.userError(error: error)) }
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
transaction.commit { (result) in
|
transaction.autoCommit { (_, error) in
|
||||||
|
|
||||||
switch result {
|
if let error = error {
|
||||||
|
|
||||||
case .success: success(userInfo)
|
failure(error)
|
||||||
case .failure(let error): failure(error)
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
success(userInfo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func perform<T>(synchronous task: ((_ transaction: SynchronousDataTransaction) throws -> T), waitForObserverNotifications: Bool = true) throws -> T {
|
/**
|
||||||
|
Performs a transaction synchronously where `NSManagedObject` creates, updates, and deletes can be made. The changes are commited automatically after the `task` closure returns. On success, the value returned from closure will be the return value of `perform(synchronous:)`. Any errors thrown from inside the `task` will be rethrown from `perform(synchronous:)`. To cancel/rollback changes, call `transaction.cancel()`, which throws a `CoreStoreError.userCancelled`.
|
||||||
|
|
||||||
|
- parameter task: the synchronous non-escaping closure 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`.
|
||||||
|
- parameter waitForAllObservers: When `true`, this method waits for all observers to be notified of the changes before returning. This results in more predictable data update order, but may risk triggering deadlocks. When `false`, this method does not wait for observers to be notified of the changes before returning. This results in lower risk for deadlocks, but the updated data may not have been propagated to the `DataStack` after returning. Defaults to `true`.
|
||||||
|
- throws: a `CoreStoreError` value indicating the failure. Cancelled `task`s will be indicated by `CoreStoreError.userCancelled`. Custom errors thrown by the user will be wrapped in `CoreStoreError.userError(error: Error)`.
|
||||||
|
- returns: the value returned from `task`
|
||||||
|
*/
|
||||||
|
public func perform<T>(synchronous task: ((_ transaction: SynchronousDataTransaction) throws -> T), waitForAllObservers: Bool = true) throws -> T {
|
||||||
|
|
||||||
let transaction = SynchronousDataTransaction(
|
let transaction = SynchronousDataTransaction(
|
||||||
mainContext: self.rootSavingContext,
|
mainContext: self.rootSavingContext,
|
||||||
queue: self.childTransactionQueue,
|
queue: self.childTransactionQueue
|
||||||
closure: { _ in }
|
|
||||||
)
|
)
|
||||||
return try transaction.transactionQueue.cs_sync {
|
return try transaction.transactionQueue.cs_sync {
|
||||||
|
|
||||||
let userInfo: T
|
let userInfo: T
|
||||||
do {
|
do {
|
||||||
|
|
||||||
userInfo = try task(transaction)
|
userInfo = try withoutActuallyEscaping(task, do: { try $0(transaction) })
|
||||||
}
|
}
|
||||||
catch let error as CoreStoreError {
|
catch let error as CoreStoreError {
|
||||||
|
|
||||||
@@ -98,46 +119,17 @@ public extension DataStack {
|
|||||||
|
|
||||||
throw CoreStoreError.userError(error: error)
|
throw CoreStoreError.userError(error: error)
|
||||||
}
|
}
|
||||||
let result = waitForObserverNotifications
|
if case (_, let error?) = transaction.autoCommit(waitForMerge: waitForAllObservers) {
|
||||||
? transaction.commitAndWait()
|
|
||||||
: transaction.commit()
|
|
||||||
switch result {
|
|
||||||
|
|
||||||
case .success: return userInfo
|
throw error
|
||||||
case .failure(let error): throw error
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
return userInfo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
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`.
|
|
||||||
*/
|
|
||||||
public func beginAsynchronous(_ closure: @escaping (_ transaction: AsynchronousDataTransaction) -> Void) {
|
|
||||||
|
|
||||||
AsynchronousDataTransaction(
|
|
||||||
mainContext: self.rootSavingContext,
|
|
||||||
queue: self.childTransactionQueue,
|
|
||||||
closure: closure).perform()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
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
|
|
||||||
*/
|
|
||||||
@discardableResult
|
|
||||||
public func beginSynchronous(_ closure: @escaping (_ transaction: SynchronousDataTransaction) -> Void) -> SaveResult? {
|
|
||||||
|
|
||||||
return SynchronousDataTransaction(
|
|
||||||
mainContext: self.rootSavingContext,
|
|
||||||
queue: self.childTransactionQueue,
|
|
||||||
closure: closure).performAndWait()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
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.
|
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.
|
||||||
|
|
||||||
@@ -164,4 +156,67 @@ public extension DataStack {
|
|||||||
)
|
)
|
||||||
self.mainContext.refreshAndMergeAllObjects()
|
self.mainContext.refreshAndMergeAllObjects()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: Deprecated
|
||||||
|
|
||||||
|
/**
|
||||||
|
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`.
|
||||||
|
*/
|
||||||
|
@available(*, deprecated: 4.0.0, message: "Use the new auto-commiting methods `perform(asynchronous:completion:)` or `perform(asynchronous:success:failure:)`. Please read the documentation on the behavior of the new methods.")
|
||||||
|
public func beginAsynchronous(_ closure: @escaping (_ transaction: AsynchronousDataTransaction) -> Void) {
|
||||||
|
|
||||||
|
let transaction = AsynchronousDataTransaction(
|
||||||
|
mainContext: self.rootSavingContext,
|
||||||
|
queue: self.childTransactionQueue
|
||||||
|
)
|
||||||
|
transaction.transactionQueue.cs_async {
|
||||||
|
|
||||||
|
closure(transaction)
|
||||||
|
|
||||||
|
if !transaction.isCommitted && transaction.hasChanges {
|
||||||
|
|
||||||
|
CoreStore.log(
|
||||||
|
.warning,
|
||||||
|
message: "The closure for the \(cs_typeName(transaction)) completed without being committed. All changes made within the transaction were discarded."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
@available(*, deprecated: 4.0.0, message: "Use the new auto-commiting method `perform(synchronous:)`. Please read the documentation on the behavior of the new methods.")
|
||||||
|
@discardableResult
|
||||||
|
public func beginSynchronous(_ closure: @escaping (_ transaction: SynchronousDataTransaction) -> Void) -> SaveResult? {
|
||||||
|
|
||||||
|
let transaction = SynchronousDataTransaction(
|
||||||
|
mainContext: self.rootSavingContext,
|
||||||
|
queue: self.childTransactionQueue
|
||||||
|
)
|
||||||
|
transaction.transactionQueue.cs_sync {
|
||||||
|
|
||||||
|
closure(transaction)
|
||||||
|
|
||||||
|
if !transaction.isCommitted && transaction.hasChanges {
|
||||||
|
|
||||||
|
CoreStore.log(
|
||||||
|
.warning,
|
||||||
|
message: "The closure for the \(cs_typeName(transaction)) completed without being committed. All changes made within the transaction were discarded."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch transaction.result {
|
||||||
|
|
||||||
|
case nil: return nil
|
||||||
|
case (let hasChanges, nil)?: return SaveResult(hasChanges: hasChanges)
|
||||||
|
case (_, let error?)?: return SaveResult(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ import Foundation
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
*/
|
*/
|
||||||
|
@available(*, deprecated: 4.0.0, message: "Use the new DataStack.perform(asynchronous:...) and DataStack.perform(synchronous:...) family of APIs")
|
||||||
public enum SaveResult: Hashable {
|
public enum SaveResult: Hashable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -34,83 +34,18 @@ import CoreData
|
|||||||
*/
|
*/
|
||||||
public final class SynchronousDataTransaction: BaseDataTransaction {
|
public final class SynchronousDataTransaction: BaseDataTransaction {
|
||||||
|
|
||||||
|
/**
|
||||||
|
Cancels a transaction by throwing `CoreStoreError.userCancelled`.
|
||||||
|
```
|
||||||
|
try transaction.cancel()
|
||||||
|
```
|
||||||
|
- Important: Never use `try?` or `try!` on a `cancel()` call. Always use `try`. Using `try?` will swallow the cancellation and the transaction will proceed to commit as normal. Using `try!` will crash the app as `cancel()` will *always* throw an error.
|
||||||
|
*/
|
||||||
public func cancel() throws -> Never {
|
public func cancel() throws -> Never {
|
||||||
|
|
||||||
throw CoreStoreError.userCancelled
|
throw CoreStoreError.userCancelled
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
Saves the transaction changes and waits for completion synchronously. This method should not be used after the `commit()` or `commitAndWait()` method was already called once.
|
|
||||||
- Important: Unlike `SynchronousDataTransaction.commit()`, this method waits for all observers to be notified of the changes before returning. This results in more predictable data update order, but may risk triggering deadlocks.
|
|
||||||
|
|
||||||
- returns: a `SaveResult` containing the success or failure information
|
|
||||||
*/
|
|
||||||
public func commitAndWait() -> SaveResult {
|
|
||||||
|
|
||||||
CoreStore.assert(
|
|
||||||
self.transactionQueue.cs_isCurrentExecutionContext(),
|
|
||||||
"Attempted to commit a \(cs_typeName(self)) outside its designated queue."
|
|
||||||
)
|
|
||||||
CoreStore.assert(
|
|
||||||
!self.isCommitted,
|
|
||||||
"Attempted to commit a \(cs_typeName(self)) more than once."
|
|
||||||
)
|
|
||||||
|
|
||||||
self.isCommitted = true
|
|
||||||
|
|
||||||
let result = self.context.saveSynchronously(waitForMerge: true)
|
|
||||||
self.result = result
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Saves the transaction changes and waits for completion synchronously. This method should not be used after the `commit()` or `commitAndWait()` method was already called once.
|
|
||||||
- Important: Unlike `SynchronousDataTransaction.commitAndWait()`, this method does not wait for observers to be notified of the changes before returning. This results in lower risk for deadlocks, but the updated data may not have been propagated to the `DataStack` after returning.
|
|
||||||
|
|
||||||
- returns: a `SaveResult` containing the success or failure information
|
|
||||||
*/
|
|
||||||
public func commit() -> SaveResult {
|
|
||||||
|
|
||||||
CoreStore.assert(
|
|
||||||
self.transactionQueue.cs_isCurrentExecutionContext(),
|
|
||||||
"Attempted to commit a \(cs_typeName(self)) outside its designated queue."
|
|
||||||
)
|
|
||||||
CoreStore.assert(
|
|
||||||
!self.isCommitted,
|
|
||||||
"Attempted to commit a \(cs_typeName(self)) more than once."
|
|
||||||
)
|
|
||||||
|
|
||||||
self.isCommitted = true
|
|
||||||
|
|
||||||
let result = self.context.saveSynchronously(waitForMerge: false)
|
|
||||||
self.result = result
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Begins a child transaction synchronously where `NSManagedObject` creates, updates, and deletes can be made. This method should not be used after the `commit()` 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 `SaveResult` value indicating success or failure, or `nil` if the transaction was not comitted synchronously
|
|
||||||
*/
|
|
||||||
@discardableResult
|
|
||||||
public func beginSynchronous(_ closure: @escaping (_ transaction: SynchronousDataTransaction) -> Void) -> SaveResult? {
|
|
||||||
|
|
||||||
CoreStore.assert(
|
|
||||||
self.transactionQueue.cs_isCurrentExecutionContext(),
|
|
||||||
"Attempted to begin a child transaction from a \(cs_typeName(self)) outside its designated queue."
|
|
||||||
)
|
|
||||||
CoreStore.assert(
|
|
||||||
!self.isCommitted,
|
|
||||||
"Attempted to begin a child transaction from an already committed \(cs_typeName(self))."
|
|
||||||
)
|
|
||||||
|
|
||||||
return SynchronousDataTransaction(
|
|
||||||
mainContext: self.context,
|
|
||||||
queue: self.childTransactionQueue,
|
|
||||||
closure: closure).performAndWait()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: BaseDataTransaction
|
// MARK: BaseDataTransaction
|
||||||
|
|
||||||
@@ -213,32 +148,109 @@ public final class SynchronousDataTransaction: BaseDataTransaction {
|
|||||||
|
|
||||||
// MARK: Internal
|
// MARK: Internal
|
||||||
|
|
||||||
internal init(mainContext: NSManagedObjectContext, queue: DispatchQueue, closure: @escaping (_ transaction: SynchronousDataTransaction) -> Void) {
|
internal init(mainContext: NSManagedObjectContext, queue: DispatchQueue) {
|
||||||
|
|
||||||
self.closure = closure
|
|
||||||
|
|
||||||
super.init(mainContext: mainContext, queue: queue, supportsUndo: false, bypassesQueueing: false)
|
super.init(mainContext: mainContext, queue: queue, supportsUndo: false, bypassesQueueing: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal func performAndWait() -> SaveResult? {
|
internal func autoCommit(waitForMerge: Bool) -> (hasChanges: Bool, error: CoreStoreError?) {
|
||||||
|
|
||||||
self.transactionQueue.sync {
|
self.isCommitted = true
|
||||||
|
let result = self.context.saveSynchronously(waitForMerge: waitForMerge)
|
||||||
self.closure(self)
|
self.result = result
|
||||||
|
return result
|
||||||
if !self.isCommitted && self.hasChanges {
|
|
||||||
|
|
||||||
CoreStore.log(
|
|
||||||
.warning,
|
|
||||||
message: "The closure for the \(cs_typeName(self)) completed without being committed. All changes made within the transaction were discarded."
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return self.result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: Private
|
// MARK: Deprecated
|
||||||
|
|
||||||
private let closure: (_ transaction: SynchronousDataTransaction) -> Void
|
/**
|
||||||
|
Saves the transaction changes and waits for completion synchronously. This method should not be used after the `commit()` or `commitAndWait()` method was already called once.
|
||||||
|
- Important: Unlike `SynchronousDataTransaction.commit()`, this method waits for all observers to be notified of the changes before returning. This results in more predictable data update order, but may risk triggering deadlocks.
|
||||||
|
|
||||||
|
- returns: a `SaveResult` containing the success or failure information
|
||||||
|
*/
|
||||||
|
@available(*, deprecated: 4.0.0, message: "Use the new auto-commit method DataStack.perform(synchronous:waitForAllObservers:)")
|
||||||
|
public func commitAndWait() -> SaveResult {
|
||||||
|
|
||||||
|
CoreStore.assert(
|
||||||
|
self.transactionQueue.cs_isCurrentExecutionContext(),
|
||||||
|
"Attempted to commit a \(cs_typeName(self)) outside its designated queue."
|
||||||
|
)
|
||||||
|
CoreStore.assert(
|
||||||
|
!self.isCommitted,
|
||||||
|
"Attempted to commit a \(cs_typeName(self)) more than once."
|
||||||
|
)
|
||||||
|
switch self.autoCommit(waitForMerge: true) {
|
||||||
|
|
||||||
|
case (let hasChanges, nil): return SaveResult(hasChanges: hasChanges)
|
||||||
|
case (_, let error?): return SaveResult(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Saves the transaction changes and waits for completion synchronously. This method should not be used after the `commit()` or `commitAndWait()` method was already called once.
|
||||||
|
- Important: Unlike `SynchronousDataTransaction.commitAndWait()`, this method does not wait for observers to be notified of the changes before returning. This results in lower risk for deadlocks, but the updated data may not have been propagated to the `DataStack` after returning.
|
||||||
|
|
||||||
|
- returns: a `SaveResult` containing the success or failure information
|
||||||
|
*/
|
||||||
|
@available(*, deprecated: 4.0.0, message: "Use the new auto-commit method DataStack.perform(synchronous:waitForAllObservers:)")
|
||||||
|
public func commit() -> SaveResult {
|
||||||
|
|
||||||
|
CoreStore.assert(
|
||||||
|
self.transactionQueue.cs_isCurrentExecutionContext(),
|
||||||
|
"Attempted to commit a \(cs_typeName(self)) outside its designated queue."
|
||||||
|
)
|
||||||
|
CoreStore.assert(
|
||||||
|
!self.isCommitted,
|
||||||
|
"Attempted to commit a \(cs_typeName(self)) more than once."
|
||||||
|
)
|
||||||
|
switch self.autoCommit(waitForMerge: false) {
|
||||||
|
|
||||||
|
case (let hasChanges, nil): return SaveResult(hasChanges: hasChanges)
|
||||||
|
case (_, let error?): return SaveResult(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Begins a child transaction synchronously where `NSManagedObject` creates, updates, and deletes can be made. This method should not be used after the `commit()` 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 `SaveResult` value indicating success or failure, or `nil` if the transaction was not comitted synchronously
|
||||||
|
*/
|
||||||
|
@available(*, deprecated: 4.0.0, message: "Secondary tasks spawned from AsynchronousDataTransactions and SynchronousDataTransactions are no longer supported. ")
|
||||||
|
@discardableResult
|
||||||
|
public func beginSynchronous(_ closure: @escaping (_ transaction: SynchronousDataTransaction) -> Void) -> SaveResult? {
|
||||||
|
|
||||||
|
CoreStore.assert(
|
||||||
|
self.transactionQueue.cs_isCurrentExecutionContext(),
|
||||||
|
"Attempted to begin a child transaction from a \(cs_typeName(self)) outside its designated queue."
|
||||||
|
)
|
||||||
|
CoreStore.assert(
|
||||||
|
!self.isCommitted,
|
||||||
|
"Attempted to begin a child transaction from an already committed \(cs_typeName(self))."
|
||||||
|
)
|
||||||
|
let childTransaction = SynchronousDataTransaction(
|
||||||
|
mainContext: self.context,
|
||||||
|
queue: self.childTransactionQueue
|
||||||
|
)
|
||||||
|
childTransaction.transactionQueue.cs_sync {
|
||||||
|
|
||||||
|
closure(childTransaction)
|
||||||
|
|
||||||
|
if !childTransaction.isCommitted && childTransaction.hasChanges {
|
||||||
|
|
||||||
|
CoreStore.log(
|
||||||
|
.warning,
|
||||||
|
message: "The closure for the \(cs_typeName(childTransaction)) completed without being committed. All changes made within the transaction were discarded."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch childTransaction.result {
|
||||||
|
|
||||||
|
case nil: return nil
|
||||||
|
case (let hasChanges, nil)?: return SaveResult(hasChanges: hasChanges)
|
||||||
|
case (_, let error?)?: return SaveResult(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,58 +0,0 @@
|
|||||||
//
|
|
||||||
// TransactionResult.swift
|
|
||||||
// CoreStore
|
|
||||||
//
|
|
||||||
// Copyright © 2017 John Rommel Estropia
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in all
|
|
||||||
// copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
// SOFTWARE.
|
|
||||||
//
|
|
||||||
|
|
||||||
import Foundation
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: - TransactionResult
|
|
||||||
|
|
||||||
public enum TransactionResult<T> {
|
|
||||||
|
|
||||||
case success(T)
|
|
||||||
|
|
||||||
case failure(CoreStoreError)
|
|
||||||
|
|
||||||
public var boolValue: Bool {
|
|
||||||
|
|
||||||
switch self {
|
|
||||||
|
|
||||||
case .success: return true
|
|
||||||
case .failure: return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// MARK: Internal
|
|
||||||
|
|
||||||
internal init(userInfo: T) {
|
|
||||||
|
|
||||||
self = .success(userInfo)
|
|
||||||
}
|
|
||||||
|
|
||||||
internal init(error: CoreStoreError) {
|
|
||||||
|
|
||||||
self = .failure(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -34,30 +34,33 @@ import CoreData
|
|||||||
*/
|
*/
|
||||||
public final class UnsafeDataTransaction: BaseDataTransaction {
|
public final class UnsafeDataTransaction: BaseDataTransaction {
|
||||||
|
|
||||||
|
// MARK: -
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Saves the transaction changes asynchronously. For an `UnsafeDataTransaction`, multiple commits are allowed, although it is the developer's responsibility to ensure a reasonable leeway to prevent blocking the main thread.
|
Saves the transaction changes asynchronously. For an `UnsafeDataTransaction`, 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 `SaveResult` argument of the block.
|
- parameter completion: the block executed after the save completes. Success or failure is reported by the optional `error` argument of the block.
|
||||||
*/
|
*/
|
||||||
public func commit(_ completion: @escaping (_ result: SaveResult) -> Void) {
|
public func commit(_ completion: @escaping (_ error: CoreStoreError?) -> Void) {
|
||||||
|
|
||||||
self.context.saveAsynchronouslyWithCompletion { (result) -> Void in
|
self.context.saveAsynchronouslyWithCompletion { (_, error) in
|
||||||
|
|
||||||
self.result = result
|
completion(error)
|
||||||
completion(result)
|
withExtendedLifetime(self, {})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Saves the transaction changes and waits for completion synchronously. For an `UnsafeDataTransaction`, multiple commits are allowed, although it is the developer's responsibility to ensure a reasonable leeway to prevent blocking the main thread.
|
Saves the transaction changes and waits for completion synchronously. For an `UnsafeDataTransaction`, multiple commits are allowed, although it is the developer's responsibility to ensure a reasonable leeway to prevent blocking the main thread.
|
||||||
|
|
||||||
- returns: a `SaveResult` containing the success or failure information
|
- throws: a `CoreStoreError` value indicating the failure.
|
||||||
*/
|
*/
|
||||||
public func commitAndWait() -> SaveResult {
|
public func commitAndWait() throws {
|
||||||
|
|
||||||
let result = self.context.saveSynchronously(waitForMerge: true)
|
if case (_, let error?) = self.context.saveSynchronously(waitForMerge: true) {
|
||||||
self.result = result
|
|
||||||
return result
|
throw error
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -142,13 +145,4 @@ public final class UnsafeDataTransaction: BaseDataTransaction {
|
|||||||
|
|
||||||
super.init(mainContext: mainContext, queue: queue, supportsUndo: supportsUndo, bypassesQueueing: true)
|
super.init(mainContext: mainContext, queue: queue, supportsUndo: supportsUndo, bypassesQueueing: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: Obsolete
|
|
||||||
|
|
||||||
@available(*, obsoleted: 3.0.0, message: "Transaction contexts are now exposed through the FetchableSource and QueryableSource protocols.", renamed: "internalContext()")
|
|
||||||
public var internalContext: NSManagedObjectContext {
|
|
||||||
|
|
||||||
fatalError()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user