00001 #import "LLThreadWorker.h"
00002
00003
00004 @interface LLThreadWorker (PrivateAPI)
00005
00016 - (LLThreadWorker *) initWithTarget:(id)target
00017 selector:(SEL)selector
00018 argument:(id)argument
00019 didEndSelector:(SEL)didEndSelector;
00020
00021
00027 - (void) startThread:(NSArray *)callingPortArray;
00028
00029
00035 -(void)runPrimaryTask:(id)notUsed;
00036
00037
00038
00039 @end
00040
00041
00042
00043
00044 @implementation LLThreadWorker
00045
00046
00051 + (LLThreadWorker *) workOn:(id)target
00052 withSelector:(SEL)selector
00053 withObject:(id)argument
00054 didEndSelector:(SEL)didEndSelector;
00055 {
00056 LLThreadWorker *tw;
00057 NSPort *port1;
00058 NSPort *port2;
00059 NSConnection *conn;
00060 NSArray *callingPortArray;
00061
00062
00063 if( ![target respondsToSelector:selector] )
00064 {
00065 NSLog( @"\nLLThreadWorker reports: Target %@ does not respond to selector %@.", target, selector );
00066 return nil;
00067 }
00068
00069
00070 tw = [[[LLThreadWorker alloc]
00071 initWithTarget:target
00072 selector:selector
00073 argument:argument
00074 didEndSelector:didEndSelector] autorelease];
00075
00076 if( !tw )
00077 return nil;
00078
00079
00080 port1 = [NSPort port];
00081 port2 = [NSPort port];
00082 conn = [NSConnection connectionWithReceivePort:port1 sendPort:port2];
00083 [conn setRootObject:target];
00084 callingPortArray = [NSArray arrayWithObjects:port2, port1, conn, nil];
00085
00086
00087 [NSThread detachNewThreadSelector:@selector(startThread:) toTarget:tw withObject:callingPortArray];
00088
00089 return tw;
00090 }
00091
00092
00093
00094
00098 - (LLThreadWorker *) initWithTarget:(id)target
00099 selector:(SEL)selector
00100 argument:(id)argument
00101 didEndSelector:(SEL)didEndSelector
00102 {
00103 if( ![super init] )
00104 return nil;
00105
00106
00107 _target = target;
00108 _selector = selector;
00109 _argument = argument;
00110 _didEndSelector = didEndSelector;
00111 _cancelled = [[NSConditionLock alloc] initWithCondition:NO];
00112
00113
00114 [_target retain];
00115 [_argument retain];
00116
00117 return self;
00118 }
00119
00120
00124 - (void)dealloc
00125 {
00126
00127 [_target release];
00128 [_argument release];
00129 [_cancelled release];
00130
00131
00132
00133
00134
00135
00136
00137
00138 _target = nil;
00139 _argument = nil;
00140 _callingConnection = nil;
00141 _conn2 = nil;
00142 _port1 = nil;
00143 _port2 = nil;
00144 _cancelled = nil;
00145
00146 [super dealloc];
00147 }
00148
00149
00150
00151
00155 -(void)markAsCancelled
00156 {
00157
00158 if( [_cancelled tryLockWhenCondition:NO] )
00159 [_cancelled unlockWithCondition:YES];
00160 }
00161
00162
00163
00164
00165
00169 -(BOOL)cancelled
00170 {
00171 return [_cancelled condition];
00172 }
00173
00174
00175
00176
00177
00183 - (void)startThread:(NSArray *)callingPortArray
00184 {
00185 NSAutoreleasePool *pool;
00186
00187
00188 pool = [[NSAutoreleasePool alloc] init];
00189
00190
00191 _port1 = [callingPortArray objectAtIndex:0];
00192 _port2 = [callingPortArray objectAtIndex:1];
00193 _conn2 = [callingPortArray objectAtIndex:2];
00194 _callingConnection = [NSConnection connectionWithReceivePort:_port1 sendPort:_port2];
00195
00196
00197
00198 [[NSRunLoop currentRunLoop]
00199 addTimer:[NSTimer scheduledTimerWithTimeInterval:0
00200 target:self
00201 selector:@selector(runPrimaryTask:)
00202 userInfo:nil
00203 repeats:NO]
00204 forMode:NSDefaultRunLoopMode];
00205
00206
00207
00208
00209
00210
00211 _endRunLoop = NO;
00212 BOOL isRunning;
00213 do {
00214 isRunning = [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
00215 beforeDate:[NSDate distantFuture]];
00216 NSLog(@"isRunning: %d, _endRunLoop: %d", isRunning, _endRunLoop );
00217 } while ( isRunning && !_endRunLoop);
00218
00219
00220 [pool release];
00221 }
00222
00223
00228 -(void)runPrimaryTask:(id)notUsed
00229 {
00230 id userInfo;
00231
00232
00233
00234 if( [[_target methodSignatureForSelector:_selector] numberOfArguments] == 4 )
00235 userInfo = [_target performSelector:_selector withObject:_argument
00236 withObject:self];
00237 else
00238 userInfo = [_target performSelector:_selector withObject:_argument];
00239
00240
00241 if( _didEndSelector )
00242 [(id)[_callingConnection rootProxy] performSelector:_didEndSelector withObject:userInfo];
00243
00244
00245 [_callingConnection invalidate];
00246 [_conn2 invalidate];
00247 [_port1 invalidate];
00248 [_port2 invalidate];
00249
00250 _endRunLoop = YES;
00251 }
00252
00253
00258 + (NSString *)description
00259 { return @"LLThreadWorker v0.7. Public Domain. Original author: Robert Harder, rob@iharder.net. Keep up-to-date at http://iHarder.net";
00260 }
00261
00262
00263
00264 @end
00265