iOS之多线程

作者: BoomLee | 来源:发表于2017-06-21 16:02 被阅读520次

    1.进程与线程的区别与联系

    1.1.进程

    广义上来讲,进程是系统中正在运行的一个应用程序,每个进程间都是独立的,每个进程都是运行在独有的空间内,空间是受保护的,这就意味着一个进程是不能访问另一个进程的独有空间的。平时接触到的应用程序都可以认为是一个进程,比如Xcode,SourceTree等。可以通过活动监视器查看Mac上运行的进程。

    进程的五态模型:

    • 进程的五态模型

    1.2.线程

    • 线程是进程的基本执行单元
    • 进程的所有任务都在线程中执行,就是说一个进程想执行任务必须有一个线程,通常是主线程,也就是iOS中的UI线程

    1.3.进程与线程的关系

    进程与线程的关系

    2.任务执行的方式

    2.1.串行

    • 串行

    2.2.并行

    • 并行

    3.多线程的实现方案

    3.1.pThread

    基于c的,没用过,不解释,有兴趣的可以研究下#import <pthread.h>

    3.2.NSThread

    3.2.1.类方法

    无返回值,自动异步执行。但无法设置属性

    + (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(nullable id)argument;
    + (void)detachNewThreadWithBlock:(void (^)(void))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
    

    3.2.2.实例方法

    需要手动调用start异步执行,因为有返回值,所以可以设置属性

    - (instancetype)init NS_AVAILABLE(10_5, 2_0) NS_DESIGNATED_INITIALIZER;
    - (instancetype)initWithTarget:(id)target selector:(SEL)selector object:(nullable id)argument NS_AVAILABLE(10_5, 2_0);
    - (instancetype)initWithBlock:(void (^)(void))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
    

    3.2.3.NSObject的category方法

    以下方法的aSelector均不能有返回值,如果arg不为空则设置一个id类型参数,否则不可设置参数。arg为执行aSelector的入参。

    - (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
    

    wait参数:如果在子线程执行以上两个方法,YES代表阻塞当前子线程直到主线程的aSelector执行完毕,NO代表不阻塞当前子线程;如果在主线程执行以上两个方法,YES代表阻塞当前主线程的方法执行直到主线程的aSelector执行完毕,NO代表不阻塞当前主线程,也就是当前主线程的方法执行完毕再执行aSelector

    - (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray<NSString *> *)array NS_AVAILABLE(10_5, 2_0);
    - (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait NS_AVAILABLE(10_5, 2_0);
        // equivalent to the first method with kCFRunLoopCommonModes
    

    thr:多了个线程参数。

    - (void)performSelectorInBackground:(SEL)aSelector withObject:(nullable id)arg NS_AVAILABLE(10_5, 2_0);
    

    创建一个子线程执行

    3.3.GCD

    3.3.1串行与并行

    使用串行队列执行任务只会创建一个线程。

    dispatch_queue_t serialQueue = dispatch_queue_create("com.gcd.queue.serial", DISPATCH_QUEUE_SERIAL);
    dispatch_get_main_queue()
    

    使用并行队列会创建多个线程

    dispatch_queue_t concurrentQueue = dispatch_queue_create("com.gcd.queue.concurrent", DISPATCH_QUEUE_CONCURRENT);
    dispatch_get_global_queue(0, 0)
    

    Xcode的log会显示进程与线程ID


    进程:2055;线程:91668

    3.3.2.dispatch_group

    当多个任务dispatch_group_async执行完毕后会在dispatch_group_notify回调。但是注意dispatch_group_async中执行的应该是同步的代码,如果是异步的代码比如本身就是异步的网络请求不会达到请求完毕的回调效果。
    如果要达到上述效果,需要如下操作

    - (void)GCDAction{
        
        dispatch_group_t group = dispatch_group_create();
        
        dispatch_group_enter(group);
        [self request1:^{
            NSLog(@"request1 done");
            dispatch_group_leave(group);
        }];
        
        dispatch_group_enter(group);
        [self request2:^{
            NSLog(@"request2 done");
            dispatch_group_leave(group);
        }];
        
        dispatch_group_notify(group, dispatch_get_global_queue(0, 0), ^{
            NSLog(@"回调完成");
            dispatch_async(dispatch_get_main_queue(), ^{
                NSLog(@"回到主线程刷新UI");
            });
        });
        
    }
    
    - (void)request1:(void(^)())block{
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            NSLog(@"start task 1");
            sleep(2);
            NSLog(@"end task 1");
            
            dispatch_async(dispatch_get_main_queue(), ^{
                if (block) {
                    block();
                }
            });
        });
    }
    
    - (void)request2:(void(^)())block{
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            NSLog(@"start task 2");
            sleep(2);
            NSLog(@"end task 2");
            
            dispatch_async(dispatch_get_main_queue(), ^{
                if (block) {
                    block();
                }
            });
        });
    }
    
    打印的log

    3.4.NSOperation

    NSOperation是对GCD的面向对象的封装。

    3.4.1.NSInvocationOperation

    NSInvocationOperation会阻塞当前线程同步执行。

    3.4.2.NSBlockOperation

    NSInvocationOperation一样会阻塞当前线程同步执行。

    3.4.3.NSOperationQueue

    如果想要异步执行,需要使用NSOperationQueue的以下方法来实现。

    - (void)addOperation:(NSOperation *)op;
    - (void)addOperations:(NSArray<NSOperation *> *)ops waitUntilFinished:(BOOL)wait NS_AVAILABLE(10_6, 4_0);
    - (void)addOperationWithBlock:(void (^)(void))block NS_AVAILABLE(10_6, 4_0);
    

    3.4.4.自定义NSOperation

    自定义的NSOperation需要重写- (void)main方法,方法里面是具体的业务实现。对于设置异步的依赖不起作用的问题,可以这样实现。

    #import "CustomOperation.h"
    
    @interface CustomOperation ()
    @property (nonatomic, assign) BOOL over;
    @end
    
    @implementation CustomOperation
    
    - (void)main{
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            sleep(1);
            if (self.isCancelled) {
                return ;
            }
            
            NSLog(@"%@", self.name);
            self.over = YES;
        });
        
        while (!self.over && !self.isCancelled) {
            [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
        }
    }
    
    @end
    
    - (void)NSOperationAction{
        
        NSOperationQueue *queue = [[NSOperationQueue alloc]init];
        
        CustomOperation *op1 = [[CustomOperation alloc]init];
        op1.name = @"op1";
        
        CustomOperation *op2 = [[CustomOperation alloc]init];
        op2.name = @"op2";
        
        CustomOperation *op3 = [[CustomOperation alloc]init];
        op3.name = @"op3";
        
        CustomOperation *op4 = [[CustomOperation alloc]init];
        op4.name = @"op4";
        
        [op1 addDependency:op2];
        [op2 addDependency:op3];
        [op3 addDependency:op4];
        
        [queue addOperation:op1];
        [queue addOperation:op2];
        [queue addOperation:op3];
        [queue addOperation:op4];
    }
    

    Xcode打印日志

    依赖关系
    上一篇:iOS图片滤镜

    相关文章

      网友评论

        本文标题:iOS之多线程

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