Introduction
Performing HTTP requests and fetching data via HTTP is a quite frequent task in iPhone applications. iPhone SDK provides three kinds of API to do that:
1. BSD sockets. Say hello to unix and old good socket(), read(), ... Of course, you can use it to do HTTP, but I bet nobody does it this way on iPhone.
2. CFNetwork. It's a Core Services framework for networking. According to ADC it's a
low-level, high-performance framework that gives you the ability to have detailed control over the protocol stack.
And according to ADC again
CFNetwork is based, both physically and theoretically, on BSD sockets.
Unfortunately, as every CF framework, it's a pure C framework so it's quite inconvenient to be used. Fortunately, there is a framework called as
ASIHTTPRequest. It's very popular and frequently recommended on forums when somebody asks about how to download an URL.
ASIHTTPRequest is based on CFNetwork framework. It's important to say that ASI is synchronous by its nature. So if you want asynchronous URL fetching, you need to use NSOperationQueue (in last versions ASIHTTPRequest can do that itself so you just call [request startAsynchronously]).
3. NSURLConnection. A pretty Objective-C class which lets you do HTTP in just a couple of lines. According to ADC it's based on top of CFNetwork. In contrast to ASIHTTPRequest, NSURLConnection is asynchronous by design. But there is a method which lets you use it in a synchronous manner.
One of the biggest benefits of ASI over NS is that ASI provides a lot of useful functionality for building multipart POST requests, using compressed requests, authentication, proxies, ....
However the question bothering me all last week is: who is faster? Apparently, since NSURLConnection is based on top of CFNetwork, pure CFNetwork should be faster in all cases. But is ASIHTTPRequest faster than NSURLConnection?
The battle
In order to find out who is faster, I've performed some tests. There was 2 tests for each mode (synchronous and asynchronous) for each framework:
- Download 64 files, 4 kb each. (256 kb in total)
- Download one 256 kb file.
All files was stored on Amazon S3.
So, in total there was 4 tests for each framework. Since results may differ from run to run (internet is a quite unstable thing), each test was run 10 times and then the best download time was picked as the result.
ASIHTTPRequest was as of 7th Dec 2009 (a3b974c67699c85bbe89277e016d277c590ccaab).
Tests was done in the Simulator and on my iPhone 2G, both laptop and iPhone was connected to the same wi-fi network.
Here is the results (in seconds):
| | Simulator | iPhone 2G |
| | ASI | NS | ASI | NS |
| Asyncronous |
| 64 files | 6.18 | 2.69 | 6.91 | 3.81 |
| 1 file | 0.64 | 0.57 | 6.33 | 5.21 |
| Synchronous |
| 64 files | 19.56 | 9.92 | 28.56 | 13.30 |
| 1 file | 0.65 | 0.59 | 6.02 | 3.98 |
You can get the source code of the test project
here. The repository contains detailed logs of the runs presented above.
Conclusion
So what do we see? In all tests ASIHTTPRequest is slower than NSURLConnection, approximately in 2 times. The difference is less when we download 1 big file, but is still sensible.
So in case you can make multipart POST requests yourself, choose NSURLConnection. :) (I'm kidding — of course, ASI provides a lot of other nice functionality, therefore if you don't care about performance much, ASI is a good choice)
Another interesting fact we can notice is that synchronous mode is quite expensive when we perform many requests.
And finally some obvious to everybody, but still important facts:
- Simulator is always faster then real iPhone. On fetching big files, up to 10 times. Moreover, you can notice that Simulator behave completely differently at all. So ALWAYS test your application performance on a real device.
- Fetching lots of files is always slower that fetching 1 single file. (NSURLConnection somehow managed to download 64 files faster than 1 file in asynchronous mode on iPhone. But if we check the logs, we see that in most cases downloading 64 files is still slower)