Getting Started with Blocks
Declaring and Using a Block
使用^操作符来声明一个block变量并且指明了block的开始。body在{}中如下的例子:
int multiplier = 7; int (^myBlock)(int) = ^(int num) { return num * multiplier;
};
};
例子解释如下:
你可以看到block body中可以访问 {}和自己是同一个scope的变量。
如果你将block声明为一个变量,那么你可以像函数一样使用它,例如:
int multiplier = 7;
int (^myBlock)(int) = ^(int num) {
return num * multiplier;
};
printf("%d", myBlock(3)); //prints "21"
Using a Block Directly
许多情况下你不需要声明block变量,而是简单写block inline作为参数。如下的例子使用qsort_b函数。qsort_b和标准的qsort_r函数很类似,但是将block作为了参数。
char *myCharacters[3] = { "TomJohn", "George", "Charles Condomine" };
qsort_b(myCharacters, 3, sizeof(char *), ^(const void *l, const void *r) { char *left = *(char **)l; char *right = *(char **)r; return strncmp(left, right, 1);
});
// myCharacters is now { "Charles Condomine", "George", "TomJohn" }
Blocks with Cocoa
如下的例子展示的就是如何使用block和nsarray方法sortedArrayUsingComparator:这个方法有一个block的参数。为了说明,这里将block定义成了NSComparator local 变量。
NSArray *stringsArray = @[ @"string 1", @"String 21", @"string 12", @"String 11",
@"String 02" ];
static NSStringCompareOptions comparisonOptions = NSCaseInsensitiveSearch | NSNumericSearch |
NSWidthInsensitiveSearch | NSForcedOrderingSearch; NSLocale *currentLocale = [NSLocale currentLocale];
NSComparator finderSortBlock = ^(id string1, id string2) {
NSRange string1Range = NSMakeRange(0, [string1 length]);
return [string1 compare:string2 options:comparisonOptions range:string1Range locale:currentLocale];
};
NSArray *finderSortArray = [stringsArray sortedArrayUsingComparator:finderSortBlock]; NSLog(@"finderSortArray: %@", finderSortArray);
/* Output: finderSortArray: (
"string 1", "String 02", "String 11", "string 12", "String 21"
) */
__block Variables
__block类型就说明了这个变量在block body中可以被改变。
NSArray *stringsArray = @[ @"string 1",
@"String 21", // <- @"string 12", @"String 11", @"Str?ng 21", // <- @"Stri?g 21", // <- @"String 02" ];
NSLocale *currentLocale = [NSLocale currentLocale]; __block NSUInteger orderedSameCount = 0;
NSArray *diacriticInsensitiveSortArray = [stringsArray sortedArrayUsingComparator:^(id string1, id string2) {
NSRange string1Range = NSMakeRange(0, [string1 length]);
NSComparisonResult comparisonResult = [string1 compare:string2 options:NSDiacriticInsensitiveSearch range:string1Range locale:currentLocale];
if (comparisonResult == NSOrderedSame) { orderedSameCount++;
}
return comparisonResult; }];
NSLog(@"diacriticInsensitiveSortArray: %@", diacriticInsensitiveSortArray); NSLog(@"orderedSameCount: %d", orderedSameCount);
/* Output:
diacriticInsensitiveSortArray: ( "String 02",
"string 1", "String 11", "string 12", "String 21", "Str\U00eeng 21",
"Stri\U00f1g 21" )
orderedSameCount: 2 */
Conceptual Overview
Block Functionality
- block 是一个匿名的code的inline collection
- 有一个类似function的类型参数
- 有一个返回类型
- 可以捕获它定义范围内的状态
- 可以有选择的改变定义范围内的状态
- 可以在定义范围销毁后继续共享和改变定义状态
Usage
blocks代表了小规模的,自容的代码片段。它们在执行并发的任务时作为封装单元尤其重要。block有别于传统callback函数的优点是:
1,它们允许你在方法执行后的某一个调用的地方书写代码
2,它们允许访问本地变量
Declaring and Creating Blocks
Declaring a Block Reference
void (^blockReturningVoidWithVoidArgument)(void);
int (^blockReturningIntWithIntAndCharArguments)(int, char);
void (^arrayOfTenBlocksReturningVoidWithIntArgument[10])(int);
没有返回类型的block必须显示表明为void类型
你也可以创建block类型当你在多个地方使用特定的signature
typedef float (^MyBlockType)(float, float);
MyBlockType myFirstBlock = // ... ; MyBlockType mySecondBlock = // ... ;
Creating a Block
以下的例子定义了一个简单的block然后分配给了一个之前声明的变量oneFrom。
float (^oneFrom)(float);
oneFrom = ^(float aFloat) { float result = aFloat - 1.0; return result;
};
Global Blocks
#import <stdio.h>
int GlobalInt = 0; int (^getGlobalInt)(void) = ^{ return GlobalInt; };
Blocks and Variables
5中类型的变量
- global variables, including static locals
- global functions
- local variables and parameters form an enclosing scope
- __block varibales
- const improts
Object and Block Variables
Objective-C Objects
当copy一个block时,它会创建一个object变量的强引用。如果你在一个执行方法中说使用block:
如果你通过引用来访问一个实例变量,就会产生self的强引用
如果你通过值来访问一个实例变量,就会产生这个变量的强引用
dispatch_async(queue, ^{ // instanceVariable is used by reference, a strong reference is made to self doSomethingWithObject(instanceVariable);
});
id localVariable = instanceVariable; dispatch_async(queue, ^{
/* localVariable is used by value, a strong reference is made to localVariable (and not to self).
*/
doSomethingWithObject(localVariable); });
Using Blocks
Invoking a Block
如果你将block声明为变量,你可以在函数中使用它,例如:
int (^oneFrom)(int) = ^(int anInt) { return anInt - 1;
};
printf("1 from 10 is %d", oneFrom(10)); // Prints "1 from 10 is 9"
float (^distanceTraveled)(float, float, float) = ^(float startingSpeed, float acceleration, float time) {
float distance = (startingSpeed * time) + (0.5 * acceleration * time * time);
return distance; };
float howFar = distanceTraveled(0.0, 9.8, 1.0); // howFar = 4.9
Using a Block as a Function Argument
你可以