关于iOS多线程的实现方式有多种,今天来共同学习一下NSThread的简单使用,有疏忽的地方,还望各位不吝赐教。
一、NSThread初始化
// 1、创建线程
/**
* 第一种方式创建线程
* 参数说明
* 第一个参数:目标对象 self
* 第二个参数:方法选择器 调用的方法
* 第三个参数:调用方法需要传递的参数 (进行赋值后可以在run:方法中当做参数接收)
*/NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(open:) object:@"创建线程"];
// 2、对线程可以进行命名。
thread.name = @"线程名称,以示区分";
// 3、线程优先级,范围是0.0-1.0 数字越大,被执行到的可能性越大,只是可能性不代表一定会被执行。
thread.threadPriority = 0.5;
// 4、开启线程
[thread start];
// 5、实现调用的方法
- (void)open:(NSString *)param{
// [NSThread currentThread] 此方法可以获得当前线程
// [NSThread mainThread] 此方法可以获得主线程
NSLog(@"%@---------%@",param,[NSThread currentThread]);
}
// 打印: 创建线程---------{number = 3, name = 线程名称,以示区分}
/**
* 第二种方式创建线程
* 参数说明
* 第一个参数:方法选择器 调用的方法
* 第二个参数:目标对象 self
* 第三个参数:调用方法需要传递的参数 (进行赋值后可以在run:方法中当做参数接收)
*/
// 1、此方法没有返回值 相当于创建并启动线程
[NSThread detachNewThreadSelector:@selector(open:) toTarget:self withObject:@"分离子线程"];
// 2、实现调用的方法
- (void)open:(NSString *)param{
NSLog(@"%@---------%@",param,[NSThread currentThread]);
}
// 打印:分离子线程---------{number = 3, name = (null)}
/**
* 第三种方式创建线程
* 参数说明
* 第一个参数:方法选择器 调用的方法
* 第二个参数:调用方法需要传递的参数 (进行赋值后可以在run:方法中当做参数接收)
*/
// 1、此方法没有返回值 隐式创建并启动线程
[self performSelectorInBackground:@selector(open:) withObject:@"开启后台线程"];
// 2、实现调用的方法
- (void)open:(NSString *)param{
NSLog(@"%@---------%@",param,[NSThread currentThread]);
}
// 打印:开启后台线程---------{number = 3, name = (null)}
二、暂停当前线程
/**
* 暂停当前线程(阻塞)方式一
* 此方法代表让当前线程休眠两秒后再进行其他操作
*/
[NSThread sleepForTimeInterval:2.0];
/**
* 暂停当前线程(阻塞)方式二
* 此方法代表让当前线程休眠两秒后再进行其他操作
*/
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:2.0]];
三、退出当前线程
/**
* 退出当前线程
* 此方法代表强制退出当前线程
*/
[NSThread exit];
四、线程之间的通信
/**
* 关于线程之间的通信的说明:
* 1、主线程是专门用来进行更新UI和处理用户事件的线程,一般耗时操作放在子线程中执行。
* 2、当子线程将任务完成后,需要和主线程进行通信,将获取的数据展示到UI中,以便和用户进行交互。
* 在此使用一个例子来进行说明:在子线程中下载一张图片,然后在主线程中进行展示。
*/
// 1、使用第二种方式创建线程
[NSThread detachNewThreadSelector:@selector(downloadImage) toTarget:self withObject:nil];
// 2、进行downloadImage方法的实现
- (void)downloadImage{
// 2.1、确定图片的URL地址
NSURL *url = [NSURL URLWithString:@"此处需要图片的URL地址"];
// 2.2、根据图片的URL地址下载图片二进制数据到本地
NSData *data = [NSData dataWithContentsOfURL:url];
// 2.3、转换图片格式 将二进制数据转换为图片数据
UIImage *image = [UIImage imageWithData:data];
NSLog(@"downloadImage-----%@",[NSThread currentThread]);
// 2.4、将图片数据交给主线程显示图片 以下三种方式任选一种即可
/**
* 与主线程通信的方式一
* 第一个参数:回到主线程调用哪个方法
* 第二个参数:前面方法要传递的参数
* 第三个参数:是否等待 如果等待相当于当前方法为阻塞状态,end的打印会在图片显示方法执行完后进行打印
*/
[self performSelectorOnMainThread:@selector(showImage:) withObject:image waitUntilDone:NO];
/**
* 与主线程通信的方式二
* 第一个参数:回到主线程调用哪个方法
* 第二个参数:指定哪个线程执行showImage:的方法(本方法相比于方式一可以指定线程执行)
* 第三个参数:前面方法要传递的参数
* 第四个参数:是否等待 如果等待相当于当前方法为阻塞状态,end的打印会在图片显示方法执行完后进行打印
*/
[self performSelector:@selector(showImage:) onThread:[NSThread mainThread] withObject:image waitUntilDone:YES];
NSLog(@"end-------------------------end");
}
// 3、显示图片的方法
- (void)showImage:(UIImage *)image{
// 打印当前线程信息
NSLog(@"showImage-----%@",[NSThread currentThread]);
// 显示图片
self.iconImageView.image = image;
}
/**
* 与主线程通信的方式三
* 说明:
* 1、使用此方法可以省略以上显示图片的方法,故而写在这里,此代码与以上建立与主线程通信代码书写的位置相同;
* 2、因为在此案例中是直接在UIImageView中进行图片赋值,所以本方法具有特殊性。
* 3、可以使用的原因是因为performSelector:onThread:方法是在NSObject的分类中,所以只要是对象就可以进行调用。
*/
[self.iconImageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:YES];
五、线程的声明周期
当线程中的任务执行完毕后才会释放,并不会因为它是一个局部变量,在出了作用域后就被释放。
关于线程的状态的声明:
1、New(创建)
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(open:) object:@"创建线程"]; // 此代码执行完毕后会在内存中创建一个线程对象。
2、Runnable(就绪状态)
[thread start]; // 线程对象进入就绪状态,并放入可调度线程池中,只有在可调度线程池中的线程对象才可以被系统调度。
3、Running(运行状态)
当线程对象被系统调度时就处在运行状态,在系统调度其他线程的时候,就进入就绪状态。
4、Blocked(阻塞状态)
在调用sleep等方法的时候,线程会进入阻塞状态。线程对象会被从可调度线程池中移除出来,这个时候线程对象还在内存中存在,但是系统不会调度这个线程对象。
当然了,当sleep的设置时间到了以后,会再从内存中将线程对象放入可调度线程池中,线程对象会再进入就绪状态。
5、Dead(死亡状态)
当线程对象把任务执行完毕或者被强制退出,则进入死亡状态。这个时候内存中线程对象被销毁,内存中已经没有此线程对象了。
六、自定义NSThread
/**
* 说明
* 1、 关于自定义的NSThread创建线程的方式可以使用allac init 进行创建;
* 2、在自定义NSThread的.m文件中实现main方法,写在这里就可以实现自定义NSThread执行指定的任务;
* 3、当查看其它工程的源码,发现NSThread创建线程的方式是以下方式,则方便查找相关任务的执行代码。
*/
// 1、进行线程的创建
GHThread *thread = [[GHThread alloc] init];
// 2、开启线程
[thread start];
// 3、在GHThread.m中实现main方法
- (void)main{
NSLog(@"end---------%@",[NSThread currentThread]);
}
// 打印:end---------{number = 5, name = (null)}