Today I want to show you something little bit more advanced than the previous tutorials. Threading is a really important part when you are building applications on any platform from Windows to mobile devices. Thread is basically a line of processes, which has been started independently on the main program thread. In Objective-C we have the NSThread class, which can handle all the threading.
If you don't want to go trough the entire tutorial, Check out this short snippetThreading usually works in the same way in most programming languages. First you have the main thread, this one is created when you launch the application. Than you can create a different thread (can be started after some user interaction as a button pressed, etc, or automatically as a part of the program).
Because I am expecting that you already know how to connect elements from the interface builder to IBAction or IBOutlet, I am not going to cover this part. For more information’s please check the previous tutorials on XProgress.com about UIButton, UISwitch, UISlider or How to build the Navigation-based Application tutorial. Once you’ll finish any of these you’ll have pretty good idea "what the hell am I talking about" :)).
Let’s start with the less theoretical, and more interesting part of this tutorial. Yes, we are going to build our first multi-threaded application.
Start a new View-based application; call it "TutorialProject" to maintain the compatibility with the code in this tutorial. Open the TutorialProjectViewController.xib and set the main interface as it is on the next picture (You really need just the Thread part and the Test part). There is in both sections just one active UILabel (the one with the 0 (zero) in it). In the Tread part we have Progress view (UIProgressView) and button (UIButton).
The test part is here just because we want to verify that the interface is responding to touches while the other thread is running. It contains just that label with a value and slider (UISlider).

