iOS fetching from managed object context before saved - ios

If I add entities to a moc and I execute a fetch request on that moc before its document gets a chance to save, will my fetch contain the newly added entities? (I'm unsure how to test this out because of the auto-save feature)

I guess you're using UIDocument when you say 'auto-saving'. If you aren't, then there is no 'auto-saving' (except when using Apple template code and the app delegate saves before termination).
When you create the fetch request, you can choose whether it should include unsaved items using the includesPendingChanges property. It defaults to YES so by default you will see unsaved items in the results.

Related

CoreData refreshAllObjects() does not refresh all objects

We have three separate apps which are in same App Group and access the same CoreData store. Problem is that when I change something in item in NSOrderedSet from relationship in managed object, save go to another app where refresh is performed, changed data are not there.
We are using NSPersistentContainer and only one context in each app, container.newBackgroundContext() saved to property in singleton. For each app when app goes to BG save() is performed on that context and when app goes to FG refreshAllObjects() is called on the context.
When I change some basic attribute in managed object it is changed properly in another app. But when I change some property in item from NSSet which is a relationship on managed object this change is not visible in another app.
While I was debugging I tried to call fetch but it also provides only old data. Only when I called context.reset() and then fetch again it returns valid new data.
Problem is that I cannot use reset on whole context because I will lose all registered objects in app.
Is this valid behavior or bug that referenced objects changes are not applied when refreshAllObjects() is used?
Is there any way how to force fetch request to get data directly from the database and not cached one from context?
I found one solution to my problem. I was able to force fetch to fetch directly from persistence (not from context) by setting shouldRefreshRefetchedObjects property of NSFetchRequest to true.
I was not able to find a solution to just refresh already fetched objects - but this way I was able to get fresh data using new fetch at least.

Coredata safe clear subEntities

I want to ask for a safe way to clear subEntities in coredata.
I have my a many-to-many relationship like this: Product *<->* Product. Therefore, I've got to create a subEntity to hold some special values between (sortPosition, groupName.....).
So it's like this: Product *<->1 ProductSubEntity 1<->*Product.
When I download products from server's API, the easiest way to update correctly correspond to the server's result is:
Remove all child relationship ([self removeProductSubEntities:self.subEntities]).
Add sub from server's result.
Result: There'd be a lot of subEntity in coredata (which won't hold relationship to any product), and this might take storage/memory/cpu when CRUD (I think?). But I can't actual delete the subEntity (in case it's being hold reference to as an viewController's Object somewhere, and it might cause crash: access to a deleted object).
QUESTION:
How can I clear those sub entities (might occur sometimes) if:
No relationship to any product.
No actual reference from anywhere (any viewControllers or objects)???
P/S: I'm thinking of implement a batch delete when terminate app. Could that be consider a safe solution?
I don't consider this to be a datastore issue, rather a UI update issue. You should delete the objects from the datastore when you don't need them any more and you should update the UI accordingly.
1 thing you didn't mention is re-use. It's possible that your download may be an update to an existing item, which you could find and update, then life is easy all round. Arguably everything below still applies in this case though as your UI might not update to reflect changes and you may need to refresh the managed object.
For the UI update it's generally wise to observe the datastore for changes, usually with an NSFetchedResultsController. If you're doing this then your UI would automatically update itself with the changes.
If you're explicitly passing entity instances around then you should have some way to trigger an update explicitly, and exactly how that works depends on your UI. Generally speaking you'd be doing something like posting a UINotification to tell the system that the datastore changed and they need to re-validate their data objects. For the UI you shouldn't be showing now-dead objects to the user, and in your question where you talk about not deleting to avoid crashes, it's probably worse to allow the user to update invalid objects and just quietly not telling them that their updates won't be saved. When the notification is received you may want to pop a (some) controller(s) off the stack, or re-query the datastore for the new data to be displayed.
If for some reason you don't want to do the above, then yes, you can query for all of the entities with a nil relationship and then batch delete them. This should be done on a background thread just like data loading and I'd recommend doing it on app load instead of close (because you won't have so many view controllers loaded and the ones that are should all have only valid references now...).

Updating NSManagedObjects in a "display" MOC when they're changed in "scratchpad" MOC

Let's say that I have a display MOC that is used to display address book contacts that are fetched from a web service. Elsewhere in the app I have a search feature that searches the web service given a query entered by the user, and I fetch and store those objects in a scratchpad MOC so that it doesn't "pollute" the display fed by the display MOC.
Now let's say the user modifies a contact in the scratchpad MOC. I'd like to synchronize these changes to any equivalent object in the display MOC, if they exist. I don't want the changed object to be added to the display MOC if it isn't already there, and I'd like the change to work the other way too (say if the user changes a contact in the display MOC, it should change in the scratchpad MOC, but only if an equivalent object already exists there). I don't want either MOCs to have objects added to them as a result of an object update. Making the scratchpad MOC a child of the display MOC sounds like the wrong solution.
What is the best pattern to ensure that equivalent objects in different MOCs stay in sync without changing the complement of objects in any other MOC?
This is the purpose of NSManagedObjectContextDidSaveNotification. Whenever a context saves changes, this notification is automatically posted, along with information about what changed. Observe this notification, and use the mergeChangesFromContextDidSaveNotification: method to take changes saved on one context and merge them into another one.

Concurrent changes to NSManagedObjectContext - how and when to save

My app sometimes inserts objects into the managed object context that are not meant to necessarily be saved. For example, when I launch an 'add entity' modal, I create a managed object and assign it to the modal. If the user saves from that modal, I save the context. If he cancels, I delete the object and no save is necessary.
I have now introduced an 'import' feature that switches to my app (using a URL scheme) and adds an entity. Because one of these modals might be open, it is not safe to save the context at this point. The transient object created for the modal will be saved, even if the user cancels, and there is no guarantee that the deletion (from the cancel operation) will be saved later - the user might quit the app.
Similarly, I can't simply save whenever my app quits. If the modal is open at that point, the temporary object will be incorrectly saved.
I am looking for a strategy to handle this architecture. I am considering some 'flagging' solution that allows me to identify the imported entities. When the user user quits the app, I will check if there are any unsaved changes to the context. If so, I will filter out everything except the imported entities, and then save. I have no idea if this is possible (selective saving) or a good idea.
Kevin and Andrew's comments (and the linked article) were enough to get me going. I got some follow-up advice in this question.
In summary, I am using a child context to create the transient object, and then merging it into the main context. In effect, I only need the temporary context as place to insert the object - if it was possible, for example, to create it outside of an insert message, I could do so and then insert it straight into the main context on confirmation.

Getting Permanent ManagedObjectIDs for Use with UILocalNotifications

I am looking for some advice.
I am using CoreData with NSFetchedResultsController to track changes in the data model. When the data model changes, I use the fetchedResultsController notification to check to see if any UILocalNotifications needs to be created, deleted, or updated.
To correlate the CoreData items with UILocalNotifications items, I add an ID into each UILocalNotification. Since UILocalNotifications can last past the execution of the app, I an using the objectID [t.objectID URIRepresentation] as the key.
Ok, so this mostly works, but the problem I have is that when I create a new object and save it, I get a call back in the NSFetchedResultsController that the item has been created WHILE the objectID is still temporary. The next time I hear about that object, the objectID is now permanent and it does not correlate with the original (temporary) ID.
Any suggestions on how to tackle this? What other ID could I use? How do I get a notification that has a permanent ID at the call to NSFetchedResultsController?
A permanent NSManagedObjectID identifies a managed object as residing in a particular persistent store. Therefore, an objectID can't be permanent until the object is saved to a store.
You can use:
[NSManagedObjectContext obtainPermanentIDsForObjects:error:]
…to force IDs to permanent but the method does have side effect similar to a save e.g. empty required properties can generate errors.
Of course, the simplest solution is to just save the managed objects before you get their objectIDs. If you want any external object to refer to them, you need to do that anyway.

Resources