Re: Async NSURLConnection + Concurrent NSOperation = Not possible under Mac OS X 10.6?
Re: Async NSURLConnection + Concurrent NSOperation = Not possible under Mac OS X 10.6?
- Subject: Re: Async NSURLConnection + Concurrent NSOperation = Not possible under Mac OS X 10.6?
- From: "Adam R. Maxwell" <email@hidden>
- Date: Sun, 30 Aug 2009 13:52:06 -0700
On Aug 30, 2009, at 12:12 PM, Ken Thomases wrote:
On Aug 30, 2009, at 1:47 PM, Adam R. Maxwell wrote:
On Aug 30, 2009, at 10:18 AM, Ken Thomases wrote:
On Aug 30, 2009, at 10:29 AM, Steven Degutis wrote:
I either would need to use NSURLConnection in a stand-alone
class, or use it
synchronously inside a non-concurrent NSOperation subclass.
(Please correct
me if I'm wrong!)
As Adam Maxwell said, you can use a non-concurrent operation which
uses the asynchronous NSURLConnection APIs and runs the run loop
itself. Handling cancel may require that you send a message from
whatever thread invoked -cancel to the thread on which your
operation is running, which may be non-trivial.
What messaging between threads is required? My suggestion is to
periodically check [self isCancelled] and run the runloop with a
timeout, and bail out if that's true. You have to do this anyway
in order to support cancellation, since it doesn't stop anything on
its own.
Well, that's polling and is generally discouraged.
Yes, but Apple's runloop documentation recommends using a timeout:
http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/Multithreading/RunLoopManagement/RunLoopManagement.html
You can certainly abuse it, but it's useful in some circumstances.
While you would have to check [self isCancelled] each time through
the run loop, if you treat cancellation as a message from one thread
to the other then you don't have to set a timeout. Processing the
message from the other thread will cause -[NSRunLoop
runMode:beforeDate:] to return, so you have the opportunity to check
then before looping back around and calling it again.
So in -start, you'd be running the runloop with +[NSDate
distantFuture] as the timeout and stash away the thread as an ivar for
later messaging in -cancel? I admit that I didn't think of overriding
-cancel as you suggest, but either way you end up with a potential
runloop/thread interaction mess. You'd also have to check download
failure conditions, but you have to do that either way.
If you're relying on a timeout, you have a trade off. Either you
check frequently, making a thread waste resources when it should be
idle, or you check infrequently, meaning there's a significant delay
between when you cancel the operation and when it actually
finishes. This, in turn, delays when any dependent operations can
start and when the queue recognizes that it has a slot free to start
any independent operation that may have been queued. Also, if you
have a GUI showing the state of the download, there may be a
worrisome delay between when the user tried to cancel and when it
actually stops.
All good points; I actually considered them all, and picked a design
that looked simple to implement and integrate with my existing
NSOperation usage. In the particular case of a download, I'm calling
CFRunLoopRunInMode with a 1 second timeout, which is negligile
overhead and still has no perceptible delay for the user when
cancelling. Of course, I also know that the download size is always
~3 MB, and won't happen more than once per day...so I factored that in
as well. I also profile my code regularly, and this has never showed
up as a problem.
Having said that, if I ever rewrite that program, I won't use
NSOperationQueue since I didn't end up using it in the way I'd
originally planned. Just using the async APIs from the main thread as
you originally suggested would work better for most of what I'm
doing. Of course, since the program is a) free, and b) working, I'm
not likely to find time for a full rewrite :).
That would probably work pretty well, assuming that generating
isExecuting/isFinished KVO notifications on the main thread is okay.
Of course that's OK. The NSOperation[Queue] docs already say that
you have to cope with the KVO notifications being delivered on any
thread.
"Because an operation may execute in any thread, any KVO
notifications associated with that operation may similarly occur in
any thread."
Before that was documented (or at least before I noticed it), I tried
binding a button's enabled state to the count of operations in a queue
that I'd created on the main thread. That blew up randomly until I
added some asserts and discovered that KVO notifications were sent on
random threads. So now I guess we can safely assume that Apple's code
can deal with KVO notifications on arbitrary threads.
On what thread would you expect delivery of the KVO notifications
from a non-current operation on the mainQueue, for example?
I'd expect them to arrive on the main thread, but be prepared to
handle them from other threads; I see -isConcurrent is now ignored on
10.6, which is interesting. Personally, I think NSOperation[Queue]'s
usage of KVO is sort of unfortunate.
Attachment:
smime.p7s
Description: S/MIME cryptographic signature
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden