Saturday 30 May 2009

[medium | advanced] Threading

How many times have you bumped your head on your desk for (one or more) of the following problems?

1. I used

[myactivityindicator startAnimating];
NSString *string = [[NSString alloc] initWithContentsOfURL......
[myActivityIndicator stopAnimating];

and the activity indicator never started + stopped spinning!

2. I tried to move a large file and use activity indicators, but It wouldn't animate.

Well, thanks to the beauty of threads there *is* a solution to your problem.

You see, when your app starts up, you are in something called the "main thread." All UIKit calls (and CF** SC**) are from this thread. Meaning, if you calling an NSString class function, then its not going to go on to animating the activity indicator, its just going to hang there and wait for the NSString operation to finish. Annoying, right? But what if we could have our own main thread, but just for our selfish needs? Maybe we want to grab the contents of a URL, and then display it, while keeping the user updated as to what exactly we are doing? Well, here's the solution. We create our own thread, do as we please, and then tell the main thread that we're done, so that it can handle accordingly.

So, to begin:

Go into your header file (for your view controller), and add the method definitions for these methods:
Code:
- (IBAction)pressed:(id)sender;
- (void)entryPoint;
- (void)done:(NSString *)status;
Also, create an activity indicator (nonatomic, retain atr.) as an IBOutlet, along with a UILabel thats an IBOutlet. Name the Acitvity Indicator "act", and name the label "label". Now, go into the view controller nib and set up these outlets (also create a button, set up the "touch up inside" event for the button to - (IBAction)pressed..) . For the purpose of this tutorial, we're going to be loading a huge text file into a variable, so that we can manipulate that variable. So, create a text file, and write "0" in it about, i don't know, a few hundred times (write a row, and then copy + paste that row). Now, drag this file into our xcode project, (make sure it's named "file.txt"). Ok, now go into your implementation file. Here's where most of the interesting stuff is. add this method:
Code:

- (IBAction)pressed:(id)sender
{
// now, we create the thread
[NSThread detachNewThreadSelector:@selector(entryP oint) toTarget:self withObject:nil];
[act startAnimating];
}

- (void)entryPoint
{
// the new thread will be spawned here. We have to set up something first
NSAutoReleasePool *pool = [[NSAutoReleasePool alloc] init];
NSString *str = [[[NSString alloc] initWithContentsOfFile:@"file.txt"] autorelease];
[self performSelectorOnMainThread:@selector(do ne:) withObject:str waitUntilDone:NO];

[pool release];
}
Ok, now a few explanations:
Code:
[self performSelectorOnMainThread:@selector(do ne:) withObject:str waitUntilDone:NO];
this is saying that we should perform the selector "done" on the main thread, and pass the variable "str" as a parameter to it (done: takes an NSString * parameter). WaitUntilDone: specifies whether or not our thread should wait for the function to return or for it to proceed while the task is pending.

Also, when you create a thread, you MUST create an autorelease pool

EX:
Code:
// create an autorelease pool
NSAutoReleasePool *pool = [[NSAutoReleasePool alloc] init];

// all code for thread goes here...

[pool release];
// release the pool, so we don't leak memory
Ok, now the done: method

Code:

- (void)done:(NSString *)result
{
[act stopAnimating];
NSLog(@"thread finished loading variable");
UIAlertView *a = [[UIAlertView alloc] initWithTitle@"Message" message:[NSString stringWithFormat:@"loaded variable:\n%@",result] delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil];
[a show];
[a release];
}
Basically, we make our spinner stop, Log that we loaded the variable, and then shoot out an AlertView saying, "Hey, its done! Here's what it is.."

Now, here's a few challenges:

1. Write a PHP program that uses mysql. Format:

http://www.mywebsite.com/ex.php?name=bob

create a mysql table called "people".
Add a column for name, and one for age.

The PHP program will traverse the table, looking for a person named the variable $_GET['name'] which is equivalent to the ?name= part.
Have the PHP program output the age if found, or "NO"

On your iphone program, accept input for a name. Start a thread which will use a formatted NSString with the input in the url:

[NSString stringWithFormat:@"http://www.mywebsite.com/ex.php?name=%@",namefield.text];

Use NSString contents of URL instance || class function to grab the contents, and use a similar done: method to process them. Wrap this all up with an activity indicator that starts and stops, and you'll be well on your way with threads.


- meowmix

No comments:

Post a Comment