[SOLVED (but not pretty)] Running run loops in 10.6
[SOLVED (but not pretty)] Running run loops in 10.6
- Subject: [SOLVED (but not pretty)] Running run loops in 10.6
- From: Jerry Krinock <email@hidden>
- Date: Sun, 20 Sep 2009 20:20:18 -0700
Well, I don't think anyone is going to like this solution, but it
seems to be working for me and it comes with a plausible explanation...
On 2009 Sep 16, at 14:07, Chris Kane wrote:
Go back to the main thread. Setup a oneshot NSTimer for the timeout
period. Setup a notification handler to listen for the
NSTaskDidTerminateNotification. If the timer fires first, kill the
task, unregister the notification handler, etc. If the notification
happens first, invalidate the timer, unregister the notification
handler, etc. Don't run the run loop yourself. Let your code be
event-driven.
This works fine for the main thread, but if I need to run this in a
secondary thread or background tool, I still need something to make
the thread's or tool's -[NSRunLoop runMode:beforeDate:] return, so
that the thread or tool can exit. To solve that problem, at the end
of my notification handler and timer handler, I send this message:
[SSYRunLoopTickler tickle] ;
to the following class. Further explanation is in the comments.
***** Header File *****
#import <Cocoa/Cocoa.h>
/*!
@brief A class providing a method to "tickle" the run loop with a
dummy input source, causing a blocked -[NSRunLoop runMode:beforeDate:]
to return.
@details This is useful in designs which worked in Mac OS 10.5
because
they have run loops in background tools or secondary threads that were
being run when needed by behind-the-scenes input sources. These input
sources were apparently added by Cocoa in Mac OS 10.5, but they are
not
added in Mac OS 10.6. This is probably because 10.6 is using Grand
Central Dispatch or something else instead of run loops for whatever
it's doing behind the scenes.
*/
@interface SSYRunLoopTickler : NSObject {
}
/*!
@brief Inserts a dummy input source into the current run loop in
NSDefaultRunLoopMode, and sends a message to it, which will cause a
blocked -[NSRunLoop runMode:beforeDate:] elsewhere in the program to
return.
@details Removes the dummy input source after a delay of 0.0.
*/
+ (void)tickle ;
@end
***** Implementation File *****
#import "SSYRunLoopTickler.h"
@implementation SSYRunLoopTickler
+ (void)tickle {
NSPort* sendPort = [NSMachPort port] ;
[[NSRunLoop currentRunLoop] addPort:sendPort
forMode:NSDefaultRunLoopMode] ;
NSPort* receivePort = [NSMachPort port] ;
NSPortMessage* message = [[NSPortMessage alloc]
initWithSendPort:sendPort
receivePort:receivePort
components:nil] ;
BOOL sentOk = [message sendBeforeDate:[NSDate
dateWithTimeIntervalSinceNow:1.0]] ;
if (!sentOk) {
// Should actually return an NSError, but I don't think
// this will ever happen in real life, so I'm just going
// to log it.
NSLog(@"%s failed to send its message.", __PRETTY_FUNCTION__) ;
}
[message release] ;
// If I remove the port now, the desired "tickle" causing a
// blocked -[NSRunLoop runMode:beforeDate:] to return will
// not occur. But if I do so with a delay of 0.0, it works.
[self performSelector:@selector(removePort:)
withObject:sendPort
afterDelay:0.0] ;
}
/*!
Just a debugging note: If the +tickle message is sent from a
secondary thread which exits, the delayed performance of this
method will not occur, but that is OK because when its thread
ends the system should remove the port.
*/
+ (void)removePort:(NSPort*)port {
[[NSRunLoop currentRunLoop] removePort:port
forMode:NSDefaultRunLoopMode] ;
}
@end
_______________________________________________
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