This section describes how to use multithreading in the iPhone SDK and precautions. Although most PC applications currently support multi-thread/multi-task development, Apple does not recommend multi-thread programming on the iPhone. Multi-threaded programming is a development trend, and it is said that the upcoming iPhone OS4 will fully support multi-threaded processing methods. Therefore, mastering the multi-threaded programming method will certainly explore the greater potential of the iPhone in some cases.
Start with an example
Start with a routine. For more information about the code, see here. You can download other routines.
For the control model of multi-threaded programs, see here. Generally, the manager/worker model is used. Here, we use NSThread in the iPhone SDK to implement it.
First, create a new View-based application project named "TutorialProject ". As shown in the interface, use UILabel to implement the two parts (Thread Part and Test Part). The Thread Part contains a UIProgressView and a UIButton. The Test Part contains a value and a UISlider.
Next, create IBOutlets for each UI control in the TutorialProjectViewController. h file.
@ 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 ------
}
At the same time, you also need to create the property of the outlets variable.
@ 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, define the action function when the button is pressed and the variable function of slider.
-(IBAction) startThreadButtonPressed :( UIButton *) sender;
-(IBAction) testValueSliderChanged :( UISlider *) sender;
Then in the TutorialProjectViewController. m file synthesize outlets, and in the file to implement dealloc release resources.
@ Synthesize threadValueLabel, threadProgressView, testValueLabel, threadStartButton;
...
-(Void) dealloc {
// ------ Tutorial code starts here ------
[ThreadValueLabel release];
[ThreadProgressView release];
[ThreadStartButton release];
[TestValueLabel release];
// ------ Tutorial code ends here ------
[Super dealloc];
}
Start the code of the thread. First, when the thread button is pressed, create a new thread.
-(IBAction) startThreadButtonPressed :( UIButton *) sender {
ThreadStartButton. hidden = YES;
ThreadValueLabel. text = @ "0 ";
ThreadProgressView. progress = 0.0;
[NSThread detachNewThreadSelector: @ selector (startTheBackgroundJob) toTarget: self withObject: nil];
}
After the button is pressed, hide the button to prevent multiple threads from being created. Then initialize the display value and progress bar, and create a new thread. The thread function is startTheBackgroundJob.
The specific startTheBackgroundJob function is defined as follows.
-(Void) startTheBackgroundJob {
NSAID utoreleasepool * pool = [[NSAID utoreleasepool alloc] init];
// Pause the thread for 3 seconds after it starts. (This is just a demonstration of the pause method. You do not have to do this)
[NSThread sleepForTimeInterval: 3];
[Self defined mselecw.mainthread: @ selector (makeMyProgressBarMoving) withObject: nil waitUntilDone: NO];
[Pool release];
}
In row 3, An NSAID utoreleasepool object is created to manage the object Resources automatically released in the thread. Here, the NSAID utoreleasepool is released when the thread exits. This complies with the general rules of the Cocoa GUI application.
In the last line, the makeMyProgressBarMoving function of the waitUntilDone status is ON.
-(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;
}
Calculate the value of the progress bar to be displayed. NSTimer increases by 0.5 every 0.01 seconds. When the value is equal to 1, the progress bar is 100%. Exit the function and display the hidden button.
Finally, add the UISlider implementation function to change the label value in the Test Part in the main thread.
-(IBAction) testValueSliderChanged :( UISlider *) sender {
TestValueLabel. text = [NSString stringWithFormat: @ "%. 2f", sender. value];
}
Compile and execute the program. Press the thread start button and you will see that the progress bar is running in the background.
Thread usage considerations
Thread stack size
Application Development on iPhone devices is also the development of embedded devices. You also need to pay attention to several issues during development of embedded devices, such as resource ceiling and processor speed.
The thread application in the iPhone is not uncontrolled. Official documents show that the stack size of the main thread in the iPhone OS is 1 MB, and that of the second thread is kb at the beginning. The value cannot be changed through the compiler switch or the thread API function.
You can use the following example to test your device. POSIX Thread (pthread) is used here, the device environment is iPhone 3GS (16 GB), and the SDK is 3.1.3.
# Include "pthread. h"
Void * threadFunc (void * arg ){
Void * stack_base = pthread_get_stackaddr_np (pthread_self ());
Size_t stack_size = pthread_get_stacksize_np (pthread_self ());
NSLog (@ "Thread: base: % p/size: % u", stack_base, stack_size );
Return NULL;
}
-(Void) applicationDidFinishLaunching :( UIApplication *) application {
Void * stack_base = pthread_get_stackaddr_np (pthread_self ());
Size_t stack_size = pthread_get_stacksize_np (pthread_self ());
Struct rlimit limit;
Getrlimit (RLIMIT_STACK, & limit );
NSLog (@ "Main thread: base: % p/size: % u", stack_base, stack_size );
NSLog (@ "rlimit-> soft: % llu/hard: % llu", limit. rlim_cur, limit. rlim_max );
Pthread_t thread;
Pthread_create (& thread, NULL, threadFunc, NULL );
// Override point for customization after app launch
[Window addSubview: viewController. view];
[Window makeKeyAndVisible];
}
The result is as follows:
Simulator
Main thread: base: 0xc0000000/size: 524288
Rlimit-> soft: 8388608/hard: 67104768
Thread: base: 0xb014b000/size: 524288
Device
Main thread: base: 0x30000000/size: 524288
Rlimit-> soft: 1044480/hard: 1044480
Thread: base: 0xf1000/size: 524288
It can be seen that when you test a multi-threaded program, the stack size of the simulator is different from that of the actual device. Pay attention to calling a large number of recursive functions.
Autorelease
If you do not consider anything and call autorelease in the thread function, the following error will occur:
NSAID utoreleasenopool (): Object 0x ********* of class NSConreteData autoreleased with no pool in place ....
Generally, the memory usage mode in the thread is that the thread initially
NSAID utoreleasepool * pool = [[NSAID utoreleasepool alloc] init];
[Pool drain] or [pool release] at the end of the thread. 1
Child Line plotting window
In multi-threaded programming, a general principle is that all UI-related operations are performed by the main thread. The sub-thread is only responsible for transactions and data processing. How can I update the UI in a child thread? If it is in windows, you will post the message to describe the updated message. On the iPhone, you need to use the receivmselecdomainmainthread to delegate the main thread for processing.
For example, if you want to update the image of UIImageView in a child thread
ImageView. image = [UIImage imageNamed: @ "Hoge.png"];
In this way, nothing will happen. You need to delegate the processing to the main thread, as shown below:
[Delegate initialize mselecw.mainthread: @ selector (theProcess :) withObject: nil waitUntilDone: YES];
OK!
So far, the iPhone development advanced series has come to an end. Next we will summarize some tips and application technologies for different development fields, and hope you will continue to pay attention to them.
Note: The difference between drain and release is that there is a GC in your system. If yes,-drain needs to send a message to GC (objc_collect_if_needed). If there is no GC, drain = release
Author: Yi Feiyang