I just want to get a few pointers on the best way to architect my first Core Data app, and the main objects and interactions I will require.
The data is stored remotely and I will need to access it via HTTP and it will respond in JSON format. I want to cache this on the device using Core Data. Each day there will be new data on the server, so I need to access this and update the Model accordingly.
Are there any SDK classes I can use to help me with this, or am I going to hand roll it?
I guess I'm looking at a Model Controller that I call to get the data, it will return the core data cached data and maybe make a background call to the web service to get latest data too and then notify the view that there is new data. When I get the data from web service in JSON format - i will need to map this to ManagedObjects an add to my core data context.
Thanks dtuckernet, here is what I did do - gathering info from lots of sources, which I believe is the best solution. Anyone feel free to criticise (constructively)....
I have my Core Data stack in CoreDataStack.h (singleton) - not entirely necessary, but it unclutters my app delegate class.
I have a base CoreDataBackedTableViewController : UITableViewController
Each of my table view screens extends CoreDataBackedTableViewController and have an ivar to a ModelController class.
An example ModelController class has a - (NSFetchedResultsController *) getData method which constructs the NSFetchedResultsController (also keeps a ref to it) and returns it to the view controller which also stores it in CoreDataBackedTableViewController (which listens for updates and edits to the data). Having the ModelController class allows me to encapsulate my data access to potentially have 2 different view controllers use this (iPhone and iPad perhaps)
In getData - i make a call to my backend webservice asynchronously. Using delegates for callbacks
The backend is using SBJSON for parsing and NSHttpConnection and a hand rolled HttpService class.
When the backend returns with data, it calls the delegate on the ModelController which updates core data - and my fetchedResultsController knows about this and automatically updates my interface ! How cool is this bit - not a lot of effort involved on my part. I have to do some detection on whether i've already downloaded the data before or not to avoid duplicates.
Ready to roll this out to the rest of my app....
If anyone wants any clarification on any of the steps, just let me know.
There are a lot of different pieces at play here. Allow me to make some suggestions:
For fetching the data from the server, I would look at ASIHTTPRequest. This is a good solution for managing your HTTP requests (whether you are using JSON, XML, or whatever..). http://allseeing-i.com/ASIHTTPRequest/
For JSON translation, I would look at SBJSON. The site has documentation on how to get started: http://code.google.com/p/json-framework/
For your overall architecture, I would implement a delegate pattern that wraps your service calls. In this delegate, you would handle the translation of the JSON data to actual Objective-C classes before the data gets passed to the rest of the application.
Once the data is parsed and placed into Objective-C objects (and I would have these objects be subclasses of NSManagedObject which ties to your data model directory), I would perform a save.
I would then use an NSNotification to inform the needed views that the data has changed.
You absolutely, definitely want to use RESTKit. This is a direct connection from your RESTful web service to Core Data. Define your data model using Xcode's built-in tool, define a mapping layer for your web service using RESTKit, and let the library do the heavy lifting. It's wonderful.
Related
I'm building an iOS client app to interface with an existing backend architecture. To reduce latency, API calls and payloads, it'd be nice to "cache" model data client-side for faster indexing and then make updates to both client/server sides accordingly as needed.
The current theoretical stack would look something like this:
Server Side >>>>>>>>>>>>>>>>> Client Side
-----------------------------------------
PHP >> JSON >> CORE DATA >> UIKit Objects
NOTE: It's also worth noting that the iOS client, while itself adhering to MVC internally would in essence be a "View" in a larger MVC client-server architecture. Thus, just like one updates the model after a user action or updates the view after a model change, the server would need to sync with a client change and the client would need to sync with a server-side change.
Some Context:
A. Many diverse data structures may be coming over the pipe and would have to be constructed into UIViews dynamically. A schema will likely have to be defined (I'm not sure if there's a "best way" to adhere to a JSON schema client-side other than remembering what the acceptable object structures are). I've realized the need to separate model data pertaining to the creation of custom views ("View" Models) from model data of what will be presented in those views ("Regular" Models).
B. End-users should be able to immediately CRUD (create, read, update, destroy) most data presented in these views (but not CRUD the views themselves). They may later need to view this in a web interface or other context.
C. RestKit looks like a good candidate for getting from the API to JSON to COREDATA. I need to find out if it structurally supports callbacks when client model copies need to be pushed to the server. Perhaps the best way is noting in the client model when a change has occurred and notifying whatever RestKit-based HTTP manager to pass it along to the server.
Ultimate Question:
Can anyone speak to best practices, pitfalls, tips, and frameworks with this type of architecture? (Particularly when it comes to performance and the distribution of work between client and server, but general advice is also much appreciated.)
I've done some work around this, hopefully I can provide some insight.
In regards to A) Yes if you're planning to use CoreData (or RestKit) you'll need to know you schema up front. You'll have no way to map dynamic objects otherwise unless you have some generic object type where you're just stashing the JSON string or something, but this doesn't sound like what you're trying to do since you mention users editing those objects.
B) RestKit will handle pushing to the server for you, but you'll still want some control over this I imagine. We handled it by always saving locally first then pushing up to the server on a successful save. This also enabled us to work when there's no network. You'll just have to handle the edge cases of what happens when the server rejects the update / create / delete your user is performing.
C) RestKit will likely get you 80% of the way there, as it did for us. Just having something to understand REST endpoints and object mapping, and abstracting the HTTP requests was a huge help. In terms of the system understanding changes, we kept a flag on managed objects as to whether the object needed a sync or not. We could fetch based on those flags and push the server up.
One thing with RestKit is that you can have other attributes in your CoreData model that aren't necessarily a part of the JSON schema, but you might need within your app. For instance I already mentioned the flag for knowing whether an object needed sync. We also kept pre-computed fields that we used to search on and some other random pieces of information for determining the order of objects to push up to the server (dependencies).
Hope this helps. If you have more specific questions I might have more answers.
I currently have a MySQL database that I wish to create a web service for.
One of the main purposes of this web service is to be used in an iPhone app. Because of this I would like to used CoreData, as it will make parsing on the iPhone side so much easier. How would I use CoreData to get the data from my MySQL database? Are there any good tutorials around?
To get the data from the server to the iPhone I would recommend JSON.
Then you need to write some code that will turn that JSON into an object that you can put into the CoreData database. You have a couple choices there, but I would recommend providing your own implementations of the NSCoding protocol. The great part about the NSCoding approach is that the object itself defines what it needs to save/restore one time, then you simply do additional implementations one time to support other formats (e.g. XML, JSON, simple serialization).
Here is the tutorial to sbjson, a JSON parser on Objective-C: sbjson project
Accessing Web Services inside an iPhone app is a matter for which I did not find a clear, beautiful solution yet. I'm not talking about how to send queries or parse responses here, but about a "big picture" answer.
Disregarding the server-side technology, how do/would you plug your Model objects to your Web Service ? How do you design your proxy objects ? How do you cache your resources ?
If your web service happens to be a Ruby on Rails application, then Objective Resource is a great tool: http://iphoneonrails.com/.
If not, then what I tend to do is use ASIHTTPRequest (http://allseeing-i.com/ASIHTTPRequest/) which provides a nice network layer. Depending on the API, you might use ASI objects directly, or else you can subclass an existing ASI class if you want to add per-request functionality (such as authentication or response parsing).
You usually want to run requests in the background, so that the UI isn't blocked while waiting for the request to finish. You can always go the background thread route, but a nice "Objective C" style approach that ASIHTTPRequest provides is to instead provide a delegate which is called when the request finishes (see also "Creating an asynchronous request" at http://allseeing-i.com/ASIHTTPRequest/How-to-use). In many cases the request delegate is the view controller that initiates the request.
The model layer depends on the complexity, and also what format the data comes in. Most of the APIs I've worked with use JSON, for which you can use SBJSON or yajl-objc to parse. These usually give you the data parsed into base classes like NSString, NSArray and NSDictionary. Sometimes that's sufficient, or if you want your models to exist as their own classes, then you can have the models inherit from a base class that takes care of turning the NSDictionary/NSArray into properties.
Finally for caching, Core Data provides a good way to persist to disk. For caching in memory, you can have the requests occur in a separate "manager" class that is shared between controllers. These managers use the Singleton design pattern as described here: What should my Objective-C singleton look like?.
So I've been trying to design a clean way of grabbing data for my models in iPhone land. All the data for my application is coming from JSON API's.
So right now when a VC needs some models, it does the JSON call itself (asynch) and when it receives the data, it builds the models. It works, but I'm trying to think of a cleaner method whereby the DAO's retrieve the information for me and return the models, all in an async manner.
My initial thought is build a protocol for my DAOs, such that the VC would instantiate a DAO and make itself the delegate. When you requested data [DAOinstance getAllUsers] the DAO would do all the network request stuff, and then when it had the data, it would call a method on its delegate (the VC) to pass the data.
So I think that's a cool solution, but realized that if I needed to use the same DAO for different purposes in the same VC, my delegate method would have to branch logic depending on which DAO instance initiated the request.
So my second thought was to be able to pass 'handler' selectors to the DAO object a la typical javascript patterns. So instead of an official protocol, I would say something like [DAOinstance getAllUsersWithSelector:"TheHandlerFunctionOnMyVC:"] Then when the DAO completed its network activities, it would call the passed selector on the VC, and pass the data back.
So am I headed in the wrong direction entirely here? Seems like maybe an ok way to go.
Any pointers or articles on designing this kind of data layer would be sweet.
Thanks!
Bob
It's pretty common to pass the a target (your VC here) and a selector (the handler method) when you need a call back and don't want to branch on the handler method caller. This is called the target-selector pattern.
Apart from that you might want to check out the RestfulCoreData and CoreResource frameworks on possible designs of this.
Also the famous ObjectiveResource framework might provide a good insight.
Web services -> core data -> controller -> view and then reverse...
Sound right?
Or is there a better way, one that avoids the complexity of SOAP?
Additionally can core Data recognize XML coming from SOAP?
Thanks // :)
There are several good REST libraries that work on the iPhone if you want to avoid SOAP.
HTTPRiot - http://labratrevenge.com/httpriot/
ASIHTTPRequest - http://allseeing-i.com/ASIHTTPRequest/
ObjectiveResource - http://iphoneonrails.com/
I've used the first and last and between those two, I really like HTTPRiot - really easy to use, doesn't get in your way and converts both XML and JSON responses into NSArrays and NSDictionaries.
Core Data doesn't have any relation to Web services natively but you can easily populate managed objects from the data you receive from one of the above libraries.