【iOS】从实际出发理解多线程二--NSThread基础操作

简介

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这个任务!具体的看下面两张图的内容就一目了然了。

 

 

相关文章

当我们远离最新的 iOS 16 更新版本时,我们听到了困扰 Apple...
欧版/美版 特别说一下,美版选错了 可能会永久丧失4G,不过只...
一般在接外包的时候, 通常第三方需要安装你的app进行测...
前言为了让更多的人永远记住12月13日,各大厂都在这一天将应...