传递块作为参数

时间:2013-02-21 14:49:28

标签: ios parameters block grand-central-dispatch nsoperation

是否可以将完全形成的块(包含其所有参数的块)传递给方法,然后在该方法中执行该块?

目前我在项目中重复了这个结构:

 if (//block exists)
        {
            if (self.returnOnMainThread)
            {
                dispatch_async(dispatch_get_main_queue(), ^
                               {
                                   //call block here
                               });
            }
            else
            {
                //call block here
            }
        }

但理想情况下,我想将上面的代码抽象出来,形成类似于以下的方法:

- (void) reportSuccessWithBlock:(GenericBlockType)block{
        if (block)
        {
            if (self.returnOnMainThread)
            {
                dispatch_async(dispatch_get_main_queue(), ^
                               {
                                   block;
                               });
            }
            else
            {
                block;
            }
        }

}

编辑:

预先不知道该块的类型。

所以调用路径看起来像这样

- (void) someMethod:(void (^)(NSArray *array))success
{
//Some code here setting up the array to be passed back

   [self reportSuccessWithBlock:success(array)];

}

上面的代码中有一些假设(我不知道是可能的):

  1. 方法可以接受通用块类型
  2. 可以传递一个块,其所有参数都存在但不实际执行

2 个答案:

答案 0 :(得分:2)

如果您在评论中有两个不同的块,则可以按如下方式合并两个块。但是,这非常hacky,你需要在调用块时检查object的类。

- (void) reportSuccessWithBlock:(void (^) (id object, NSUInteger value)) block {

    if (!block)
        return;

    if (self.returnOnMainThread) {
        dispatch_async(dispatch_get_main_queue(), block((id)someObject, value)); // return 0 instead if there is no value
    }

    else {
        block((id) someObject, value)); // return 0 instead if there is no value
    }
}

因此,当调用块时,您需要做的就是检查类并对返回的对象执行任何操作:

- (void) someMethod {

    [self reportSuccessWithBlock:^(id object, NSUInteger value) {

        if ([object isKindOfClass:[NSArray class]]) {

            // returned an NSArray and `value` is 0 (unset)

        }

        else if ([object isKindOfClass:[NSDictionary class]]) {

            // returned an NSDictionary and the `value` is not 0 (unset)

        }

        else {

            // something has gone wrong somewhere!

        }

    }];

}

答案 1 :(得分:1)

好的,我认为使用NSArray参数的想法是可行的,因此您可以为您的块提供相同的签名:

typedef void ^(MYBLOCK)(NSArray *args);

将您的方法实施为:

- (void)reportSuccessWithBlock:(GenericBlockType)block
                  andArguments:(NSArray *)args
{
    if (block != nil)
    {
       if (self.returnOnMainThread)
       {
            dispatch_async(dispatch_get_main_queue(), ^{
                block(args);
            });
       }
       else
       {
           block(args);
       }
    }
}

然后这只是一个确保正确类型的参数以正确的顺序给予块的情况(听起来微不足道,但如果你弄错了会导致各种各样的仇恨)。

MYBLOCK block1 = ^(NSArray *args) {
    // I accept NSNumber, NSString, NSValue
    NSAssert(args.count == 3, @"Invalid argument count");
    NSNumber *arg1 = args[0];
    NSString *arg2 = args[1];
    NSValue *arg3 = args[2];

    // Do my thing
};

并将其称为:

[someClass reportSuccessWithBlock:block1
                     andArguments:@[ @(1), @"Hello", @(cgpoint) ]];