第六章 块(Block)与大中枢派发(Grand Central Dispatch,GCD)

总结

一、理解“块”这一概念

1、块的基础知识

(1)、概念:

块用“^”符号来表示,后面跟着一对花括号,括号里面是块的实现代码。例如:

^{
    // Block implementation here
}

块其实就是个值,也有其相关类型,可以把块赋给变量并使用它。块类型的语法与函数指针近似。例如,无参数无返回值的块类型定义如下:

void (^someBlock)() = ^{
        //  Block implementation here
};

因此,我们可以把块类型的语法结构写成这样子,如下:

return_type (^block_name) (parameters)

例子:

int (^addBlock) (int a, int b) = ^(int a, int b) {
    return a + b;
};

(2)、块的内部结构

块本身也是对象,在存放块对象的内存区域中,首个变量是指向Class对象的指针(isa),下图描述了块对象的内存布局。


WechatIMG156.jpeg

在内存布局中,最重要的就是invoke变量,这是个函数指针,指向块的实现代码。

(3)、全局块、栈块及堆块

定义块的时候,其所占的内存区域是分配在栈中的。
若要在块定义的范围之外使用,则需给块对象发送copy消息以拷贝之,这样就把块从栈复制到堆了,拷贝后的块就可以在定义它的那个范围之外使用了。
块也可以定义成全局的。

2、为常用的块类型创建typedef

为了隐藏复杂的块类型,需要使用类型定义,如:

typedef int (^EOCSomeBlock) (BOOL flag, int value);
EOCSomeBlock block = ^(BOOL flag, int value) {
    //Implementation
};

3、用 handler 块降低代码分散程度

在程序里使用delegate的地方都可以使用Block来替换,其使用方法如下:

typedef void (^EOCNetworkFetcherCompletionHandler) (NSData *data, NSError *error);

@interface EOCNetworkFetcher : NSObject
- (void)startWithCompletionHandler:(EOCNetworkFetcherCompletionHandler)handler;
@end

4、用块引用其所属对象时不要出现保留环

1、如果块所捕获的对象直接或间接地保留了块本身,那么久得当心保留环的问题。
2、一定要找个适当的时机解除保留环。

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

1、有种简单而高效的办法可以代替同步块或锁对象,那就是使用“串行同步队列”。

dispatch_queue_t  _syncQueue = dispatch_queue_create("com.effectiveobjectivec.syncQueue", NULL);
- (NSString *)someString {
  __block NSString *localSomeString;
  dispatch_sync(_syncQueue, ^{
       localSomeString = _someString;
  });
  return localSomeString;
}

- (void)setSomeString:(NSString *)someString {
    dispatch_sync(_syncQueue, ^{
        _someString = someString;
    });
}

进一步优化,可以将设置实例变量的方法中所用到的块同步改成异步:dispatch_async(_syncQueue, ^{});

你可能感兴趣的:(第六章 块(Block)与大中枢派发(Grand Central Dispatch,GCD))