美文网首页
iOS多线程之NSThread的使用

iOS多线程之NSThread的使用

作者: iOS心安 | 来源:发表于2020-12-03 14:55 被阅读0次

    NSThread是多线程的一种,优缺点如下:

    (1)优点:NSThread 比GCD、NSOperation都轻量级

    (2)缺点:需要自己管理线程的生命周期,线程同步。线程同步对数据的加锁会有一定的系统开销
    NSThread有两种方法创建子线程,一种是隐式创建,另一种是显示创建。

    第一种是隐式创建,有以下几种方式:

    (1)多用于串行,且在主线程中执行。

    - (id)performSelector:(SEL)aSelector withObject:(id)object;
    

    (2)后台执行,多用于并行,开辟新的子线程,并在子线程中执行。

    - (void)performSelectorInBackground:(SEL)aSelector withObject:(nullable id)arg;
    

    (3)延迟执行,在主线程中执行。

    - (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay;
    

    (4)回到主线程执行

    - (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait;
    

    停止执行的方法

    + (void)cancelPreviousPerformRequestsWithTarget:(id)aTarget selector:(SEL)aSelector object:(nullable id)anArgument;
    
    + (void)cancelPreviousPerformRequestsWithTarget:(id)aTarget
    

    示例:创建子线程-隐式方法

    // 串行,先后顺序执行,在主线程中执行
    - (void)runSerial
    {
        [self performSelector:@selector(showTime:) withObject:@11];
        [self performSelector:@selector(showTime:) withObject:@12];
        [self performSelector:@selector(showTime:) withObject:@13];
    }
     
    - (void)showTime:(id)object
    {
            NSLog(@"主线程:%d, 线程名称:%@, object = %@", [NSThread isMainThread], [NSThread currentThread], object);
    }
     
    2018-03-06 14:35:46.010 DemoThread[6369:1254531] 主线程:1, 线程名称:<NSThread: 0x600000077d40>{number = 1, name = main}, object = 11
    2018-03-06 14:35:46.011 DemoThread[6369:1254531] 主线程:1, 线程名称:<NSThread: 0x600000077d40>{number = 1, name = main}, object = 12
    2018-03-06 14:35:46.011 DemoThread[6369:1254531] 主线程:1, 线程名称:<NSThread: 0x600000077d40>{number = 1, name = main}, object = 13
    
    // 并行,同时进行,执行结果没有午后顺序,开辟新的子线程,并在子线程中执行
    - (void)runParallel
    {
        [self performSelectorInBackground:@selector(showTime:) withObject:@110];
        [self performSelectorInBackground:@selector(showTime:) withObject:@120];
        [self performSelectorInBackground:@selector(showTime:) withObject:@130];
    }
     
    - (void)showTime:(id)object
    {    
            NSLog(@"主线程:%d, 线程名称:%@, object = %@", [NSThread isMainThread], [NSThread currentThread], object);
    }
     
    2018-03-06 14:37:04.270 DemoThread[6392:1256565] 主线程:0, 线程名称:<NSThread: 0x600000074ac0>{number = 11, name = (null)}, object = 130
    2018-03-06 14:37:04.270 DemoThread[6392:1256563] 主线程:0, 线程名称:<NSThread: 0x60000006d000>{number = 9, name = (null)}, object = 110
    2018-03-06 14:37:04.270 DemoThread[6392:1256564] 主线程:0, 线程名称:<NSThread: 0x60000007acc0>{number = 10, name = (null)}, object = 120
    
    // 延迟执行,在主线程中执行
    - (void)runDelay
    {
        [self performSelector:@selector(showTime:) withObject:@210 afterDelay:1.0];
        [self performSelector:@selector(showTime:) withObject:@220 afterDelay:2.0];
        [self performSelector:@selector(showTime:) withObject:@230 afterDelay:3.0];
    }
     
    - (void)showTime:(id)object
    {    
            NSLog(@"主线程:%d, 线程名称:%@, object = %@", [NSThread isMainThread], [NSThread currentThread], object);
    }
     
    // 根据打印时间,可以看出延迟执行时间
    2018-03-06 14:38:03.808 DemoThread[6420:1257666] 主线程:1, 线程名称:<NSThread: 0x60000007e640>{number = 1, name = main}, object = 210
    2018-03-06 14:38:04.809 DemoThread[6420:1257666] 主线程:1, 线程名称:<NSThread: 0x60000007e640>{number = 1, name = main}, object = 220
    2018-03-06 14:38:05.809 DemoThread[6420:1257666] 主线程:1, 线程名称:<NSThread: 0x60000007e640>{number = 1, name = main}, object = 230
    
    // 在主线程中执行,waitUntilDone为NO时,表示非阻塞当前线程,即先执行完当前线程,再执行showTime:方法
    - (void)runMain
    {
        NSLog(@"begin");
        [self performSelectorOnMainThread:@selector(showTime:) withObject:@310 waitUntilDone:NO];
        [self performSelectorOnMainThread:@selector(showTime:) withObject:@320 waitUntilDone:NO];
        [self performSelectorOnMainThread:@selector(showTime:) withObject:@330 waitUntilDone:NO];
        NSLog(@"end");
    }
     
    - (void)showTime:(id)object
    {    
            NSLog(@"主线程:%d, 线程名称:%@, object = %@", [NSThread isMainThread], [NSThread currentThread], object);
    }
     
    2018-03-06 14:40:04.668 DemoThread[6463:1260294] begin
    2018-03-06 14:40:04.668 DemoThread[6463:1260294] end
    2018-03-06 14:40:04.669 DemoThread[6463:1260294] 主线程:1, 线程名称:<NSThread: 0x608000067440>{number = 1, name = main}, object = 310
    2018-03-06 14:40:04.669 DemoThread[6463:1260294] 主线程:1, 线程名称:<NSThread: 0x608000067440>{number = 1, name = main}, object = 320
    2018-03-06 14:40:04.669 DemoThread[6463:1260294] 主线程:1, 线程名称:<NSThread: 0x608000067440>{number = 1, name = main}, object = 330
    
    // 在主线程中执行,waitUntilDone为YES时,表示阻塞当前线程,即先执行完showTime:方法,再执行当前线程
    - (void)runMain
    {
        NSLog(@"begin");
        [self performSelectorOnMainThread:@selector(showTime:) withObject:@310 waitUntilDone:YES];
        [self performSelectorOnMainThread:@selector(showTime:) withObject:@320 waitUntilDone:YES];
        [self performSelectorOnMainThread:@selector(showTime:) withObject:@330 waitUntilDone:YES];
        NSLog(@"end");
    }
     
    - (void)showTime:(id)object
    {    
            NSLog(@"主线程:%d, 线程名称:%@, object = %@", [NSThread isMainThread], [NSThread currentThread], object);
    }
     
    2018-03-06 14:44:05.614 DemoThread[6495:1264100] begin
    2018-03-06 14:44:05.614 DemoThread[6495:1264100] 主线程:1, 线程名称:<NSThread: 0x608000064a40>{number = 1, name = main}, object = 310
    2018-03-06 14:44:05.615 DemoThread[6495:1264100] 主线程:1, 线程名称:<NSThread: 0x608000064a40>{number = 1, name = main}, object = 320
    2018-03-06 14:44:05.615 DemoThread[6495:1264100] 主线程:1, 线程名称:<NSThread: 0x608000064a40>{number = 1, name = main}, object = 330
    2018-03-06 14:44:05.615 DemoThread[6495:1264100] end
    
    第二种是显示创建,方式如下:
    + (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(nullable id)argument;
    
    + (void)detachNewThreadWithBlock:(void (^)(void))block;
    
    - (instancetype)initWithTarget:(id)target selector:(SEL)selector object:(nullable id)argument;
    

    注意:
    (1)通过方法" - (void)start; "开始执行;
    (2)通过方法" - (void)cancel; "停止执行;

    示例:创建子线程-显示方法

    // 并行,同时进行,执行结果没有先后顺序,开辟新的子线程,并在子线程中执行
    - (void)runDetach
    {
        [NSThread detachNewThreadSelector:@selector(showTime:) toTarget:self withObject:@410];
        [NSThread detachNewThreadSelector:@selector(showTime:) toTarget:self withObject:@420];
        [NSThread detachNewThreadSelector:@selector(showTime:) toTarget:self withObject:@430];
        
        [NSThread detachNewThreadWithBlock:^{
            [self showTime:@4100];
        }];
    }
     
    - (void)showTime:(id)object
    {    
            NSLog(@"主线程:%d, 线程名称:%@, object = %@", [NSThread isMainThread], [NSThread currentThread], object);
    }
     
    2018-03-06 14:47:23.918 DemoThread[6535:1268056] 主线程:0, 线程名称:<NSThread: 0x6080000773c0>{number = 13, name = (null)}, object = 430
    2018-03-06 14:47:23.918 DemoThread[6535:1268054] 主线程:0, 线程名称:<NSThread: 0x608000063940>{number = 11, name = (null)}, object = 410
    2018-03-06 14:47:23.919 DemoThread[6535:1268055] 主线程:0, 线程名称:<NSThread: 0x60800007da80>{number = 12, name = (null)}, object = 420
    2018-03-06 14:47:23.919 DemoThread[6535:1268057] 主线程:0, 线程名称:<NSThread: 0x60000007bd80>{number = 14, name = (null)}, object = 4100
    
    self.thread = [[NSThread alloc] initWithTarget:self selector:@selector(showCount:) object:@(61)];
     self.thread.name = @"计数";
     [self.thread start];
     [self.thread cancel];
    

    代码示例

    - (void)showCount:(NSNumber *)number
    {
        NSInteger count = arc4random() % 1000;
        count = 1000;
        for (int i = 0; i < count; i++)
        {
            NSLog(@"第 %@ 个 i = %@", number, @(i));
            
            // 休眠n秒再执行
            [NSThread sleepForTimeInterval:0.2];
            
            // 停止
    //        BOOL isStop = [self.thread isCancelled];
    //        if (isStop)
    //        {
    //            NSLog(@"2 停止");
    //            break;
    //        }
            if (isCancelThread)
            {
                NSLog(@"2 停止");
                break;
            }
        }
    }
    
    bool isCancelThread = NO;
    - (void)stopClick
    {
        [NSObject cancelPreviousPerformRequestsWithTarget:self];
        
        if (self.thread)
        {
            BOOL isExecuting = [self.thread isExecuting];
            if (isExecuting)
            {
                NSLog(@"1 停止");
    //            [self.thread cancel];
                isCancelThread = YES;
            }
        }
    }
    
    
    - (void)downloadImage:(NSString *)imageUrl
    {
        NSURL *url = [NSURL URLWithString:imageUrl];
        NSData *data = [[NSData alloc] initWithContentsOfURL:url];
        UIImage *image = [[UIImage alloc] initWithData:data];
        if (image == nil)
        {
            
        }
        else
        {
    //        [self performSelectorOnMainThread:@selector(updateImage:) withObject:image waitUntilDone:YES];
            [self performSelectorInBackground:@selector(updateImage:) withObject:image];
        }
        
    //    NSURL *url = [NSURL URLWithString:imageUrl];
    //    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    //    NSURLSession *session = [NSURLSession sharedSession];
    //    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler: ^(NSData *data, NSURLResponse *response, NSError *error) {
    //        
    //        // 输出返回的状态码,请求成功的话为200
    //        NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
    //        NSInteger responseStatusCode = [httpResponse statusCode];
    //        NSLog(@"%ld", responseStatusCode);
    //        
    //        UIImage *image = [UIImage imageWithData:data];
            [self performSelectorOnMainThread:@selector(updateImage:) withObject:image waitUntilDone:YES];
    //        [self performSelectorInBackground:@selector(updateImage:) withObject:image];
    //    }];
    //    
    //    // 使用resume方法启动任务
    //    [dataTask resume];
    }
    
    - (void)updateImage:(UIImage *)image
    {
        self.imageview.image = image;
        
    //    self.imageview = [[UIImageView alloc] initWithFrame:CGRectMake(10.0, 10.0, (CGRectGetWidth(self.view.bounds) - 10.0 * 2), (CGRectGetWidth(self.view.bounds) - 10.0 * 2))];
    //    [self.view addSubview:self.imageview];
    //    self.imageview.backgroundColor = [UIColor colorWithWhite:0.5 alpha:0.2];
    //    
    //    self.imageview.image = image;
    }
    
    
    NSString *imageUrl = @"http://ww1.sinaimg.cn/crop.0.0.1242.1242.1024/763fb12bjw8empveq3eq8j20yi0yiwhw.jpg";
    // 隐藏创建
    // [self performSelectorInBackground:@selector(downloadImage:) withObject:imageUrl];
    [self performSelectorOnMainThread:@selector(downloadImage:) withObject:imageUrl waitUntilDone:YES];
    // 创建子线程-显示方法
    self.thread = [[NSThread alloc] initWithTarget:self selector:@selector(downloadImage:) object:imageUrl];
    self.thread.name = @"imageDownload";
    [self.thread start];
    

    其他

    // 线程信息
    NSLog(@"%@", [NSThread currentThread]);
     
    2018-03-06 14:19:02.575 DemoThread[6214:1238492] <NSThread: 0x600000072bc0>{number = 1, name = main}
    
    // 线程大小 512 KB
    NSLog(@"主线程栈区空间大小 => %tu", [NSThread currentThread].stackSize / 1024);
     
    2018-03-06 14:19:02.575 DemoThread[6214:1238492] 主线程栈区空间大小 => 512
    
    // 是否主线程
    NSLog(@"主线程:%d, ", [NSThread isMainThread]);
     
    2018-03-06 14:19:02.576 DemoThread[6214:1238663] 主线程:0
    

    本文来自 番薯大佬

    上一篇:GCD详细总结

    相关文章

      网友评论

          本文标题:iOS多线程之NSThread的使用

          本文链接:https://www.haomeiwen.com/subject/wneswktx.html