Now we have the user interface done ad we can move to the actual coding. Open the TutorialProjectViewController.h and create all the necessary IBOutlets for out interface.
@interface TutorialProjectViewController : UIViewController {
// ------ Tutorial code starts here ------
// Thread part
IBOutlet UILabel *threadValueLabel;
IBOutlet UIProgressView *threadProgressView;
IBOutlet UIButton *threadStartButton;
// Test part
IBOutlet UILabel *testValueLabel;
// ------ Tutorial code ends here ------
}
Now we need to create properties for our outlets (variables).
@property (nonatomic, retain) IBOutlet UILabel *threadValueLabel; @property (nonatomic, retain) IBOutlet UIProgressView *threadProgressView; @property (nonatomic, retain) IBOutlet UIProgressView *threadStartButton; @property (nonatomic, retain) IBOutlet UILabel *testValueLabel;
Next thing we need to do is to create IBAction’s. They are going to handle the events (actions) released when the button is pressed and when you’ll move the slider.
- (IBAction) startThreadButtonPressed:(UIButton *)sender; - (IBAction) testValueSliderChanged:(UISlider *)sender;
The entire code for TutorialProjectViewController.h is here:
// // TutorialProjectViewController.h // TutorialProject // // Created by Ondrej Rafaj on 5.8.09. // Copyright Home 2009. All rights reserved. // #import@interface TutorialProjectViewController : UIViewController { // ------ Tutorial code starts here ------ // Thread part IBOutlet UILabel *threadValueLabel; IBOutlet UIProgressView *threadProgressView; IBOutlet UIButton *threadStartButton; // Test part IBOutlet UILabel *testValueLabel; // ------ Tutorial code ends here ------ } // ------ Tutorial code starts here ------ @property (nonatomic, retain) IBOutlet UILabel *threadValueLabel; @property (nonatomic, retain) IBOutlet UIProgressView *threadProgressView; @property (nonatomic, retain) IBOutlet UIButton *threadStartButton; @property (nonatomic, retain) IBOutlet UILabel *testValueLabel; - (IBAction) startThreadButtonPressed:(UIButton *)sender; - (IBAction) testValueSliderChanged:(UISlider *)sender; // ------ Tutorial code ends here ------ // This function is for button which takes you to the xprogress.com website - (IBAction) runXprogressComButton: (id) sender; @end
Now open the TutorialProjectViewController.m file and synthesize the outlets.
@synthesize threadValueLabel, threadProgressView, testValueLabel, threadStartButton;
And after synthesizing don’t forget to release these from the memory in the dealloc function. You can find this one on the end of the file.
- (void)dealloc {
// ------ Tutorial code starts here ------
[threadValueLabel release];
[threadProgressView release];
[threadStartButton release];
[testValueLabel release];
// ------ Tutorial code ends here ------
[super dealloc];
}
Now we are going to do the actual threading. First of all we need to create a definition for our IBAction which will be called after the Start my thread button is pressed.
- (IBAction) startThreadButtonPressed:(UIButton *)sender {
threadStartButton.hidden = YES;
threadValueLabel.text = @"0";
threadProgressView.progress = 0.0;
[NSThread detachNewThreadSelector:@selector(startTheBackgroundJob) toTarget:self withObject:nil];
}
First we are hiding the button, because we don’t want users to press this button twice. On the second line we are setting the text to 0 (zero), resetting the progress bar on the third line and detaching a new thread on the fourth line, which calls the startTheBackgroundJob function.
Now we need to define the startTheBackgroundJob function.
- (void)startTheBackgroundJob {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// wait for 3 seconds before starting the thread, you don't have to do that. This is just an example how to stop the NSThread for some time
[NSThread sleepForTimeInterval:3];
[self performSelectorOnMainThread:@selector(makeMyProgressBarMoving) withObject:nil waitUntilDone:NO];
[pool release];
}
On the first line we are setting a new autorelease pool. Every time autorelease is sent to an object, it is added to the outer-most autorelease pool. When the pool is drained, it simply sends -release to all the objects in the pool.
Autorelease pools are simply a convenience that allows you to defer sending -release until "later". That "later" can happen in several places, but the most common in Cocoa GUI apps is at the end of the current run loop cycle.
The second line is here just because I wanted to show you how to pause the thread for a while, in this case, for 3 seconds. Last line is actually starting a function makeMyProgressBarMoving, and because the waitUntilDone statement is on NO, this function will be actually running on the background.
- (void)makeMyProgressBarMoving {
float actual = [threadProgressView progress];
threadValueLabel.text = [NSString stringWithFormat:@"%.2f", actual];
if (actual < 1) {
threadProgressView.progress = actual + 0.01;
[NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(makeMyProgressBarMoving) userInfo:nil repeats:NO];
}
else threadStartButton.hidden = NO;
}
Here we are getting the actual value of the progress bar, setting a value for the label and if the value is less than 1 (which is the maxim value for the UIProgressView, equals to 100%) we are adding 0.01 to the progress and setting a new timer (NSTimer), which will call this function again in 0.5 second. If the progress bar is in 100% (1) we are going to show the button again.
To finish our application we need to add the code, which handles UISlider and we are done.
- (IBAction) testValueSliderChanged:(UISlider *)sender {
testValueLabel.text = [NSString stringWithFormat:@"%.2f", sender.value];
}
The entire source code for the TutorialProjectViewController.m is here:
//
// TutorialProjectViewController.m
// TutorialProject
//
// Created by Ondrej Rafaj on 5.8.09.
// Copyright Home 2009. All rights reserved.
//
#import "TutorialProjectViewController.h"
@implementation TutorialProjectViewController
@synthesize threadValueLabel, threadProgressView, testValueLabel, threadStartButton;
// ------ Tutorial code starts here ------
- (IBAction) startThreadButtonPressed:(UIButton *)sender {
threadStartButton.hidden = YES;
threadValueLabel.text = @"0";
threadProgressView.progress = 0.0;
[NSThread detachNewThreadSelector:@selector(startTheBackgroundJob) toTarget:self withObject:nil];
}
- (void)startTheBackgroundJob {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// wait for 3 seconds before starting the thread, you don't have to do that. This is just an example how to stop the NSThread for some time
[NSThread sleepForTimeInterval:3];
[self performSelectorOnMainThread:@selector(makeMyProgressBarMoving) withObject:nil waitUntilDone:NO];
[pool release];
}
- (void)makeMyProgressBarMoving {
float actual = [threadProgressView progress];
threadValueLabel.text = [NSString stringWithFormat:@"%.2f", actual];
if (actual < 1) {
threadProgressView.progress = actual + 0.01;
[NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(makeMyProgressBarMoving) userInfo:nil repeats:NO];
}
else threadStartButton.hidden = NO;
}
- (IBAction) testValueSliderChanged:(UISlider *)sender {
testValueLabel.text = [NSString stringWithFormat:@"%.2f", sender.value];
}
// ------ Tutorial code ends here ------
/*
// The designated initializer. Override to perform setup that is required before the view is loaded.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
// Custom initialization
}
return self;
}
*/
/*
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView {
}
*/
/*
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
}
*/
/*
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
*/
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
// This function is for button which takes you to the xprogress.com website
- (IBAction) runXprogressComButton: (id) sender {
NSURL *url = [ [ NSURL alloc ] initWithString: @"http://www.xprogress.com/" ];
[[UIApplication sharedApplication] openURL:url];
}
- (void)dealloc {
// ------ Tutorial code starts here ------
[threadValueLabel release];
[threadProgressView release];
[threadStartButton release];
[testValueLabel release];
// ------ Tutorial code ends here ------
[super dealloc];
}
@end
Now you need to open Interface builder and set all the IBOutlets and IBAction’s to the elements on your view. Connect threadStartButton with the Start my thread button, threadValueLabel with the 0 label above the progress bar, threadProgressView with progress bar and testValueLabel with the 0 (zero) UILabel above your testing UISlider.
Now connect Start my thread button’s Touch Up Inside action with startThreadButtonPressed., and testValueSliderChanged with the Value Changed event on your UISlider.
WooohoooOOO, the work is done. Launch the application in the simulator on the actual device, press the Start thread button and start using the UISlider to test that even if the application is running a thread on the background, you can still work with the application without loosing the respond ability in the UI.
Thanks for your time and I hope that I’ll see your next visit in my Google Analytics stats soon :))
All the source codes are available for download, including the printer friendly version in MS Word.
Ondrej



