NSURLConnection and different ways of making asynchronous requests - ios

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.

Related

Good practice using NSURLConnection and its callbacks? Objective-C

I don't have a current problem really, but rather a question that I can't seem to find a satisfying answer to.
What is good practice to use when handling callbacks and invokations of NSURLConnection in objective-c? Let's look at some examples.
Let's say I have 3 different ViewControllers, and I've created a class that does the network calls with NSURLConnection in order to obtain a JSON from some site. All 3 VC's will be doing different kinds of network calls. How would one go about doing this without having to repeat code or have the network handling all spread out? And what if I need to make more network calls depending on the result of a previous call?
I use the normal NSURLConnection delegates, such as didReceiveResponse, didReceiveData, connectionDidFinishLoading etc. So what I do is I store the statusCode in didReceiveResponse and in connectionDidFinishLoading I call a function I name handleResponse which checks the statusCode and if the statusCode states that the call was successful I translate the NSData* object that I've stored the data I received from didReceiveData delegate. This is all fine, but the data I translate I want to be sent to the correct viewController.
There are several options to do this:
I let the delegate for the NSURLConnection calls be the
ViewController itself. This sucks, since I have to duplicate the
NSURLConnection code in every VC I want to make a network call,
obviously.
Or I could handle all the data in the Network class that performs
the NSURLConnection calls. This sucks since I get logic code in a
network class, and I don't really want that? This also requires that the Network Class knows about classes and data structures that it probably shouldn't. It's a network class and should not do anything but networking stuff.
My final approach, which I try for the first time now, is to let the
ViewController tell the network class that it wants to make a
NSURLConnection call, and sets a NSNotification message which the
Network class should invoke in the handleResponse method I
mentioned earlier. The Network class sends the data it received
through that NSNotification and the logic for handling that data
falls on the VC that asked for instead. To me this is most logical
and feels like a somewhat good way of doing things.
The problem with solution 3 is that I have to have different Notification methods to handle different kinds of data, which could result in quite a few such methods. If different VC's also use the same kind of data handling as another NSNotification method, then I have to duplicate that code as well. I'm also fairly new to using NSNotification in general and not very knowledgeable about its drawbacks.
Final question, let's say I want to make 4 different NSURLConnection calls, one after the other has been confirmed finished and successful. How would you go about that? I've done this a few times, but it ends up as a counter in the form of an enum to keep track of which network call was just made and which one should be next, which results in switch-statements executing certain code depending on which was just performed. I'm thinking about maybe implementing some sort of queue which goes through all calls in a sequence instead.
I appreciate any kind of input!
Most if not all of these problems are solved by AFNetworking. Specially the problems concerning having to duplicate requests or connections.
For the final question, for example you can do it with blocks AFNetworking provides such a structure, so you can specifically coordinate multiple calls.
AFNetworking
There are a lot of tutorials out there and the brief documentation of the library github site provides short, concise and easy to understand examples. Getting to use it takes a few minutes.

AFHTTPSessionManager convenience methods (GET, POST, PUT, etc) and background transfers

I've built an app around AFNetworking 2.0's AFHTTPSessionManager and its nice HTTP convenience methods. I now need to ensure that all of this networking functionality can run in the background, and I'm rather concerned.
Reading Apple's documentation, I can see that data tasks are not supported for background sessions. After looking briefly at AFHTTPSessionManager's implementation of GET, POST, PUT et al, it seems to use NSURLSessionDataTask across the board.
Is there something I'm missing, or do I have some redesign and rework to do?
In the event that I'm right (and I suspect I am), and that this codepath won't allow me to background uploads and downloads, is there any reason I couldn't wrap AFURLSessionManager's other methods that use non-data tasks in the same way the current HTTP methods wrap "dataTaskWithRequest:completionHandler"? For example for a POST I could perhaps use "uploadTaskWithRequest:fromData:progress:completionHandler"?
I'm asking, since I'm wondering if this is a viable route, why the AFNetworking devs didn't use it, so that AFHTTPSessionManager's convenience methods would allow for background transfers.
AFNetworking allows you to perform background requests (though be careful to not use any of the task-specific completion blocks and make sure you implement the appropriate app delegate methods; see AFNetworking 2.0 and background transfers). You probably also can use requestWithMethod of AFHTTPRequestSerializer to simplify the process of building the request, too (though, IIRC, you cannot use HTTPBody of the request with background upload requests, so you might have to save the body of the request to a file and then issue your background upload request using that file).
But you're absolutely correct that you cannot use the AFHTTPSessionManager methods to initiate NSURLSessionDataTask tasks when using background session. Regarding why they implemented it that way, that's a question better suited for their issues forum.

