现在的位置: 首页 > 综合 > 正文

使用blocks

2019年09月30日 ⁄ 综合 ⁄ 共 3393字 ⁄ 字号 评论关闭

译自:Using Blocks

翻译不不到位之处,请指正,建议点击上面链接看苹果官网介绍。

1. 调用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

但是,通常情况下将block作为参数传递给函数或者方法。这种情况下通常创建一个内联的block。

2. 将block作为方法的参数

你可以将block像其他参数一样作为函数参数传递。但是在这种情况下,你没有必要声明blocks,只需要在它需要作为参数的地方内联实现它。下面的例子使用了 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);
});
// Block implementation ends at "}"
 
// myCharacters is now { "Charles Condomine", "George", "TomJohn" }

注意:该block包含在函数的参数列表中。

下面的这个例子展示了如何在 dispatch_apply 函数中使用block。dispatch_apply 的函数声明如下:

void dispatch_apply(size_t iterations, dispatch_queue_t queue, void (^block)(size_t));

The function submits a block to a dispatch queue for multiple invocations. 它有三个参数:第一个表示执行的迭代次数,第二个参数指定block将要提交的队列,第三个参数是block本身,它带有一个参数(当前迭代的索引)。

你可以使用 dispatch_apply 函数打印迭代的索引,如下所示:

#include <dispatch/dispatch.h>
size_t count = 10;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
 
dispatch_apply(count, queue, ^(size_t i) {
    printf("%u\n", i);
});

3. 将block作为函数的参数

cocoa 提供了使用blocks的许多函数。你可以像其他任何参数一样将block作为函数参数传递。下面的这个例子的作用是:数组中前5个元素中的任何一个元素,如果在给定过滤器中出现过,则返回该元素的index。

NSArray *array = [NSArray arrayWithObjects: @"A", @"B", @"C", @"A", @"B", @"Z",@"G", @"are", @"Q", nil];
NSSet *filterSet = [NSSet setWithObjects: @"A", @"Z", @"Q", nil];
 
BOOL (^test)(id obj, NSUInteger idx, BOOL *stop);
 
test = ^ (id obj, NSUInteger idx, BOOL *stop) {
 
    if (idx < 5) {
        if ([filterSet containsObject: obj]) {
            return YES;
        }
    }
    return NO;
};
 
NSIndexSet *indexes = [array indexesOfObjectsPassingTest:test];
 
NSLog(@"indexes: %@", indexes);
 
/*
Output:
indexes: <NSIndexSet: 0x10236f0>[number of indexes: 2 (in 2 ranges), indexes: (0 3)]
*/

下面的例子判定由局部变量指定的单词是否包含在 NSSet 对象中。如果该单词包含在NSSet对象中则停止搜索,并设定另一局部变量(found)为 YES;注意found是定义为__block类型的,并且block是内联的。

__block BOOL found = NO;
NSSet *aSet = [NSSet setWithObjects: @"Alpha", @"Beta", @"Gamma", @"X", nil];
NSString *string = @"gamma";
 
[aSet enumerateObjectsUsingBlock:^(id obj, BOOL *stop) {
    if ([obj localizedCaseInsensitiveCompare:string] == NSOrderedSame) {
        *stop = YES;
        found = YES;
    }
}];
 
// At this point, found == YES

4. 复制 blocks

通常情况你不必 copy 或者 retain 一个 block。只有当你需要在定义该 block 的作用域被销毁之后继续使用block时,对 block 进行copy。copy 操作会将block移动到堆上。你可以使用C函数进行拷贝和释放 blocks :

Block_copy();
Block_release();

如果你使用 Objective-C, 你可以向 block 发送 copy, retain, release,autorelease消息。

为了避免内存泄露,必须总是保持 Block_copy() 和 Block_release() 成对出现,或 保持 copy 或者 retain 和 release(autorelease)成对出现,除非使用了垃圾回收机制。

5. 应避免的形式

block literal(^{ . . . })是代表block的堆栈数据结构的地址。堆栈数据结构的作用域是闭合的复合语句(the enclosing compound statement),所以你应该避免下面例子中所显示的形式:

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 = random():
    if (i > 1000) {
        block = ^{ printf("got i at: %d\n", i); };
        // WRONG: The block literal scope is the "then" clause
    }
    // ...
}

6. 调试

可以设定断电并且单步调试跳进 block, 可以在gdb调试会话时使用 invoke-block 调用block,如下所示:

$ invoke-block myBlock 10 20

如果你想传递 C 字符串, 必须使用双引号括起来。例如,如果你想向 doSomethingWithString 传递 this string 参数时,可以像下面所示传递参数:

$ invoke-block doSomethingWithString "\"this string\""

最后,欢迎大家远离我的微博:http://weibo.com/caryaliu

抱歉!评论已关闭.