Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Networking pattern based on NSURLSession

I've been traditionally using a pattern where NSOperation subclasses create and manage their own NSURLConnection. The NSOperation subclass is instantiated by the view controller and will do its work without bothering the controller until it has finished. When it finishes retrieving data, it executes the completion block supplied by the view controller.

  1. ViewController instantiates NSOperation subclass (which encapsulates URL, parameters etc)
  2. NSOperation subclass instanciates NSURLConnection (which performs synchronous request and retrieves data)
  3. NSURLConnection dumps data to NSOperation-subclass
  4. NSOperation-subclass executes the completion block supplied by the view controller.

I'm trying to implement the same pattern with NSURLSession now. I want to be able to encapsulate the url and parameters required to make a network request inside a single object. Do I achieve this using NSURLSession subclasses or NSURLSessionTask subclasses?

I like to create separate classes for every network operation based on the actor design pattern.

like image 718
NSExplorer Avatar asked Jan 15 '14 20:01

NSExplorer


2 Answers

The NSURLSessionTask class (and its subclasses) look a bit like operations, but they're not. Thus, you can remove operations from your code as you transition to NSURLSession, but if you do, you will lose certain NSOperation functionality (dependencies, controlling degree of concurrency, etc.). I'm not sure why you'd want to excise operations from your code as you transition to NSURLSession. Personally, anywhere I used to wrap a NSURLConnection in an operation, I now wrap a NSURLSessionTask with an operation.

As an aside, one of the significant annoyances with NSURLSession, though, is that the task delegates are set at the session object. We can make guesses why Apple did that, but it has all sorts of unfortunate implications. Clearly you can get around this by using the block based factory methods for creating your tasks, but then you lose the richness of the delegate API, if you happened to need that.

The implication of this is that if using block-based task factory methods, wrapping the task in a concurrent NSOperation subclass is fairly obvious. But, if using the delegate-based tasks, though, if you want custom handlers for the tasks, you have to go through some silliness with maintaining a mapping between task identifiers and the appropriate completion blocks (which I personally put in a session manager object that I used to wrap the NSURLSession). (FYI, I believe an implementation like this is expected in a forthcoming AFNetworking update, too. See the latter part of the discussion on Issue 1504 on the AFNetworking github site.)

Anyway, others have answered the question how you could replace your operation-based NSURLConnection code with non-operation-based NSURLSession code, but I'd personally suggest staying with operations.


By the way, I've uploaded a example implementation of an operation-based NSURLSession implementation on github: https://github.com/robertmryan/NetworkManager

This is not intended to be a complete solution, but illustrates the idea of how you might implement a delegate-based NSURLSession with NSOperation subclasses.

like image 54
Rob Avatar answered Oct 21 '22 15:10

Rob


You can use the same pattern, replacing NSURLConnection with NSURLSessionTask subclasses (e.g. NSURLSessionDataTask).

As @CouchDeveloper suggests in the comments, an alternative is to wrap NSURLSessionTask in an non-NSOperation object with asynchronous semantics (cancel, resume, etc.). This wrapper object would do little more than encode and decode parameters, delegating most operations to the wrapped task.

In either case, to instantiate NSURLSessionTask, you will need a NSURLSession. (NSURLSession is the NSURLSessionTask factory.) If all of your operations use the same configuration (cookies, proxy, caching, etc.), you can simply use the shared session (+[NSURLSession sharedSession]). If they need different configurations, you'll have to give them a NSURLSession or enough information to create their own.

like image 33
jonahb Avatar answered Oct 21 '22 15:10

jonahb