iOS基础深入补完计划--NSThread

iOS基础深入补完计划--NSThread
文章图片
(由于合在一起感觉一篇太长翻着累)
iOS多线程目前总结了四篇

  • iOS基础深入补完计划--多线程(面试题)汇总
  • iOS基础深入补完计划--NSThread
  • iOS基础深入补完计划--GCD
  • iOS基础深入补完计划--NSOperation
欢迎移步O(∩_∩)O
NSThread
NSThread是轻量级的多线程开发、使用起来也并不复杂、但是使用NSThread需要自己管理线程生命周期、实在不是特别优雅。
(个人)通常的用处分为以下几个地儿吧:
  • 判断/获取当前线程
if (![[NSThread currentThread] isMainThread]) { dispatch_sync(dispatch_get_main_queue(), ^{ //主线程执行 }); }

  • 休眠当前线程
+ (void)sleepForTimeInterval:(NSTimeInterval)time; + (void)sleepUntilDate:(NSDate *)date;

  • 给线程起个名字
[NSThread currentThread].name =@"我要标记这个线程"];

总之NSThread基本都是对线程本身进行操作才会用到。
NSThread相关的几个坑:
  • [thread cancel]和[NSThread exit];
    • 调用实例对象的- (void)cancel; 方法、并不会直接取消线程。其作用只是对应线程的cancel属性设置为YES、线程依旧继续执行。在此之后:
      thread.cancel为YES。
      thread.executing为YES。
      thread.finished为NO。(除非全执行完了)
    • 我们需要在适当的位置执行[NSThread exit]; 才可以真正关闭线程、余下的代码不会继续执行。同时:
      thread.cancel为你设置的状态(默认应该是NO)。
      thread.executing为NO。
      thread.finished为YES。
  • 一些NSObject的相关扩展方法(performSelector
(主要)依赖Runtime的扩展
- (id)performSelector:(SEL)aSelector; - (id)performSelector:(SEL)aSelector withObject:(id)object;

基本等于自己手动调用方法、但是其最基本原理是runtime、编译的时候也不会做任何校验。所有的performSelector方法、都是基于runtime进行消息转发的。
(主要)依赖NSThread的扩展
- (void)performSelectorInBackground:(SEL)aSelector withObject:(nullable id)arg; - (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait;

举了两个例子、注意这里都只跟线程有关(OnMainThread/InBackground)。
(主要)依赖Runloop的扩展
- (void)performSelector:(SEL)aSelector target:(id)target argument:(nullable id)arg order:(NSUInteger)order modes:(NSArray *)modes; - (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay;

第一个很明显了、依赖Runloop的NSRunLoopMode。
第二个表面上看没什么关系、但内部依赖定时器。同时、定时器是依赖Runloop的。
NSThred的API
@interface NSThread : NSObject{ @private id _private; uint8_t _bytes[44]; }// 获取当前线程 + (NSThread *)currentThread; // 创建新线程 + (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(nullable id)argument; // 是否是多线程 + (BOOL)isMultiThreaded; /** *每个线程都维护了一个“键-值”的字典,它可以在线程里面的任何地方被访问, *可以使用该字典来保存一些信息,这些信息在整个线程的执行过程中都保持不变。 *比如,可以使用它来存储在整个线程过程中RunLoop里面多次迭代的状态信息。 *使用:通过threadDictionary方法获取一个NSMutableDictionary对象,然后添加需要的字段和数据 */ @property (readonly, retain) NSMutableDictionary *threadDictionary; // 设置线程睡眠/堵塞 + (void)sleepUntilDate:(NSDate *)date; // 设置线程睡眠/堵塞 + (void)sleepForTimeInterval:(NSTimeInterval)ti; // 结束/退出进程 + (void)exit; // 获取线程的优先级 + (double)threadPriority; // 设置线程优先级,取值范围0.0~1.0 + (BOOL)setThreadPriority:(double)p; // 线程优先级,iOS8以后推荐使用qualityOfService属性,通过量化的优先级枚举值来设置 @property double threadPriority; /** 线程优先级 qualityOfService的枚举值如下: NSQualityOfServiceUserInteractive:最高优先级,用于用户交互事件 NSQualityOfServiceUserInitiated:次高优先级,用于用户需要马上执行的事件 NSQualityOfServiceDefault:默认优先级,主线程和没有设置优先级的线程都默认为这个优先级 NSQualityOfServiceUtility:普通优先级,用于普通任务 NSQualityOfServiceBackground:最低优先级,用于不重要的任务 */ @property NSQualityOfService qualityOfService; // 返回当前线程在栈中所占的地址所组成的数组 + (NSArray *)callStackReturnAddresses NS_AVAILABLE(10_5, 2_0); // 返回栈空间的符号表 + (NSArray *)callStackSymbols NS_AVAILABLE(10_6, 4_0); // 线程名称 @property (nullable, copy) NSString *name NS_AVAILABLE(10_5, 2_0); // 栈的所占空间大小 @property NSUInteger stackSize NS_AVAILABLE(10_5, 2_0); // 是否是主线程 @property (readonly) BOOL isMainThread NS_AVAILABLE(10_5, 2_0); // 判断当前线程是否是主线程 + (BOOL)isMainThread NS_AVAILABLE(10_5, 2_0); // reports whether current thread is main// 获取主线程 + (NSThread *)mainThread NS_AVAILABLE(10_5, 2_0); // 初始化线程 - (instancetype)init NS_AVAILABLE(10_5, 2_0) NS_DESIGNATED_INITIALIZER; // 初始化线程 - (instancetype)initWithTarget:(id)target selector:(SEL)selector object:(nullable id)argument NS_AVAILABLE(10_5, 2_0); // 是否正在执行 @property (readonly, getter=isExecuting) BOOL executing NS_AVAILABLE(10_5, 2_0); // 是否执行完毕 @property (readonly, getter=isFinished) BOOL finished NS_AVAILABLE(10_5, 2_0); // 是否已经取消/中止 @property (readonly, getter=isCancelled) BOOL cancelled NS_AVAILABLE(10_5, 2_0); // 取消线程,不能再开始 - (void)cancel NS_AVAILABLE(10_5, 2_0); // 开始线程 - (void)start NS_AVAILABLE(10_5, 2_0); /** main是线程入口 *- (void)main的使用: *1. 一般创建线程会子类化NSThread,重写main方法,把关于线程执行的方法都写在里面,这样可以在任何需要这个线程方法的地方直接使用。 *2. 把线程执行的方法写在main里,是因为线程的操作应该属于线程的本身,而不是每次使用都通过initWithTarget:selector:object:方法,且再一次实现某个方法。 *3. 当重写了main方法后,同时使用initWithTarget:selector:object:方法初始化,调用某个方法执行任务,系统默认只执行main方法里面的任务。 *4. 如果直接使用NSThread创建线程,线程内执行的方法都是在当前的类文件里面的。 */ - (void)main NS_AVAILABLE(10_5, 2_0); @end

最后
【iOS基础深入补完计划--NSThread】本文主要是自己的学习与总结。如果文内存在纰漏、万望留言斧正。如果不吝赐教小弟更加感谢。

    推荐阅读