Register FAQ / Rules Forum Spy Search Today's Posts Mark Forums Read
Go Back   MacRumors Forums > Apple Systems and Services > Programming > iPhone/iPad Programming

Reply
 
Thread Tools Search this Thread Display Modes
Old Apr 9, 2009, 03:00 AM   #1
Sean7512
macrumors 6502a
 
Join Date: Jun 2005
Some help with NSThread please

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...

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
__________________
Check out my iOS Apps - Pilot Ace - iPhone/iPad | the Lunch Train - iPhone Only
Be Yourself, Only Better
Sean7512 is offline   0 Reply With Quote
Old Apr 9, 2009, 09:55 AM   #2
Sean7512
Thread Starter
macrumors 6502a
 
Join Date: Jun 2005
I believed that I've narrowed it down to the GUI update method. If I comment out the following line, it works fine:

Code:
[self performSelectorOnMainThread:@selector(downloadComplete:) withObject:newData waitUntilDone:NO];
This is obviously not a good solution, as the app needs to have visual feedback during download. Does anyone see anything that jumps out at them in my code?

Thanks,
Sean
__________________
Check out my iOS Apps - Pilot Ace - iPhone/iPad | the Lunch Train - iPhone Only
Be Yourself, Only Better
Sean7512 is offline   0 Reply With Quote
Old Apr 9, 2009, 10:06 AM   #3
PhoneyDeveloper
macrumors 68030
 
PhoneyDeveloper's Avatar
 
Join Date: Sep 2008
NSURLConnection does threaded downloads. You are basically duplicating its functionality. You're better off using that class.

Also, if you must use your own threads you are better off using NSOperationQueue. It's simpler to use.
PhoneyDeveloper is offline   0 Reply With Quote
Old Apr 9, 2009, 10:29 AM   #4
Sean7512
Thread Starter
macrumors 6502a
 
Join Date: Jun 2005
Quote:
Originally Posted by PhoneyDeveloper View Post
NSURLConnection does threaded downloads. You are basically duplicating its functionality. You're better off using that class.

Also, if you must use your own threads you are better off using NSOperationQueue. It's simpler to use.
Once the information is downloaded, it needs handled in a special way, so either way, I'll need to manually create my own thread.

I'll look into NSOperationQueue, although I thought the NSThread was simple, but anything to rid my runtime exception!

Finally, this is the exact error I am receiving:

Code:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSCFNumber coordinate]: unrecognized selector sent to instance 0x103a20'
__________________
Check out my iOS Apps - Pilot Ace - iPhone/iPad | the Lunch Train - iPhone Only
Be Yourself, Only Better
Sean7512 is offline   0 Reply With Quote
Old Apr 9, 2009, 12:07 PM   #5
PhoneyDeveloper
macrumors 68030
 
PhoneyDeveloper's Avatar
 
Join Date: Sep 2008
I don't see your code using the method 'coordinate' in the code you posted and it's not a UIKit method. I guess I'll assume it's from your code but not in the code you posted.

The usual cause of this run time exception is that something hasn't been retained correctly. In your case it would be an object of whatever class implements the coordinate method.

Also, don't cross-post like this.
PhoneyDeveloper is offline   0 Reply With Quote

Reply
MacRumors Forums > Apple Systems and Services > Programming > iPhone/iPad Programming

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Forum Jump

All times are GMT -5. The time now is 06:52 AM.

Mac Rumors | Mac | iPhone | iPhone Game Reviews | iPhone Apps

Mobile Version | Fixed | Fluid | Fluid HD
Copyright 2002-2013, MacRumors.com, LLC