> On Aug 14, 2015, at 6:24 PM, Ken Thomases <k...@codeweavers.com> wrote:
> 
> On Aug 14, 2015, at 8:07 PM, Carl Hoefs <newsli...@autonomy.caltech.edu> 
> wrote:
> 
>> Here's what I'm trying to do, but in code rather than words:
>> 
>>   . . .
>>   [self doStatusChecks];  // start endless checking at 1-min intervals
>>   . . .
>> 
>> 
>> - (void)doStatusChecks
>> {
>>   [jobQueue addOperation:[[NSInvocationOperation alloc] initWithTarget:self 
>>                 selector:@selector(checkStatus) object:nil]];
>> }
>> 
>> - (void)checkStatus
>> {
>>   //    Access device & read status
>>   //    If bad, do work...
>> 
>>   //    Enqueue another operation, but after 60 sec delay
>> 
>>   [self performSelector:@selector(doStatusChecks)
>>              withObject:nil
>>              afterDelay:60.0];  // <-- This never fires!
>> 
>>   [self doStatusChecks];        // <-- Fires immediately, but not what I want
>> }
> 
> -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.

-Carl


_______________________________________________

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