您的位置:首页 > 移动开发 > IOS开发

iOS多线程总结

2016-05-09 16:40 423 查看
线程的注意点:

1.不要同时开太多的线程(1~3条线程即可,不要超过5条)

2.线程概念:

1>主线程:UI线程,显示、刷新UI界面,处理UI控件的事件

2>子线程:后台线程,异步线程

3.不要把耗时的操作放在主线程,要放到子线程中执行

一、NSThread

1.创建和启动线程的三种方式

1>先创建,后启动

//创建

NSThread *thread = [[NSThread alloc] initWihtTarget:self selector:@selector(download:) object:nil];

//启动

[thread start];

2>创建完自动启动

[NSThread detachNewThreadSelector:@selector(download:) toTarget:self withObject:@"http://a.jpg"];

3>隐式创建(自动启动)

[self performSelectorInBackground:@selector(download:) withObject:@"http://c.gif"];

2.常见方法

1>获得当前线程

+ (NSThread *)currentThread;

2>获得主线程

+ (NSThread *)mainThread;

3>睡眠(暂停)线程

+ (void)sleepUntilDate:(NSDate *)date;

+ (void)sleepForTimeInterval:(NSTimeInterval)ti;

4>设置线程的名字

- (void)setName:(NSString *)name;

- (NSString *)name;

3.线程同步

1>实质:为了防止多个线程抢夺同一个资源造成的数据安全问题

2>实现:给代码加一个互斥锁(同步锁)

@synchronized (self) {

//被锁住的代码

}

二、GCD

// dispatch_sync : 同步,不具备开启线程的能力

// dispatch_async : 异步,具备开启线程的能力

// 并发队列:多个任务可以同时执行

// 串行队列:一个任务执行完后,再执行下一个任务

1.队列和任务

1>任务:需要执行什么操作

*用block来封装任务

2>队列:存放任务

(1)全局的并发队列:可以让任务并发执行

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);

dispatch_async(queue, ^{//将任务添加全局队列中去异步执行

NSLog(@"-----下载图片1---%@", [NSThread currentThread]);

});

(2)自己创建的串行队列:让任务一个接一个地执行

dispatch_queue_t queue = dispatch_queue_create("cn.heima.queue",NULL);

dispatch_async(queue, ^{// 2.将任务添加到串行队列中异步执行

NSLog(@"-----下载图片1---%@", [NSThread currentThread]);

});

(3)主队列

// 1.主队列(添加到主队列中的任务,都会自动放到主线程中去执行)

dispatch_queue_t queue = dispatch_get_main_queue();

// 2.添加任务到主队列中异步执行

dispatch_async(queue, ^{

NSLog(@"-----下载图片1---%@", [NSThread currentThread]);

});

2.执行任务的函数

1>dispatch_sync :同步,不具备开启线程的能力

*注意:dispatch_sync不能使用主队列(会被卡死){

// 1.主队列(添加到主队列中的任务,都会自动放到主线程中去执行)

dispatch_queue_t queue = dispatch_get_main_queue();

// 2.添加任务到主队列中异步执行

dispatch_sync(queue, ^{

NSLog(@"-----下载图片1---%@", [NSThread currentThread]);

});

}

2>dispatch_async :异步,具备开启线程的能力

3.常见的组合

1>dispatch_async +全局并发队列

2>dispatch_async +自己创建的串行队列

4.线程间的通信

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{

NSLog(@"donwload---%@", [NSThread currentThread]);

// 1.子线程下载图片

NSURL *url = [NSURL URLWithString:@"http://d.hiphotos.baidu.com/image/pic/item/37d3d539b6003af3290eaf5d362ac65c1038b652.jpg"];

NSData *data = [NSData dataWithContentsOfURL:url];

UIImage *image = [UIImage imageWithData:data];

// 2.回到主线程设置图片

dispatch_async(dispatch_get_main_queue(), ^{

NSLog(@"setting---%@ %@", [NSThread currentThread], image);

[self.button setImage:image forState:UIControlStateNormal];

});

});

5.GCD的所有API都在libdispatch.dylib,Xcode会自动导入这个库

*主头文件: #import <dispatch/dispatch.h>

6.延时执行

