1、进程与线程
进程在iOS开发中相当于我们手机运行中的app,每一个app都是一个进程。而线程则是在app内部执行的某个任务,比如你在使用app下载视频时也可以看视频,下载视频和看视频是两个不同的任务,这时为了不影响你看视频,程序就会另外开辟一个线程用来下载视频。
在上图中主线程就是我们看视频的任务,而下载视频的任务则是子线程。
在进程与线程的关系中,进程就好像是一个工厂,主线程就是工厂中主要生产线,子线程就是根据实际情况需要来生产的产线,子线程在工作的时候不会影响主线程。
在实际的开发中,有关UI界面的响应和操作都是放在主线程中进行的,而一些数据相关的任务则可以放在子线程中进行以节省时间。
注意:不要直接在子线程中对UI界面进行操作,会导致程序崩溃。
2、NSThread
1.NSThread的创建方法
–(instancetype)init;
–(instancetype)initWithTarget:(id)target selector:(SEL)selector object:(nullable id)argument;
+(void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(nullable id)argument;
前两个方法创建的子线程需要使用 [thread start] 方法开启线程,第三个类方法在创建完成以后会自动开启线程。
//这个初始化方法不用多说
NSThread *thread = [[NSThread alloc]init];
//这个方法中的前两个参数也不多说,大家见的都不少,第三个参数是传到前边方法里面的参数
NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(function:) object:object];
//这个方法里的参数跟上边那个一样,只不过这个方法没有返回值
[NSThread detachNewThreadSelector:@selector(function:) toTarget:self withObject:object];
使用NSThread线程需要我们手动对线程的生命周期进行管理,我感觉这个是比较麻烦的。
2.使用NSThread
在具体的应用中,我们可以使用子线程来下载数据
- (void)viewDidLoad{
[super viewDidLoad];
//创建一个NSThread线程
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(thread:) object:@"thread"];
//开启线程
[thread start];
}
- (void)thread:(NSString *)sender{
//从网络上加载一张图片数据
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:aUrl]];
//使用加载的网络数据创建一个图片对象
UIImage *image = [UIImage imageWithData:data];
}
注意:不要直接在子线程中对UI界面进行操作,会导致程序崩溃
这样,我们就从网络上获取了一张图片,但是获取到图片的位置是在子线程中,子线程中是不能直接对UI进行操作的,怎么办呢?
这时我们就要跳转回主线程,并将下载好的网络数据带到主线程中进行UI操作。
//可以使用这个方法跳转会主线程,并执行方法选择器选择的方法,object就是可以携带的对象
//第三个参数是指是否等待将要执行线程执行完毕,一般为YES
[self performSelectorOnMainThread:@selector(function:) withObject:object waitUntilDone:YES];
//同样,我们也可以从一个子线程跳转到另外一个子线程
//参数形式跟跳转回主线程方法一样,thread就是要跳转到的线程
[self performSelector:@selector(function:) onThread:thread withObject:object waitUntilDone:YES];
3.其他关于线程的方法
//获取当前线程
+ (NSThread *)currentThread;
//线程是否为子线程
+ (BOOL)isMultiThreaded;
//使线程休眠 第一个为休眠到某个时间 第二个为休眠多久
+ (void)sleepUntilDate:(NSDate *)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
//退出线程
+ (void)exit;
//线程优先级
+ (double)threadPriority;
+ (BOOL)setThreadPriority:(double)p;
//线程是否为主线程 获取主线程的类方法
+ (BOOL)isMainThread;
+ (NSThread *)mainThread;
//取消线程
- (void)cancel;
//开始线程
- (void)start;
//在后台隐式创建一个线程
- (void)performSelectorInBackground:(SEL)aSelector withObject:(nullable id)arg;
注意:在退出线程时需要先取消线程。