On Aug 14, 2015, at 8:43 PM, Carl Hoefs <newsli...@autonomy.caltech.edu> wrote:

> On Aug 14, 2015, at 6:24 PM, Ken Thomases <k...@codeweavers.com> wrote:
>> 
>> -performSelector:withObject:afterDelay: depends on the run loop.  The 
>> threads that service any non-main NSOperationQueue don't run their run loop. 
>>  In fact, you can't rely on them surviving past the end of your operation's 
>> code returning.
>> 
>> You will need to shunt this to a thread which reliably runs its run loop.  
>> The obvious candidate is the main thread.
>> 
>> You could do some combination of 
>> -performSelectorOnMainThread:withObject:waitUntilDone: with 
>> -performSelector:withObject:afterDelay:, but it's really much simpler to use 
>> GCD.
>> 
>> One approach is to use dispatch_after().  You could schedule a task to 
>> invoke -doStatusChecks on the main thread:
>> 
>>   dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 60ULL * NSEC_PER_SEC), 
>> dispatch_get_main_queue(), ^{
>>       [self doStatusChecks];
>>   });
>> 
>> Depending on why you're using a custom operation queue, you might skip the 
>> middle man and do:
>> 
>>   dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 60ULL * NSEC_PER_SEC), 
>> dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
>>       [self checkStatus];
>>   });
>> 
>> Finally, since this is a recurring task, you can use a dispatch timer source 
>> to do it all:
>> 
>>   dispatch_source_t timer = 
>> dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, 
>> dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
>>   dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 60ULL * NSEC_PER_SEC, 
>> 1ULL * NSEC_PER_SEC);
>>   dispatch_source_set_event_handler(timer, ^{
>>       [self checkStatus];
>>   });
>>   dispatch_resume(timer);
>> 
> 
> Thanks, Ken. The reason I'm using a custom operation queue instead of GCD is 
> that I need to permit only exclusive access to the device (e.g., to obtain 
> its status requires writing to it), but allow other operations enqueued to 
> use the device, not just the status checks. So I have an NSOperationQueue 
> that has maxConcurrentOperationCount set to 1, but I need a status-check 
> operation to be automatically queued up 1 minute after the last one has run.
> 
> So, if the device is accessed otherwise the status checks won't interfere 
> with that because only 1 operation can be active in the queue, thus 
> everything stays well ordered and exclusive access is permitted to all, one 
> at a time. I just can't figure a way to have the status check operation 
> trigger another one to be magically enqueued 60 seconds later.

You can use a serial GCD queue for the same purpose with my above suggestions.  
But even if you want to keep using an NSOperationQueue, you can still use my 
first dispatch_after() suggestion.  It works just like your code except for 
replacing -performSelector:withObject:afterDelay: with dispatch_after().  This 
changes doesn't affect anything about how -doStatusChecks works.  It will still 
use your NSOperationQueue.

You don't need to use the main GCD queue for my dispatch_after() suggestion, 
you can use a global concurrent queue.  Either works.

Regards,
Ken


_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to