Objective-C传递块作为参数

时间:2011-10-29 02:17:12

标签: objective-c objective-c-blocks

如何将Block传递给Function / Method

我试了- (void)someFunc:(__Block)someBlock但没有用。

即。 Block类型是什么?

11 个答案:

答案 0 :(得分:246)

块的类型因其参数及其返回类型而异。在一般情况下,块类型的声明方式与函数指针类型相同,但用*替换^。将块传递给方法的一种方法如下:

- (void)iterateWidgets:(void (^)(id, int))iteratorBlock;

但正如你所看到的那样,这很麻烦。您可以使用typedef来使块类型更清晰:

typedef void (^ IteratorBlock)(id, int);

然后将该块传递给类似的方法:

- (void)iterateWidgets:(IteratorBlock)iteratorBlock;

答案 1 :(得分:51)

这可能会有所帮助:

- (void)someFunc:(void(^)(void))someBlock;

答案 2 :(得分:48)

这个问题最简单的解释是遵循以下模板:

<强> 1。阻止作为方法参数

<强> 模板

- (void)aMethodWithBlock:(returnType (^)(parameters))blockName {
        // your code
}

<强> 实施例

-(void) saveWithCompletionBlock: (void (^)(NSArray *elements, NSError *error))completionBlock{
        // your code
}

案件的其他用途:

<强> 2。阻止作为财产

<强> 模板

@property (nonatomic, copy) returnType (^blockName)(parameters);

<强> 实施例

@property (nonatomic,copy)void (^completionBlock)(NSArray *array, NSError *error);

第3。阻止作为方法参数

<强> 模板

[anObject aMethodWithBlock: ^returnType (parameters) {
    // your code
}];

<强> 实施例

[self saveWithCompletionBlock:^(NSArray *array, NSError *error) {
    // your code
}];

<强> 4。阻止作为局部变量

<强> 模板

returnType (^blockName)(parameters) = ^returnType(parameters) {
    // your code
};

<强> 实施例

void (^completionBlock) (NSArray *array, NSError *error) = ^void(NSArray *array, NSError *error){
    // your code
};

<强> 5。阻止作为typedef

<强> 模板

typedef returnType (^typeName)(parameters);

typeName blockName = ^(parameters) {
    // your code
}

<强> 实施例

typedef void(^completionBlock)(NSArray *array, NSError *error);

completionBlock didComplete = ^(NSArray *array, NSError *error){
    // your code
};

答案 3 :(得分:23)

您可以这样做,将块作为块参数传递:

//creating a block named "completion" that will take no arguments and will return void
void(^completion)() = ^() {
    NSLog(@"bbb");
};

//creating a block namd "block" that will take a block as argument and will return void
void(^block)(void(^completion)()) = ^(void(^completion)()) {
    NSLog(@"aaa");
    completion();
};

//invoking block "block" with block "completion" as argument
block(completion);

答案 4 :(得分:8)

在下面的示例中使用с函数传递块的另一种方法。 我已经创建了在后台和主队列中执行任何操作的函数。

blocks.h文件

void performInBackground(void(^block)(void));
void performOnMainQueue(void(^block)(void));

blocks.m文件

#import "blocks.h"

void performInBackground(void(^block)(void)) {
    if (nil == block) {
        return;
    }

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), block);
}

void performOnMainQueue(void(^block)(void)) {
    if (nil == block) {
        return;
    }

    dispatch_async(dispatch_get_main_queue(), block);
}

在必要时导入blocks.h并调用它:

- (void)loadInBackground {

    performInBackground(^{

        NSLog(@"Loading something in background");
        //loading code

        performOnMainQueue(^{
            //completion hadler code on main queue
        });
    });
}

答案 5 :(得分:6)

如果适用于您,您还可以将块设置为简单属性:

@property (nonatomic, copy) void (^didFinishEditingHandler)(float rating, NSString *reviewString);

确保block属性为“copy”!

当然你也可以使用typedef:

typedef void (^SimpleBlock)(id);

@property (nonatomic, copy) SimpleBlock someActionHandler;

答案 6 :(得分:5)

您也可以使用常用的c函数语法

