在Objective-C块中,你可以让外部方法返回吗?一个Ruby的过程?

时间:2013-05-03 05:45:31

标签: objective-c ruby closures

在Ruby中,在块内部调用return甚至嵌套块将从最里面的包装方法转移控制和返回,我正在谈论proc。在一个Ruby lambda return从块本身返回并且调用方法继续,这也是Objective-C阻塞工作的方式。

有没有办法在Objective-C中返回Ruby的proc语义w.r.t?我希望在块内返回以返回外部方法。

2 个答案:

答案 0 :(得分:1)

简答为NO,块内的return语句只会从块中返回。如下所示,你可以使用异常,@try语句和宏的组合来构建一些不优雅的东西,但最后我认为这会比其他任何东西更容易混淆。

@interface MPReturnFromNestedBlockException : NSException
+ (void) returnExceptionWithResult:(id)result;
@end;

@implementation MPReturnFromNestedBlockException
+ (void) returnExceptionWithResult:(id)result
{
    MPReturnFromNestedBlockException *exception = (id)
        [self exceptionWithName:@"MPReturnFromMethodException"
                         reason:nil
                       userInfo:@{@"result":result}];
    [exception raise];
}
@end

#define abruptReturn(value)\
    ({ [MPReturnFromNestedBlockException returnExceptionWithResult:value]; })

#define blockMayReturnAbruptly(block)\
({\
    id result = nil;\
    @try { block(); }\
    @catch(MPReturnFromNestedBlockException *exception) {\
        result = exception.userInfo[@"result"];\
    }\
    result;\
})


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

        NSArray *numbers = @[@1, @2, @3];

        id value = blockMayReturnAbruptly(^{
            [numbers enumerateObjectsUsingBlock:^(id numA, NSUInteger index, BOOL *stop) {
                double a = [numA doubleValue];
                [numbers enumerateObjectsUsingBlock:^(id numB, NSUInteger index, BOOL *stop) {
                    double b = [numB doubleValue];
                    NSLog(@"%f x %f = %f", a, b, a*b);
                    if (a * b > 3)
                        abruptReturn(@(a*b));
                }];
            }];
        });

        NSLog(@"Result = %@", value);
    }
    return 0;
}

输出如下:

1.000000 x 1.000000 = 1.000000
1.000000 x 2.000000 = 2.000000
1.000000 x 3.000000 = 3.000000
2.000000 x 1.000000 = 2.000000
2.000000 x 2.000000 = 4.000000
Result = 4

答案 1 :(得分:1)

我不熟悉Ruby,但是ObjC Block对其封闭方法施加控制的唯一方法是使该方法测试其返回值。

这可以很简单:

- (id)bloviate:(id (^)(void))bombast 
{
    // The method returns the results of the Block call;
    // thus, strictly speaking, the method returns when
    // the Block does.
    return bombast();
}

或者您可以检查返回值并从方法中有条件地返回:

- (id)elucidate:(BOOL (^)(id))explanation
{
    id obj = /* Get some object */;
    if( explanation(obj) ) {
        return obj;
    }
    // Else continue
}