PDF版 ePub版

# 使用块 - Working with Blocks

## 块语法

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

    void (^simpleBlock)(void);

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

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

simpleBlock();

### 有参数和返回值的块

double (^multiplyTwoValues)(double, double);

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

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

 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

### 你可以把块作为方法或函数的参数

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

[self hideProgressIndicator];
}];
}

- (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:^{
}];

### 使用类型定义简化块语法

typedef void (^XYZSimpleBlock)(void);

XYZSimpleBlock anotherBlock = ^{
...
};
- (void)beginFetchWithCallbackBlock:(XYZSimpleBlock)callbackBlock {

...
callbackBlock();
}

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

complexBlock 变量是指一个块需要另一块作为一个参数（ABLOCK）并返回另一个块。

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

### 对象用属性来跟踪块

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

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

typedef void (^XYZSimpleBlock)(void);

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

### 在捕捉自时避免强引用循环

@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
}
}

## 块可以简化枚举

- (void)enumerateObjectsUsingBlock:(void (^)(id obj, NSUInteger idx, BOOL *stop))block;

NSArray *array = ...
[array enumerateObjectsUsingBlock:^ (id obj, NSUInteger idx, BOOL *stop) {
NSLog(@"Object at index %lu is %@", idx, obj);
}];

[array enumerateObjectsUsingBlock:^ (id obj, NSUInteger idx, BOOL *stop) {
if (...) {
*stop = YES;
}
}];

    [array enumerateObjectsWithOptions:NSEnumerationConcurrent
usingBlock:^ (id obj, NSUInteger idx, BOOL *stop) {
...
}];

 NSDictionary 类同样提供基于块的方法，包括：
NSDictionary *dictionary = ...
[dictionary enumerateKeysAndObjectsUsingBlock:^ (id key, id obj, BOOL *stop) {
NSLog(@"key: %@, value: %@", key, obj);
}];

## 模块可以简化并发任务

OS X和ios提供了多种并发技术，其中包括两个任务调度机制：操作队列和中央调度。这些机制是围绕着等待被调用的任务队列的一个想法。你按照调用顺序将你的块加入队列，然后在处理器资源可用时，你的系统将从队列中取出调用。

### 使用块操作与运行队列

NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
...
}];

// schedule task on main queue:
NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];

// schedule task on background queue:
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:operation];

### 用GCD技术在调度队列调度块

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_async(queue, ^{
NSLog(@"Block for asynchronous execution");
});

dispatch_sync() 方法不会返回指导块完成执行；比如，在一个需要等待其他工作完成才能继续的并发块中你可以运用该方法。