ios里面多线程有多种实现方案,下面先来了解一下NSThread,这个算是最基础的一个了。
首先看NSThread创建,NSThread的创建有三种方法,分别是:
-(void)threadCreate{
NSLog(@"%s",__PRETTY_FUNCTION__);
//1.
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadCreateFunc:) object:@"普通线程"];
[thread start];
//2.
[NSThread detachNewThreadSelector:@selector(threadCreateFunc:) toTarget:self withObject:@"分离子线程"];
//3.
[self performSelectorInBackground:@selector(threadCreateFunc:) withObject:@"后台线程"];
}
-(void)threadCreateFunc:(NSString*)string{
NSLog(@"test - %@ - %@", [NSThread currentThread],string);
}
三种方法比较:
方法一:
优点:可以拿到线程对象,并设置相关属性
缺点:需要手动启动线程
方法二和三:
优点:代码简介
缺点:无法拿到线程对象,并设置相关属性
如果需要设置线程属性,比较常用的属性就是线程的name和priority了,比如
-(void)threadPriority{
NSLog(@"%s",__PRETTY_FUNCTION__);
NSThread* threadA = [[NSThread alloc]initWithTarget:self selector:@selector(threadPriorityFunc:) object:@"子线程"];
threadA.name = @"子线程A";
NSThread* threadB =[[NSThread alloc]initWithTarget:self selector:@selector(threadPriorityFunc:) object:@"子线程"];
threadB.name =@"子线程B";
NSThread* threadC =[[NSThread alloc]initWithTarget:self selector:@selector(threadPriorityFunc:) object:@"子线程C"];
threadC.name=@"子线程C";
threadA.threadPriority = 0.1;
threadB.threadPriority = 1.0;
threadC.threadPriority = 0.5;
[threadA start];
[threadB start];
[threadC start];
}
-(void)threadPriorityFunc:(NSString*)string{
for(int i=0;i<100;i++){
NSLog(@"%d - %@", i + 1, [NSThread currentThread].name);
}
}
18-05-01 15:56:49.258160+0800 ocLearner[5100:219761] 59 - 子线程C
2018-05-01 15:56:49.258790+0800 ocLearner[5100:219760] 93 - 子线程B
2018-05-01 15:56:49.258882+0800 ocLearner[5100:219761] 60 - 子线程C
2018-05-01 15:56:49.258475+0800 ocLearner[5100:219759] 31 - 子线程A
2018-05-01 15:56:49.259150+0800 ocLearner[5100:219760] 94 - 子线程B
2018-05-01 15:56:49.259252+0800 ocLearner[5100:219761] 61 - 子线程C
2018-05-01 15:56:49.260346+0800 ocLearner[5100:219760] 95 - 子线程B
2018-05-01 15:56:49.260924+0800 ocLearner[5100:219761] 62 - 子线程C
2018-05-01 15:56:49.261092+0800 ocLearner[5100:219760] 96 - 子线程B
2018-05-01 15:56:49.261141+0800 ocLearner[5100:219759] 32 - 子线程A
2018-05-01 15:56:49.261493+0800 ocLearner[5100:219761] 63 - 子线程C
2018-05-01 15:56:49.261636+0800 ocLearner[5100:219760] 97 - 子线程B
2018-05-01 15:56:49.262173+0800 ocLearner[5100:219760] 98 - 子线程B
2018-05-01 15:56:49.262780+0800 ocLearner[5100:219760] 99 - 子线程B
从打印的效果截图上看,明显B的次数最多,C次之,A最少
关于线程的状态,启动一个线程可以用
-(void)start;
这个就不多说了。
如果想暂停线程,可以用下面两个方法
+(void)sleepUntilDate:(NSDate*)date;
+(void)sleepForTimeInterval:(NSTimeInterval)ti;
强行停止线程:
+(void)exit;
下面直接贴代码吧:
double now1=[[NSDate date] timeIntervalSince1970];
NSLog(@"%@ - now1:%f",[NSThread currentThread],now1);
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:3.0]];
double now2=[[NSDate date] timeIntervalSince1970];
NSLog(@"%@ - now2:%f,interval from now1:%f",[NSThread currentThread],now2,now2-now1);
[NSThread sleepForTimeInterval:3.0];
double now3=[[NSDate date] timeIntervalSince1970];
NSLog(@"%@ - now3:%f,interval from now2:%f",[NSThread currentThread],now3,now3-now2);
for (int i = 0; i < 100; ++i) {
NSLog(@"%d - %@", i, [NSThread currentThread]);
if (i == 10) {
[NSThread exit];
}
}
NSLog(@"----end----");
运行以后的效果图:
2018-05-03 23:18:39.073311+0800 ocLearner[21985:585836]
2018-05-03 23:18:42.078887+0800 ocLearner[21985:585836]
2018-05-03 23:18:42.079323+0800 ocLearner[21985:585836] 0 -
2018-05-03 23:18:42.080153+0800 ocLearner[21985:585836] 1 -
2018-05-03 23:18:42.081480+0800 ocLearner[21985:585836] 2 -
2018-05-03 23:18:42.082837+0800 ocLearner[21985:585836] 3 -
2018-05-03 23:18:42.083649+0800 ocLearner[21985:585836] 4 -
2018-05-03 23:18:42.084172+0800 ocLearner[21985:585836] 5 -
2018-05-03 23:18:42.084891+0800 ocLearner[21985:585836] 6 -
2018-05-03 23:18:42.085270+0800 ocLearner[21985:585836] 7 -
2018-05-03 23:18:42.085622+0800 ocLearner[21985:585836] 8 -
2018-05-03 23:18:42.085831+0800 ocLearner[21985:585836] 9 -
2018-05-03 23:18:42.086067+0800 ocLearner[21985:585836] 10 -
可以看到,exit会使线程强行退出的。
关于线程,还有一个可能用到的比较多,就是线程之间的通讯。一个比较常见的场景就是从网络下载完图片资源后需要更新到界面上去的时候。必须要在主线程里更新,不能够在下载线程中之间更新。还是直接上代码吧:
-(void)threadCommunication{
NSLog(@"%s",__PRETTY_FUNCTION__);
NSURL* url = [NSURL URLWithString:@"http://pic1.win4000.com/wallpaper/2/4fcec0bf0fb7f.jpg"];
NSData* data = [NSData dataWithContentsOfURL:url];
UIImage* image =[UIImage imageWithData:data];
NSLog(@"download-%@",[NSThread currentThread]);
//方法1
[self performSelectorOnMainThread:@selector(showImage:) withObject:image waitUntilDone:YES];
//方法2
//[self performSelector:@selector(showImage:) onThread:[NSThread mainThread] withObject:image waitUntilDone:YES];
//方法3
//[self.imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:YES];
}
-(void)showImage:(UIImage*)image{
self.imageView.image = image;
NSLog(@"showImage - %@", [NSThread currentThread]);
}
由其他线程,切回主线程有下面三个方法:
//方法1
[self performSelectorOnMainThread:@selector(showImage:) withObject:image waitUntilDone:YES];
//方法2
//[self performSelector:@selector(showImage:) onThread:[NSThread mainThread] withObject:image waitUntilDone:YES];
//方法3
//[self.imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:YES];
其中最后一个方法不需要再直接定义新函数了。比较简便。
好了。NSThread还是一个很轻量级的多线程。大多数重量级的多线程一般都是用GCD了。所以,这里也就简单介绍一下吧。不在详细说明了