iOS多线程总结

来源:互联网 发布:知善恶树英文 编辑:程序博客网 时间:2024/05/18 01:28

    线程的注意点:

        1.不要同时开太多的线程(1~3条线程即可,不要超过5条)

        2.线程概念:

            1>主线程:UI线程,显示、刷新UI界面,处理UI控件的事件

            2>子线程:后台线程,异步线程

        3.不要把耗时的操作放在主线程,要放到子线程中执行


一、NSThread

1.创建和启动线程的三种方式

    1>先创建,后启动

    //创建

    NSThread *thread = [[NSThread alloc] initWihtTarget:self selector:@selector(download:) object:nil];

    //启动

    [thread start];


    2>创建完自动启动

    [NSThread detachNewThreadSelector:@selector(download:) toTarget:self withObject:@"http://a.jpg"];


    3>隐式创建(自动启动)

    [self performSelectorInBackground:@selector(download:) withObject:@"http://c.gif"];

2.常见方法

    1>获得当前线程

    + (NSThread *)currentThread;


    2>获得主线程

    + (NSThread *)mainThread;


    3>睡眠(暂停)线程

    + (void)sleepUntilDate:(NSDate *)date;

    + (void)sleepForTimeInterval:(NSTimeInterval)ti;


    4>设置线程的名字

    - (void)setName:(NSString *)name;

    - (NSString *)name;

3.线程同步

    1>实质:为了防止多个线程抢夺同一个资源造成的数据安全问题


    2>实现:给代码加一个互斥锁(同步锁)

@synchronized (self) {

    //被锁住的代码

}


二、GCD

// dispatch_sync : 同步,不具备开启线程的能力

// dispatch_async : 异步,具备开启线程的能力


// 并发队列:多个任务可以同时执行

// 串行队列:一个任务执行完后,再执行下一个任务

1.队列和任务

    1>任务:需要执行什么操作

        *block来封装任务


    2>队列:存放任务

        1)全局的并发队列:可以让任务并发执行

        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);


        dispatch_async(queue, ^{//任务添加全局队列中去异步执行

            NSLog(@"-----下载图片1---%@", [NSThread currentThread]);

        });


        2)自己创建的串行队列:让任务一个接一个地执行

        dispatch_queue_t queue = dispatch_queue_create("cn.heima.queue",NULL);


        dispatch_async(queue, ^{// 2.将任务添加到串行队列中异步执行

            NSLog(@"-----下载图片1---%@", [NSThread currentThread]);

        });


        3)主队列

        // 1.主队列(添加到主队列中的任务,都会自动放到主线程中去执行)

        dispatch_queue_t queue = dispatch_get_main_queue();


        // 2.添加任务到主队列中异步执行

        dispatch_async(queue, ^{

            NSLog(@"-----下载图片1---%@", [NSThread currentThread]);

        });


2.执行任务的函数

    1>dispatch_sync :同步,不具备开启线程的能力

        *注意:dispatch_sync不能使用主队列(会被卡死){

           // 1.主队列(添加到主队列中的任务,都会自动放到主线程中去执行)

            dispatch_queue_t queue = dispatch_get_main_queue();

            

            // 2.添加任务到主队列中异步执行

            dispatch_sync(queue, ^{

                NSLog(@"-----下载图片1---%@", [NSThread currentThread]);

            });

        }


    2>dispatch_async :异步,具备开启线程的能力


3.常见的组合

    1>dispatch_async +全局并发队列

    2>dispatch_async +自己创建的串行队列


4.线程间的通信

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{

        NSLog(@"donwload---%@", [NSThread currentThread]);

        // 1.子线程下载图片

        NSURL *url = [NSURL URLWithString:@"http://d.hiphotos.baidu.com/image/pic/item/37d3d539b6003af3290eaf5d362ac65c1038b652.jpg"];

        NSData *data = [NSData dataWithContentsOfURL:url];

        UIImage *image = [UIImage imageWithData:data];

    

        // 2.回到主线程设置图片

        dispatch_async(dispatch_get_main_queue(), ^{

            NSLog(@"setting---%@ %@", [NSThread currentThread], image);

            [self.button setImage:image forState:UIControlStateNormal];

        });

    });


5.GCD的所有API都在libdispatch.dylibXcode会自动导入这个库

    *主头文件 #import <dispatch/dispatch.h>


