NSThread 是苹果官方提供的面向对象类线程操作技术,简单方便,可以直接操作线程对象,不过需要自己控制线程的生命周期,在平时使用较少。
使用 NSThread 开启线程有类方法和实例方法两种,类方法会直接执行任务,实例方法需要在实例初始化后调用 start 方法才能开始执行任务。
使用类方法创建线程后会自动开始任务,不需要手动开启。类方法创建线程有如下两种方式:
// block 方式
+ (void)detachNewThreadWithBlock:(void (^)(void))block;
// SEL 方式
+ (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(nullable id)argument;
block 方式:
[NSThread detachNewThreadWithBlock:^{
NSLog(@"class method -- task in block, current thread is %@", [NSThread currentThread]);
}];
// 执行后打印:class method -- task in block, current thread is {number = 4, name = (null)}
SEL 方式:
[NSThread detachNewThreadSelector:@selector(classMethodTest) toTarget:self withObject:nil];
- (void)classMethodTest {
NSLog(@"class method -- task in SEL, current thread is %@", [NSThread currentThread]);
}
// 执行后打印:class method -- task in SEL, current thread is {number = 3, name = (null)}
实例方法创建线程也是分为 block 和 SEL 两种方式:
// block 方式
- (instancetype)initWithBlock:(void (^)(void))block;
// SEL 方式
- (instancetype)initWithTarget:(id)target selector:(SEL)selector object:(nullable id)argument;
block 方式:
// 1. 创建线程
NSThread *oneThread = [[NSThread alloc] initWithBlock:^{
NSLog(@"instance method -- task in block, current thread is %@", [NSThread currentThread]);
}];
// 2. 开始执行
[oneThread start];
// 执行后打印:instance method -- task in block, current thread is {number = 5, name = (null)}
SEL 方式:
// 1. 创建线程
NSThread *anotherThread = [[NSThread alloc] initWithTarget:self selector:@selector(instanceMethodTest) object:nil];
// 2. 开始执行
[anotherThread start];
- (void)instanceMethodTest {
NSLog(@"instance method -- task in SEL, current thread is %@", [NSThread currentThread]);
}
// 执行后打印:instance method -- task in SEL, current thread is {number = 6, name = (null)}
下面,来看一下 NSThread 中都有哪些属性:
当前线程(类属性)
@property (class, readonly, strong) NSThread *currentThread;
线程字典
每个线程都维护了一个 键-值 字典,它可以在线程里面的任何地方被访问。可以使用该字典来保存一些信息,这些信息在整个线程的执行过程中都保持不变。
@property (readonly, retain) NSMutableDictionary *threadDictionary;
NSThread *myThread = [[NSThread alloc] initWithBlock:^{
NSLog(@"the threadDictionary of myThread is %@", [NSThread currentThread].threadDictionary);
}];
[myThread.threadDictionary setValue:@"value1" forKey:@"key1"];
[myThread.threadDictionary setValue:@"value2" forKey:@"key2"];
[myThread start];
// 执行后打印:
/*
the threadDictionary of myThread is {
key1 = value1;
key2 = value2;
}
*/
线程优先级
@property double threadPriority; // 已废弃,官方建议使用下方的 qualityOfService 属性
@property NSQualityOfService qualityOfService;
// 注意:线程启动后该属性只读
typedef NS_ENUM(NSInteger, NSQualityOfService) {
NSQualityOfServiceUserInteractive = 0x21,
NSQualityOfServiceUserInitiated = 0x19,
NSQualityOfServiceUtility = 0x11,
NSQualityOfServiceBackground = 0x09,
NSQualityOfServiceDefault = -1
};
线程名称
@property (nullable, copy) NSString *name;
线程使用栈区大小(默认是 512K)
@property NSUInteger stackSize;
线程是否是主线程
@property (readonly) BOOL isMainThread;
NSLog(@"myThread is%@ main thread.", myThread.isMainThread ? @"" : @" not");
// 打印:myThread is not main thread.
线程是否正在执行
@property (readonly, getter=isExecuting) BOOL executing;
线程是否执行完毕( 注意:线程取消之后 isFinished 的值也是 YES )
@property (readonly, getter=isFinished) BOOL finished;
线程是否已经取消
@property (readonly, getter=isCancelled) BOOL cancelled;
当前线程是否是主线程(类属性)
@property (class, readonly) BOOL isMainThread; // reports whether current thread is main
NSLog(@"current thread is%@ main thread.", NSThread.isMainThread ? @"" : @" not");
// 在主线程中打印:current thread is main thread.
获取主线程(类属性)
@property (class, readonly, strong) NSThread *mainThread;
NSLog(@"the main thread is %@", NSThread.mainThread);
// 打印:the main thread is {number = 1, name = main}
栈返回地址记录(类属性)
线程调用就会有函数的调用,函数的调用就会有栈返回地址的记录,在这里读取的是函 数调用返回的虚拟地址,也就是在该线程中函数调用的虚拟地址的数组。
@property (class, readonly, copy) NSArray<NSNumber *> *callStackReturnAddresses;
栈返回标志记录(类属性)
和上面的属性类似,只不过读取的是该线程调用函数的名字的数组。
@property (class, readonly, copy) NSArray<NSString *> *callStackSymbols;
注意:callStackReturnAddress 和 callStackSymbols 这两个只读属性可以同 NSLog 函数联合使用用来跟踪线程的函数调用情况,是编程调试的重要手段。
初始化方法:
- (instancetype)init;
- (instancetype)initWithTarget:(id)target selector:(SEL)selector object:(nullable id)argument;
- (instancetype)initWithBlock:(void (^)(void))block;
启动线程
- (void)start;
取消线程
- (void)cancel;
线程的入口函数
- (void)main;
开启新线程(自动执行任务)
+ (void)detachNewThreadWithBlock:(void (^)(void))block;
+ (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(nullable id)argument;
当前线程是否是子线程
+ (BOOL)isMultiThreaded;
线程休眠
// 休眠至指定日期
+ (void)sleepUntilDate:(NSDate *)date;
// 休眠指定时间
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
退出当前线程
+ (void)exit;
获取当前线程的优先级
+ (double)threadPriority;
设置当前线程的优先级(优先级的取值范围是 0.0 ~ 1.0,默认是 0.5,值越大,优先级越高。)
+ (BOOL)setThreadPriority:(double)p;
在 NSObject 的 NSThreadPerformAdditions 分类中,包含如下方法,也就是说所有继承 NSObject 的类的实例对象都可调用以下方法:
在主线程中执行指定的方法
参数1:SEL 方法
参数2:方法参数
参数3:是否等待当前任务执行完毕
参数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;
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait;
// equivalent to the first method with kCFRunLoopCommonModes
在开启的子线程中执行指定的方法
参数1:SEL 方法
参数2:方法参数
- (void)performSelectorInBackground:(SEL)aSelector withObject:(nullable id)arg;
好用请点
赞 ???