objective-c中block as function argument的执行顺序是什么?

What's the executive order of block as function argument in objective-c?

正如苹果文档所说,

"Blocks are also used for callbacks, defining the code to be executed when a task completes."

所以块应该在传递块的函数体执行后执行。但是我写了下面的测试代码:

void testBlock(void(^test)()){
    NSLog(@"1");
};

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        testBlock(^{
            NSLog(@"2");
        });
    }
}

输出只有“1”。 那么 NSLog(@"2") 在哪里?

@Julian Król 但是看看AFNetworking中的这个函数:

- (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
                          failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
{
// completionBlock is manually nilled out in AFURLConnectionOperation to break the retain cycle.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-retain-cycles"
#pragma clang diagnostic ignored "-Wgnu"
self.completionBlock = ^{
    if (self.completionGroup) {
        dispatch_group_enter(self.completionGroup);
    }

    dispatch_async(http_request_operation_processing_queue(), ^{
        if (self.error) {
            if (failure) {
                dispatch_group_async(self.completionGroup ?: http_request_operation_completion_group(), self.completionQueue ?: dispatch_get_main_queue(), ^{
                    failure(self, self.error);
                });
            }
        } else {
            id responseObject = self.responseObject;
            if (self.error) {
                if (failure) {
                    dispatch_group_async(self.completionGroup ?: http_request_operation_completion_group(), self.completionQueue ?: dispatch_get_main_queue(), ^{
                        failure(self, self.error);
                    });
                }
            } else {
                if (success) {
                    dispatch_group_async(self.completionGroup ?: http_request_operation_completion_group(), self.completionQueue ?: dispatch_get_main_queue(), ^{
                        success(self, responseObject);
                    });
                }
            }
        }

        if (self.completionGroup) {
            dispatch_group_leave(self.completionGroup);
        }
    });
};
#pragma clang diagnostic pop
}

这个函数没有显式调用块,而且块参数甚至没有名称,所以似乎不应该执行块。但是当我按如下方式使用此功能时:

AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = [AFXMLParserResponseSerializer serializer];
operation.responseSerializer.acceptableContentTypes = [NSSet setWithObject:@"application/rss+xml"];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {

    NSXMLParser *XMLParser = (NSXMLParser *)responseObject;
    [self.parserDictionary setObject:XMLParser forKey:urlString];
    [XMLParser setShouldProcessNamespaces:YES];
    XMLParser.delegate = self;
    [XMLParser parse];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    //When an error occurs while parsing.
    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error Loading Data"
                                                        message:[error localizedDescription]
                                                       delegate:nil
                                              cancelButtonTitle:@"Ok"
                                              otherButtonTitles:nil];
    [alertView show];
    [MBProgressHUD hideHUDForView:self.tableView animated:YES];

}];

并且块被真正执行。这是什么原因?

你没有在内部调用传递的块,这就是为什么输出只有 NSLog(@"2");

你应该有这样的东西:

void testBlock(void(^test)()){
    NSLog(@"1");
    test();
};

您还应该检查传递的块是否为 nil(因为如果是 nil 则调用它会崩溃)

您可以将块视为可以像变量一样传递的代码块。你像函数一样调用块,所以在你的情况下你会做类似 !test ?: test(); 这在语义上等同于:

if (test != nil) {
    test();
}

您可能会发现以下示例很有用:

// Define block that returns void and takes void arguments
typedef void (^MyBlock)(void);
// Define block that takes two ints and returns an int
typedef int (^AddBlock)(int a, int b);

@interface MyClass : NSObject

// NOTE: You have to COPY the block variables.
@property (copy) MyBlock blockOne;
@property (copy) AddBlock blockTwo;

@end

@implementation ...

- (void)runBlocks
{
    !self.blockOne ?: self.blockOne();
    if (self.blockTwo != nil) {
        int sum = self.blockTwo(1, 2);
    }
}

@end

function in AFNetworking:

几件事:

1) 你不应该有失败和成功块。而是像这样定义一个块:

typdef void (^CompletionHandler)(AFHTTPRequestOperation *op, id responseObj, NSError *error);

然后当您实现该块时,您可以像这样检查错误:

...^(AFHTTPRequestOperation *op, id responseObj, NSError *error) {
    if (error != nil) {
        // Handle the error
    } else {
        // YAY everything went well
    }
}];

2) 你在这里忽略了循环保留,这不是一件好事。相反,您应该定义一个 self 的弱版本,您可以像这样在块中引用它:

__weak __block MyClass *welf = self;
myBlock = ^{
   welf.coolProperty = coolValue;
};

查看 this SO question 了解有关 __weak__block

的信息