02-iOS多线程 | pthread,NSThread

115 阅读2分钟

大神链接

1. pthread

  • pthread是一套通用的多线程的 API,可以在Unix / Linux / Windows 等系统跨平台使用,使用 C 语言编写,需要程序员自己管理线程的生命周期,使用难度较大,在 iOS 开发中几乎不使用 pthread

2. NSThread

NSThread 是苹果官方提供的,使用起来比 pthread 更加面向对象,简单易用,可以直接操作线程对象。 不过也需要需要程序员自己管理线程的生命周期(主要是创建),我们在开发的过程中偶尔使用 NSThread。

  • 获取当前线程
[NSThread currentThread];
  • 先创建线程,在启动
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:NULL];
[thread start];
  • 创建线程后自启动线程
[NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:NULL];
  • 创建并启动线程
[self performSelectorInBackground:@selector(run) withObject:NULL];
  • NSThread相关方法
// 获得主线程
+ (NSThread *)mainThread;    

// 判断是否为主线程(对象方法)
- (BOOL)isMainThread;

// 判断是否为主线程(类方法)
+ (BOOL)isMainThread;    

// 获得当前线程
NSThread *current = [NSThread currentThread];

// 线程的名字——setter方法
- (void)setName:(NSString *)n;    

// 线程的名字——getter方法
- (NSString *)name;
  • NSThread控制
#启动线程
- (void)start;
#阻塞(暂停)线程
+ (void)sleepUntilDate:(NSDate *)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
#强制停止线程
+ (void)exit;
  • 线程之间通信 在开发中,我们经常会在子线程进行耗时操作,操作结束后再回到主线程去刷新 UI。这就涉及到了子线程和主线程之间的通信
#在主线程上执行操作
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray<NSString *> *)array;

#在指定线程上执行操作
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray *)array NS_AVAILABLE(10_5, 2_0);
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait NS_AVAILABLE(10_5, 2_0);

#在当前线程上执行操作,调用 NSObject 的 performSelector:相关方法
- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
  • 下面是一个子线程下载图片,主线程展示图片
-(void)downloadImageOnThread
{
    // 在子线程下载图片
    [NSThread detachNewThreadSelector:@selector(downloadImage) toTarget:self withObject:NULL];
}

-(void)downloadImage
{
    NSURL *imageUrl = [[NSURL alloc] initWithString:@"https://ysc-demo-1254961422.file.myqcloud.com/YSC-phread-NSThread-demo-icon.jpg"];
    NSData *imageData = [NSData dataWithContentsOfURL:imageUrl];
    self.image = [UIImage imageWithData:imageData];
    // 回到主线程展示图片
    [self performSelectorOnMainThread:@selector(refreshOnMainThread:) withObject:self waitUntilDone:YES];
}

-(void)refreshOnMainThread:(UIImage *)image
{
    self.imageView.image = image;
}
  • 经典卖票案例
/*
 * 设置20张票和AB两个窗口
 */
-(void)initSaleSiticket
{
    self.ticketCount = 20;
    
    // A窗口卖票线程
    self.saleWindowA = [[NSThread alloc] initWithTarget:self selector:@selector(saleSicketAction) object:NULL];
    self.saleWindowA.name = @"A窗口";
    // B窗口卖票线程
    self.saleWindowB = [[NSThread alloc] initWithTarget:self selector:@selector(saleSicketAction) object:NULL];
    self.saleWindowB.name = @"B窗口";
    
    // 开始卖票
    [self.saleWindowA start];
    [self.saleWindowB start];
}


-(void)saleSicketAction
{
    while (YES) {
        [self.lock lock];
        if (self.ticketCount > 0) {
            self.ticketCount--;
            NSLog(@"%@ : %ld",[NSThread currentThread].name,(long)self.ticketCount);
        } else {
            NSLog(@"票卖完了");
            break;
        }
        [self.lock unlock];
        [NSThread sleepForTimeInterval:1.0];
    }
}