This library is described as "Insanely Fast", and performance feats on various connection types are described.
Is the implication that it performs some optimization that regular sockets could not do? Or is it merely faster than some alternative? I don't know terribly much about the i* ecosystem, but it seems like speed should be the least distinctive attribute for networking libraries; providing a helpful abstraction is the real concern, and only by considerably folly or cleverness would performance differ noticeably.
AFNetworking boasts really fast performance in the way that it makes concurrent requests and processes them asynchronously. That, in combination with careful tuning of the stock networking libraries makes.
There are no hard performance benchmarks, but you'll get a good sense of how fast it is if you download and run the example app--I've yet to see any apps match the table view image loading performance.
FWIW, people who have switched from ASI usually report an overall networking speedup of 2-3x.
"careful tuning of the stock networking libraries" <-- Care to expand?
I am skeptical about claims that simply changing how it makes concurrent requests will make it 'insanely fast'. Bottom line is, outside of some careful tuning that uses knowledge of iOS internals, there isn't any real way a library can impact how fast bits travel over the wire.
Here's some feedback - if you wish to substantiate this claim, it shouldn't be hard to write the same app using ASI and then extract some real performance numbers (bonus points for publishing your test code to get doubters like me to shut up).
Well, the most perceptible tuning AF does is turning on HTTP pipelining for image requests (which are off, by default). Other than that, it's just small steps to use HTTP correctly as much as possible. </admittedly vague cop-out>
I understand and respect your skepticism, since by using NSURLConnection, its performance is bound by the same thing most other libraries are (although ASI was wrapped the lower-level CFNetwork APIs, FWIW). It's the stuff around the network activity--the way the application interacts with the data that makes AF fast. I've gone out of my way to design a minimal API that is performant no matter how you (mis)use it.
But you're right: I'll have to get around to writing a benchmark app at some point :)
Rather than building cacheing in, AFNetworking is designed to work with NSURLCache. I strongly recommend Peter Steinberger's [SDURLCache](https://github.com/steipete/SDURLCache) fork, which includes disk cacheing on iOS.
I haven't reviewed the implementation, but the API alone appears to be a significant improvement over the previously available options.
However, the use of non-prefixed category methods (monkey-patching) is an inappropriate design choice, given the fact that the likelihood of conflict is actually higher than 0 when using non-prefixed category methods.
Let's say you were doing a gradual migration from ASIHTTP -- you'd have a non-deterministic conflict on the -[UIImageView setImageWithURL:] category method.
Unfortunately -- and despite repeated advisements to not do so by Apple engineers and others -- AFNetworking isn't the only library to add such a category method, and in fact, a number of libraries and third-party code add different, conflicting -[UIImageView setImageWithURL:] category methods. It's not too hard to wind up with a conflict.
Category methods should always be name-prefixed to avoid conflict, if you're going to use them at all:
As a follow-up -- are there any of the authors here?
The implementation looks pretty good, but some questions.
It looks like you might be using -[NSRunLoop run] to spin a background runloop? That will return immediately if no sources are scheduled in the runloop, which will result in a CPU-heavy busy-waiting thread -- unless I'm missing something here?
I was also wondering about choices like the use of a single statically allocated serial dispatch queue for performing all JSON parsing, rather than using concurrent queues and letting GCD figure out how much concurrency to leverage given the application state and hardware available.
Also, it appears that all callbacks are directly dispatched onto the main thread. Is there any interest in adding support for allowing the caller to specify dispatch onto other queues, in the case that they don't want to hit the main queue for background processing?
- As I understand threading and run loop scheduling, the run loop will spin up as needed when an NSURLConnection attaches itself to it, and back down again when no more connections are active. The dedicated network thread is there only to manage that run loop.
- Regarding processing queues, like the JSON one, I thought it would be a good idea to isolate that from the global queue; it could always target another queue if needed. Also, unless I'm mistaken, those queues should be concurrent rather than serial.
- As for dispatching to the main thread, this only happens it after all of the work in the operation is done. This just seems like good default behavior. If you wanted to, you could very easily override this by manually setting the `completionBlock` yourself.
I've been using AFNetworking for a month or two, now, and I cannot say enough good things about it. Mattt isn't joking when he describes it as a 'delightful' library; it really is a joy to use, and the community that has sprung up around it is incredibly dedicated and very responsive to suggestions and bug reports.
We've only experimented with converting over to AF, but the experience has been fairly pleasant. In particular, Mattt has been very receptive to talking a few things out with me and even sent me a follow up this morning when one of my complaints was fixed. Interacting with the community is important for this sort of project, and Mattt has a good start on that.
13 comments
[ 3.0 ms ] story [ 39.4 ms ] threadIs the implication that it performs some optimization that regular sockets could not do? Or is it merely faster than some alternative? I don't know terribly much about the i* ecosystem, but it seems like speed should be the least distinctive attribute for networking libraries; providing a helpful abstraction is the real concern, and only by considerably folly or cleverness would performance differ noticeably.
There are no hard performance benchmarks, but you'll get a good sense of how fast it is if you download and run the example app--I've yet to see any apps match the table view image loading performance.
FWIW, people who have switched from ASI usually report an overall networking speedup of 2-3x.
I am skeptical about claims that simply changing how it makes concurrent requests will make it 'insanely fast'. Bottom line is, outside of some careful tuning that uses knowledge of iOS internals, there isn't any real way a library can impact how fast bits travel over the wire.
Here's some feedback - if you wish to substantiate this claim, it shouldn't be hard to write the same app using ASI and then extract some real performance numbers (bonus points for publishing your test code to get doubters like me to shut up).
I understand and respect your skepticism, since by using NSURLConnection, its performance is bound by the same thing most other libraries are (although ASI was wrapped the lower-level CFNetwork APIs, FWIW). It's the stuff around the network activity--the way the application interacts with the data that makes AF fast. I've gone out of my way to design a minimal API that is performant no matter how you (mis)use it.
But you're right: I'll have to get around to writing a benchmark app at some point :)
However, the use of non-prefixed category methods (monkey-patching) is an inappropriate design choice, given the fact that the likelihood of conflict is actually higher than 0 when using non-prefixed category methods.
Let's say you were doing a gradual migration from ASIHTTP -- you'd have a non-deterministic conflict on the -[UIImageView setImageWithURL:] category method.
Unfortunately -- and despite repeated advisements to not do so by Apple engineers and others -- AFNetworking isn't the only library to add such a category method, and in fact, a number of libraries and third-party code add different, conflicting -[UIImageView setImageWithURL:] category methods. It's not too hard to wind up with a conflict.
Category methods should always be name-prefixed to avoid conflict, if you're going to use them at all:
The implementation looks pretty good, but some questions.
It looks like you might be using -[NSRunLoop run] to spin a background runloop? That will return immediately if no sources are scheduled in the runloop, which will result in a CPU-heavy busy-waiting thread -- unless I'm missing something here?
I was also wondering about choices like the use of a single statically allocated serial dispatch queue for performing all JSON parsing, rather than using concurrent queues and letting GCD figure out how much concurrency to leverage given the application state and hardware available.
Also, it appears that all callbacks are directly dispatched onto the main thread. Is there any interest in adding support for allowing the caller to specify dispatch onto other queues, in the case that they don't want to hit the main queue for background processing?
- As I understand threading and run loop scheduling, the run loop will spin up as needed when an NSURLConnection attaches itself to it, and back down again when no more connections are active. The dedicated network thread is there only to manage that run loop.
- Regarding processing queues, like the JSON one, I thought it would be a good idea to isolate that from the global queue; it could always target another queue if needed. Also, unless I'm mistaken, those queues should be concurrent rather than serial.
- As for dispatching to the main thread, this only happens it after all of the work in the operation is done. This just seems like good default behavior. If you wanted to, you could very easily override this by manually setting the `completionBlock` yourself.