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?.
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 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.
Is there a general Cocoa or Cocoa Touch library for interacting with any web service API, or one which can be used as a basis for creating my own library for a web service? For example, I could add some details about how to interact with the Vimeo API (how to verify user details, what URLs to call). I'm not sure how this would work in reality.
If not, can anyone suggest an web service library which I could alter to change the API calls? It would need to be fairly simple (a small API) and easy to adapt. An example is this Cocoa library for Twitter (although it would probably be too complicated to adapt). Would it be easier just to code it up from scratch?
I don't think there is a library that will automagically work with any web API. In fact I don't even think it's possible to write such a library, since you can define your web API any way you want to. That library would have to be pretty smart in order to figure out how to use an arbitrary API.
I think the closest you'll get is something like ASIHTTPRequest, which is a great library for interacting with web services. If you add a JSON and/or XML parser you'll have everything you need to interact with almost any web API.
Found another library for interacting with RESTful web services. It's called RestKit. From their description:
RestKit is a Cocoa framework for interacting with RESTful web services in Objective C on iOS and Mac OS X. It provides a set of primitives for interacting with web services wrapping GET, POST, PUT and DELETE HTTP verbs behind a clean, simple interface. RestKit also provides a system for modeling remote resources by mapping them from JSON (or XML) payloads back into local domain objects. Object mapping functions with normal NSObject derived classes with properties. There is also an object mapping implementation included that provides a Core Data backed store for persisting objects loaded from the web.
I have question regarding RESTful resources similar to this other question.
We're also developing an iphone app that will access the REST services but one of the concerns is that the first screen makes a few calls to the service and that it should be just one (A dto of the resources).
I'm trying to keep the service as RESTful as possible so I was wondering how to access it cleaning.
I was thinking of considering the iphone (or any other device) as a resource and that this dto is a property. The URI would be something like this:
example.com/rest/Device/iphone/HomeScreen
Would something like this be acceptable or is there a better solution?
Thanks
Tony
What you are doing IMHO is perfectly acceptable. The REST principles are much easier to apply when your resources more focused around the requirements of the client UI.
I do exactly the type of thing you are doing:
http://myserver.com/desktop/{dataset}/shell
http://myserver.com/shopclient/{dataset}/login
http://myserver.com/mobile/{dataset}/home
I'd say that if you're able to roll up all the data your wanting to shove over the wire and name it something that makes sense, that might be better than what you currently have.
Whatever you end up calling that structure, I'll call it 'foo', the GET for example.com/rest/foo would return that
I agree that it is important to limit the chattiness of your app since you own both the app and the service and probably nobody else will be consuming your service.
The iPhone is like a special client which needs the output formatted in a special way (like AJAX sometimes needs JSON insted of HTML).
So I'd recommend to keep the url as short as possible:
example.com/rest/HomeScreen
Now you have do determine in your controller which format is requested (html, json, iphone). You could do this by determine the user agent or by appending an extension like:
example.com/rest/HomeScreen.iphone
example.com/rest/HomeScreen.html
example.com/rest/HomeScreen.xml
etc.
I wouldn't design a HomeScreen resource (it feels very front-end specific). What does you HomeScreen display? I rather would expose the model which is displayed on HomeScreen as the HomeScreen model itself.
We have iphone app using REST api which is calling several resources (multiple calls). Still the app feels very quick, because "performance boosters" are used (caching, control over payload size, compression).
Regarding content-negotation I think an interoperable format for iphone is sufficient (json or xml). The mobile device then can render this model how it likes.
I'm developing an app that will talk with a web service exposing multiple methods. I'm trying to figure out what the best pattern would be to centralize the access to the web service, give options for synchronous and asynchronous access, and return data to clients. Has anybody tackled this problem yet?
One class for all methods seems like it would centralize everything well, but I'm thinking it would get confusing to return data to the correct places, especially when dealing with multiple asynchronous calls. Another thought I had was a separate subclass for each method, with some sort of factory brokering access, but I'm thinking that might be overengineering the situation.
(note: not asking for what method calls to use/how to parse response/etc, looking for a high level design pattern solution to the general problem)
I recently came across the same problem. While I don't believe my solution to be optimal, it may help you out.
I created a web service manager and an endpoint protocol. Each object that implements the endpoint protocol is responsible for connecting to a web service endpoint(method), parsing the returned data, and notifying its delegate(usually the web service manager) of completion or any errors. I ended up creating an EndpointBase class that I use 99% of the time.
The web service manager is responsible for instantiating the endpoints as needed and invoking them. All of the calls happen asynchronously.
All in all it seems to work pretty well for me. I did end up with a situation in which one endpoint relied on the response of another (I used the command pattern there).
SDK Components that you'll want to look at are:
NSURLConnection
NSXMLParser
Factories? We don't need no stinkin' factories.
I've done this a few times, and I basically do what you're saying: one object that provides methods for all the web service calls, encapsulating the details of communicating with the service, handling connection issues, etc. In one app it was a singleton, because it needed to keep session state; in another app it was just a collection of static methods.
Along with some formatting of the response data, that's the entirety of its responsibility.
It's left up to the callers is whether the call is synchronous or asynchronous; the class itself is written synchronously, and a caller just uses it in a separate thread if necessary. Cocoa's performSelector... methods make that easy.
If REST is a good fit for your data interactions, then I would suggest the ObjectiveResource library . It's designed to work seamlessly with a Ruby on Rails app, but it basically speaks JSON or POX (plain old XML) over HTTP using rails ActiveResource conventions.
It's basically a set of categories on NSObject and some of the primitive object types that will let you make calls like [Dog findAllRemote] to return a list of Dog objects, or [myDog saveRemote] to send changes made to the myDog object back to the server.