dispatch_sync在队列为空之前返回

时间:2013-06-16 01:32:25

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

我有两个类,一个是视图控制器,另一个是(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);

1 个答案:

答案 0 :(得分:4)

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

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

在清空队列时执行某些操作的概念通常不是一种有用的方法(除非您难以管理队列,并且最后执行的项目保证是该任务的最后一项,可能会触发新的多项阻止任务并重新使用队列。

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

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