Originally created by @ruslanskorb on GitHub (Jun 15, 2016).
Hi John,
I have noticed that if you add the argument -com.apple.CoreData.ConcurrencyDebug 1 to Arguments Passed On Launch and try to invoke the code I provided below NSManagedObjectContext will throw the exception +[NSManagedObjectContext __Multithreading_Violation_AllThatIsLeftToUsIsHonor__].
Apparently, this is because you are creating an object directly in your own transaction queue, not using neither the performBlockAndWait(_:) method nor the performBlock(_:) method of the managed object context.
To fix it you can update the performAndWait() method of SynchronousDataTransaction with the following code:
internalfuncperformAndWait()->SaveResult?{self.transactionQueue.sync{self.context.performBlockAndWait({self.closure(transaction:self)})if!self.isCommitted&&self.hasChanges{CoreStore.log(.Warning,message:"The closure for the \(typeName(self)) completed without being committed. All changes made within the transaction were discarded.")}}returnself.result}
And commit(_:), perform() and performAndWait() methods of AsynchronousDataTransaction with the following code:
publicfunccommit(completion:(result:SaveResult)->Void={_in}){CoreStore.assert(self.transactionQueue.isCurrentExecutionContext(),"Attempted to commit a \(typeName(self)) outside its designated queue.")CoreStore.assert(!self.isCommitted,"Attempted to commit a \(typeName(self)) more than once.")self.isCommitted=trueself.context.saveAsynchronouslyWithCompletion{(result)->Voidinself.result=resultcompletion(result:result)}}
internalfuncperform(){self.transactionQueue.async{self.context.performBlock({self.closure(transaction:self)if!self.isCommitted&&self.hasChanges{CoreStore.log(.Warning,message:"The closure for the \(typeName(self)) completed without being committed. All changes made within the transaction were discarded.")}})}}
internalfuncperformAndWait()->SaveResult?{self.transactionQueue.sync{self.context.performBlockAndWait({self.closure(transaction:self)})if!self.isCommitted&&self.hasChanges{CoreStore.log(.Warning,message:"The closure for the \(typeName(self)) completed without being committed. All changes made within the transaction were discarded.")}}returnself.result}
Originally created by @ruslanskorb on GitHub (Jun 15, 2016).
Hi John,
I have noticed that if you add the argument `-com.apple.CoreData.ConcurrencyDebug 1` to **Arguments Passed On Launch** and try to invoke the code I provided below `NSManagedObjectContext` will throw the exception `+[NSManagedObjectContext __Multithreading_Violation_AllThatIsLeftToUsIsHonor__]`.
``` swift
CoreStore.beginSynchronous { (transaction) -> Void in
let place = transaction.create(Into(Place))
// ...
}
```
Apparently, this is because you are creating an object directly in your own transaction queue, not using neither the `performBlockAndWait(_:)` method nor the `performBlock(_:)` method of the managed object context.
To fix it you can update the `performAndWait()` method of `SynchronousDataTransaction` with the following code:
``` swift
internal func performAndWait() -> SaveResult? {
self.transactionQueue.sync {
self.context.performBlockAndWait({
self.closure(transaction: self)
})
if !self.isCommitted && self.hasChanges {
CoreStore.log(
.Warning,
message: "The closure for the \(typeName(self)) completed without being committed. All changes made within the transaction were discarded."
)
}
}
return self.result
}
```
And `commit(_:)`, `perform()` and `performAndWait()` methods of `AsynchronousDataTransaction` with the following code:
``` swift
public func commit(completion: (result: SaveResult) -> Void = { _ in }) {
CoreStore.assert(
self.transactionQueue.isCurrentExecutionContext(),
"Attempted to commit a \(typeName(self)) outside its designated queue."
)
CoreStore.assert(
!self.isCommitted,
"Attempted to commit a \(typeName(self)) more than once."
)
self.isCommitted = true
self.context.saveAsynchronouslyWithCompletion { (result) -> Void in
self.result = result
completion(result: result)
}
}
```
``` swift
internal func perform() {
self.transactionQueue.async {
self.context.performBlock({
self.closure(transaction: self)
if !self.isCommitted && self.hasChanges {
CoreStore.log(
.Warning,
message: "The closure for the \(typeName(self)) completed without being committed. All changes made within the transaction were discarded."
)
}
})
}
}
```
``` swift
internal func performAndWait() -> SaveResult? {
self.transactionQueue.sync {
self.context.performBlockAndWait({
self.closure(transaction: self)
})
if !self.isCommitted && self.hasChanges {
CoreStore.log(
.Warning,
message: "The closure for the \(typeName(self)) completed without being committed. All changes made within the transaction were discarded."
)
}
}
return self.result
}
```
As I mentioned in those threads, you don't need to turn the com.apple.CoreData.ConcurrencyDebug argument on because CoreStore is strict with its own queueing mechanism.
@JohnEstropia commented on GitHub (Jun 15, 2016):
This has been reported [here](https://github.com/JohnEstropia/CoreStore/issues/28) and [here](https://github.com/JohnEstropia/CoreStore/issues/60).
As I mentioned in those threads, you don't need to turn the `com.apple.CoreData.ConcurrencyDebug` argument on because CoreStore is strict with its own queueing mechanism.
@JohnEstropia Sorry that I did not look for it in the already closed tasks.
But can you please explain why you don't want to use performBlock(_:) / performBlockAndWait(_:) in your own perform() and performAndWait() methods that will allow to turn the com.apple.CoreData.ConcurrencyDebug argument on?
As they say Better safe than sorry :-]
@ruslanskorb commented on GitHub (Jun 15, 2016):
@JohnEstropia Sorry that I did not look for it in the already closed tasks.
But can you please explain why you don't want to use `performBlock(_:)` / `performBlockAndWait(_:)` in your own `perform()` and `performAndWait()` methods that will allow to turn the `com.apple.CoreData.ConcurrencyDebug` argument on?
As they say **Better safe than sorry** :-]
CoreStore queues transactions serially, so it manages transactions through children contexts in such a way that they will never interleave (with the exception of UnsafeDataTransactions).
In effect, there really is no point in using performBlock() because there is no other context to protect against. In fact, enclosing performBlock() from within the transaction queue actually introduces opportunities to deadlock. The context will be bound within multiple queues, and any attempt to cross another queue (e.g. fetching objects, which taps the parent context and/or the persistent store) becomes a deadlock risk.
@JohnEstropia commented on GitHub (Jun 15, 2016):
CoreStore queues transactions serially, so it manages transactions through children contexts in such a way that they will never interleave (with the exception of `UnsafeDataTransaction`s).
In effect, there really is no point in using `performBlock()` because there is no other context to protect against. In fact, enclosing `performBlock()` from within the transaction queue actually introduces opportunities to deadlock. The context will be bound within multiple queues, and any attempt to cross another queue (e.g. fetching objects, which taps the parent context and/or the persistent store) becomes a deadlock risk.
@JohnEstropia Thanks for the explanation and special thanks for the library! 👍
One thing I would like to suggest is to add a small note about com.apple.CoreData.ConcurrencyDebug in the README.
And the issue can be closed :-]
@ruslanskorb commented on GitHub (Jun 15, 2016):
@JohnEstropia Thanks for the explanation and special thanks for the library! :thumbsup:
One thing I would like to suggest is to add a small note about `com.apple.CoreData.ConcurrencyDebug` in the README.
And the issue can be closed :-]
You're right, this should be explained in the documentation. I'll try to print a warning log when com.apple.CoreData.ConcurrencyDebug is turned on as well.
Thanks for the feedback! Really appreciate it :)
@JohnEstropia commented on GitHub (Jun 16, 2016):
You're right, this should be explained in the documentation. I'll try to print a warning log when `com.apple.CoreData.ConcurrencyDebug` is turned on as well.
Thanks for the feedback! Really appreciate it :)
I'll add a note in the Installation section of CoreStore 2.0's README regarding com.apple.CoreData.ConcurrencyDebug. (corestore2_develop branch)
@JohnEstropia commented on GitHub (Jun 16, 2016):
I'll add a note in the `Installation` section of CoreStore 2.0's README regarding `com.apple.CoreData.ConcurrencyDebug`. (corestore2_develop branch)
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Originally created by @ruslanskorb on GitHub (Jun 15, 2016).
Hi John,
I have noticed that if you add the argument
-com.apple.CoreData.ConcurrencyDebug 1to Arguments Passed On Launch and try to invoke the code I provided belowNSManagedObjectContextwill throw the exception+[NSManagedObjectContext __Multithreading_Violation_AllThatIsLeftToUsIsHonor__].Apparently, this is because you are creating an object directly in your own transaction queue, not using neither the
performBlockAndWait(_:)method nor theperformBlock(_:)method of the managed object context.To fix it you can update the
performAndWait()method ofSynchronousDataTransactionwith the following code:And
commit(_:),perform()andperformAndWait()methods ofAsynchronousDataTransactionwith the following code:@ruslanskorb commented on GitHub (Jun 15, 2016):
If I'm right about that I'll be happy to create a PR :-]
@JohnEstropia commented on GitHub (Jun 15, 2016):
This has been reported here and here.
As I mentioned in those threads, you don't need to turn the
com.apple.CoreData.ConcurrencyDebugargument on because CoreStore is strict with its own queueing mechanism.@ruslanskorb commented on GitHub (Jun 15, 2016):
@JohnEstropia Sorry that I did not look for it in the already closed tasks.
But can you please explain why you don't want to use
performBlock(_:)/performBlockAndWait(_:)in your ownperform()andperformAndWait()methods that will allow to turn thecom.apple.CoreData.ConcurrencyDebugargument on?As they say Better safe than sorry :-]
@JohnEstropia commented on GitHub (Jun 15, 2016):
CoreStore queues transactions serially, so it manages transactions through children contexts in such a way that they will never interleave (with the exception of
UnsafeDataTransactions).In effect, there really is no point in using
performBlock()because there is no other context to protect against. In fact, enclosingperformBlock()from within the transaction queue actually introduces opportunities to deadlock. The context will be bound within multiple queues, and any attempt to cross another queue (e.g. fetching objects, which taps the parent context and/or the persistent store) becomes a deadlock risk.@ruslanskorb commented on GitHub (Jun 15, 2016):
@JohnEstropia Thanks for the explanation and special thanks for the library! 👍
One thing I would like to suggest is to add a small note about
com.apple.CoreData.ConcurrencyDebugin the README.And the issue can be closed :-]
@JohnEstropia commented on GitHub (Jun 16, 2016):
You're right, this should be explained in the documentation. I'll try to print a warning log when
com.apple.CoreData.ConcurrencyDebugis turned on as well.Thanks for the feedback! Really appreciate it :)
@JohnEstropia commented on GitHub (Jun 16, 2016):
I'll add a note in the
Installationsection of CoreStore 2.0's README regardingcom.apple.CoreData.ConcurrencyDebug. (corestore2_develop branch)@ruslanskorb commented on GitHub (Jun 16, 2016):
@JohnEstropia 👍