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: Steven Degutis <email@hidden>
- Date: Sun, 30 Aug 2009 10:29:14 -0500
Ken,
Thanks for your detailed response. Originally the plan for this class was to
be an NSOperation on the advise of Steve Streza who mentioned that on Snow
Leopard, NSOperationQueues take advantage of GCD, which would improve
performance.
Previously (read: in the source of CocoaREST's class SDNetTask), I was using
the synchronous method of NSURLConnection to get data back from a server,
which was done in a non-concurrent NSOperation subclass. This was much
harder to cancel (actually, impossible as far as I know) than the async
method, and thus I wanted to avoid having non-cancelable operations simply
so it would not block out an NSOperationQueue when (especially dependencies
are involved, but also otherwise).
So, the idea here was basically to create an NSOperation subclass that could
deal with dependencies, and fit inside an NSOperationQueue (for plenty of
reasons), which used the async methods for getting HTTP data. However,
either removing NSOperation as the superclass, or requiring it be run on
+mainQueue both defeat the purpose of this class's flexibility, so it seems
like it would be a step backwards.
To be honest, I'm not entirely sure what the proper solution here is. From
what you're saying and from what the docs state, there's no decent way to
have my cake and eat it too... that is to say, if I use NSURLConnection
inside an NSOperation, it seems I would need to get rid of its
cancel-ability by using it synchronously, and, furthermore, I definitely
wouldn't be able to have the class function the same on iPhone, Leopard, and
Snow Leopard using NSOperationQueue, since they all behave differently. So,
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!)
--
Steven Degutis
http://www.thoughtfultree.com/
http://www.degutis.org/
On Sun, Aug 30, 2009 at 9:53 AM, Ken Thomases <email@hidden> wrote:
> On Aug 30, 2009, at 9:09 AM, Steven Degutis wrote:
>
> Unfortunately, the code I wrote completely broke yesterday when I upgraded
>> to Snow Leopard (fortunately I hadn't published it yet for that same
>> reason)
>> and it was narrowed down to the NSOperation subclass not getting any of
>> NSURLConnection's delegate methods at all. In fact, it seemed that the
>> object wasn't even getting any messages from
>> -performSelector:withObject:afterDelay: either, which made me wonder
>> whether
>> the NSRunLoop of the current NSThread was borked, or if the NSThread
>> itself
>> was in fact not intact.
>>
>> Interestingly, it still worked fine when the NSOperation object was run
>> with
>> -start, it only failed when run by being added to an NSOperationQueue.
>>
>
> In 10.6, NSOperationQueue ignores the -isConcurrent property of the
> operations and always invokes -start on one of its work threads. This may
> have contributed to your problem.
>
> That said, I don't think it's ever been a safe assumption that the thread
> on which either -start or -main is invoked has a run loop that's regularly
> serviced. If you need the run loop to be run, you should run it yourself.
> However, you should probably reconsider whether you need to be using a
> secondary thread, at all. An API which relies on the run loop, like
> NSURLConnection, is typically already asynchronous (ignoring for the moment
> the +sendSynchronousRequest:returningResponse:error: method). That is, you
> can set it up to work on the main thread without blocking it.
>
> A middle ground on 10.6 might be to schedule your operation on
> +[NSOperationQueue mainQueue]. Then, its -start will be guaranteed to be
> invoked on the main thread. In that case, you should implement the
> operation as concurrent. Your -start override should not block while the
> operation runs to completion. It should set things going and then return
> immediately. Naturally, this requires the very asynchronous nature of
> NSURLConnection that I mention above in order to work, which is why wrapping
> it up as an operation is largely unnecessary. It does let you integrate
> with other operations via the dependency mechanism, though.
>
>
> So after more researching of NSOperationQueue's documentation,
>> specifically
>> under "Avoid Per-Thread Storage" section of the "Operation Queues" guide,
>> it
>> states the following:
>>
>> "If an operation queue provides a thread for you, you should consider that
>> thread to be owned by the queue and not to be touched by your operation.
>> Specifically, you should never associate any data with a thread that you
>> do
>> not create yourself or manage. The threads managed by an operation queue
>> come and go depending on the needs of the system and your application.
>> Therefore, passing data between operations using per-thread storage is
>> unreliable and likely to fail."
>>
>> It seems to be that this exactly describes what is happening when
>> NSURLConnection is run asynchronously; it tries to use the thread it's
>> current in and its runloop, even though it created neither, since
>> NSOperationQueue did.
>>
>> First of all, am I reading and interpreting this correctly? I could be
>> mistaken on what this means, as I'm no expert to threads and runloops.
>>
>
> You are basically interpreting it correctly, yes. I would nitpick with
> your claim that it happens "when NSURLConnection is run asynchronously". It
> happens when NSURLConnection is run in a thread and that thread's run loop
> is not guaranteed to be serviced (a.k.a. run).
>
>
> Secondly, if so, would it be unwise to set up a thread and runloop
>> specifically for the NSURLConnection itself?
>>
>
> That would also work, but, again, the NSURLConnection is inherently an
> asynchronous API which can be run on the main thread (and main thread's run
> loop) without causing trouble. Spinning off your own thread to just sit in
> its run loop is unnecessary.
>
> The primary benefit NSURLConnection would get from running async inside an
>> NSOperation subclass is that it will be more easily cancelable
>>
>
> I don't understand this claim. NSURLConnection is just about as easily
> cancelable as is possible. You just invoke its -cancel method. It seems to
> me to be more easily cancelable than if it is wrapped in an NSOperation
> subclass.
>
> Regards,
> Ken
>
>
--
Steven Degutis
http://www.thoughtfultree.com/
http://www.degutis.org/
_______________________________________________
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