1

在 Ruby 中,return在块甚至嵌套块内调用将转移控制并从最内层的包装方法返回,我说的是 proc。在 Ruby 中,lambdareturn从块本身返回,调用方法继续,这也是 Objective-C 块的工作方式。

有没有办法让 Ruby 的 proc 语义在 Objective-C 中返回?我想要一个块内的返回来返回外部方法。

4

2 回答 2

1

简短的回答是否定的,块内的 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
于 2013-05-03T07:13:58.317 回答
1

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

这可能很简单:

- (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
}
于 2013-05-03T07:16:27.973 回答