iOS 多线程基础知识

多线程注意点: 不要同时开太多线程,耗时操作不要再主线程执行,放到子线程执行

线程概念

a. 主线程:UI线程,显示、刷新UI界面,处理UI控件的事件
b. 子线程:后台线程,异步线程

一、NSThread

  • 1.1 创建和启动线程的三种方式
1
2
3
4
5
6
7
8
9
// 先创建后启动
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
[thread start];
// 创建完自动启动
[NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];
// 隐式创建自动启动
[self performSelectorInBackground:@selector(run) withObject:nil];
  • 1.2 常见用法
1
2
3
4
5
6
7
8
9
+ (NSThread *)currentThread;
+ (NSThread *)mainThread;
// 睡眠、暂停当前线程
+ (void)sleepUntilDate:(NSDate *)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
// 线程的名字
@property (copy) NSString *name

二、线程同步

  • 本质: 防止多个线程访问同一个资源造成数据安全问题
  • 实现: 加一个互斥锁(同步锁)
1
2
3
@synchronized(self) {
// code
}

三、GCD(Grand Central Dispatch)

    1. 队列和任务

      • 1.1 任务: 需要执行的操作block
      • 1.2 队列: 存放任务

        • 1.2.1 全局并发队列(系统提供)

          1
          dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        • 1.2.2 串行队列(手动创建)

          1
          dispatch_queue_t queue = dispatch_queue_create("aQueue”, NULL);
        • 1.2.3 主队列(主线程中执行)

          1
          dispatch_queue_t queue = dispatch_get_main_queue();
  • 2 执行任务的函数

dispatch_sync… 同步执行: 不具备开启新线程的能力
dispatch_async… 异步执行: 具备开启新线程的能力

  • 3 常用组合

dispatch_async… + 并发队列
dispatch_async… + 串行队列

  • 4 线程间通信
1
2
3
4
5
6
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 执行耗时的操作...
dispatch_async(dispatch_get_main_queue(), ^{
// 回到主线程刷新UI
});
});
  • 5 GCD的所有API都在 libdispatch.dylib, Xcode会自动导入主头文件:

#import \

  • 6 延迟执行
1
2
3
4
5
6
7
8
perform..
[self performSelector:@selector(download:) withObject:@"http://555.jpg" afterDelay:3];
dispatch_after..
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, ^{
延迟执行的代码
});
  • 7 只执行一次
1
2
3
4
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// 此处的代码程序整个运行过程只执行一次
});
  • 8 队列组

dispatch_group_async \ dispatch_group_notify

四、单例模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// 懒汉式
// GCD方式
@interface HMDataTool : NSObject
+ (instancetype)sharedDataTool;
+
@end
#import "HMDataTool.h"
@implementation HMDataTool
static id instace;
+ (id)allocWithZone:(struct _NSZone *)zone {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
instace = [super allocWithZone:zone];
});
return instace;
}
+ (instancetype)sharedDataTool {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instace = [[self alloc] init];
});
return instace;
}
- (id)copyWithZone:(NSZone *)zone {
return instace;
}
@end

五、NSOperation

NSOperation 是一个抽象的基类, 一般使用子类 NSBlockOperation 或 NSOperationQueue

  • 1 队列的类型
1
2
3
4
5
// 主队列: 添加到主队列中的操作在主线程中执行
[NSOperationQueue mainQueue]
// 非主队列: 添加到非主队列中的操作在子线程中执行
[[NSOperationQueue alloc] init]
  • 2 添加任务到队列
1
2
3
- (void)addOperation:(NSOperation *)operation;
- (void)addOperationWithBlock:(void(^)(void))block;
  • 3 常见用法
1
2
3
4
5
6
7
8
9
10
11
// 最大并发数
@property NSInteger maxConcurrentOperationCount;
// 取消所有操作
[queue cancelAllOperations];
// 暂停所有操作
[queue setSuspended:YES];
// 恢复所有操作
[queue setSuspended:NO];
  • 4 设置依赖
1
2
3
4
// NSOperation 之间可以设置依赖关系来保证执行顺序
// 操作B依赖操作A(A执行完毕之后才会执行B)
[operationB addDependency:operationA];
// 注意: 不能相互依赖, 但可以在不同队列的操作之间设置依赖关系.
  • 5 线程之间的通信
1
2
3
4
5
6
7
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperationWithBlock:^{
// 异步线程执行耗时操作
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
// 回到主线程刷新界面
}];
}];

六、从其他线程回到主线程的三种方式

1
2
3
4
5
6
7
8
9
10
11
12
// perform…
[self performSelectorOnMainThread:(SEL) withObject:(id) waitUntilDone:(BOOL)];
// GCD
dispatch_async(dispatch_get_main_queue(), ^{
// code
});
// NSOperationQueue
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
// code
}];

七、判断编译器的环境

1
2
3
4
5
#if _has_feature(objc_arc)
// ARC环境
#else
// MRC环境
#endif

八、类的初始化方法

1
2
3
4
5
// 启动程序时类第一次加载到内存时调用(绝对只执行一次)
+ (void)load
+
// 第一次使用类(调用alloc方法等)时调用(一般只执行一次)
+ (void)initialize