当您感兴趣的任务完成时,是什么使完成处理程序执行该块? [英] What makes a completion handler execute the block when your task of interest is complete?

查看:67
本文介绍了当您感兴趣的任务完成时,是什么使完成处理程序执行该块?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在询问并试图了解完成处理程序的工作方式.香港专业教育学院使用了很多,我已经阅读了许多教程.我将在这里发布我使用的代码,但是我希望能够创建自己的代码而无需使用其他人的代码作为参考.

I have been asking and trying to understand how completion handlers work. Ive used quite a few and I've read many tutorials. i will post the one I use here, but I want to be able to create my own without using someone else's code as a reference.

我了解此调用程序方法的完成处理程序:

I understand this completion handler where this caller method:

-(void)viewDidLoad{
[newSimpleCounter countToTenThousandAndReturnCompletionBLock:^(BOOL completed){
        if(completed){ 
            NSLog(@"Ten Thousands Counts Finished");
        }
    }];
}

,然后在被调用的方法中:

and then in the called method:

-(void)countToTenThousandAndReturnCompletionBLock:(void (^)(BOOL))completed{
    int x = 1;
    while (x < 10001) {
        NSLog(@"%i", x);
        x++;
    }
    completed(YES);
}

然后我根据许多SO帖子提出了这一点:

Then I sorta came up with this one based on many SO posts:

- (void)viewDidLoad{
    [self.spinner startAnimating];
    [SantiappsHelper fetchUsersWithCompletionHandler:^(NSArray *users) {
        self.usersArray = users;
        [self.tableView reloadData];
    }];
}

在调用此方法后,它将使用接收到的数据用户重新加载表视图:

which will reload the tableview with the received data users after calling this method:

typedef void (^Handler)(NSArray *users);

+(void)fetchUsersWithCompletionHandler:(Handler)handler {
    NSURL *url = [NSURL URLWithString:@"http://www.somewebservice.com"];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:10];
    [request setHTTPMethod: @"GET"];
    **// We dispatch a queue to the background to execute the synchronous NSURLRequest**
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
        // Perform the request
        NSURLResponse *response;
        NSError *error = nil;
        NSData *receivedData = [NSURLConnection sendSynchronousRequest:request
                                                     returningResponse:&response
                                                                 error:&error];
        if (error) { **// If an error returns, log it, otherwise log the response**
            // Deal with your error
            if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
                NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
                NSLog(@"HTTP Error: %d %@", httpResponse.statusCode, error);
                return;
            }
            NSLog(@"Error %@", error);
            return;
        }
        **// So this line won't get processed until the response from the server is returned?**
        NSString *responseString = [[NSString alloc] initWithData:receivedData encoding:NSUTF8StringEncoding];

        NSArray *usersArray = [[NSArray alloc] init];
        usersArray = [NSJSONSerialization JSONObjectWithData:[responseString dataUsingEncoding:NSASCIIStringEncoding] options:0 error:nil];
        // Finally when a response is received and this line is reached, handler refers to the block passed into this called method...so it dispatches back to the main queue and returns the usersArray
        if (handler){
            dispatch_sync(dispatch_get_main_queue(), ^{
            handler(usersArray);
            });
        }
    });
}

在反例中可以看到它,被调用的方法(带有传递的块)在完成之前永远不会退出循环.因此,完成"部分实际上取决于所调用方法中的代码,而不取决于传递给它的代码块?

I can see it in the counter example, that the called method (with the passed block) will never exit the loop until it is done. Thus the 'completion' part actually depends on the code inside the called method, not the block passed into it?

在这种情况下,完成"部分取决于对NSURLRequest的调用是同步的事实.如果它是异步的怎么办?在我的数据被NSURLResponse填充之前,我将如何能够阻止调用该块?

In this case the 'completion' part depends on the fact that the call to NSURLRequest is synchronous. What if it was asynchronous? How would I be able to hold off calling the block until my data was populated by the NSURLResponse?

推荐答案

您的第一个示例是正确而完整的,也是理解完成模块的最佳方法.他们没有进一步的魔力.它们永远不会自动执行.当一些代码调用它们时,它们就会执行.

Your first example is correct and complete and the best way to understand completion blocks. There is no further magic to them. They do not automatically get executed ever. They are executed when some piece of code calls them.

您注意到,在后一个示例中,很容易在正确的时间调用完成块,因为所有内容都是同步的.如果是异步的,则需要将块存储在实例变量中,并在异步操作完成后调用它.您可以安排在操作完成时(可能使用 its 完成处理程序)获得通知.

As you note, in the latter example, it is easy to call the completion block at the right time because everything is synchronous. If it were asynchronous, then you need to store the block in an instance variable, and call it when the asynchronous operation completed. It is up to you to arrange to be informed when the operation completes (possibly using its completion handler).

在ivar中存储块时要小心.您的示例之一包括:

Do be careful when you store a block in an ivar. One of your examples includes:

   self.usersArray = users;

self的调用将导致该块保留self(调用对象).这可以轻松地创建一个保留循环.通常,您需要像这样弱引用self:

The call to self will cause the block to retain self (the calling object). This can easily create a retain loop. Typically, you need to take a weak reference to self like this:

- (void)viewDidLoad{
  [self.spinner startAnimating];
  __weak typeof(self) weakSelf = self;
  [SantiappsHelper fetchUsersWithCompletionHandler:^(NSArray *users) {
    typeof(self) strongSelf = weakSelf;
    if (strongSelf) {
      [strongSelf setUsersArray:users];
      [[strongSelf tableView] reloadData];
    }
  }];
}

这是weakSelf/strongSelf模式的一个相当古板的版本,在这种情况下可以简化一些,但是它演示了您可能需要的所有组件.您对self进行了弱引用,以免创建保留循环.然后,在完全块中,请采用强引用,以使self不会在块中间消失在您身上.然后,确保self实际上仍然存在,然后再继续. (由于消息nil是合法的,因此在这种特殊情况下,您可以跳过strongSelf步骤,并且将是相同的.)

This is a fairly pedantic version of the weakSelf/strongSelf pattern, and it could be done a little simpler in this case, but it demonstrates all the pieces you might need. You take a weak reference to self so that you don't create a retain loop. Then, in the completely block, you take a strong reference so that self so that it can't vanish on you in the middle of your block. Then you make sure that self actually still exists, and only then proceed. (Since messaging nil is legal, you could have skipped the strongSelf step in this particular case, and it would be the same.)

这篇关于当您感兴趣的任务完成时,是什么使完成处理程序执行该块?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