Hey everyone,
I am working on my app and seem to have hit some mysterious run-time errors once I introduced threading. Below is my code before introducing threads, and it works 100% fine...
Now the code above works fine, however there are two problems with it. First, this is all on the UI thread, which may take a while to complete and that is obviously not good. Also, I need to have the code inside a loop so it continually gets new data "pushed" to the UITextView. This would continue until the user presses a "Stop" button. So, With this in mind, I re-wrote my code to what is below:
So now the code above is multi-threaded and does exactly what I need it to. However, its never that easy...Sometimes the code above works 100% flawless, other times it crashes upon pressing "Download" or other times it will crash in the middle of updating the UITextView, etc. The error the console is showing is "Invalid selector sent to object at <some memory address>." It used to crash everytime, but adding in those few synchronized blocks has helped, so I am suspecting that there is some concurrency issue that I am just overlooking. Anyone have any ideas, my eyes are burning and I would appreciate it if another pair of eyes looked at it real quick.
Thanks!
-Sean
I am working on my app and seem to have hit some mysterious run-time errors once I introduced threading. Below is my code before introducing threads, and it works 100% fine...
Code:
- (IBAction)downloadButtonPressed:(id)sender {
statusLabel.text = @"Getting new data...";
ServerManager *sm = [[ServerManager alloc] init];
NSArray *temp = [sm getDataAtLocation:currentLocation];
[userData addObjectsFromArray:temp];
for(int i=0; i<[userData count]; i++) {
Car *aCar = (Car *) [userData objectAtIndex:i];
NSString *st = [[NSString alloc] initWithFormat:@"Year: %@", aCar.Year];
[aCar release];
// Update UITextView log
results.text = [results.text stringByAppendingString:st];
[st release];
}
// Scroll to last line
[results scrollRangeToVisible:NSMakeRange([results.text length], 0)]
[sm release];
statusLabel.text = @"Download Finished.";
}
Now the code above works fine, however there are two problems with it. First, this is all on the UI thread, which may take a while to complete and that is obviously not good. Also, I need to have the code inside a loop so it continually gets new data "pushed" to the UITextView. This would continue until the user presses a "Stop" button. So, With this in mind, I re-wrote my code to what is below:
Code:
- (IBAction)stopButtonPressed:(id)sender {
keepScanning = false;
statusLabel.text = @"Stopped by user";
}
- (void) startDownload:(NSString*)s {/
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
while (keepDownloading) {
ServerManager *sm = [[ServerManager alloc] init];
NSArray *newData = nil;
@synchronized (currentLocation) {
newData = [sm getDataAtLocation:currentLocation];
}
@synchronized (userData) {
[userData addObjectsFromArray:newData];
}
//Use callback to update GUI
[self performSelectorOnMainThread:@selector(downloadComplete:) withObject:newData waitUntilDone:NO];
[newData retain];
[NSThread sleepForTimeInterval:1];
}
// release thread's pool
[pool release];
}
//callback
- (void) downloadComplete: (NSArray *)newData {
for(int i=0; i<[newData count]; i++) {
Car *aCar = (Car *) [newData objectAtIndex:i];
NSString *st = [[NSString alloc] initWithFormat:@"Year: %@", aCar.Year];
[aCar release];
@synchronized (results) {
// Update UITextView log
results.text = [results.text stringByAppendingString:st];
[st release];
// Scroll to last line
[results scrollRangeToVisible:NSMakeRange([results.text length], 0)];
}
}
}
- (IBAction) downloadButtonPressed:(id)sender {
// If already downloading, do nothing
if (!keepDownloading) {
keepDownloading = true;
statusLabel.text = @"Getting new data...";
//Start our threads -- this class method creates a new NSThread object to execute
//the selector of our choice.
[NSThread detachNewThreadSelector:@selector(startDownload:) toTarget:self withObject:nil];
}
}
So now the code above is multi-threaded and does exactly what I need it to. However, its never that easy...Sometimes the code above works 100% flawless, other times it crashes upon pressing "Download" or other times it will crash in the middle of updating the UITextView, etc. The error the console is showing is "Invalid selector sent to object at <some memory address>." It used to crash everytime, but adding in those few synchronized blocks has helped, so I am suspecting that there is some concurrency issue that I am just overlooking. Anyone have any ideas, my eyes are burning and I would appreciate it if another pair of eyes looked at it real quick.
Thanks!
-Sean