ios基础

iOS 编写高质量Objective-C代码(七)—— GCD专

2018-10-15  本文已影响90人  齐舞647

《编写高质量OC代码》已经顺利完成一二三四五六七篇!
附上链接:
iOS 编写高质量Objective-C代码(一)—— 简介
iOS 编写高质量Objective-C代码(二)—— 面向对象
iOS 编写高质量Objective-C代码(三)—— 接口和API设计
iOS 编写高质量Objective-C代码(四)—— 协议与分类
iOS 编写高质量Objective-C代码(五)—— 内存管理机制
iOS 编写高质量Objective-C代码(六)—— block专栏
iOS 编写高质量Objective-C代码(七)—— GCD专栏


本篇的主题是iOS中的 “ 大中枢开发 GCD ”

先简单介绍一下今天的主角:GCD

一、多用派发队列,少用同步锁

问:在iOS开发中,如何通过锁来提供同步机制?(以前面试中,经常问道的问题..)

答:在GCD出现之前,有两种方式:

- (void)synchronizedMethod {
    
    @synchronized (self) {
        
        // Safe area...
    }
}
_lock = [[NSLock alloc] init];

- (void)synchronizedMethod {
    
    [_lock lock];    
    // Safe area..    
    [_lock unlock];
}

不过这两种写法效率很低,如果有很多属性,那么每个属性的同步块都要等其他同步块执行完毕才能执行。

GCD出现后,GCD与Block相结合,使开发变得更加简单、高效。

问:如何保证属性读写时线程绝对安全?
答:在属性写入时,使用栅栏块barrier。只有当前所有并发块都执行完毕后,才会执行barrier块,然后才会继续向下处理。

_syncQueue = dispatch_queue_create("syncQueue", DISPATCH_QUEUE_CONCURRENT);

//! 读取字符串
- (NSString *)someString {

    __block NSString *localSomeString;

    dispatch_sync(_syncQueue, ^{
        localSomeString = _someString;
    });

    return localSomeString;
}

- (void)setSomeString:(NSString *)someString {

     dispatch_barrier_async(_syncQueue, ^{
        _someString = someString;
    });
}

二、多用GCD,少用performSelector系列方法

performSelector系列方法的缺点有两个:

  1. performSelector系列方法可能引起内存泄漏:
    在ARC环境下,编译器并不知道将要调用的选择子是什么,有没有返回值,返回值是什么,所以ARC不能判断返回值是否能释放,因此ARC做了一个比较谨慎的做法:只添加retain,不添加release。因此在有返回值或参数的时候可能导致内存泄漏。
  2. performSelector系列方法的返回值只能是void或OC对象类型。
  3. performSelector系列方法最多只能传入两个参数。

因此可以使用GCD来代替performSelector系列方法:

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        
    //do something..
});

三、掌握GCD及操作队列的使用时机

GCD性能很棒,但在执行后台任务时,GCD并不一定是最佳选择。在iOS开发中,还有一种技术叫NSOperationQueueGCD是基于C语言的API,性能较高。而NSOperationQueue是基于GCD的抽象。

使用NSOperationNSOperationQueue的优点:

四、通过Dispatch Group机制,根据系统资源状况来执行任务

dispatch groupGCD的一项特性,能够把任务进行分组管理,然后等待这组任务执行完毕时会有通知,开发者可以拿到结果然后继续下一步操作。
另外,通过dispatch group在并发队列上同时执行多项任务的时候,GCD会根据系统资源状态来帮忙调度这些并发执行的任务。

五、使用dispatch_once来执行只需要运行一次的线程安全代码

例如:我们开发中写一个单例,就可以使用dispatch_once

+ (instancetype)sharedInstance {
    
    static Class *manager = nil;

    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        manager = [[Class alloc] init];
    });

    return manager;
}

六、不要使用dispatch_get_current_queue

理由如下:

上一篇 下一篇

猜你喜欢

热点阅读