Replacing NSURLConnection with NSURLSession - ios

I have been starting a design for NetworkCommunication. I had a design where NSOperation subclasses create and manage their own NSURLConnection. The NSOperation subclass is instantiated by a NetworkManger class which adds it to the NSOperationQueue. Once the request is finished the delegate(ex:ViewController will be called). This is the flow:
The Network Manger instantiates NSOperation subclass (which encapsulates URL, parameters etc) and adds it to a NSOperationQueue it maintains.
NSOperation subclass instantiates NSURLConnection (which performs asynchronous request and retrieves data)
NSURLConnection dumps data to NSOperation-subclass
NSOperation-subclass executes the completion block supplied by the delegate( 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.
Is it fine if i use the same pattern if I use NSURLSession. I checked AFNetworking classes. But, they have not subclassed NSOperation for NSURLSession. And, moreover where should the session object go. Will it be a part of the NSOperation class.
Can someone give some expert advice on this. I should be able to cancel requests, do uploading(POST/PUT), downloading of data. The Network Manager class would be the single point of contact for any network request.

Update:
NSURLConnection is deprecated effective Mac OS 10.11 and iOS 9. So, at this point NSURLSession should be used in lieu of NSURLConnection. As the NSURLConnection.h header says:
Deprecated: The NSURLConnection class should no longer be used. NSURLSession is the replacement for NSURLConnection.
My original answer is below.
The answer depends upon whether you need the richness of the various NSURLSession delegate methods or not. If you're ok using the completion block renditions (i.e. no progress callbacks, no streaming, etc.), the conversion from NSURLConnection to NSURLSession is pretty trivial. Just put your NSURLSession instance in your NetworkManager class, and then wrap the delegate based NSURLSessionTask instances in a concurrent NSOperation subclass and you're done. Just adopt the standard asynchronous/concurrent NSOperation subclass pattern.
If you're using the delegate-based renditions of NSURLSession, it's a whole different kettle of fish. The main hassle is that the various NSURLSessionTask delegate methods are called on the session delegate rather than a task delegate object. At first blush, this might sound like it's a trivial issue, but if your operation instances have unique completion/progress blocks, for example, you're stuck with the hassle of how to have the session object map these delegate method callbacks to the individual original request operation instances.
To tackle this, you have to maintain a mapping of task identifiers to your NSOperation subclass objects. You can then implement these NSURLSessionTask (including task, download task, and upload task) delegate methods at the respective NSOperation subclass. The NSURLSession network manager class can then, when it receives a NSURLSessionTask delegate call, use the task identifier to identify the appropriate NSOperation instance, and then call the appropriate delegate method there.
Finally, if you intend to handle background NSURLSession instances, life gets even more difficult (because background tasks will continue even after your app has terminated and all of its objects have been discarded). Background sessions simply don't lend themselves to an NSOperation-based approach.
Bottom line, this is trivial if you only need the completion-block NSURLSession methods, but it's a bit of a hassle if you need the delegate-based rendition.

Related

How to change delegate to NSURLSession

I am using NSURLSession for server communication. I am having 2 class individually for Downloading and uploading files. I want to use Single NSURLSession for downloading and uploading operation. In such I can't change the delegate for NSURLSession at run time by using setDelegate option, since I'm using Delegates to validate data. Is there any way to change delegate object for NSURLSession at run time?
Thanks.
As Rob says, you can't change the delegate of an NSURLSession.
You have a few other options.
You can set up a download manager object (probably a singleton) that
manages the NSURLSession and is it's delegate, and have it forward
messages to whatever object requested the upload or download.
You can create multiple instances of NSURSession, one for uploading
and one for downloading, each with a separate delegate. (You said you
don't want to do that, but you should revisit that option.
You can use the NSURLSession methods that pass a completion handler
rather than using a delegate..
The delegate cannot be changed. It is the delegate that was "assigned when this object was created." And as the documentation goes on to say:
Note:
This delegate object must be set at object creation time and may not be changed.
So, you'll have to design a delegate object that can differentiate between your various network tasks, handling each appropriately.
You could, theoretically, create separate delegate objects, and maintain a dictionary, keyed by the task identifier, of pointers to secondary delegate objects. You can then write a delegate for the NSURLSession that, for the task delegate methods, looked up the task identifier in its dictionary, calling the appropriate method in the appropriate delegate object. But this is a bit inelegant, so you should probably stop and ask yourself if there are simpler ways to solve the problem.

Do I have to create NSOperation subclass for each web service?

I always fetch data from web services using GCD. Now I have to use NSOperation and NSOperationQueue. But I am confused with the working of NSOperation and NSOperationQueue.
Suppose I have two APIs, Login API and Registration API. Do I have to create two NSOperation subclasses for it, like LoginOperation and RegistrationOperation? Or I could send various request in one NSOperation Class?
And how should I keep NSOperationQueue class central so that I keep adding operation class objects to it.
Please provide link for this type of sample project.
This will vary from project to project but generally you may want to have only one base subclass of NSOperation and subclass that for your specific requests such as LoginOperation or RegistrationOperation. You may want to look into AFNetworking since that is already a very well established networking library that subclasses NSOperation.
Depending on what you app is doing and how you want to manage your requests you may need more that one NSOperationQueue. This will help you keep track of the various requests and know if they have completed if needed, need to be syncronized, etc.
Have a look at this for something more in depth:
http://www.objc.io/issue-2/concurrency-apis-and-pitfalls.html

Can I start an NSOperation inside of another NSOperation without a queue?

My application gets the current device location, POSTs this to my server, and returns a dictionary to be displayed in a table view. Currently I am using the CLLocationManager delegate methods and AFJSONRequestOperation (AFNetworking's retrieve-data-through-NSURLConnection-in-NSOperation class) to do the job, but this functionality is inside one view controller method and I'd like to be able to reuse this across other view controllers.
I am planning to make my own NSOperation subclass, but first I wanted to know if there are any unseen pitfalls in having NSOperations (AFJSONRequestOperation) start inside of another NSOperation. Does this work as expected or should I find a way to make a queue with dependencies among the operations?
Scheduling a NSULRL connection operation within a NSOperation will fail unless you schedule it on the main run loop. AFJSONOperation (or any subclass of AFURLOperation) will succeed because under the hood, AFNetworking operations are scheduled on their own NSOperationQueue and on a custom run loop.
So - Yes. Go for it. I use NSOperation subclasses to isolate all of my worker processes. It is much cleaner than flat out GCD in the middle of your VCs or Models.
Caveat - Since all AFNetworking operations are block based and return asynchronously, your NSOperation subclass will need to be concurrent. Apple provides a detailed description of how to build this in their docs for Concurrent NSOperation Subclasses
Optionally - you could just skip building a concurrent NSOperation subclass, and fire your network operation synchronously from within your NSOperation since you're already off of the main queue.
All the NSOperation stuff uses GCD under the hood, and GCD has no issues with nested dispatch_async calls, so I doubt nesting NSOperations will cause you problems as long as your logic is correct.

Do you need to consider thread-safety using NSURLConnection? - iOS

I've just been wondering for a while now how exactly asynchrounous requests work with NSURLConnection.
For example, suppose you have several upload processes running in your application, all initialized using different instances of NSURLConnection. As uploading processes, your wrapper objects gets the NSURLConnection delegate methods called, like:
-(void)connectionDidFinishLoading:(NSURLConnection*)connection;
Suppose that in all your NSURLConnection wrapper objects share the same delegate object which have a list of all active uploads in an array, and that when the connectionDidFinishLoading gets called for all your connections, they go in and remove themself from that list in the shared delegate object.
The question then is, do you have to worry about thread-safety when those connection objects can access the same array? Or does all those delegate methods go back to the main-thread in such a way that you are not supposed to worry about thread-safety?
The trick is that the delegate methods are called on the thread on which you created your NSURLConnection, which unless you specifically change it will be the main thread. The OS uses one of the threading Queueing APIs to call the delegate method over and over on that thread in the order each connection finishes.
With NSURLConnection its only really the transfer that needs to be threaded. If the transfer happened on the main thread then during the transfer the User wouldn't be able to interact with your iOS application. Doing stuff with the result takes a relatively short time, but if it takes a long time whether you choose to do that processing in the background (on a different thread) or not is then up to you.

NSNotification-based iOS App

I am currently thinking about the data-model for my iOS App. The app does only receive Information from a server and therefore, the "model" itself generally does all the web-requests, ...
However, these network requests have to be performed in the background - I mean another task, not the iOS background state - and after the request has finished, the information in the Application has to be updated.
Would it make more sense to write a delegate to inform the controller or could I also use NSNotificationCenter? I think an NSNotification-based solution could make the model more universal, e.g. in a desktop application.
And maybe, I should add: the model (since it saves some session Information) is a singleton, so a regular delegate based method would not work...
I don't think that it would be a good idea to use a separate thread to handle the communication. Apart from being complex, it is not necessary since NSURLConnection/NSURLRequest do allow you to handle communication asynchronously, i.e., without blocking.
In detail, you can create an NSURLRequest executing:
NSURLRequest* yourReq = [NSURLRequest requestWithURL:yourURL];
then create an NSURLConnection with:
NSURLConnection* yourConnection = [NSURLConnection connectionWithRequest:yourReq delegate:yourDelegate];
and start it with:
[yourConnection start];
When the data is ready, one of the methods for your delegate (connectionDidFinishLoading:, or connection:didFailWithError:) will be called so that you can update your UI.
All this without blocking.
An even better alternative to using NSURLConnection/NSURLRequest, is using ASIHTTPRequest, which seems to be more resilient as to memory management and also offers a great caching mechanism.
EDIT: if your concern is that being your model a singleton, you cannot have a delegate, let me suggest that you look further into the matter.
Your model may be a singleton and the delegate to your request may have nothing to do with the model, apart from knowing how to access it (which is pretty trivial being the model a singleton).
This is possible by several mechanisms with NSURLConnection, but if you use ASIHTTPRequest, it will become really easy, because each ASIHTTRequest can have its own delegate.
A delegate solution does work and is recommended. It looks something like:
[[DataLayer sharedInstance] fetchDataWithDelegate:self];
That method can spawn a background thread and respond to the delegate on the main thread.

Resources