How to change delegate to NSURLSession - ios

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.

Related

Is it a good approach to use multiple download tasks with a single URLSessionDownloadDelegate confirming class?

Currently I'm working on implementing a network manager for handling download and upload tasks. I have a class that confirms to URLSessionDownloadDelegate, URLSessionDelegate. The problem I'm facing is I'm using a single session object which is used for all the service calls. So when multiple network operations are being processed, all the response call backs will be handled in the class that is implementing the delegate methods. So to find for which call a response has been arrived, I'm comparing the task parameter of the delegate method and all the tasks that are running currently(I have closure property for each of the delegate methods in the class that confirms to session protocols). Is there any other ways to achieve this result ?(I think this won't be a good solution when handling large number of requests)
Ideally, you shouldn't be doing comparisons yourself, but rather should store the closures in a dictionary keyed by the task objects. Be sure to update the dictionary in any delegate methods that replace one task with another. And be sure to do dictionary lookups and stores on the same thread or serial queue every time.

Replacing NSURLConnection with NSURLSession

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.

NSURLConnection and different ways of making asynchronous requests

I need to communicate with RESTful services either through HTTP and HTTPS. I am reading some examples about performing asynchronous requests by means of the NSURLConnection class, and some of them use the sendAsynchronousRequest:queue:completionHandler: method, and other use the connectionWithRequest:delegate: method and implements the NSURLConnectionDelegate methods. I'm not able to make clear what implications each of these approaches has, if difference is only in implementation but performance and results are the same, or if one of the approaches is better or more correct than the other...
Thanks!
There are two differences that are usually key.
First, the return type of both methods. [NSURLConnection
sendAsynchronousRequest:queue:completionHandler:] has a return type
of void which means you cannot capture the NSURLConnection e.g. in
a property, so you lose quite some control over it, i.e. you can not
[NSURLConnection cancel] it. On the other hand, [NSURLConnection connectionWithRequest:delegate:] does return the connection back to you, so you retain full control.
Second, if you are downloading a large file, the block based method
will load the data into memory and 'deliver' it when the block
executes. Presuming a small RESTful answer, this might be ok for you.
However if you are downloading a large file you might want to write
the incoming data directly into a file handle to reduce memory
consumption. For this you need the delegate method
[NSURLConnectionDataDelegate connection:didReceiveData:]. Sadly the
NSURLConnectionDataDelegate documentation is not readily linked in the current Apple documentation.
If you set yourself to be the delegate of the NSURLConnection, those
methods will be called.
Hope this helps.

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