Multithreading basics in iOS development
Time-consuming operation drill code walkthrough compilation time-consuming Method
- (void)longOperation { for (int i = 0; i < 10000; ++i) { NSLog(@"%@ %d", [NSThread currentThread], i); }}
Call the time-consuming method directly
// 1> directly call the time-consuming method [self longOperation];
Running Test Results
How to execute time consumption in the background
// 2> run the time consumption method in the background [self defined mselectorinbackground: @ selector (longOperation) withObject: nil];
Running Test Results
Summary
[NSThread currentThread]
: Current thread object
It can be used in all multithreading technologies! Usually used in multi-thread development, whether the Log Code is running in the main thread
number
number == 1
Main thread
number != 1
The background thread should not tangle with the specific number pthread Drill
pthread
Yes
POSIX
Multi-threaded development framework, because it is a cross-platform C language framework, there is no detailed comment in the Apple header file for reference
pthread
For information, visit the http://baike.baidu.com to import header files
#import
Pthread Drill
// Create a thread and execute the demo function-(void) pthreadDemo {/** parameter in the thread: 1> pointer to the thread identifier, in C, the end of the type is usually _ t/Ref, and you do not need to use * 2> to set the thread attribute 3> the start address of the thread running function 4> the return value of the parameter running function: -If the thread is successfully created, 0 is returned.-If the thread fails to be created, an error code */pthread_t threadId = NULL is returned. NSString * str = @ "Hello Pthread "; int result = pthread_create (& threadId, NULL, demo, (_ bridge void *) (str); if (result = 0) {NSLog (@ "create thread OK");} else {NSLog (@ "failed to create thread % d", result );}} // The background thread calls the void * demo (void * params) {NSString * str = (_ bridge NSString *) (params) function ); NSLog (@ "% @-% @", [NSThread currentThread], str); return NULL ;}
Summary in C language, no
Object
Object is
Struct
Normally, in the C language framework, the object type is
_t/Ref
And does not need to be used for declaration.
*
In Cvoid *
And in OCid
Is equivalentMemory Management
In OC, if it is
ARC
During compilation, the compiler automatically adds
retain
/
release
/
autorelease
However,
ARC
Only responsible for management
OC
Part of the memory management, not responsible
C Language
Therefore, if you use
C
Language framework appearance
retain
/
create
/
copy
/
new
Most of the functions require
release
Otherwise, memory leakage occurs during hybrid development.
C
And
OC
Use
__bridge
Bridge,
Bridging
The purpose is to tell the compiler how to manage the addition of memory bridging. You can use Xcode's auxiliary functions to add
MRC
You do not need to use bridging three methods to create a thread to prepare a function.
// MARK:-the backend thread calls the function-(void) longOperation :( id) obj {NSLog (@ "% @-% @", [NSThread currentThread], obj );}
1. alloc/init-start
// MARK:-NSThread drill-(void) threadDemo1 {// 1. instantiated thread object => alloc (memory allocation)/init (initialization) NSThread * t = [[NSThread alloc] initWithTarget: self selector: @ selector (longOperation :) object: @ "alloc/init"]; // 2. start thread [t start]; // 3. current thread? NSLog (@ "% @", [NSThread currentThread]);}
Drill Summary
[t start];
After execution, it will be executed in another thread
demo
Method in OC, the code of any method is the code of the same method executed in the top-down order, and is executed in the same thread (
block
Except) 2. detachNewThreadSelector
-(Void) threadDemo2 {// detach => Detach a subthread to execute demo: method [NSThread detachNewThreadSelector: @ selector (longOperation :) toTarget: self withObject: @ "detach"]; // 2. current thread? NSLog (@ "% @", [NSThread currentThread]);}
Drill Summary
detachNewThreadSelector
Class method does not need to be started. After the thread is created, the thread is automatically started for execution.
@selector
Method 3. Classification Method
-(Void) threadDemo3 {// 1. Run the @ selector method [self defined mselectorinbackground: @ selector (longOperation :) withObject: @ "category"] in the background; // 2. What is the current thread? NSLog (@ "% @", [NSThread currentThread]);}
performSelectorInBackground
Yes
NSObject
The classification method of does not exist.
thread
It will be executed in the background thread immediately
@selector
Method All
NSObject
You can use this method in other threads! Custom object Person class
// MARK:-Person class @ interface Person: NSObject // name @ property (nonatomic, copy) NSString * name; @ end @ implementation Person // use the dictionary to instantiate the object + (instancetype) personWithDict :( NSDictionary *) dict {Person * p = [[Person alloc] init]; [p setValuesForKeysWithDictionary: dict]; return p;} // load data-(void) loadData {NSLog (@ "load data %%%@", [NSThread currentThread], self. name) ;}@ end
Use the classification method for the Person class
- (void)threadDemo4 { Person * p = [Person personWithDict:@{@"name": @"zhangsan"}]; [p performSelectorInBackground:@selector(loadData) withObject:nil];}
Thread status drill code
// MARK:-thread status drill-(void) statusDemo {NSLog (@ "Sleep"); [NSThread sleepForTimeInterval: 1.0]; for (int I = 0; I <20; ++ I) {if (I = 8) {NSLog (@ "Sleep"); [NSThread sleepUntilDate: [NSDate dateWithTimeIntervalSinceNow: 1.0];} NSLog (@ "% @ % d", [NSThread currentThread], I); if (I = 10) {NSLog (@ "88 "); [NSThread exit] ;}} NSLog (@ "Can you come? ");}
-(Void) touchesBegan :( NSSet *) touches withEvent :( UIEvent *) event {// do not call the exit method on the main thread // [NSThread exit]; // instantiate the thread object (new) NSThread * t = [[NSThread alloc] initWithTarget: self selector: @ selector (statusDemo) object: nil]; // The thread is ready (added to the scheduling thread pool) [t start];}
Blocking method execution process. When a certain condition is met, you can use
sleep
Method To let the thread enter
Blocking
Status
1>sleepForTimeInterval
From now on
Seconds
2>sleepUntilDate
Sleep from now on to the specified date of death
[NSThread exit];
Once the thread is forcibly terminated, all subsequent code will not be executed.
Note: Before terminating the thread, pay attention to releasing the previously allocated objects!Ready-> RUN
Thread slaveReady
AndRun
Switching between statuses is causedCPU
Responsible, programmers cannot intervene
Thread property drill code
// MARK:-thread Attribute-(void) threadProperty {NSThread * t1 = [[NSThread alloc] initWithTarget: self selector: @ selector (demo) object: nil]; // 1. thread name t1.name = @ "Thread AAA"; // 2. priority t1.threadPriority = 0; [t1 start]; NSThread * t2 = [[NSThread alloc] initWithTarget: self selector: @ selector (demo) object: nil]; // 1. thread name t2.name = @ "Thread BBB"; // 2. priority t2.threadPriority = 1; [t2 start];}-(void) demo {fo R (int I = 0; I <10; ++ I) {// stack size NSLog (@ "% @ stack size: % tuK", [NSThread currentThread], [NSThread currentThread]. stackSize/1024);} // simulate the crash // determine whether it is the main thread // if (! [NSThread currentThread]. isMainThread) {// NSMutableArray * a = [NSMutableArray array]; // [a addObject: nil]; //}
Attribute 1.
name
-The thread name is in a large commercial project. Generally, when the program crashes, obtain the thread where the program runs accurately. 2.
threadPriority
-Thread priority, which is a floating point number with a value range from
0~1.0
1.0
Highest priority
0.0
Indicates that the lowest priority is
0.5
The high priority only ensures the possibility of CPU scheduling. I personally suggest that you do not modify the priority of multi-thread during development. The goal is to put time-consuming operations in the background, the main thread and user interaction are not blocked! Multi-threaded development principles: simplicity 3.
stackSize
-Stack zone size: by default, whether it is the main thread or sub-thread, the stack zone size is
512K
Stack zone size can be set
[NSThread currentThread].stackSize = 1024 * 1024;
4.
isMainThread
-Whether to share resources in the main thread-Ticket Selling
Multi-threaded development is relatively complex. You can write code as follows during development:
First, make sure that a single thread executes the correct logic of adding a thread to sell tickets
-(Void) touchesBegan :( NSSet *) touches withEvent :( UIEvent *) event {self. tickets = 20; [self saleTickets];} // ticket selling logic-each ticket sales logic (window) should sell all tickets-(void) saleTickets {while (YES) {if (self. tickets> 0) {self. tickets --; NSLog (@ "remaining votes % d % @", self. tickets, [NSThread currentThread]);} else {NSLog (@ "no votes % @", [NSThread currentThread]); break ;}}}
Add thread
-(Void) touchesBegan :( NSSet *) touches withEvent :( UIEvent *) event {self. tickets = 20; NSThread * t1 = [[NSThread alloc] initWithTarget: self selector: @ selector (saleTickets) object: nil]; t1.name = @ "conductor "; [t1 start]; NSThread * t2 = [[NSThread alloc] initWithTarget: self selector: @ selector (saleTickets) object: nil]; t2.name = @ "conductor B "; [t2 start];}
Add sleep
-(Void) saleTickets {while (YES) {// simulate sleep [NSThread sleepForTimeInterval: 1.0]; if (self. tickets> 0) {self. tickets --; NSLog (@ "remaining votes % d % @", self. tickets, [NSThread currentThread]);} else {NSLog (@ "no votes % @", [NSThread currentThread]); break ;}}}
Test result
Add mutex lock
-(Void) saleTickets {while (YES) {// simulate sleep [NSThread sleepForTimeInterval: 1.0]; @ synchronized (self) {if (self. tickets> 0) {self. tickets --; NSLog (@ "remaining votes % d % @", self. tickets, [NSThread currentThread]);} else {NSLog (@ "no votes % @", [NSThread currentThread]); break ;}}}}
The mutex lock summary ensures that only one thread can execute the code in the lock at the same time! The lock range of the mutex should be as small as possible. The larger the lock range, the worse the efficiency! Stenography skills
[[NSUserDefaults standardUserDefaults] synchronize];
Any lock allowed by mutex lock Parameters
NSObject
Object
Note: The lock object must be accessible by all threads.If there is only one place in the code that requires locking, most of them use
self
This avoids the creation of another lock object atomic attribute (thread security). It is designed for multithreading and is the default attribute when multiple threads write atomic attributes (called
setter
To ensure that only one thread executes write operations at a time.
Single (thread) write multiple (thread) read
Multithreading technology
Atomic attributes are more efficient than mutex locks.
, But it may appear
Dirty data
When defining attributes, you must specify
nonatomic
Drill code
@ Interface ViewController () @ property (atomic, strong) NSObject * obj1; @ property (atomic, strong) NSObject * obj2; @ end @ implementation ViewController @ synthesize obj1 = _ obj1; // atomic property simulation code // obj1-getter-(NSObject *) obj1 {return _ obj1;} // obj1-setter-(void) setObj1 :( NSObject *) obj1 {@ synchronized (self) {_ obj1 = obj1;}-(void) touchesBegan :( NSSet *) touches withEvent :( UIEvent *) event {long largeNumber = 1000*1000; // mutex lock test CFAbsoluteTime start = CFAbsoluteTimeGetCurrent (); for (int I = 0; I <largeNumber; ++ I) {self. obj1 = [[NSObject alloc] init];} NSLog (@ "% f", CFAbsoluteTimeGetCurrent ()-start); // spin lock Test start = CFAbsoluteTimeGetCurrent (); for (int I = 0; I <largeNumber; ++ I) {self. obj2 = [[NSObject alloc] init];} NSLog (@ "% f", CFAbsoluteTimeGetCurrent ()-start);} @ end
The internal lock of the atomic attribute isSpin lock
,The execution efficiency of spin locks is higher than that of mutex locks.
Spin lock & mutex lock
Commonalities
Only one thread executes the Code with the lock range at the same time.
Differences
Mutex lock
: If other threads are executing the locked code, the thread will
Enter sleep status
Wait until the execution of other threads is completed. After the lock is opened, the thread will be
Wake up
Spin lock
: If other threads are executing the locked code, the thread will
Endless loop
Wait until the lock code execution is complete.
Conclusion
The spin lock is more suitable for executing very short code. No matter what the lock is, it must pay the price. When multiple threads perform read/write operations, the correct results are still returned, known as thread security, to achieve thread security, it must be used
Lock
For better user experience,
UIKit is NOT thread-safe
Convention: all operations to update the UI must be performed on the main thread!
Therefore,
Main thread
Also known
UI thread
It is recommended that all attributes be declared
nonatomic
Avoid multiple threads to snatch the same resource as much as possible. The business logic of locking and resource grabbing should be handed over to the server for processing, reducing the pressure on the mobile client. The main thread of Inter-thread communication must implement the defined attributes.
/// The root view is a rolling view @ property (nonatomic, strong) UIScrollView * scrollView; // The Image view @ property (nonatomic, weak) UIImageView * imageView; /// image downloaded over the network @ property (nonatomic, weak) UIImage * image;
LoadView
The role of the loadView method:
Loading view hierarchies using functions and
Storyboard
&
XIB
Is equivalent
If you overwriteloadView
,Storyboard
&XIB
Invalid
- (void)loadView { self.scrollView = [[UIScrollView alloc] init]; self.scrollView.backgroundColor = [UIColor orangeColor]; self.view = self.scrollView; UIImageView *iv = [[UIImageView alloc] init]; [self.view addSubview:iv]; self.imageView = iv;}
After the viewDidLoad view is loaded, you can perform some data initialization. If you use code-only development, do not set the UI in this method.
-(Void) viewDidLoad {[super viewDidLoad]; // download the image [self downloadImage];}
Download network images
-(Void) downloadImage {// 1. network image resource path NSURL * url = [NSURL URLWithString: @ "http://c.hiphotos.baidu.com/image/pic/item/4afbfbedab64034f42b14da1aec379310a551d1c.jpg"]; // 2. instantiate binary data (Network Access) from the network resource path NSData * data = [NSData dataWithContentsOfURL: url]; // 3. convert binary data to image UIImage * image = [UIImage imageWithData: data]; // 4. set image self. image = image ;}
Set Images
-(Void) setImage :( UIImage *) image {// 1. set the image self in the Image view. imageView. image = image; // 2. set the size of the Image view according to the image size [self. imageView sizeToFit]; // 3. sets the contentSize self of the scroll view. scrollView. contentSize = image. size ;}
Set the zoom of the scroll View
1> set the zoom attribute of the scroll View
// 1> Minimum zooming ratio self. scrollView. minimumZoomScale = 0.5; // 2> maximum zoomscale self. scrollView. maximumZoomScale = 2.0; // 3> set proxy self. scrollView. delegate = self;
2> implement proxy-tell the scroll view which view is scaled
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView { return self.imageView;}
3> trackingscrollView
Zoom Effect
- (void)scrollViewDidZoom:(UIScrollView *)scrollView { NSLog(@"%@", NSStringFromCGAffineTransform(self.imageView.transform));}
Inter-thread communication downloads images in background threads
[self performSelectorInBackground:@selector(downloadImage) withObject:nil];
Set the image in the main thread
[self performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:NO];}