ios - dispatch_sync 在队列为空之前返回

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

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

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

即使我将第一个请求放在我创建的队列中,我在用户按下按钮时调用的命令 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);

最佳答案

dispatch_sync 保证它不会返回,直到通过该 API 排队的 block 被执行。不多也不少。

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

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

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

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

关于ios - dispatch_sync 在队列为空之前返回,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17129423/

相关文章:

javascript - 如果最初隐藏,则 Twitter 按钮不显示

ios - 如何在警报通知时自动启动应用程序?

ios - 通知程序调用早于预期

ios - Parse.com 查询字符串是否包含在数组中

objective-c - 在 iOS 8 应用程序中隐藏状态栏

asp.net-mvc-4 - 在 MVC 中使用 oAuth 安排推文

ios - 如何在 Twitter 和 Fabric 中将应用程序 ID 从一个帐户转移到另一个帐户

ios - 从 SWRevealViewController 中存在的 tableview 单元格展开 segue

ios - 循环函数中的异步调用。仅在异步完成时返回

html - 如何在 iOS 中分隔 xml 标记内的值