6.延时执行

    1>3秒后自动回到当前线程调用selfdownload:方法。并且传递参数:@"http://555.jpg"

    // 一旦定制好延迟任务后,不会卡住当前线程

    [self performSelector:@selector(download:) withObject:@"http://555.jpg" afterDelay:3];


    2>// 3秒后自动开启新线程执行block中的代码

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), queue, ^{

        NSLog(@"------task------%@", [NSThread currentThread]);

    });

7.一次性代码

static dispatch_once_t onceToken;

dispatch_once(&onceToken, ^{//这里面的代码永远只会执行一次

    NSLog(@"----once");

    

});


三、NSOperation

作用:配合使用NSOperationNSOperationQueue也能实现多线程编程

NSOperationNSOperationQueue实现多线程的具体步骤:

    先将需要执行的操作封装到一个NSOperation对象中,然后将NSOperation对象添加到NSOperationQueue中,系统会自动将NSOperationQueue中的NSOperation取出来,并把封装的操作放到一条新线程中执行。


NSOperation是一个抽象类,并不具备封装操作的能力,必须使用它的子类。

使用NSOperation子类的方式有3种:

    (1).NSInvocationOperation

        {// 创建队列

            NSOperationQueue *queue = [[NSOperationQueue alloc] init];

    

            // 创建操作

            NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download) object:nil];

            // operation直接调用start,是同步执行(在当前线程执行操作)

            //    [operation start];

    

           //添加操作到队列中,会自动异步执行

            [queue addOperation:operation];

        }

        - (void)download

        {

            NSLog(@"download-----%@", [NSThread currentThread]);

        }

    (2).NSBlockOperation

    (3).自定义子类继承NSOperation,实现内部相应的方法

1.队列的类型

    1>主队列

        *主队列:[NSOperationQueue mainQueue];

        *添加到主队列中的操作,都会放到主线程中执行。

    2>非主队列

        *创建一个队列(非主队列)

        NSOperationQueue *queue = [[NSOperationQueue alloc] init];

        *添加到"非主队列"中的操作,都会放到子线程中执行

2.队列添加任务

* - (void)addOperation:(NSOperation *)op;

* - (void)addOperationWithBlock:(void (^)(void))block;


3.常见用法

    1> 设置最大并发数

        - (NSInteger)maxConcurrentOperationCount;

        - (void)setMaxConcurrentOperationCount:(NSInteger)cnt;

    2>队列的其他操作

    *取消所有的操作

        - (void)cancelAllOperations;

    *暂停所有操作

        [queue setSuspended:YES];

    *恢复所有操作

        [queue setSuspended:NO];

4.操作之间的依赖

*NSOperation之间可以设置依赖来保证执行顺序

*[operationB addDependency:operationA];//操作B依赖于操作A(只有操作A执行完以后才能执行操作B

*注意:不能相互依赖,比如A依赖BB依赖A

*可以在不同queueNSOperation之间创建依赖关系


5.线程之间的通讯

NSOperationQueue *queue = [[NSOperationQueue alloc] init];

[queue addOperationWithBlock:^{

    // 1.异步下载图片(执行一些比较耗时的操作)

    NSURL *url = [NSURL URLWithString:@"http://d.hiphotos.baidu.com/image/pic/item/37d3d539b6003af3290eaf5d362ac65c1038b652.jpg"];

    NSData *data = [NSData dataWithContentsOfURL:url];

    UIImage *image = [UIImage imageWithData:data];

    

    // 2.回到主线程,显示图片

    //        [self performSelectorOnMainThread:<#(SEL)#> withObject:<#(id)#> waitUntilDone:<#(BOOL)#>];

    //        dispatch_async(dispatch_get_main_queue(), ^{

    //

    //        });

    [[NSOperationQueue mainQueue] addOperationWithBlock:^{

        self.imageView.image = image;

    }];

}];


四、从其他线程回到主线程的方式:

1.perform....

    [self performSelectorOnMainThread:<#(SEL)#> withObject:<#(id)#> waitUntilDone:<#(BOOL)#>];

2.GCD

    dispatch_async(dispatch_get_main_queue(), ^{

        

    });

3.NSOperation

    [[NSOperationQueue mainQueue] addOperationWithBlock:^{

    

    }];

五、判断编译器的环境:ARC还是MRC

#if __has_feature(objc_arc)

//当前的编译器环境是ARC


#else

//当前的编译器环境是MRC


#endif



0 0
原创粉丝点击