NSManagedObjectContext Access #5

Closed
opened 2025-12-29 15:21:53 +01:00 by adam · 8 comments
Owner

Originally created by @mrichtsfeld on GitHub (Jul 24, 2015).

Hi John,

I found you're library a few days ago and it is really nice. I especially like the concept of how managed object contexts interact with each other. The write and read only store are a really great way to properly use CoreData. +1 for that.

I already use it for my new project, but I found one downside and don't know yet how to overcome it. I use a background sync mechanism which is syncing data from a server to all clients via socket connection. Everytime data is received the sync library requests a managed object context where it applies the updates and saves them. Each context is only used once.

That is my situation so far. Since I don't want to make my sync library depending on CoreStore and want to keep a simple and basic NSMangedObjectContexts for that matter. You wrap up all contexts in your library to enforce correct usage, so unless I misunderstood something I'm pretty lost on how to use it with my sync mechanism.

I hope we can find a solution for this and I would like to contribute the solution to your code.

Thanks in advance.

Originally created by @mrichtsfeld on GitHub (Jul 24, 2015). Hi John, I found you're library a few days ago and it is really nice. I especially like the concept of how managed object contexts interact with each other. The write and read only store are a really great way to properly use CoreData. +1 for that. I already use it for my new project, but I found one downside and don't know yet how to overcome it. I use a background sync mechanism which is syncing data from a server to all clients via socket connection. Everytime data is received the sync library requests a managed object context where it applies the updates and saves them. Each context is only used once. That is my situation so far. Since I don't want to make my sync library depending on CoreStore and want to keep a simple and basic NSMangedObjectContexts for that matter. You wrap up all contexts in your library to enforce correct usage, so unless I misunderstood something I'm pretty lost on how to use it with my sync mechanism. I hope we can find a solution for this and I would like to contribute the solution to your code. Thanks in advance.
adam added the enhancementin progress labels 2025-12-29 15:21:53 +01:00
adam closed this issue 2025-12-29 15:21:53 +01:00
Author
Owner

@JohnEstropia commented on GitHub (Jul 25, 2015):

@mrichtsfeld, thanks for the feedback!

I understand your case and I am sure a lot of frameworks out there work with arbitrary NSManagedObjectContexts, but I'm not quite sure how to provide a solution that wont turn the rest of CoreStore to an all-bets-are-off state. Here are some I can think of:

  1. Let the BaseDataTransaction instances expose their child NSManagedObjectContext.
    • Pros: Seems a natural fit for CoreStore.beginDetached(...), as it already bypasses the serialism of transactions and allows arbitrary saves.
    • Cons: The sync library should not just save the context passed to it, but also the context's parentContext and all the ancestor contexts. If it doesn't, the ListObservers and ObjectObservers will never get notified of changes; worse, the changes won't be saved to the persistent store.
  2. Let DataStack expose its root saving NSManagedObjectContext.
    • Pros: Since it's the root context, saved changes will properly propagate to the read-only context and the persistent store.
    • Cons: You have to make sure that absolutely nothing else is writing to this context, including transactions created from CoreStore. If two tasks are working on the root context, they may work on assumptions that the other task may easily break anytime (objects deleted/popping out of nowhere, properties changing unknowingly). Also, if the first task decides to call save(), the second task's partial changes will be saved as well and you run a high risk of validation errors because of missing data, which in turn results in nothing from both tasks being saved.
  3. Provide a closure to DataStack where the root context can be safely updated as a semi-transaction.
    • Pros: The closure will be executed on the same queue as other transactions, so serialism is maintained.
    • Cons: All changes should be done synchronously. If the context is dispatched away from the closure's scope (e.g. calling performBlock() or dispatch_async()), then all the Cons in solution (2) apply.

If it's possible, can you tell me what syncing library you are using? It might help if I consider how other libraries use and abuse their NSManagedObjectContexts.

In any case, all solutions above still requires you to design your app just to work around CoreStore's intricacies, so you may find it easier to just use another Core Data library that allows you to use contexts freely in the first place.

