一個運行的程序就是一個進程或者叫做一個任務
一個進程至少包含一個線程,線程是程序的執行流
iOS 程序啟動時,在創建一個進程的同事,會開始運行一個程序,該程序被稱作主線程
主線程是其他線程最終的父線程,所有界面的顯示操作必須在主線程進行!?。?!
后臺線程無法更新UI界面和響應用戶點擊事件
系統中的每一個進程都是有自己獨立的虛擬內存空間,而同一個進程中的多個線程則公用進程的內存空間
每創建一個新的線程,都會消耗一定內存的CPU時間
當多線程對同一個資源出現爭奪的時候需要注意線程安全問題
線程的使用不是無節制的 :iOS 主線程的堆棧大小是1M,從第二個線程開始就是512KB,這些數值不能通過編譯器開關和線程API函數更改
只有主線程有直接修改UI的能力
一、NSObject多線程方法
1、[NSThread currentThread]; 可以返回當前運行的線程
num = 1 說明是主線程
在任務多線程技術中,均可以使用此方法查看當前的線程情況。
2、新建后臺線程,調度任務
[selfperformSelectorInBackground:@selector(bgTask)withObject:nil];
使用performSelectorInBackground是可以修改UI的,不是強烈不建議這樣使用。
3、更新界面
使用performSelectorOnMainThread可以在主線程上執行任務。
提示:NSObject對象均可以調用此方法。
4、內存管理
線程任務要包在@autoreleasepool(自動釋放池)中,否則容易引起內存泄露,而且非常難發現。
5、總結:使用簡單,量級輕,不能控制線程的執行順序
例如:
@implementation ViewController
- (void)viewDidLoad {
[superviewDidLoad];
UIButton *button1 =[UIButtonbuttonWithType:UIButtonTypeCustom];
button1.backgroundColor =[UIColorredColor];
button1.frame =CGRectMake(50,50, 100,50);
[button1 setTitle:@"耗時操作"forState:UIControlStateNormal];
[button1 addTarget:selfaction:@selector(buttton1)forControlEvents:UIControlEventTouchUpInside];
[self.viewaddSubview:button1];
UIButton *button2 =[UIButtonbuttonWithType:UIButtonTypeCustom];
button2.backgroundColor =[UIColorredColor];
button2.frame =CGRectMake(50,150, 100,50);
[button2 setTitle:@"普通操作"forState:UIControlStateNormal];
[button2 addTarget:selfaction:@selector(button2)forControlEvents:UIControlEventTouchUpInside];
[self.viewaddSubview:button2];
}
-(void)buttton1
{
//后臺耗時操作
//performSelectorInBackground會創建一個后臺線程,并在該線程中執行調用的方法
// performSelectorInBackground是可以修改UI的但是強烈不建議使用
[selfperformSelectorInBackground:@selector(bgTask)withObject:nil];
}
-(void)button2
{
}
-(void)bgTask
{
@autoreleasepool {
for (int i =0; i < 30000000; i++) {
NSLog(@"%d",i);
}
//在主線程中修改所需要的操作或界面內容;withObject:所需要傳遞的參數
[selfperformSelectorOnMainThread:@selector(change)withObject:nilwaitUntilDone:YES];
}
}
-(void)change
{
}
二、NThread1、類方法
detachNewThreadSelector直接啟動線程,調用選擇器方法
2、成員方法
initWithTarget需要使用start方法才能啟動實例化出來的線程
優點:簡單
缺點:控制線程的生命周期比較困難
控制并發線程數
先后順序困難
例如:
#import "ViewController.h"
@interface ViewController ()
@PRoperty(nonatomic,strong)NSSet *imageViewSet;
@end
@implementation ViewController
-(void)setUpUI{
//實例化圖像視圖集合
NSMutableSet *imageSet = [NSMutableSetsetWithCapacity:28];
NSInteger w =self.view.frame.size.width/8;
NSInteger h =self.view.frame.size.height/8;
for (int row =0; row < 7; row++) {
for (int col =0; col < 4; col++) {
//計算圖片的位置
NSInteger x = col * w;
NSInteger y = row * h;
UIImageView *imageview =[[UIImageViewalloc]initWithFrame:CGRectMake(x, y, w, h)];
//順序填充圖片
NSInteger num = (row *4 * col) % 17 +1;
NSString *imageName =[NSStringstringWithFormat:@"圖片名稱%ld",num];
UIImage *image = [UIImageimageNamed:imageName];
[imageview setImage:image];
[self.viewaddSubview:imageview];
[imageSet addObject:imageview];
}
}
self.imageViewSet = imageSet;
//添加按鈕
UIButton *button =[UIButtonbuttonWithType:UIButtonTypeRoundedRect];
[button setFrame:CGRectMake(110,self.view.frame.size.height - 80, 100,50)];
[button setTitle:@"刷新圖片"forState:UIControlStateNormal];
[button addTarget:selfaction:@selector(click)forControlEvents:UIControlEventTouchUpInside];
[self.viewaddSubview:button];
}
-(void)click
{
[selfthreadLoad];
}
#pragma mark - NSThread方法
-(void)threadLoadImage:(UIImageView *)imageView{
@autoreleasepool {
NSInteger num =arc4random_uniform(17) +1;
NSString *imageName = [NSStringstringWithFormat:@"圖片名稱%ld",num];
UIImage *image =[UIImageimageNamed:imageName];
//主線程更新UI
[imageView performSelectorOnMainThread:@selector(setImage:)withObject:image waitUntilDone:YES];
}
}
-(void)threadLoad
{
for (UIImageView *imagevin self.imageViewSet) {
//新建線程調用threadLoadImage方法
// [NSThread detachNewThreadSelector:@selector(threadLoadImage:) toTarget:self withObject:imagev];
NSThread *thread = [[NSThreadalloc]initWithTarget:selfselector:@selector(threadLoadImage:)object:imagev];
//啟動線程
[thread start];
}
}
- (void)viewDidLoad {
[superviewDidLoad];
[selfsetUpUI];
}
三、NSOperation
1、NSOperation的兩個子類NSInvocationOperation,NSBlockOperation例如:
#import "ViewController.h"
@interface ViewController ()
@property(nonatomic,strong)NSSet *imageViewSet;
@property(strong,nonatomic)NSOperationQueue *queue;
@end
@implementation ViewController
-(void)setUpUI{
//實例化圖像視圖集合
NSMutableSet *imageSet = [NSMutableSetsetWithCapacity:28];
NSInteger w =self.view.frame.size.width/8;
NSInteger h =self.view.frame.size.height/8;
for (int row =0; row < 7; row++) {
for (int col =0; col < 4; col++) {
//計算圖片的位置
NSInteger x = col * w;
NSInteger y = row * h;
UIImageView *imageview =[[UIImageViewalloc]initWithFrame:CGRectMake(x, y, w, h)];
//順序填充圖片
NSInteger num = (row *4 * col) % 17 +1;
NSString *imageName =[NSStringstringWithFormat:@"圖片名稱%ld",num];
UIImage *image = [UIImageimageNamed:imageName];
[imageview setImage:image];
[self.viewaddSubview:imageview];
[imageSet addObject:imageview];
}
}
self.imageViewSet = imageSet;
//添加按鈕
UIButton *button =[UIButtonbuttonWithType:UIButtonTypeRoundedRect];
[button setFrame:CGRectMake(110,self.view.frame.size.height - 80, 100,50)];
[button setTitle:@"刷新圖片"forState:UIControlStateNormal];
[button addTarget:selfaction:@selector(click)forControlEvents:UIControlEventTouchUpInside];
[self.viewaddSubview:button];
}
-(void)click
{
// [selfoperationLoad];
[selfoperationBlockLoad];
}
#pragma mark - NSOperation方法
-(void)operationBlockLoad
{
for (UIImageView *imagevin self.imageViewSet) {
NSBlockOperation *op = [NSBlockOperationblockOperationWithBlock:^{
[selfoperationLoadImage:imagev];
}];
[self.queueaddOperation:op];
}
}
-(void)operationLoadImage:(UIImageView *)imageView{
@autoreleasepool {
NSInteger num =arc4random_uniform(17) +1;
NSString *imageName = [NSStringstringWithFormat:@"圖片名稱%ld",num];
UIImage *image =[UIImageimageNamed:imageName];
//主線程更新UI
[[NSOperationQueuemainQueue]addOperationWithBlock:^{
[imageView setImage:image];
}];
}
}
-(void)operationLoad
{
//隊列可以設置同時并發線程的數量
[self.queuesetMaxConcurrentOperationCount:3];
for (UIImageView *imagevin self.imageViewSet) {
NSInvocationOperation *op =[[NSInvocationOperationalloc]initWithTarget:selfselector:@selector(operationLoadImage:)object:imagev];
//如果直接調用start,實在主線程隊列上運行的,不會開啟新的線程
[op start];
//Invocation添加到隊列,一添加到隊列,就會開啟新的線程執行任務
[self.queueaddOperation:op];
}
}
#pragma mark - NSOperation操作之間的順序
-(void)operationDemo
{
NSBlockOperation *op1 = [NSBlockOperationblockOperationWithBlock:^{
}];
NSBlockOperation *op2 = [NSBlockOperationblockOperationWithBlock:^{
}];
NSBlockOperation *op3 = [NSBlockOperationblockOperationWithBlock:^{
}];
//Dependency依賴依賴關系可以多重依賴
[op2 addDependency:op1];
[op3 addDependency:op2];
[self.queueaddOperation:op3];
[self.queueaddOperation:op1];
[self.queueaddOperation:op2];
}
- (void)viewDidLoad {
[superviewDidLoad];
[selfsetUpUI];
//實例化操作隊列
self.queue = [[NSOperationQueuealloc]init];
}
四、GCD#import "ViewController.h"
@interface ViewController ()
@property(nonatomic,strong)NSSet *imageViewSet;
@end
@implementation ViewController
-(void)setUpUI{
//實例化圖像視圖集合
NSMutableSet *imageSet = [NSMutableSetsetWithCapacity:28];
NSInteger w =self.view.frame.size.width/8;
NSInteger h =self.view.frame.size.height/8;
for (int row =0; row < 7; row++) {
for (int col =0; col < 4; col++) {
//計算圖片的位置
NSInteger x = col * w;
NSInteger y = row * h;
UIImageView *imageview =[[UIImageViewalloc]initWithFrame:CGRectMake(x, y, w, h)];
//順序填充圖片
NSInteger num = (row *4 * col) % 17 +1;
NSString *imageName =[NSStringstringWithFormat:@"圖片名稱%ld",num];
UIImage *image = [UIImageimageNamed:imageName];
[imageview setImage:image];
[self.viewaddSubview:imageview];
[imageSet addObject:imageview];
}
}
self.imageViewSet = imageSet;
//添加按鈕
UIButton *button =[UIButtonbuttonWithType:UIButtonTypeRoundedRect];
[button setFrame:CGRectMake(110,self.view.frame.size.height - 80, 100,50)];
[button setTitle:@"刷新圖片"forState:UIControlStateNormal];
[button addTarget:selfaction:@selector(click)forControlEvents:UIControlEventTouchUpInside];
[self.viewaddSubview:button];
}
-(void)click
{
[selfgcdLoad];
}
#pragma mark - GCD加載圖像
-(void)gcdLoad
{
//派發dispatch異步async執行,并發執行
//PRIORITY優先級,一般選擇默認的即可
//獲取全局隊列
dispatch_queue_t queue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
for (UIImageView *imagevin self.imageViewSet) {
dispatch_async(queue, ^{
NSInteger num =arc4random_uniform(17) +1;
NSString *imageName = [NSStringstringWithFormat:@"圖片名稱%ld",num];
UIImage *image =[UIImageimageNamed:imageName];
//設置圖像,在主線程隊列設置UI
dispatch_async(dispatch_get_main_queue(), ^{
[imagev setImage:image];
});
});
}
}
#pragma mark - GCD
-(void)gcdDemo
{
//全局隊列中調用異步任務開發時候不用考慮并發線程數量問題
// dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// dispatch_async(queue, ^{
//
// });
// dispatch_async(queue, ^{
//
// });
// dispatch_async(queue, ^{
//
// });
//串行隊列,需要創建,不能夠get
dispatch_queue_t queue =dispatch_queue_create("myQUeue",DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
});
dispatch_async(queue, ^{
});
dispatch_async(queue, ^{
});
}
- (void)viewDidLoad {
[superviewDidLoad];
[selfsetUpUI];
}
@end
新聞熱點
疑難解答