如何在Objective-C中编写lambda方法?

71

如何在Objective-C中编写lambda方法?


虽然有点晚了,但如果还有人在寻找关于这个的官方文档,可以在这里找到:https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/WorkingwithBlocks/WorkingwithBlocks.html - rsp1984
5个回答

95

在Objective-C中,lambda的概念现在用Blocks来封装,它们是按引用传递函数的等效形式。当然,在C语言中,使用函数指针的想法已经具有了这个功能;Blocks只是一种也可以捕获本地状态(即可成为闭包)的方式。事实上,Blocks也可以在其他C语言中使用(在Mac上)- 提议使其成为标准C语法的一部分。

以下是定义一个lambda将两个数字相乘的示例:

int (^mult)(int, int) = ^(int a, int b) { return a*b; };

首先声明了一个变量,类型为^int(int,int),然后将其赋值给lambda表达式(也称为块),该表达式返回它的两个参数的乘积。然后可以传递此函数,定义它在其他地方等等;甚至可以在其他函数中使用它。

下面是一个定义函数的示例,当调用时,它返回另一个函数:

multiplyBy = ^(int a) { return ^(int b) { return b*a; }; };
triple = multiplyBy(3);

请注意,您可以将块与对象类型混合使用(通常使用id作为对象类型),许多新的Objective-C对象数据结构也具有某种块级操作。 GCD还使用块来传递任意事件;但是,请注意,GCD也可以与函数指针一起使用。


请注意,块支持已经通过Plausible Blocks项目移植到10.5和iPhone OS。http://code.google.com/p/plblocks/ - Chuck
1
请注意,块可以在iOS 4中使用,无需Plausible Blocks项目。 - Tim Swast
+1优秀的例子,AIBlue,感谢您如此简洁地展示了块的灵活性。 - KomodoDave
2
ObjC的blocks与Smalltalk的blocks类似,但在Objective C中尚不清楚如何或是否可能定义、实现、传递、接受和调用任意类型的blocks。 - mcandre
你在哪里声明了 multiplyBy 的类型? - Anonymous White
+1,但请不要使用“等效”的词语,因为您提到可以在环境中关闭。可以使用类似的词语。引用函数之间存在巨大的差距。运行时必须进行处理才能实现闭包,而仅使用引用函数无法使闭包正常工作。 - mathk

29

OS X 10.6引入了blocks。请参见AlBlue的答案以获取示例。

如果您没有使用Snow Leopard,则可以使用其他各种功能来获得接近函数组合的内容。

使用C函数指针的示例:

void sayHello() {
    NSLog(@"Hello!");
}

void doSomethingTwice(void (*something)(void)) {
    something();
    something();
}

int main(void) {
    doSomethingTwice(sayHello);
    return 0;
}

使用命令模式的示例:

@protocol Command <NSObject>
- (void) doSomething;
@end

@interface SayHello : NSObject <Command> {
}
@end

@implementation SayHello
- (void) doSomething {
    NSLog(@"Hello!");    
}
@end

void doSomethingTwice(id<Command> command) {
    [command doSomething];
    [command doSomething];
}

int main(void) {
    SayHello* sayHello = [[SayHello alloc] init];
    doSomethingTwice(sayHello);
    [sayHello release];
    return 0;
}

使用选择器的例子:

@interface SaySomething : NSObject {
}
- (void) sayHello;
@end

@implementation SaySomething
- (void) sayHello {
    NSLog(@"Hello!");    
}
@end

void doSomethingTwice(id<NSObject> obj, SEL selector) {
    [obj performSelector:selector];
    [obj performSelector:selector];
}

int main(void) {
    SaySomething* saySomething = [[SaySomething alloc] init];
    doSomethingTwice(saySomething, @selector(sayHello));
    [saySomething release];
    return 0;
}

1
这可能在早期是正确的,但现在该语言确实具有Blocks,允许您定义真正的lambda表达式。话虽如此,像上面描述的能够传递@selector()非常有用,是Objective-C工具包中的一个重要机制。 - AlBlue
1
-1 表示缺少关于块的信息,块是一项中心新功能,可在使用苹果的 GCC 的新版 OS X 10.6 中的 C、ObjC 和 C++ 中使用。 - harms
在某些情况下,提供比块更可取的设计模式可以得到+1分。 - user2398029

3
我听说过安德烈·庞在NSConference上谈论下一个Objective-C版本将引入block。
这将允许函数式编程。
编辑:自从Snow Leopard发布以来,情况确实如此。Objective-C现在有了Blocks


-1
嗯,我认为你可以这样写你的匿名函数:
myBlock = ^( int number )
{
    return [ NSString stringWithFormat: @"Passed number: %i", number ];
};

为此,您需要添加以下语法:
NSString * ( ^ myBlock )( int );

总的来说,这个链接写了一些关于obj-c和obj-c++的内容,希望能对你有所帮助。

https://xs-labs.com/en/archives/articles/objc-blocks/


请不要发布重复的答案。这并没有增加其他答案所没有涵盖的内容。 - HangarRash
请阅读网站。 - cunknown

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接