@JohnEstropia commented on GitHub (Jul 25, 2015): @mrichtsfeld, thanks for the feedback! I understand your case and I am sure a lot of frameworks out there work with arbitrary `NSManagedObjectContext`s, but I'm not quite sure how to provide a solution that wont turn the rest of CoreStore to an all-bets-are-off state. Here are some I can think of: 1. Let the `BaseDataTransaction` instances expose their child `NSManagedObjectContext`. - **Pros:** Seems a natural fit for `CoreStore.beginDetached(...)`, as it already bypasses the serialism of transactions and allows arbitrary saves. - **Cons:** The sync library should not just save the context passed to it, but also the context's `parentContext` and all the ancestor contexts. If it doesn't, the `ListObserver`s and `ObjectObserver`s will never get notified of changes; worse, the changes won't be saved to the persistent store. 2. Let `DataStack` expose its root saving `NSManagedObjectContext`. - **Pros:** Since it's the root context, saved changes will properly propagate to the read-only context and the persistent store. - **Cons:** You have to make sure that absolutely nothing else is writing to this context, including transactions created from CoreStore. If two tasks are working on the root context, they may work on assumptions that the other task may easily break anytime (objects deleted/popping out of nowhere, properties changing unknowingly). Also, if the first task decides to call `save()`, the second task's partial changes will be saved as well and you run a high risk of validation errors because of missing data, which in turn results in nothing from both tasks being saved. 3. Provide a closure to `DataStack` where the root context can be safely updated as a semi-transaction. - **Pros:** The closure will be executed on the same queue as other transactions, so serialism is maintained. - **Cons:** All changes should be done synchronously. If the context is dispatched away from the closure's scope (e.g. calling `performBlock()` or `dispatch_async()`), then all the _Cons_ in solution (2) apply. If it's possible, can you tell me what syncing library you are using? It might help if I consider how other libraries use and abuse their `NSManagedObjectContext`s. In any case, all solutions above still requires you to design your app just to work around CoreStore's intricacies, so you may find it easier to just use another Core Data library that allows you to use contexts freely in the first place.
Author
Owner

@mrichtsfeld commented on GitHub (Jul 25, 2015):

@JohnEstropia, thanks for you answer.

I understand your concerns, but maybe we find a solution. Your library is the only one I found in Cocoapods that enforces proper setup and usage of Coredata, that's why I wanna use it and push it so it can be used for even more use cases.

I think only 1 provides a solution. Let's create a separate transaction type derived from the detached transaction which exposes the NSManagedObjectContext and can be used for cases like mine. Then it needs to be ensured that saving is done correctly and all contexts are updated correctly.
In my case I would let the sync library ask for a temporary edit context which is requested on the sync queue. All changes are added and then the context is passed back to my main program still on the sync queue. Then the main program will save it properly by calling .commit() so updates work correctly.
What do you think about this?

For syncing I use two different libraries. For the first project I use Firebase with a completely custom sync. It basically receives changes in real time on a background queue which are save to Coredata.
My second project is pretty new and my business partner and me are currently writing a real time sync library which can sync any sql server database to any client. We make it Open Source as soon as it has received a state in which this makes sense.

@mrichtsfeld commented on GitHub (Jul 25, 2015): @JohnEstropia, thanks for you answer. I understand your concerns, but maybe we find a solution. Your library is the only one I found in Cocoapods that enforces proper setup and usage of Coredata, that's why I wanna use it and push it so it can be used for even more use cases. I think only 1 provides a solution. Let's create a separate transaction type derived from the detached transaction which exposes the `NSManagedObjectContext` and can be used for cases like mine. Then it needs to be ensured that saving is done correctly and all contexts are updated correctly. In my case I would let the sync library ask for a temporary edit context which is requested on the sync queue. All changes are added and then the context is passed back to my main program still on the sync queue. Then the main program will save it properly by calling `.commit()` so updates work correctly. What do you think about this? For syncing I use two different libraries. For the first project I use Firebase with a completely custom sync. It basically receives changes in real time on a background queue which are save to Coredata. My second project is pretty new and my business partner and me are currently writing a real time sync library which can sync any sql server database to any client. We make it Open Source as soon as it has received a state in which this makes sense.
Author
Owner

