Cowboy Tech

Blocks

原文链接:working with block

什么是block

  1. 块是添加在 c,object-c 和 c++ 语言中的语言级别的形式,它允许你编写一个独特的代码段,这个代码段能够在作为值方法和函数中传递。
  2. 块是 object-c 的对象,这意味着他们能够被添加到像NASArray或是NSDictionary的集合中.

没有参数和返回值的块

定义一个块

^{
     NSLog(@"This is a block");
}

声明块变量

void (^simpleBlock)(void);

块变量赋值

void (^simpleBlock)(void) = ^{
    NSLog(@"This is a block");
};

块变量赋值的简约形式

simpleBlock = ^{
    NSLog(@"This is a block");
};

调用块命令

simpleBlock();

有参数和返回值的块

定义一个块

//1.

^ (double firstValue, double secondValue) {
    return firstValue * secondValue;
}

//2.
^ double (double firstValue, double secondValue) {
    return firstValue * secondValue;
}

声明块变量

double (^multiplyTwoValues)(double, double);    

调用块命令

double (^multiplyTwoValues)(double, double) =
                          ^(double firstValue, double secondValue) {
                              return firstValue * secondValue;
                          };

double result = multiplyTwoValues(2,4);

NSLog(@"The result is %f", result);

块的值域

如果你在一个方法中声明了块,他可以捕捉到任何在方法域中可以访问到的值

- (void)testMethod {
int anInteger = 42;

void (^testBlock)(void) = ^{
    NSLog(@"Integer is: %i", anInteger);
};

testBlock();
}

一旦捕获后,即使在捕获后和调用期间改变值,不受影响.块不能够改变初始变量的值,或者是被捕获的值

int anInteger = 42;

void (^testBlock)(void) = ^{
    NSLog(@"Integer is: %i", anInteger);
};

anInteger = 84;

testBlock();  

//Integer is: 42 

__block变量(块变量的改变)

变量和块共享存储空间。变量改变,块内的也改变

__block int anInteger = 42;

void (^testBlock)(void) = ^{
NSLog(@"Integer is: %i", anInteger);
};

anInteger = 84;
testBlock(); 

//Integer is:84

变量可以在块内被改变

__block int anInteger = 42;

void (^testBlock)(void) = ^{
    NSLog(@"Integer is: %i", anInteger);
    anInteger = 100;
};

testBlock();
NSLog(@"Value of original variable is now: %i", anInteger); 

//Integer is: 42
//Value of original variable is now: 100  

块作为方法或函数的参数

- (void)beginTaskWithCallbackBlock:(void (^)(void))callbackBlock;


- (void)beginTaskWithCallbackBlock:(void (^)(void))callbackBlock {
...
callbackBlock();
}

- (void)doSomethingWithBlock:(void (^)(double, double))block {
...
block(21.0, 2.0);
}

块应该总是一个方法的最后一个参数

//声明
- (void)beginTaskWithName:(NSString *)name completion:(void(^)(void))callback;

//调用
[self beginTaskWithName:@"MyTask" completion:^{
    NSLog(@"The task is complete");
}];

块也用于回调 — 定义了当一个任务结束时将被执行的代码

- (IBAction)fetchRemoteInformation:(id)sender {
[self showProgressIndicator];

XYZWebTask *task = ...

[task beginTaskWithCallbackBlock:^{
    [self hideProgressIndicator];
}];
}

定义块的数据类型

typedef void (^XYZSimpleBlock)(void);


XYZSimpleBlock anotherBlock = ^{
    ...
};


- (void)beginFetchWithCallbackBlock:(XYZSimpleBlock)callbackBlock {

...
callbackBlock();
}

该 complexBlock 变量是指一个块需要另一块作为一个参数(ABLOCK)并返回另一个块

void (^(^complexBlock)(void (^)(void)))(void) = ^ (void (^aBlock)(void)) {
...
return ^{
    ...
};
};

重写代码使用类型定义使其可读性更高,将块定义成数据类型

XYZSimpleBlock (^betterBlock)(XYZSimpleBlock) = ^ (XYZSimpleBlock aBlock) {
...
return ^{
    ...
};
};

定义块为属性

@interface XYZObject : NSObject
@property (copy) void (^blockProperty)(void);  //通常使用copy,why?
@end


self.blockProperty = ^{
    ...
};
self.blockProperty();


使用块属性声明的类型定义

typedef void (^XYZSimpleBlock)(void);

@interface XYZObject : NSObject
@property (copy) XYZSimpleBlock blockProperty;
@end

Avoid Strong Reference Cycles when Capturing self

Blocks maintain strong references to any captured objects, including self, which means that it’s easy to end up with a strong reference cycle。 block对任何捕获的对象是强引用。

@interface XYZBlockKeeper : NSObject
@property (copy) void (^block)(void);
@end

@implementation XYZBlockKeeper
- (void)configureBlock {
self.block = ^{
    [self doSomething];    // capturing a strong reference to self
                           // creates a strong reference cycle
};
}
...
@end

正确做法如下

- (void)configureBlock {
XYZBlockKeeper * __weak weakSelf = self;
self.block = ^{
    [weakSelf doSomething];   // capture the weak reference
                              // to avoid the reference cycle
}
}

By capturing the weak pointer to self, the block won’t maintain a strong relationship back to the XYZBlockKeeper object. If that object is deallocated before the block is called, the weakSelf pointer will simply be set to nil.

块可以简化枚举 (待阅)

使用块操作与运行队列 (待阅)

用GCD技术在调度队列调度块 (待阅)