1.Block声明

编译器和运行时让block中引用的所有变量都被保存下来,以备在block的所有副本的生命周期中使用。

1
2
3
4
5
6
7
- (void)block1
{
int (^myTest)(int) = ^(int num){
return num * num;
};
NSLog(@"double: %d",myTest(9));
}

2.在block中改变的外部变量,需要用__block声明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
- (void)block2
{
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: %lu", (unsigned long)orderedSameCount);
}

3.block支持不定个数的参数(variadic arguments)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
- (void)block3
{
void (^variadicParams)(NSString*, ...) = ^(NSString *format, ...) {
id eachObject;
va_list argumentList; // va_list是指向变量列表的指针
if (format) { // 第一个参数并不是变量列表中的一个
NSMutableArray *tmpArray = [NSMutableArray arrayWithObject:format];
va_start(argumentList, format); // 初始化va_list,并让它指向传入的参数(format)后面紧跟的第一个参数
while ((eachObject = va_arg(argumentList, id)) != nil){ // va_arg,取出列表中的下一个参数。必须指明参数的类型(这样va_arg才能知道该给它分配多少空间)
[tmpArray addObject:eachObject]; // 不会把任何nil对象添加到tmpArray中
}
va_end(argumentList); // 释放va_list这个数据结构所持有的任何内存
NSLog(@"variadic params: %@",tmpArray);
}
};
variadicParams(@"11",@"22",@"333",@"666",nil); //  Calios:这里最后一个参数必须传nil,args必须有最后一个结尾,否则是无法判断的。But,why?
}

4.几种类型的变量与block的交互

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
NSInteger CounterGlobal; //  Calios:It throws out error for not finding CounterGlobal if extern is added. But, why?
static NSInteger CounterStatic;
- (void)block4
{
NSInteger localCounter = 42;
__block char localCharacter;
void (^aBlock)(void) = ^(void) {
++CounterGlobal;
++CounterStatic;
CounterGlobal = localCounter; // localCounter fixed at block creation
localCharacter = 'a'; // sets localCharacter in enclosing scope
};
++localCounter; // unseen by the block
localCharacter = 'b';
aBlock(); // execute the block
// localCharacter now 'a'
}

5.当block被复制的时候,它会对block中使用的对象变量产生强引用。

如果你在一个方法的实现中使用了block:

  • 如果你使用了实例变量的引用,那么就对 self 产生了强引用;
  • 如果你使用了实例变量的值,那么就对 该变量 产生了强引用。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    - (void)block5
    {
    void (^doSomethingWithObject)(id) = ^(id var){
    NSLog(@"do something: %@",var);
    };
    dispatch\_queue\_t queue = dispatch\_queue\_create("com.calios.BlockSample.someQueue", DISPATCH\_QUEUE\_SERIAL);
    dispatch\_async(queue, ^{ // dispatch\_async()是将block拷贝到指定的queue中,而复制操作(Block\_copy())会将block移动到堆上。
    // 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);
    });
    }

6.应该避免的做法

block字面量(即^{ … })是代表这个block的局部栈数据结构的地址。因此,局部栈数据结构的作用于就是仅限于大括号中的语句,所以你应 避免 向下面这样使用block。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
- (void)block6
{
dontDoThis();
dontDoThisEither();
}
void dontDoThis() {
void (^blockArray[3])(void); // an array of 3 block references
for (int i = 0; i < 3; ++i) {
blockArray[i] = ^{ printf("hello, %d\n", i); };
// WRONG: The block literal scope is the "for" loop.
}
}
void dontDoThisEither() {
void (^block)(void);
int i = arc4random() % 1024;
if (i > 1000) {
block = ^{ printf("got i at: %d\n", i); };
// WRONG: The block literal scope is the "then" clause.
}
// ...
}


Ref: