Sending mutable data across thread boundaries is a good recipe for problems. You should always use NSArray
, NSString
, NSSSet
, etc, instead of their mutable subclass when sending an object to another thread. This simple rule makes multithreading so much more pleasant.
Thankfully all collection classes implements the NSCopying
protocol and thus have a nifty -[copy]
method that return s an immutable copy of itself.
Next thing you need to decide is what to do if you mutate the original array. Sould you:
- Just enqueue a new pathfinder operation?
- Discard the current pathfinder operation, and start a new?
Option 1. to just add a new operation is easiest, but may/will waste time if your original arrays are mutated frequently.
Option 2. require some more work on your part. More specifically:
- You must hold onto the last operation so that you can send a
-[NSOperation cancel]
message to it. Or alternatively if you have a queuededicated to only pathfinding that you can cancel all operations on it using [NSOperationQueue cancelAllOperations]
.
- You should bail out early from your operations if they are cancelled. This requires you to subclass
NSOperation
, you can no longer just use NSInvocationOperation
as-is.
Your NSOperation
subclass implementation should look something like this:
@implementation CWPathfinderOperation
-(id)initWithFiends:(NSArray*)fiends delegate:(id<CWPathfinderOperation>)delegate {
self = [super init];
if (self) {
self.fiends = fiends;
self.delegate = delegate;
}
return self;
}
-(void)main {
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
while (notDone) {
if ([self isCancelled]) goto bailOut;
// Do smallpart of work
}
[self.delegate performSelectorOnMainThread:@selector(pathfinderOperatioDidFindPaths:)
withObject:result
waitUntilDone:NO];
bailOut:
[pool release];
}
@end