简介
NSthread是苹果官方提供面向对象操作线程的技术,简单方便,可以直接操作线程对象,不过需要自己控制线程的生命周期。在平时使用较少,常用的就是下面的方法来获取当前线程。
[NSThread currentThread]
使用
1.实例初始化、属性和实例方法
初始化
切记下面两个方法初始化的NSThread必须手动start开启线程
//创建线程 NSThread *newThread = [[NSThread alloc]initWithTarget:self selector:@selector(demo:) object:@"Thread"]; //或者 NSThread *newThread=[[NSThread alloc]init]; NSThread *newThread= [[NSThread alloc]initWithBlock:^{ NSLog(@"initWithBlock"); }];
属性
线程字典
/** 每个线程都维护了一个键-值的字典,它可以在线程里面的任何地方被访问。 你可以使用该字典来保存一些信息,这些信息在整个线程的执行过程中保持不变。 比如,你可以使用它来存储在你的整个线程过程中 Run loop 里面多次迭代的状态信息。 NSThread实例可以使用以下方法 */ @property (readonly, retain) NSMutableDictionary *threadDictionary; NSMutableDictionary *dict = [thread threadDictionary];
优先级
@property double threadPriority ; //优先级
线程优先级
/** NSQualityOfService: NSQualityOfServiceUserInteractive:最高优先级,主要用于提供交互UI的操作,比如处理点击事件,绘制图像到屏幕上 NSQualityOfServiceUserInitiated:次高优先级,主要用于执行需要立即返回的任务 NSQualityOfServiceDefault:默认优先级,当没有设置优先级的时候,线程默认优先级 NSQualityOfServiceUtility:普通优先级,主要用于不需要立即返回的任务 NSQualityOfServiceBackground:后台优先级,用于完全不紧急的任务 */ @property NSQualityOfService qualityOfService
线程名称
@property (nullable, copy) NSString *name;
线程使用栈区大小,默认是512k
@property NSUInteger stackSize ;
线程状态(正在执行、执行结束、是否可以取消)
@property (readonly, getter=isExecuting) BOOL executing; @property (readonly, getter=isFinished) BOOL finished; @property (readonly, getter=isCancelled) BOOL cancelled;
实例方法
// 启动线程 实例化线程需要手动启动才能运行 - (void)start; [thread stary] // 是否为主线程 - (BOOL)isMainThread; isMain = [thread isMainThread]; //设置线程名称 - (void)setName:(NSString *) name; [thraed setName:@"name"]; // 取消线程 - (void)cancel; [thread cancel]; // 线程的入口函数 - (void)main; [thread main]; // 线程是否正在执行 - (void)isExecuting; isRunning=[thread isExecuting]; // 线程是否已经结束 - (void)isFinished; isEnd=[thread isFinished]; // 线程是否撤销 - (void)isCancelled; isCancel=[thread isCancelled];
类创建方法
/* 创建子线程并开始 创建后就可执行,不需要手动开启
但是不能获取NSThread对象 */ /** block方式 具体的任务在Block中执行 */ + (void)detachNewThreadWithBlock:(void (^)(void))block; /** SEL方式 利用selector方法初始化NSThread,target指selector方法从属于的对象 selector方法也 是指定的target对象的方法 */ + (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(nullable id)argument;
类使用方法
// 获取当前线程 + (void)currentThread; [NSThread currentThread]; //当前代码运行所在线程是否为子线程 + (BOOL)isMultiThreaded; isMulti = [NSThread isMultiThreaded]; // 当前代码所在线程睡到指定时间 + (void)sleepUntilDate: (NSDate *)date; [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:1.0]]; // 线程沉睡时间间隔,这个方法在设置启动页间隔的时候比较常见 + (void)sleepForTimeInterval: (NSTimeInterval)time; [NSThread sleepForTimeInterval:1.0]; // 退出当前线程 + (void)exit; [NSThread exit]; // 设置当前线程优先级 + (double)threadPriority; double dPriority=[NSThread threadPriority]; // 给当前线程设定优先级,调度优先级的取值范围是0.0 ~ 1.0,默认0.5,值越大,优先级越高。 + (BOOL)setThreadPriority:(double)priority; BOOL isSetting=[NSThread setThreadPriority:(0.0~1.0)]; // 线程的调用都会有行数的调用函数的调用,就会有栈返回地址的记录, 在这里返回的是函数调用返回的虚拟地址 说白了就是在在该先出中函数调用的虚拟地址的数组 + (NSArray *)callStackReturnAddresses; NSArray *addressArray=[NSThread callStackReturnAddresses]; // 同上面的方法一样,只不过返回的是该线程调用函数的名字数字 + (NSArray *)callStackSymbols; NSArray* nameNumArray=[NSThread callStackSymbols]; 注意:callStackReturnAddress和callStackSymbols这两个函数可以同NSLog联合使用来跟踪线程的函数调用情况,是编程调试的重要手段
隐式创建&线程间通讯
以下方法位于NSObject(NSThreadPerformAdditions)分类中,所有继承自NSObject实例化对象都可以调用以下方法。
/** 指定方法在主线程中执行 参数1. SEL 方法 2.方法参数 3.BOOL类型 表示是否等待当前aSelector方法执行完毕 4.指定的Runloop model */ - (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 /** 指定方法在某个线程中执行 参数1. SEL 方法 2.方法参数 3.是否等待当前执行完毕 4.指定的Runloop model */ - (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray<NSString *> *)array API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0)); - (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0)); // equivalent to the first method with kCFRunLoopCommonModes /** 指定方法在开启的子线程中执行 参数1. SEL 方法 2.方法参数 */ - (void)performSelectorInBackground:(SEL)aSelector withObject:(nullable id)arg API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
注意:我们提到的线程间通讯就是这几个方法,没有多高大上多复杂。
再注意:苹果声明UI更新一定要在UI线程(主线程)中执行,虽然不是所有后台线程更新UI都会出错。
再注意:waitUntilDone后面的这个BOOL类型的参数,这个参数的意义有点像我们是否同步执行aSelector这个任务!具体的看下面两张图的内容就一目了然了。