博客> iOS开发之多线程NSThread
iOS开发之多线程NSThread
2017-08-15 05:52 评论:0 阅读:501 wzt
前言

这篇文章主要讲NSThread的使用,相关博客如下:
iOS开发之多线程理论部分
NSOperation
GCD

What
NSThread是轻量级的多线程开发,使用并不复杂,但使用NSThread需要自己管理线程的生命周期。
NSThread常用方法
    使用NSThread开辟线程的两种方式:
        创建并手动开启线程

        NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(compete) object:nil];   
        [thread start];

        创建并自动开启线程

        [NSThread detachNewThreadSelector:@selector(compete) toTarget:self withObject:nil];

    NSThread的常用方法

        判断当前进程是否是多线程

        BOOL isMultiThread = [NSThread isMultiThreaded];

        获取当前线程对象

        //输出当前线程的信息
        NSLog(@"当前所在的线程=%@",[NSThread currentThread]);

        控制台

            NSThread[10433:1182963] viewDidLoad 方法所在的线程=<NSThread>{number = 1, name = main}

        number = 1 : 线程的编号,由系统设置,主线程的编号为1
        name = main:指当前所在的线程的名字叫做main,可以自己设置,主线程的名字默认是main,其他线程如果不给他设置名字默认是nil。

        使当前线程睡眠指定的时间,单位为秒

        //这句代码在哪个线程执行就让哪个线程睡眠。
        [NSThread sleepForTimeInterval:2];

        线程一旦休眠就进入阻塞状态,就是正在运行的线程没有运行结束,暂时让出CPU,这时其他处于就绪状态的线程就可以获得CPU时间,进入运行状态。

        设置线程的优先级

         //取值范围(0.0~1.0),默认为0.5,取值越大,优先级越大。
         thread.threadPriority = 1.0;

        判断当前线程是否为主线程

        [NSThread isMainThread];

        给线程设置名字

        [thread setName:@"线程名字"];

        NSThread对象可知的三种状态

        isExecuting:是否正在执行,只读
        isFinished:是否已经完成,只读
        isCancellled:是否已经取消,可通过[thread cancel]手动设置,线程取消意味着该线程处于准备退出状态,但不会影响线程的运行。

        退出当前线程

        //线程退出前,必须要要,该线程之后的代码将不在执行
        if (thread.isCancelled == YES) {
            [NSThread exit];
         }

