当我学习目标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;在内存中处理? 或者更快/更安全? 它们中的任何一个都可以用作类定义中的方法吗?
谢谢。
答案 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
那样,是不可能的。您需要创建一个结构来保存状态。
除了类型之外,没有从周围范围捕获局部变量的块(如示例所示)与普通函数没有太大区别。