AFNetworking: A Delightful Networking Library for iOS and Mac OS X
engineering.gowalla.com
engineering.gowalla.com
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:
-[UIImageView af_setImageWithURL:]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.
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.
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 :)