
I have a native iPhone application in development which requires me to interact with a server that uses a stateful protocol over a persistent connection to transfer messages over the wire. This is definitely not a trivial application to write, even though the UI itself is very simple.
The Problem
Stateful protocols and persistent connections are often interrelated, but not by design. My first problem was to divide the original problem in two: how to manage the persistent connection, and how to handle the underlying protocol so that the stateful aspects did not bubble up throughout the UI.
Persistent connections can be difficult to manage, particularly when the network topology can change so drastically (such as on mobile devices). In this sense, there is nothing new here– while the framework can notify you of connection events, it is still up to the developer to decide on the appropriate action.
The statefulness of the protocol, however, is trickier to deal with. We must track the state of the connection, and notify the caller of ‘certain’ errors. I say ‘certain’ because there is a class of errors that can be dealt with on behalf of the client in a reliable way, affording the rest of the application to treat the protocol as if it were stateless in most cases.
In dealing with the issue of maintaining the persistent connection, I wanted a solution which prevented me from having to manage separate thread(s), run loops, or NSOperationQueue. It is not that these approaches could not work, only that I wanted fewer failure points in the code, and experience has shown that many times there is a better way. Synchronous network calls were obviously not an option (if you didn’t get a visceral reaction upon the very idea, just try and go that route– it is not a happy place to be).
Managing the Persistent Connection
Luckily, AsyncSocket can do much of this for you. It’s a great library for this sort of work, and I would recommend it over just using the NS connection classes alone. This library, however, does not do everything for you. You still have to refer to the connection from your code (either through a shared singleton approach, or as an injected dependency).
Managing the Stateful Protocol
I first attempted to create an interface on top of the network protocol, and quickly realized that this path would involve quite a bit of ‘target/action’ callbacks. So the choice was to either create a delegate protocol around my interface, or else use the NSNotification model to notify interested parties when certain events completed. Again, both of these options are possible, but there was just one problem…
…NSURLConnection and NSURLConnectionDelegate provide a lot of this for you. Knowing this, why wouldn’t I want to capitalize on the framework? No synchronous calls, no extra delegate protocols to write. You get certain faculties for free using this route as well– an established architecture for managing credentials, caching strategies, and in some cases, a way in which you can write and test your application against stateless protocols (say, HTTP) in a controlled, test environment, before actually testing against your custom, stateful protocol (let’s presume access to the server is limited).
I was sold.
The Work
At this point, the problem became one of first developing a URL scheme for my needs, and then subclassing NSURLProtocol. My own implementation of NSURLProtocol checks the state of the single, persistent connection on each request, and issues an authentication challenge to the caller if the connection could not be created (this gives the user the ability to intercede, enter a password, or just cancel the connection).
The URL scheme is fairly straightforward, as the ‘path’ element of NSURL translates directly to commands on the server. Query parameters represent arguments.
The Way Forward
There is still more work to be done, of course, but the architecture is very clear. As mentioned above, I plan to handle changes in the network connection. Without this, a slow cellular connection, say, would still be used even when a faster connection type suddenly became available. Since the handling of the underlying connection is behind the protocol layer, this becomes an easier change to manage than if all parts of the code had to concern themselves with changes in the network connection itself.
My experience so far has taught me a few things about both the URL loading system in Cocoa, and how to deploy these kind of apps in the wild. There are not many examples of NSURLProtocol out there. This is a common complaint, but the points above, along with the existing sample code, should help steer you in the right direction.
Related Services: iPhone Application Development, Custom Software Development
