Re: Recurrent NSInvocationOperations on an NSOperationQueue?
Re: Recurrent NSInvocationOperations on an NSOperationQueue?
- Subject: Re: Recurrent NSInvocationOperations on an NSOperationQueue?
- From: Ken Thomases <email@hidden>
- Date: Fri, 14 Aug 2015 20:24:49 -0500
On Aug 14, 2015, at 8:07 PM, Carl Hoefs <email@hidden> 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);
Regards,
Ken
_______________________________________________
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