Why use GCD and blocks for HTTP downloads?

In a job interview, I was asked why I should use blocks and GCD instead of NSURLConnection in order to download files asyncronously. After some research I haven't found a good reason to do that. I have multiple apps where I use just NSURLConnection just fine for multiple simultaneous downloads. Is their question attempting to ascertain whether I'm conforming to whatever is trendy (GCD, blocks) or is there any actual, substantial advantage to doing async fetches in this way?
Thanks.
In iOS 7, you generally should not use block-based methods to download files asynchronously. In order to support background transfers, you must use NSURLSession with delegate methods, and cannot use the block-based methods. Beyond that, I'm not sure what is meant here by "instead of NSURLConnection" in any case.
If they meant sendAsynchronousRequest:queue:completionHandler: (which is NSURLConnection), it's convenient, but much less flexible and powerful than the delegate-based NSURLConnection, so the only answer I would have is "because sometimes it's more convenient, and keeps the code closer together, when you don't need much flexibility."
Unless what they actually mean is the part of GCD that really does this: Dispatch I/O. There are reasons to use that directly (particularly if you're using non-HTTP protocols, or if you're managing an HTTP server rather than a client), but they're rare, and not usually for "downloading files asynchronously." The higher level APIs are preferred in most cases.
If you were doing many, many connections, transferring a ton of data over a very fast network connection, I can perhaps see how NSURLConnection's use the runloop for I/O handling and callbacks might become problematic, if you're scheduling these NSURLConnections on the main runloop. That said, you could just as easily spool up a lower priority background thread with its own runloop to keep those operations off the main thread.
If you didn't need all the extra machinery of NSURLConnection (caching, authentication, etc), dispatch_io* is almost certainly a lower overhead mechanism for handling raw network I/O, but you would really be giving up quite a bit of functionality for what I expect, practically speaking, to be a very marginal performance improvement.
I'm not sure. Mainly because NSURLConnection's sendAsynchronousRequest method has a completion handler built into it which uses a block.
Maybe a trick question? To me, it seems like the interviewer just wanted to see if you could conclude that they both can serve the same function.
Blocks and GCD aren't specifically for downloads, but they can make downloading easier. You would have to use them in conjunction with something that did the downloading (like NSURLConnection).
The advantage of using GCD with an NSURLConnection is that you can package it together nicely and don't have to rely on spread-out delegate methods. You can limit the number of connections easily too as well as pausing and stopping connections.
My "go to" set up for complex networking is to use an NSOperationQueue and NSOperation subclasses to do the work.
Each operation then uses a NSURLConnection and its delegate methods to download the data and then process it.
In a way this is already using GCD through the NSOperationQueue but I can't see a reason to use any other method combining blocks and GCD etc...
Did they give you a "correct" answer?

Is there a difference between using NSURLConnection with delegate call backs and sendAsynchronousRequest:queue:completionHandler:?

I'd like to understand what the difference is between using –initWithRequest:delegate: with delegate methods and +sendAsynchronousRequest:queue:completionHandler:.
Are there some performance differences based on the number of requests, or any other criteria?
sendAsynchronousRequest:queue:completionHandler is an easier call to make. initWithRequest:delegate gives you more control over things like caching, redirects, downloading large or incremental amounts of data, canceling requests, etc, etc.

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