前两篇文章已经将了现在主流的GCD和NSOperationQueue,现在我们在聊一下NSThread。
创建NSThread
方法一 类方法1
+ (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(nullable id)argument;
方法二 实例方法
1
- (instancetype)initWithTarget:(id)target selector:(SEL)selector object:(nullable id)argument NS_AVAILABLE(10_5, 2_0);
这两者的区别是 类方法是创建新的线程并且立即启动,而第二个方法是创建线程,但是没有启动,启动需要[thread start]
。
获取线程的状态
1 | 正在执行 |
更改线程状态
1 | 取消 |
在子线程中想要更新UI怎么办,这里官方直接提供了在子线程执行方法的函数,很实用的。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray<NSString *> *)array;
在主线程执行
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait;
// equivalent to the first method with kCFRunLoopCommonModes
- (void)performSelector:(SEL)aSelector
onThread:(NSThread *)thr
withObject:(nullable id)arg
waitUntilDone:(BOOL)wait
modes:(nullable NSArray<NSString *> *)array NS_AVAILABLE(10_5, 2_0);
- (void)performSelector:(SEL)aSelector
onThread:(NSThread *)thr
withObject:(nullable id)arg
waitUntilDone:(BOOL)wait NS_AVAILABLE(10_5, 2_0);
// equivalent to the first method with kCFRunLoopCommonModes
- (void)performSelectorInBackground:(SEL)aSelector
withObject:(nullable id)arg NS_AVAILABLE(10_5, 2_0);
代码
1 | - (void)test6{ |
从输出结果看出来[self performSelectorInBackground:@selector(print) withObject:nil];
又自动生成了子线程并且在子线程执行print
函数。
把test6函数改成下面的情况1
2
3
4
5
6//当waitUntilDone 是yes的时候,是同步执行
[self performSelectorOnMainThread:@selector(print) withObject:nil waitUntilDone:NO];
_thread = [[NSThread alloc]initWithTarget:self selector:@selector(op1) object:nil];
_thread.name = @"test6";
[_thread start];
[self performSelectorInBackground:@selector(print) withObject:nil];
输出:1
2
3
4**2016-04-13 10:41:32.534 GCD_Demo[34026:652753] test6 ****开始运行了**
**2016-04-13 10:41:32.534 GCD_Demo[34026:652754] ****线程****info : <NSThread: 0x7fb7320a1bf0>{number = 3, name = (null)}**
**2016-04-13 10:41:32.537 GCD_Demo[34026:652708] ****线程****info : <NSThread: 0x7fb730c05a20>{number = 1, name = main}**
**2016-04-13 10:41:35.539 GCD_Demo[34026:652753] test6 ****结束**[self performSelectorOnMainThread:@selector(print)
withObject:nil
waitUntilDone:NO];
waitUntilDone为YES的时候是同步执行代码,为NO的时候异步执行代码。[self performSelectorInBackground:@selector(print) withObject:nil];
开启子线程执行print函数。
cancel thread
1 | - (void)test6{ |
输出:1
2
3
4**2016-04-13 10:50:46.685 GCD_Demo[34128:657263] test6 ****开始运行了**
**2016-04-13 10:50:48.686 GCD_Demo[34128:657214] test6 canceld**
**2016-04-13 10:50:48.692 GCD_Demo[34128:657214] ****线程****info : <NSThread: 0x7ffb34004fb0>{number = 1, name = main}**
**2016-04-13 10:51:16.689 GCD_Demo[34128:657263] test6 ****结束**
其实thread取消也是在执行中的线程是没办法直接取消的,[thread cancel]
紧紧是改了状态,却没有终止线程。和[NSOperation cancel]
类似,当你cancel之后,如果线程在执行,那么他会执行完毕,如果线程还没执行,那么他会终止执行。
关于thread的通知1
2
3
4
5
6
7
8
9
10
11
12
13//将要变成多线程 在有新的线程启动的时候会发送此通知
FOUNDATION_EXPORT NSString * const NSWillBecomeMultiThreadedNotification;
//将要变成单独线程 官方标注: Not implemented.【没有实现】
FOUNDATION_EXPORT NSString * const NSDidBecomeSingleThreadedNotification;
//线程退出
FOUNDATION_EXPORT NSString * const NSThreadWillExitNotification;
通过这三个通知可以监测线程的启动和现成的退出。
//监测线程启动,启动的线程是未知的所以object是nil
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(becomeMultiNsthread) name:NSWillBecomeMultiThreadedNotification object:nil];
//监测线程退出
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(exit:) name:NSThreadWillExitNotification object:nil];
线程的讨论暂时就这么多,有问题我们一起讨论,欢迎留言。。