1

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

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

 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. 一个块可以在其所有参数存在的情况下传递,但没有实际执行
4

2 回答 2

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!

        }

    }];

}
于 2013-02-21T15:31:12.500 回答
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) ]];
于 2013-02-21T15:47:30.940 回答