比较目标C中的块和函数

时间:2014-09-08 01:14:57

标签: objective-c function block

当我学习目标C时,我的理解是新的和不完整的。块的概念与函数非常相似。他们甚至看起来几乎相同:

FUNCTION命名'乘以'

#import <Foundation/Foundation.h>

int multiply (int x, int y)
{

    return x * y;

}

int main(int argc, char *argv[]) {
    @autoreleasepool {

        int result = multiply(7, 4); // Result is 28.
        NSLog(@"this is the result %u",result);

        }
}

BLOCK命名为&#39; Multiply&#39;

#import <Foundation/Foundation.h>

int (^Multiply)(int, int) = ^(int num1, int num2) {

    return num1 * num2;
};

int main(int argc, char *argv[]) {

    @autoreleasepool {

        int result = Multiply(7, 4); // Result is 28.
        NSLog(@"this is the result %u",result);
    }
}

我在网上发现了各种各样的声明: &#34;块被实现为Objective-C对象,除了它们可以放在堆栈上,因此它们不一定必须是malloc&#d ;;如果你保留对块的引用,它将虽然)被复制到堆上。 &#34;

Ray Wenderlich说: &#34;块是一流的功能&#34;

我不知道这一切意味着什么。我的例子表明,同样的事情是作为一个块或一个函数完成的。有人可以展示一个例子,哪些块可以做某些功能不能?或相反亦然? 或者它是更微妙的东西,就像变量&#39;结果&#39;在内存中处理? 或者更快/更安全? 它们中的任何一个都可以用作类定义中的方法吗?

谢谢。

2 个答案:

答案 0 :(得分:9)

块是Objective-C对象,功能不是。实际上,这意味着您可以将一个代码块传递给另一个代码块,如下所示:

NSArray *names = @[@"Bob", @"Alice"];
[names enumerateObjectsUsingBlock:^(id name, NSUInteger idx, BOOL *stop) {
    NSLog(@"Hello, %@", name);
}];

在C中,您可以通过传递指向函数的指针来实现类似的效果。但是,执行此操作和使用块之间的主要区别在于块可以捕获值。例如,在上面的示例中,如果我们想要使用变量问候语:

NSString *greeting = @"Hello";
NSArray *names = @[@"Bob", @"Alice"];
[names enumerateObjectsUsingBlock:^(id name, NSUInteger idx, BOOL *stop) {
    NSLog(@"%@, %@", greeting, name);
}];

在这个例子中,编译器可以看到该块依赖于局部变量greeting并且将&#34;捕获&#34; greeting的值并将其与块一起存储(在这种情况下,这意味着保留并存储指向NSString的指针)。无论块最终被使用(在这种情况下,在[NSArray -enumerateObjectsUsingBlock:]的实现中),它都可以访问greetings变量,就像声明块一样。 这使您可以在块的范围内使用任何局部变量,而不必担心将它们传递到块中。

要使用C中的函数指针执行相同的操作,greeting必须作为变量传入。但是,这不可能发生,因为调用者(在这种情况下,NSArray)无法知道(特别是在编译时)它必须传递给您的函数的确切参数。即使它确实如此,你也需要以某种方式将greeting的值传递给NSArray,以及你想要使用的所有其他局部变量,这会很快变得毛茸茸:

void greet(NSString *greeting, NSString *name) {
    NSLog(@"%@, %@", greeting, name);
}

// NSArray couldn't actually implement this
NSString *greeting = @"Hello";
NSArray *names = @[@"Bob", @"Alice"];
[names enumerateObjectsUsingFunction:greet withGreeting:greeting];

答案 1 :(得分:4)

块是闭包 - 它们可以从周围的范围捕获局部变量。这是块(和其他现代语言中的匿名函数)和C中的函数之间的巨大差异。

这是一个高阶函数makeAdder的示例,它创建并返回一个&#34;加法器&#34;,这是一个向其参数添加特定基数的函数。此基数由makeAdder的参数设置。因此makeAdder可以返回不同的&#34;加法器&#34;有不同的行为:

typedef int (^IntFunc)(int);

IntFunc makeAdder(int x) {
    return ^(int y) { return x + y; }
}

IntFunc adder3 = makeAdder(3);
IntFund adder5 = makeAdder(5);

adder3(4); // returns 7
adder5(4); // returns 9
adder3(2); // returns 5

这对C中的函数指针是不可能的,因为每个函数指针必须指向代码中的实际函数,其中有一个在编译时固定的有限数,以及每个函数的行为在编译时固定。因此,能够创建几乎无限数量的潜在&#34;加法器&#34;取决于运行时的值,如makeAdder那样,是不可能的。您需要创建一个结构来保存状态。

除了类型之外,没有从周围范围捕获局部变量的块(如示例所示)与普通函数没有太大区别。