I have an application that talks to a remote API using RestKit with an SQLite store for Core Data. When I got to the point of adding server-side searching, I was faced with having to find a way to efficiently display search results. To accomplish this, I used an NSFetchedResultsController that is tied to another in-memory store of the same schema as the SQLite store, and also backed by RestKit. When RestKit searches against the API's search endpoint, it maps the responses back to the in-memory store.
This works really well for what I need, but has now caused another issue. When I get these "transient" objects back from the server, and the user selects one, it needs to be copied into the persistent store at that point (various interactions beyond that point will load additional objects from the server and attempt to tie them back to the original object - which will fail if they're in two different object contexts).
tl;dr
Does anyone have any suggestions on how to copy an entire object (entity and relations) from one core data store to another? Or, is that even necessary? Is there an easier way to accomplish this same task using RestKit?
Would I be better served by changing my search instead, to not use an in-memory store? If so, how should I store these objects?
I wouldn't use the in-memory store. I'd just put the search results into the main store and bypass the issues with copying. I'd then have a purge that ran to clean out the old search results that aren't required any more. You might want to tag search results that need to be kept around for some reason. And you can get RestKit to do the purge automatically when each new search is performed (see "Fetch Request Blocks and Deleting Orphaned Objects" in these docs)
For your other question, about tagging. When you make the search request, the search term is in the URL. If you use RKObjectManager and routing then you can access the metadata that is provided to the mapping to get the search term and store it into the returned objects. Something like:
#"#metadata.routing.parameters.searchTerm": #"searchTerm",
See the metadata docs here.
Related
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.
I'm writing a login sequence for an iOS app and I'm using the following path to request user information:
"profiles/:email" (RKRequestMethodGET)
Unfortunately I also have to use this path to check if a certain e-mail address has already been taken as well.
My question is, how do I prevent RestKit from updating/inserting an Account object into the Managed Object Store when I already have an Entity Response Mapping in place for that path? Is there a way to tell the RK request that is shouldn't do any mapping to the Managed Object Store but still report back to me that a successful mapping has occurred?
Not really.
You could have 2 different RKObjectManager instances, 1 that is used for Core Data and actually updating and managing the users. The other is used without Core Data and just for validation. This allows the 2 different object managers to have different response descriptors.
An alternative would be to add and remove the response descriptors depending on what requests you're making. But, this is messy and potentially error prone.
Can I use this technique, or will it get my app rejected by Apple?
The application starts, downloads some JSON data, and stores it in an array.
A UITableView loads the data from the array.
When the user starts the application again, the application again downloads the JSON data and stores it in the array, and the UITableView again loads the data from the array.
Is this OK, or I should use Core Data to store the data?
Note that some data may change in the JSON, so if I store it using Core Data, it will be difficult for me to track changes and reflect them in Core Data.
or I should use core data to store the data from JSON.
I don't even know what makes to think you'd be obliged to use CoreData if you're using JSON. It's definitely not a must. They are two distinct technologies, with a totally different purpose. For example, using JSON for quick communication to your server is just fine.
PassKit is right, that you should think about what you want the app to do if there's no Internet connection. Do you want the app to crash or just show nothing at all? Probably better, show the user the last known information, perhaps showing them the date and time that it was last refreshed and/or warn them that it might not be current.
To do that, you will want to save the JSON after it's successfully downloaded. You don't need to use Core Data for that (in fact, that's almost certainly overkill), but you probably do want to save it to your Documents folder. You can just save the JSON object to a file using writeToFile. Then, when it tries to retrieve the information from the server at some future date, if it's not found, look for the information in the Documents folder.
I need help understanding how to manage the API for an iPhone application that persists remote objects using CoreData. From my understanding, when the iOS app fetches the remote objects, it loads all the objects at the resource path.
For subsequent requests, I want to reduce overhead by having the web server return only objects that have been updated since the last update time. I perform this by returning objects where updated_at is newer than the last_update time of the request.
RestKit then parses and maps the modified objects to CoreData. Is this implementation the proper way of performing synchronization using RestKit and CoreData or am I missing a layer somewhere in between?
Thanks!
Typically RESTful interfaces should try and head "back to the basics". In your case I recommend using the HTTP Header If-Modified-Since. It is slightly cleaner than passing another parameter because RestKit will handle the HTTP status responses without you doing anything.
Otherwise, your method seems normal. Server synchronization is an enormous problem and there is a lot of literature and methods dealing with it. If you want to do something more complex then a quick web search will turn up a handful of methods, but your approach is what I usually end up doing.
If a user can edit data on your app, then there is the problem of synchronizing modifications made on the device. For this you typically set a object scope "modified" flag and only upload an object if it is modified.
I'm about to write a simple iPhone app that uses Core Data to store local copy of remote data that is fetched via RESTful web service. The data changes (new records being added) quite often. I came across RestKit and I'm wondering if it can do what I need. And what I need is to load all records in the beginning and then periodically download ONLY records that were added since previous check. Obviously there is no mystery about how that can be accomplished even by simply using NSURLConnection, but I hoped RestKit (probably in combination with a proper web service) would do that without me having to write all the synchronization logic. Again the key for me is that only new/changed data is fetched from the server.
I agree - RestKit can do this, we've recently used it to do something similar in a recent project. We used a last-modified-date request header to indicate the last successful 'sync' time, which the server can use to return only the records modified since that date. A http 304 'not modified' status code was used to indicate no change when appropriate.
RestKit also includes a seeding facility, so you know up front the initial data set - you can seed it as the initial database easily, and fetch the updates, even upon first use of the application.
Some information I found useful regarding RestKit & CoreData mapping - https://github.com/RestKit/RestKit/blob/master/Docs/Object%20Mapping.md, and the Google group is a good source as well - https://groups.google.com/group/restkit. Hope this all helps.
First of all: YES
RestKit handles CoreData very well. All you need to do is to provide mapping of your entities and it does the work for you.
For the second thing about selective sync, I really recommend checking StorageRoomApp it is a great, and not so expensive service that does exactly what you need.
They have a very good API that extends RestKit, it is very easy to use and their support is great. Take a look.