Ondrej
from 87.194.**.** @If there will be anything you don't understand in this article ... please tell me and I'll fix it :)
Lars
from 82.83.**.** @Hey man! Nice tutorial! Keep it up!
HM50
from 75.51.**.** @Very nice tutorial! Excellent description of methods and each line of code.
Phil
from 68.5.**.** @I get these errors when trying to download the zip ...
Deprecated: Assigning the return value of new by reference is deprecated in /customers/xprogress.com/xprogress.com/httpd.www/admin/pear/HTTP/Download.php on line 243
Deprecated: Assigning the return value of new by reference is deprecated in /customers/xprogress.com/xprogress.com/httpd.www/admin/pear/HTTP/Download.php on line 705
Ondrej
from 87.194.**.** @Downloads are back online, sorry for any inconvenience caused ...
neha
from 123.237.**.** @Ondrej, thanx for such a nice tut! I have a doubt when I tried to create another thread in the same application the same way, after "performSelectorOnMainThread" method it doesn't execute the specified method in the selector. Can you please tell me why?
Ondrej
from 188.95.**.** @Are u absolutely sure that you are in the function where the call is made, try nslog some message there and inside of your function and if there will be any further problem, just try to post your code,
O.
Shyam
from 119.226.**.** @This tutorial explains lot. It is starter kit to big solutions.
sommeralex
from 193.110.**.** @I cant read everything - the codeboxes are cutting the text in Firefox..
Ondrej
from 90.192.**.** @That's strange, there should be a scroll bar and an option to switch to the plain code ... do u have enabled javascript?
Ryan
from 66.25.**.** @I am guessing any UI events, like showing a UIAlertView should be processed on the main thread? Thanks, and very helpful tutorial!
Grizzlynetch
from 93.99.**.** @I still feel like newbie in iphone development, but this tutorial confused me just a little.
First thing is that you start new thread, wait for 3 seconds, perform selector on main thread (in background - waitUntilDone:NO) and then just let the thread quit. Isn't it better to just do all the logic in thread and don't let the main thread do the logic and just informing the main thread that something changed and it should update GUI objects?
And second (just detail): I've red in book, that [self perfomSelector:_cmd withObject:nil afterDelay:xx] should be also used in repeatedly calling same method instead of using NSTimer(BUT! this method is also performed with cooperation of NSTimer class, so in fact it's about code transparency and habits) :)
LelmenrodeLof
from 24.176.**.** @I dont mean to hijack your forums but I have been looking for work all over the net.There seems to be allot of people here needingsome help and I wanted to drop in and see if I could be of service to anyone.
Checkout my resume and let me know if I can help out. http://www.linkedin.com/pub/jason-evans/19/a19/462
Thanks for your Time, Jason
mitySquinty
from 79.140.**.** @thanks! nice forum. i add www.xprogress.com to my bookmarks
Sunnyvegas
from 68.4.**.** @So I understand threading in the sense of it being able to run multiple functions in the background but what I am wondering is how exactly useful is that to the app. Meaning will this double the limit of limit you can use or how much to a degree is it possible to optimize your app being able to run things at the same time. I am just trying to grasp the scope of usefulness so I know how much I should use it and how often to use it, becuz I am sure there could be a such of thing as too much threading. or not?