@JohnEstropia commented on GitHub (Jul 26, 2015):

@mrichtsfeld
Can you check the commit I made here (1c6085ad82) and see if this should be enough for your usage?

I didn't see any need to make another kind of transaction. Since DetachedDataTransaction already provides the flexibility we need we just needed to expose its context (see new internalContext property).

@JohnEstropia commented on GitHub (Jul 26, 2015): @mrichtsfeld Can you check the commit I made here (https://github.com/JohnEstropia/CoreStore/commit/1c6085ad82288711bc20e9c1e3f1a2d890ec1468) and see if this should be enough for your usage? I didn't see any need to make another kind of transaction. Since `DetachedDataTransaction` already provides the flexibility we need we just needed to expose its context (see new `internalContext` property).
Author
Owner

@mrichtsfeld commented on GitHub (Jul 26, 2015):

@JohnEstropia
That looks great, but I'm not 100% confident about the Queue usage. So it is still possible to create a main queue concurrency and a private queue concurrency context, right? As far as I have seen the context determines automatically which type to use based on the queue.
Regarding the internalContext this is exactly what I need, thanks.

Just one question aside. You are using new Swift 2.0 features in your GCDKit so I can only test with xcode 7, correct?

@mrichtsfeld commented on GitHub (Jul 26, 2015): @JohnEstropia That looks great, but I'm not 100% confident about the Queue usage. So it is still possible to create a main queue concurrency and a private queue concurrency context, right? As far as I have seen the context determines automatically which type to use based on the queue. Regarding the `internalContext` this is exactly what I need, thanks. Just one question aside. You are using new Swift 2.0 features in your GCDKit so I can only test with xcode 7, correct?
Author
Owner

@JohnEstropia commented on GitHub (Jul 27, 2015):

@mrichtsfeld
I changed the detached transactions to use private concurrency context so you can use it on any dispatch queue, even the main thread. It was previously set to main queue concurrency which would have caused the main queue to lag if you call performBlock on the context.

CoreStore 1.0.0 is written in Swift 2.0/XCode 7. If you need it for Swift 1.2 you'll need to branch from git tag 0.2.0 and cherrypick the commit above.

@JohnEstropia commented on GitHub (Jul 27, 2015): @mrichtsfeld I changed the detached transactions to use private concurrency context so you can use it on any dispatch queue, even the main thread. It was previously set to main queue concurrency which would have caused the main queue to lag if you call `performBlock` on the context. CoreStore 1.0.0 is written in Swift 2.0/XCode 7. If you need it for Swift 1.2 you'll need to branch from git tag 0.2.0 and cherrypick the commit above.
Author
Owner

@mrichtsfeld commented on GitHub (Jul 27, 2015):

@JohnEstropia
Thanks for clarification regarding the concurrency type and queues.

Regarding Swift 2.0 that is what I assumed and I have already used tag 0.2.0 in my xcode 6 project.

Thanks for the fast extension, this is much appreciated.

@mrichtsfeld commented on GitHub (Jul 27, 2015): @JohnEstropia Thanks for clarification regarding the concurrency type and queues. Regarding Swift 2.0 that is what I assumed and I have already used tag 0.2.0 in my xcode 6 project. Thanks for the fast extension, this is much appreciated.
Author
Owner

@JohnEstropia commented on GitHub (Jul 27, 2015):

I currently have no projects that heavily use the DetachedDataTransaction so if you find any problems just post new issues! I'll close this one for now.

@JohnEstropia commented on GitHub (Jul 27, 2015): I currently have no projects that heavily use the `DetachedDataTransaction` so if you find any problems just post new issues! I'll close this one for now.
Author
Owner

@mrichtsfeld commented on GitHub (Jul 27, 2015):

Ok, great, thanks.

@mrichtsfeld commented on GitHub (Jul 27, 2015): Ok, great, thanks.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/CoreStore#5