CoreData refreshAllObjects() does not refresh all objects - ios

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.

Related

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...).

RESTkit, CoreData: process object right before trasferring it to CoreData

I have a problem.
I have iOS client app that has to allow multiple users to log in and store their data locally.
Data is synchronized with RESTful service, and the latest snapshot along with user's changes should be stored locally for all users.
Previously this app was implemented with SQLlite as data storage engine.
Now I would like to migrate to CoreData.
What do I have:
server returns me entities for current user. User ID is not sent, as the user authorizes and gets their session;
I know who is logged in an should store all data for this particular user. In order to do that I need to say CoreData to store the object for the user with ID=12345.
The problem is:
I have to tell CoreData to store the particular object associated with particular user's ID.
I need a way to somehow alter the object mapped with RESTkit - setting proper ID field for it.
This task was straight and simple with SQLlite but looks problematic with CoreData.
I am still thinking that I don't know something about CoreData asking you to help me with clarifications or useful links.
There isn't a good way to do it.
Hacky, you could add the id as a parameter in the request so you can map it back again (requires RestKit dev branch at time of writing).
Non-hacky is to update and re-save the objects returned in the mapping result.
Alternatively you could use one operation to download the JSON, then mutate it, then run another operation to map it.

iOS fetching from managed object context before saved

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.

NSManagedObject delete not working properly

I am deleting a NSManagedObject using the statement
[managedObjectContext deleteObject:obj];
And after that am storing the changes to that persistent store. And when I tried to view my actual table using some database viewer, I could see the object still there in the table. I was confused and I made a refresh call after deletion as below (just before saving into persistent store).
[managedObjectContext refreshObject:obj mergeChanges:YES];
And when I tried to view the table now, I couldn't see the object. It's working now, but I am confused because of 2 reasons.
1: I am deleting many objects in many other places, and am not making a refresh every where, though am saving into the persistent store.
2: I don't understand the concept of refreshing an object that was already deleted.
Can any one help me out? Thanks in advance!
it is not easy to answer without a little bit more context.
That said, if you delete a managed object, fetchedResultsController won't be updated unless they were created on the same managedobjectContext. In other words two database fetch if issued from two different managed context will have an out of sync view of the database state.
I would advise you to check if this isn't the case.
Also, you shouldn't have to perform a refresh - except in very specific cases - NSFetchresultController is notified about the database changes, provided you implemented the NSFetchedResultsControllerDelegate protocol.

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