《EffectiveObjective-c 2.0》第六章 块与

2017-08-29  本文已影响0人  神的旨意

第37条:理解“块”这一概念

  1. 块的基础知识
int additional = 5;
    int (^addOption)(int a, int b) = ^(int a, int b){
        additional = 7;//Variable is not assignable (missing __block type specifier)
        return a + b + additional;
    };
    int result = addOption(2, 5);

除非加上__block关键字,但是如果是实例变量就可以直接修改,且不用加__block

  1. 块的内部结构

第38条:为常用的块类型创建typedef

  1. 以typedef重新定义块类型,可令块变量用起来更加简单。
  2. 定义新类型时应遵从现有的命名习惯,勿使用其名称与别的类型相冲突
typedef void (^VCComplete)(BOOL flag,int value);

//使用
VCComplete complete = ^(BOOL flag,int value){
        
    };

第39条:用handle块降低代码分散程度

  1. 在创建对象时,可以使用内联的handler块将相关业务逻辑一并声明。
  2. 在有多个实例需要监控时,如果采用委托模式,那么需要经常要根据传入的对象来切换,而若改用handler块来实现,则可直接将块与相关对象放在一起。(推荐使用handler块,且有错误的块也放在一起
    倾向于:

    而不是
  3. 设计API时如果用到了handler块,那么可以增加一个参数,使调用者可以通过此参数来决定应该把块安排到哪个队列上执行。

第40条:用块引用其所属对象时不要出现保留环

  1. 使用块所捕获的对象直接或间接地保留了块本身,那么就得当心保留环问题。
  2. 一定要找个适当的时机解除保留环,而不能把责任推给API调用者。
    下面情况注意:
//保留环
int (^addOption)(int a, int b) = ^(int a, int b){
        _additional = 7;//_additional实例变量,_additional等效于self. additional,所以该块捕获到了self对象
        return a + b + _additional;
    };

块复制过后,调用执行块后,要把块置为nil,打破保留环

第41条:多用派发队列,少用同步锁

  1. 使用get,set方法做同步操作的时候,可以使用GCD,少用同步锁 @synchronized(self) 等方法。原因是GCD更高效,不会阻塞执行异步派发的线程,同步锁会产生死锁现象。
  2. 使用同步队列及栅栏块,可以令同步行为更叫高效。
    栅栏执行的逻辑是,栅栏前面的队列可以并发执行,当遇到栅栏的时候,等到前面的队列全部执行完后,再执行栅栏里面的操作,栅栏执行完后,在执行栅栏后的操作。
    WX20170817-180958.png
    栅栏块的效果

第42条:多用GCD,少用performSelector系列方法

  1. 情况一
    使用performSerlector在下面这种情况下,会提示警告
 BOOL fool = YES;
    SEL selector;
    if(fool){
        selector = @selector(fetchData);
    }else{
        selector = @selector(fetchData1);
    }
    [self performSelector:selector];
//警告:PerformSelector may cause a leak because its selector is unknown

警告的原因是:编译器并不知道将要调用的选择子是什么,因此,也就不了解其方法签名及返回值,甚至是否有返回值都不清楚,而且,编译器不知道方法名,所以就没有办法运用ARC的内存管理规则来判断返回值是不是应该释放,ARC选择不释放,所以可能导致内存泄漏。

情况二


这里的 newObject,copy这两个创建的对象需要手动释放,someProperty不需要收到释放,参考上一章的第30条。
  1. 总结


第43条:掌握GCD及操作队列的使用时机

  1. 在解决多线程与任务管理问题时,派发队列并非唯一方案。
  2. 操作队列提供了一套高层的Objective-C API,能实现纯GCD所具备的绝大部分功能,而且还能完成一些更为复杂的操作,那些操作若改用GCD来实现,则需另外编写代码。
  3. NSOperationNSOperationQueue的好处如下:

第44条:通过Dispatch Group 机制,根据系统资源状况来执行任务

  1. dispatch group 能够把任务分组,调用者可以等待这组任务执行完毕,可以在提供回调函数之后继续往下执行,这组任务完成时,调用者会得到通知。最重要的是执行操作后,可以得到通知,以便可以根据结果处理相应操作。重要用法:就是把将要并发执行的多个任务合为一组,于是调用者就可以知道这些任务何时才能全部执行完毕
// 1. 创建组
dispatch_group_t group = dispatch_group_create();

// 2. 异步调用,dispatch_group_async没啥特殊用途,就是把队列归属到一个组里面,同dispatch_async
dispatch_group_async(dispatch_group_t group,
    dispatch_queue_t queue,
    dispatch_block_t block);
// 或者是指定任务所属的组
void dispatch_group_enter(dispatch_group_t group);//加入到组中
void dispatch_group_leave(dispatch_group_t group);//从组中移除队列
//前者是分组里正要执行的任务递增,后者使之递减,必须成对出现。如果调用enter之后,没有相应的leave操作,那么这组任务永远执行不完。

// 3. 等待组执行完,阻塞线程,dispatch_group_wait前面的先执行,等时间超过timeout,再执行dispatch_group_wait后面的代码,起到阻塞作用
long dispatch_group_wait(dispatch_group_t group, dispatch_time_t timeout);

// 4. 等到组中的线程都执行完后,再执行这个通知
void dispatch_group_notify(dispatch_group_t group,
    dispatch_queue_t queue,
    dispatch_block_t block);

// 5. 遍历某个collection,每个任务可以并发执行,且是阻塞线程的,dispatch_apply后面的任务要等到该函数遍历执行完后,才放开线程。
void dispatch_apply(size_t iterations, dispatch_queue_t queue,
        DISPATCH_NOESCAPE void (^block)(size_t));

第45条:使用dispatch_once来执行只需运行一次的线程安全代码

  1. 使用dispatch_once可以简化代码更高效,且彻底保证线程安全。它没有使用重量级的同步机制,若是那样做的话,每次运行代码前都要获取锁,相反,此函数采用“原子访问”来查询标记,判断其所对应的代码是否已经执行过。
+ (id)sharedInstance{
    static WCCPerson *sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[self alloc] init];
    });
    return sharedInstance;
}

+ (id)sharedInstance{
    static WCCPerson *sharedInstance = nil;
    @synchronized(self) {
        if (!sharedInstance) {
            sharedInstance = [[self alloc] init];
        }
    }
    return sharedInstance;
}
//两者执行的时间差不多
    CFAbsoluteTime startTime =CFAbsoluteTimeGetCurrent();
    WCCPerson *persion = [WCCPerson sharedInstance];
    CFAbsoluteTime linkTime = (CFAbsoluteTimeGetCurrent() - startTime);
    //once 0.019968 0.015020 0.009000  
    //sync 0.010967 0.011027 0.010014
    NSLog(@"Linked in %f ms", linkTime *1000.0);

第46条:不要使用dispatch_get_current_queue

没看,不适用的函数了

点击进入 第七章

上一篇 下一篇

猜你喜欢

热点阅读