How can I make update with mainContext? #50

Closed
opened 2025-12-29 15:23:06 +01:00 by adam · 6 comments
Owner

Originally created by @Koshub on GitHub (Apr 24, 2016).

Due the CoreData cache sometimes I have to call refreshAndMerge to refetch objects from persistaten store. Do we have an API to update objects directly with main context, not with child of main?

Originally created by @Koshub on GitHub (Apr 24, 2016). Due the CoreData cache sometimes I have to call `refreshAndMerge` to refetch objects from persistaten store. Do we have an API to update objects directly with main context, not with child of main?
adam added the question label 2025-12-29 15:23:06 +01:00
adam closed this issue 2025-12-29 15:23:06 +01:00
Author
Owner

@JohnEstropia commented on GitHub (Apr 26, 2016):

CoreStore's main context is strictly readonly. This was designed for performance and data integrity.

I suggest you use ListMonitor or ObjectMonitor; objects managed by NSFetchedResultsController automatically gets refreshed.

@JohnEstropia commented on GitHub (Apr 26, 2016): CoreStore's main context is strictly readonly. This was designed for performance and data integrity. I suggest you use ListMonitor or ObjectMonitor; objects managed by NSFetchedResultsController automatically gets refreshed.
Author
Owner

@Koshub commented on GitHub (Apr 26, 2016):

Not sure your suggestion will resolve the issue. For example, I update Project entity and then after that immediately I try to load entity (FeedItem) with one-to-one relation of that Project and I receive unupdated object. Here is my code with comments where I have to put refresh calls:

    func updateProject(project: Project) {
        CoreStore.beginSynchronous { (transaction) -> Void in
            if let projectModel = transaction.fetchOne(From(CDProject), Where("identifier == %@", project.identifier)) {
                projectModel.updateWithProject(project)
            }
            transaction.commitAndWait()
        }
    }

    func feedItemWithId(id: String) -> FeedItem? {
        if let feedItemModel = CoreStore.fetchOne(From(CDFeedItem), Where("identifier == %@", id)) {
            // Need to call here feedItemModel.refreshAndMerge()
            var item = FeedItemMapper.fromCDFeedItem(feedItemModel)
            if let projectModel = feedItemModel.project {
                // Need to call here projectModel.refreshAndMerge()
                item.project = ProjectMapper.fromCDProject(project: projectModel)
            }
            return item
        } else {
            return nil
        }
    }

@Koshub commented on GitHub (Apr 26, 2016): Not sure your suggestion will resolve the issue. For example, I update `Project` entity and then after that immediately I try to load entity (`FeedItem`) with one-to-one relation of that `Project` and I receive unupdated object. Here is my code with comments where I have to put refresh calls: ``` swift func updateProject(project: Project) { CoreStore.beginSynchronous { (transaction) -> Void in if let projectModel = transaction.fetchOne(From(CDProject), Where("identifier == %@", project.identifier)) { projectModel.updateWithProject(project) } transaction.commitAndWait() } } func feedItemWithId(id: String) -> FeedItem? { if let feedItemModel = CoreStore.fetchOne(From(CDFeedItem), Where("identifier == %@", id)) { // Need to call here feedItemModel.refreshAndMerge() var item = FeedItemMapper.fromCDFeedItem(feedItemModel) if let projectModel = feedItemModel.project { // Need to call here projectModel.refreshAndMerge() item.project = ProjectMapper.fromCDProject(project: projectModel) } return item } else { return nil } } ```
Author
Owner

@JohnEstropia commented on GitHub (Apr 27, 2016):

This behaviour is NSManagedObject's caching mechanism and beyond CoreStore's control
(and thus the existence of refreshAndMerge() and refreshAsFault() methods.)

Like I mentioned, NSFetchedResultsController does this for free, but with the cost of constantly processing its objects. Otherwise, calling refreshAndMerge() like how you did is correct.

For the record, we can extend CoreStore to do this automatically all the time, but the performance cost may not be worth it.

@JohnEstropia commented on GitHub (Apr 27, 2016): This behaviour is `NSManagedObject`'s caching mechanism and beyond CoreStore's control (and thus the existence of `refreshAndMerge()` and `refreshAsFault()` methods.) Like I mentioned, `NSFetchedResultsController` does this for free, but with the cost of constantly processing its objects. Otherwise, calling `refreshAndMerge()` like how you did is correct. For the record, we can extend CoreStore to do this automatically all the time, but the performance cost may not be worth it.
Author
Owner

@Koshub commented on GitHub (Apr 27, 2016):

Thank you for response. I can't use NSFetchedResultsController. I think if I have the API to update objects with main context, not child, I will fetch always correct objects. I understand that you need child context to implement amazing transactions logic. Also I understand that I can use main context through fetched managed objects. Although I think you have the other reasons to make main context readonly I will be very happy if you try to provide some API to interact directly with main context. Thank you for your time and excellent Pod library.

@Koshub commented on GitHub (Apr 27, 2016): Thank you for response. I can't use `NSFetchedResultsController`. I think if I have the API to update objects with main context, not child, I will fetch always correct objects. I understand that you need child context to implement amazing transactions logic. Also I understand that I can use main context through fetched managed objects. Although I think you have the other reasons to make main context readonly I will be very happy if you try to provide some API to interact directly with main context. Thank you for your time and excellent Pod library.
Author
Owner

@JohnEstropia commented on GitHub (Apr 28, 2016):

Allowing updates to the main context objects means two things:

  1. You are bypass all transactions, which breaks the deterministic order of updates.
  2. You introduce a "non-saved" state in the main context. This is bad because 1) the main context's children (i.e. in transactions) will see a different snapshot of objects, and 2) you may be showing the User something that is not actually in the disk file yet.
  3. CoreData's processing gets loaded to the main queue (which is the main context's queue). This introduces UI lags and the risk of deadlock.

So sorry, I prefer the main context the way it is. IMO it's a small price to pay for all the safety and guarantees that CoreStore offers.

@JohnEstropia commented on GitHub (Apr 28, 2016): Allowing updates to the main context objects means two things: 1. You are bypass all transactions, which breaks the deterministic order of updates. 2. You introduce a "non-saved" state in the main context. This is bad because 1) the main context's children (i.e. in transactions) will see a different snapshot of objects, and 2) you may be showing the User something that is not actually in the disk file yet. 3. CoreData's processing gets loaded to the main queue (which is the main context's queue). This introduces UI lags and the risk of deadlock. So sorry, I prefer the main context the way it is. IMO it's a small price to pay for all the safety and guarantees that CoreStore offers.
Author
Owner

@Koshub commented on GitHub (Apr 28, 2016):

I see. I understand all these things. You are right. Thank you.

@Koshub commented on GitHub (Apr 28, 2016): I see. I understand all these things. You are right. Thank you.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/CoreStore#50