1>3秒后自动回到当前线程调用self的download:方法。并且传递参数:@"http://555.jpg"

// 一旦定制好延迟任务后,不会卡住当前线程

[self performSelector:@selector(download:) withObject:@"http://555.jpg"
afterDelay:3];

2>// 3秒后自动开启新线程执行block中的代码

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), queue, ^{

NSLog(@"------task------%@", [NSThread currentThread]);

});

7.一次性代码

static dispatch_once_t onceToken;

dispatch_once(&onceToken, ^{//这里面的代码永远只会执行一次

NSLog(@"----once");

});

三、NSOperation

作用:配合使用NSOperation和NSOperationQueue也能实现多线程编程

NSOperation和NSOperationQueue实现多线程的具体步骤:

先将需要执行的操作封装到一个NSOperation对象中,然后将NSOperation对象添加到NSOperationQueue中,系统会自动将NSOperationQueue中的NSOperation取出来,并把封装的操作放到一条新线程中执行。

NSOperation是一个抽象类,并不具备封装操作的能力,必须使用它的子类。

使用NSOperation子类的方式有3种:

(1).NSInvocationOperation

{// 创建队列

NSOperationQueue *queue = [[NSOperationQueue alloc] init];

// 创建操作

NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download) object:nil];

// operation直接调用start,是同步执行(在当前线程执行操作)

// [operation start];

//
添加操作到队列中,会自动异步执行

[queue addOperation:operation];

}

- (void)download

{

NSLog(@"download-----%@", [NSThread currentThread]);

}

(2).NSBlockOperation

(3).自定义子类继承NSOperation,实现内部相应的方法

1.队列的类型

1>主队列

*主队列:[NSOperationQueue mainQueue];

*添加到“主队列”中的操作,都会放到主线程中执行。

2>非主队列

*创建一个队列(非主队列)

NSOperationQueue *queue = [[NSOperationQueue alloc] init];

*添加到"非主队列"中的操作,都会放到子线程中执行

2.队列添加任务

* - (void)addOperation:(NSOperation *)op;

* - (void)addOperationWithBlock:(void (^)(void))block;

3.常见用法

1>
设置最大并发数

- (NSInteger)maxConcurrentOperationCount;

- (void)setMaxConcurrentOperationCount:(NSInteger)cnt;

2>队列的其他操作

*取消所有的操作

- (void)cancelAllOperations;

*暂停所有操作

[queue setSuspended:YES];

*恢复所有操作

[queue setSuspended:NO];

4.操作之间的依赖

*NSOperation之间可以设置依赖来保证执行顺序

*[operationB addDependency:operationA];//操作B依赖于操作A(只有操作A执行完以后才能执行操作B)

*注意:不能相互依赖,比如A依赖B,B依赖A

*可以在不同queue的NSOperation之间创建依赖关系

5.线程之间的通讯

NSOperationQueue *queue = [[NSOperationQueue alloc] init];

[queue addOperationWithBlock:^{

// 1.异步下载图片(执行一些比较耗时的操作)

NSURL *url = [NSURL URLWithString:@"http://d.hiphotos.baidu.com/image/pic/item/37d3d539b6003af3290eaf5d362ac65c1038b652.jpg"];

NSData *data = [NSData dataWithContentsOfURL:url];

UIImage *image = [UIImage imageWithData:data];

// 2.回到主线程,显示图片

// [self performSelectorOnMainThread:<#(SEL)#> withObject:<#(id)#> waitUntilDone:<#(BOOL)#>];

// dispatch_async(dispatch_get_main_queue(), ^{

//

// });

[[NSOperationQueue mainQueue] addOperationWithBlock:^{

self.imageView.image = image;

}];

}];

四、从其他线程回到主线程的方式:

1.perform....

[self performSelectorOnMainThread:<#(SEL)#> withObject:<#(id)#> waitUntilDone:<#(BOOL)#>];

2.GCD

dispatch_async(dispatch_get_main_queue(), ^{

});

3.NSOperation

[[NSOperationQueue mainQueue] addOperationWithBlock:^{

}];

五、判断编译器的环境:ARC还是MRC?

#if __has_feature(objc_arc)

//当前的编译器环境是ARC

#else

//当前的编译器环境是MRC

#endif
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: