I'm in the process of rethinking my approach to the request architecture of a large app I'm developing. I'm currently using ASIHTTPRequest to actually make requests, but since I need many different types of requests as a result of many different actions taken in different view controllers, I'm trying to work out the best system of organizing these requests.
I'm currently building singleton "requesters" that are retained by the app delegate and sit around listening for NSNotifications that signal a request needs to be made; they make the request, listen for the response, and send out a new NSNotification with the response data. This solves most of my problems, but doesn't elegantly handle failed requests or simultaneous requests to the same singleton requester.
Anyone have any success devising a clear, OO architecture for making many different types of requests in an iOS app?
After having tried several approaches, this is one architecture that is giving me excellent results, is easy to document, understand, maintain and extend:
- I have a single object taking care of network connectivity, let's call it a "network manager". Typically this object is a singleton (created using Matt Gallagher's Cocoa singleton macro).
- Since you use ASIHTTPRequest (which I always do, wonderful API) I add an ASINetworkQueue ivar inside my network manager. I make the network manager the delegate of that queue.
- I create subclasses of ASIHTTPRequest for each kind of network request that my app requires (typically, for each backend REST interaction or SOAP endpoint). This has another benefit (see below for details :)
- Every time one of my controllers requires some data (refresh, viewDidAppear, etc), the network manager creates an instance of the required ASIHTTPRequest subclass, and then adds it to the queue.
- The ASINetworkQueue takes care of bandwidth issues (depending on whether you are on 3G, EDGE or GPRS or Wifi, you have more bandwidth, and you can process more requests, etc). This is done by the queue, which is cool (at least, that's one of the things I understand this queue does, I hope I'm not mistaken :).
- Whenever a request finishes or fails, the network manager is called (remember, the network manager is the queue's delegate).
- The network manager doesn't know squat about what to do with the result of each request; hence, it just calls a method on the request! Remember, requests are subclasses of ASIHTTPRequest, so you can just put the code that manages the result of the request (typically, deserialization of JSON or XML into real objects, triggering other network connections, updating Core Data stores, etc). Putting the code into each separate request subclass, using a polymorphic method with a common name accross request classes, makes it very easy to debug and manage IMHO.
- Finally, I notify the controllers above about interesting events using notifications; using a delegate protocol is not a good idea, because in your app you typically have many controllers talking to your network manager, and then notifications are more flexible (you can have several controllers responding to the same notification, etc).
Anyway, this is how I've been doing it for a while, and frankly it works pretty well. I can extend the system horizontally, adding more ASIHTTPRequest subclasses as I need them, and the core of the network manager stays intact.
Hope it helps!