How

    使用多线程加载一张url图片
        在self.view上放一个UIImageView试图
        开辟一条子线程
        在子线程中将url图片转成image对象
        回到主线程

        在主线程中将image对象给UIImageView试图

        //
        //  ViewController.m
        //  NSThread
        //
        //  Created by GG on 16/2/18.
        //  Copyright © 2016年 GG. All rights reserved.
        //

        #import "ViewController.h"

        #define kUrl @"http://store.storeimages.cdn-apple.com/8748/as-images.apple.com/is/image/AppleInc/aos/published/images/s/38/s38ga/rdgd/s38ga-rdgd-sel-201601?wid=848&hei=848&fmt=jpeg&qlt=80&op_sharpen=0&resMode=bicub&op_usm=0.5,0.5,0,0&iccEmbed=0&layer=comp&.v=1454777389943"

        @interface ViewController ()
        {
            UIImageView *imageView;
        }

        @end

        @implementation ViewController

        - (void)viewDidLoad {
            [super viewDidLoad];

            /*
             * 1、在self.view上放一个UIImageView试图
             */
            imageView = [[UIImageView alloc]initWithFrame:CGRectMake(50, 50, 200, 200)];
            [self.view addSubview:imageView];

            /*
             * 2、 开辟一条子线程(我这里采用创建并手动开启线程的方式)

             * target: 信息发送者

             * selector: 方法选择器选择一个方法

             * object: 如果上面选择的方法有参数,则object便是这个方法的参数

             */
            NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(downloadImage:) object:kUrl];

            //给线程起名字
            thread.name = @"子线程";

            // 开启线程
            [thread start];

        }

        /*
         * 3、 在`子线程`中将url图片转成image对象

         *  downloadImage该方法的参数取决于创建线程时传给object的参数

         */
        - (void)downloadImage:(NSString *)url{

            //将图片的url地址转化为data对象
            NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:kUrl]];

            //将data对象转化为image对象
            UIImage *image = [UIImage imageWithData:data];

            /* 
             * 4. 是NSObject的一个方法,用来回到主线程

             * 方法updataUI将在主线程中执行

             * withObject:updateUI的参数

             * waitUntilDone: 设为YES,会阻塞当前子线程,去主线程执行updateUI方法,也就是更新UI,直到UI更新完毕。设为NO,意味着在主线程updateUI方法执行到一半时可能会被打断去做其他线程的工作,也就是说我主线程的UI还没有显示完就程序就跳出了主线程。
             */
            [self performSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES];

            /*

             * 查看打印结果

             * number = 1 :线程的编号,由系统设置,主线程的编号为1

             * name = main:指当前所在的线程的名字叫做main,可以自己设置,主线程的名字默认是main,其他线程如果不给他设置名字默认是nil

             */
            NSLog(@"downlaodImage方法所在的线程 = %@",[NSThread currentThread]);

                    }

        /*
         * 5、 在主线程中将image对象给UIImageView试图
         */

        - (void)updateUI:(UIImage *)image{

            imageView.image = image;

            NSLog(@"downlaodImage方法所在的线程 = %@",[NSThread currentThread]);

        }

        @end

    使用多线程加载多张图片
        在self.view上放多个UIImageView试图
        开辟多条子线程
        在子线程中将url图片转成image对象
        回到主线程

        在主线程中将image对象给UIImageView试图

        //
        //  MoreImageViewViewController.m
        //  NSThread
        //
        //  Created by GG on 16/2/22.
        //  Copyright © 2016年 GG. All rights reserved.
        //

        #pragma mark ------------------NSThread分析详解 http://www.jianshu.com/p/b1c2bd572e81-------------

        #import "MoreImageViewViewController.h"

        #define kUrl @"http://store.storeimages.cdn-apple.com/8748/as-images.apple.com/is/image/AppleInc/aos/published/images/s/38/s38ga/rdgd/s38ga-rdgd-sel-201601?wid=848&hei=848&fmt=jpeg&qlt=80&op_sharpen=0&resMode=bicub&op_usm=0.5,0.5,0,0&iccEmbed=0&layer=comp&.v=1454777389943"

        @interface MoreImageViewViewController ()
        {
            int imageIndex;

            NSMutableArray *threadArrays;

            UIImage *image;
        }

        @end

        @implementation MoreImageViewViewController

        - (void)viewDidLoad {
            [super viewDidLoad];

            UILabel *lable = [[UILabel alloc]initWithFrame:CGRectMake(100, 300, 0, 0)];
            lable.text = @"点击屏幕停止加载";
            lable.textColor = [UIColor blackColor];
            [lable sizeToFit];
            [self.view addSubview:lable];

            //创建多个UIImageView
            self.title = @"多线程加载多张图片";
            self.edgesForExtendedLayout = UIRectEdgeNone;
            self.view.backgroundColor = [UIColor whiteColor];

            imageIndex = 100;

            for (int  row= 0; row<3 xss=removed xss=removed xss=removed xss=removed xss=removed xss=removed xss=removed xss=removed xss=removed xss=removed xss=removed xss=removed xss=removed xss=removed xss=removed> *)touches withEvent:(UIEvent *)event{

            for (int i=0; i&lt;6; i++) {
                NSThread *thread= threadArrays[i];
                //判断线程是否完成,如果没有完成则设置为取消状态
                //注意设置为取消状态仅仅是改变了线程状态而言,并不能终止线程
                if (!thread.isFinished) {
                    [thread cancel];

                    NSLog(@"============");

                }
            }

        }

        @end

        顺序启动的线程一般不会按照启动顺序执行,这是因为线程都创建好以后,CPU会根据实际情况(网速、启动时间、优先级等)来决定执行线程的先后顺序,在这里我采用线程sleep的方式实现了线程的顺序执行。
补充

为了简化多线程开发过程,苹果官方对NSObject进行分类扩展(本质还是创建NSThread),对于简单的多线程操作可以直接使用这些扩展方法。

//在后台执行一个操作,本质就是重新创建一个线程执行当前方法。
- (void)performSelectorInBackground:(SEL)aSelector withObject:(id)arg:

//在指定的线程上执行一个方法,需要用户创建一个线程对象。
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait:

//在主线程上执行一个方法(前面已经使用过)。
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait:

GitHub - wangliguang/NSThread — demo下载 
收藏
0
sina weixin mail 回到顶部