【问题标题】:dispatch_sync return before queue is emptydispatch_sync 在队列为空之前返回
【发布时间】:2013-06-16 01:32:24
【问题描述】:

我有两个类,一个视图控制器和另一个 (TwitterCrawler) 向 Twitter API 执行网络请求。我在视图控制器加载时发出第一个网络请求,在用户按下按钮时发出第二个网络请求。

我希望在第一个请求完成时执行第二个请求,这意味着如果用户在第一个请求完成之前按下按钮,它会等待它结束然后执行第二个。

即使我将第一个请求放在我创建的队列中,我在用户按下按钮时调用的命令dispatch_sync 也会在队列清空之前调用。

这是我的代码:

//TwitterCrawler.m

-(void) getTwitterUsersInPosition: (Position*) position
{
dispatch_queue_async(twitterQueue, ^ {        
    ACAccountStore *accountStore = [[ACAccountStore alloc] init];
    ACAccountType *accountType = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];

    [accountStore requestAccessToAccountsWithType:accountType options:nil completion:^(BOOL granted, NSError *error){
        if (granted) {

            NSArray *accounts = [accountStore accountsWithAccountType:accountType];

            if (accounts.count > 0)
            {
                ACAccount *twitterAccount = [accounts objectAtIndex:0];
                NSArray *keys = [NSArray arrayWithObjects:@"geocode", @"count", nil];
                NSArray *objects = [NSArray arrayWithObjects:@"37.781157,-122.398720,100mi", @"100", nil];
                NSDictionary *dictionary = [NSDictionary dictionaryWithObjects:objects
                                                                       forKeys:keys];

                SLRequest *twitterInfoRequest = [SLRequest requestForServiceType:SLServiceTypeTwitter requestMethod:SLRequestMethodGET URL:[NSURL URLWithString:@"https://api.twitter.com/1.1/search/tweets.json"] parameters:dictionary];
                [twitterInfoRequest setAccount:twitterAccount];
                // Making the request

                [twitterInfoRequest performRequestWithHandler: ^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
                    //dispatch_async(dispatch_get_main_queue(), ^{
                    dispatch_async(twitterQueue, ^{
                        ...adding object to nsmutablearray* twitterUsers
                    });
                }];
              }
            } 
            else {
            NSLog(@"No access granted");
            }
    }];
});
}

-(void) printUsers
{
// wait for queue to empty
dispatch_sync (twitterQueue, ^{
    dispatch_async(dispatch_get_main_queue(), ^{
        for (NSString* str in twitterUsers)
        {
            NSLog(@"%@",str);
        }
    });
});
}



//ViewController.m

- (void)viewDidLoad
{
    [super viewDidLoad];
    twitter_crawler=[[TwitterCrawler alloc] initTwitterCrawler];
    [twitter_crawler getTwitterUsersInPosition:position];
}

- (IBAction)pressButton:(id)sender {
    [twitter_crawler printUsers];
}

因此,如果用户在twitterUsers 被来自第一个请求的数据填充之前按下按钮,它将返回一个空数组。

编辑:

队列是串行的,我是这样创建的:

dispatch_queue_t twitterQueue = dispatch_queue_create("com.example.MyQueue", NULL);

【问题讨论】:

    标签: ios objective-c twitter objective-c-blocks grand-central-dispatch


    【解决方案1】:

    dispatch_sync 保证在通过该 API 排队的块被执行之前它不会返回。不多也不少。

    如果twitterQueue 是一个并发队列,那么通过dispatch_sync 排队的块可能会立即执行,而不管其他块在做什么。如果是串行队列,则该块将在已经入队的内容之后执行。但是,如果将新项目添加到队列中,它们将在同步调度之后运行。

    当队列被清空时做某事的想法通常不是一个有用的方法(除非你很难管理队列并且最后执行的项目保证是该任务的最后一个项目,可能会触发一个新的多阻塞任务并重用队列)。

    您最好使用信号量或调度屏障或任何其他分组机制来严格控制您的并发性,包括何时更新主队列。

    这是一个很好的starting point document。还有一些更高级的并发指南可用。

    【讨论】:

    • 我介绍过的;如果您的队列是串行的,那是因为您的块处于意外顺序。你需要有某种形式的“这些块被排队并且那个块是停止块”。障碍为此工作。也可以使用信号量。
    猜你喜欢
    • 2012-06-14
    • 2012-05-02
    • 2011-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-16
    • 2015-10-18
    • 1970-01-01
    相关资源
    最近更新 更多