调用或调用块
-(void)iterateWidgets:(IteratorBlock)iteratorBlock{

    iteratorBlock(someId, someInt);
}

有关块的更多信息

http://developer.apple.com/library/ios/#documentation/cocoa/Conceptual/Blocks/Articles/bxGettingStarted.html#//apple_ref/doc/uid/TP40007502-CH7-SW1

答案 7 :(得分:3)

我总是倾向于忘记块语法。当我需要声明一个块时,我总会想到这一点。我希望它可以帮助某人:)

http://fuckingblocksyntax.com

答案 8 :(得分:2)

尽管在这个帖子上给出了答案,但我真的很难写出一个函数,它将Block作为一个函数 - 并带有一个参数。最终,这是我提出的解决方案。

我想编写一个通用函数loadJSONthread,它将获取JSON Web服务的URL,在后台线程上从此URL加载一些JSON数据,然后将NSArray *的结果返回给调用函数。

基本上,我希望将所有后台线程复杂性隐藏在通用的可重用函数中。

以下是我将如何调用此函数:

NSString* WebServiceURL = @"http://www.inorthwind.com/Service1.svc/getAllCustomers";

[JSONHelper loadJSONthread:WebServiceURL onLoadedData:^(NSArray *results) {

    //  Finished loading the JSON data
    NSLog(@"Loaded %lu rows.", (unsigned long)results.count);

    //  Iterate through our array of Company records, and create/update the records in our SQLite database
    for (NSDictionary *oneCompany in results)
    {
        //  Do something with this Company record (eg store it in our SQLite database)
    }

} ];

...这就是我所挣扎的:如何声明它,以及如何在加载数据后调用Block函数,并传递Block NSArray *加载的记录:

+(void)loadJSONthread:(NSString*)urlString onLoadedData:(void (^)(NSArray*))onLoadedData
{
    __block NSArray* results = nil;

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{

        // Call an external function to load the JSON data 
        NSDictionary * dictionary = [JSONHelper loadJSONDataFromURL:urlString];
        results = [dictionary objectForKey:@"Results"];

        dispatch_async(dispatch_get_main_queue(), ^{

            // This code gets run on the main thread when the JSON has loaded
            onLoadedData(results);

        });
    });
}

这个StackOverflow问题涉及如何调用函数,将块作为参数传递,因此我简化了上面的代码,而不包括loadJSONDataFromURL函数。

但是,如果您有兴趣,可以在此博客上找到此JSON加载函数的副本: http://mikesknowledgebase.azurewebsites.net/pages/Services/WebServices-Page6.htm

希望这有助于其他一些XCode开发人员! (不要忘记将这个问题和我的答案投票,如果有的话!)

答案 9 :(得分:2)

我为一个类写了一个completionBlock,它会在它们被动摇之后返回骰子的值:

  1. 使用returnType(.h声明上方@interface)定义typedef

    typedef void (^CompleteDiceRolling)(NSInteger diceValue);
    
  2. 为块(@property

    定义.h
    @property (copy, nonatomic) CompleteDiceRolling completeDiceRolling;
    
  3. 使用finishBlock.h

    定义方法
    - (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock;
    
  4. .m文件中插入以前定义的方法,然后将finishBlock提交到

    之前定义的@property
    - (void)getDiceValueAfterSpin:(void (^)(NSInteger diceValue))finishBlock{
        self.completeDiceRolling = finishBlock;
    }
    
  5. 触发completionBlock将预定义的variableType传递给它 (别忘了检查completionBlock是否存在)

    if( self.completeDiceRolling ){
        self.completeDiceRolling(self.dieValue);
    }
    

答案 10 :(得分:0)

完整的模板看起来像

- (void) main {
    [self someMethodWithSuccessBlock:^{[self successMethod];}
                    withFailureBlock:^(NSError * error) {[self failureMethod:error];}];
}

- (void) someMethodWithSuccessBlock:(void (^) (void))successBlock
                   withFailureBlock:(void (^) (NSError*))failureBlock {

    //Execute a block
    successBlock();
//    failureBlock([[NSError alloc]init]);

}

- (void) successMethod {

}

- (void) failureMethod:(NSError*) error {

}