如何正确使用dispatch_sync?

时间:2012-11-05 00:07:24

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

我从自定义NSObject类获取twitter时间线数据,这个类具有调用API和解析数据的所有系数。 我从我的视图控制器调用这个类,它有一个表视图,需要使用来自twitter的数据填充tableview。但是由于dispatch_sync的一些问题,我的视图控制器调用了twitter类,并且控件返回到视图控制器,然后Array(我用来填充tableview)填充了数据。

以下是一些代码:

#import <UIKit/UIKit.h>
#import "SecondViewController.h"
#import "SpinnerController.h"
#import "proAlertView.h"
#import "SBJson.h"
#import <Accounts/Accounts.h>
#import <Twitter/Twitter.h>

@interface TwitterDataLoad : NSObject<UIAlertViewDelegate>
{
    NSMutableData * receivedData;
    NSArray * results;
    NSArray * cellContent;
    NSMutableArray * totalContent;
    SpinnerController * spinner;
    proAlertView * av;
    NSString *json_string;
    NSDictionary * jsonResults;
    SBJsonParser * parser;
    NSMutableArray * dataForTable;

}
@property(nonatomic, strong) ACAccount * account;
@property(nonatomic, strong) NSArray * accounts;
@property(nonatomic, strong) ACAccountStore * accountStore;
@property (nonatomic ,retain) SecondViewController * tbView;

- (void)loadData;

@end

#import "TwitterDataLoad.h"


@interface TwitterDataLoad ()

@end

@implementation TwitterDataLoad
@synthesize tbView;


-(id) init {
    self = [super init];
    if (self) {
        [self loadData];
    }
    return self;
}

- (void)loadData
{
    dataForTable = [[NSMutableArray alloc]init];
    //Twitter new code

    if (_accounts == nil) {
        if (_accountStore == nil) {
            _accountStore = [[ACAccountStore alloc] init];
        }
        ACAccountType *accountTypeTwitter =
        [_accountStore
         accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
        [_accountStore requestAccessToAccountsWithType:accountTypeTwitter
                                     withCompletionHandler:^(BOOL granted, NSError *error) {
                                         if(granted) {
                                             dispatch_sync(dispatch_get_main_queue(), ^{
                                                 _accounts = [_accountStore
                                                                  accountsWithAccountType:accountTypeTwitter];

                                                 [self sendRequest];
                                             });
                                         }
                                     }];
    }
}

-(void) sendRequest {

    totalContent = [[NSMutableArray alloc]init];
    _account = [_accounts objectAtIndex:0];

    TWRequest *postRequest = [[TWRequest alloc]
                              initWithURL:
                              [NSURL URLWithString:@"https://api.twitter.com/1/statuses/user_timeline.json?screen_name=test&count=20"]
                              parameters:nil
                              requestMethod:TWRequestMethodGET];

    av = [[proAlertView alloc]initWithTitle:nil message:@"Getting latest news..." delegate:self cancelButtonTitle:nil otherButtonTitles:nil, nil];
    UIActivityIndicatorView * indicator = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
    indicator.frame = CGRectMake(120, 55, 35, 35);
    [av addSubview:indicator];
    [indicator startAnimating];
    [av setBackgroundColor:[UIColor clearColor] withStrokeColor:[UIColor blackColor]];
    [av show];


    [postRequest setAccount:_account];
    [postRequest performRequestWithHandler:^(NSData *responseData,
                                             NSHTTPURLResponse *urlResponse,
                                             NSError *error) {
        if ([urlResponse statusCode] == 200) {
            NSError *jsonError = nil;
            results = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:&jsonError];

            dispatch_sync(dispatch_get_main_queue(), ^{
                [av dismissAlert];
                [self parseJson];
            });
        }
        else {
            [self showMessage];
        }
    }];

}

-(void)showMessage {

    av = [[proAlertView alloc]initWithTitle:@"Connection Problem" message:@"Please confirm the device is connected to the Internet." delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];
    [av setBackgroundColor:[UIColor clearColor] withStrokeColor:[UIColor blackColor]];
    [av show];
}

-(void)parseJson {

    NSMutableArray * complete = [[NSMutableArray alloc]init];
    for (NSDictionary * tweets in results)
        {
        NSString * status = [tweets objectForKey:@"text"];
        NSString * date = [tweets objectForKey:@"created_at"];
        NSDictionary * user = [tweets objectForKey:@"user"];
        NSString * artistName = [user objectForKey:@"name"];
        NSString * screenName = [user objectForKey:@"screen_name"];
        NSString * artistImage = [user objectForKey:@"profile_image_url"];
        cellContent = [NSArray arrayWithObjects:status,date,artistName,screenName,artistImage, nil];
        [complete addObject:cellContent];
        }

        SecondViewController * tmpView = [[SecondViewController alloc]initWithNibName:@"SecondViewController_iPhone" bundle:nil];
            tmpView.dataToDisplay = complete;
}

这个类的调用方式如下:

- (void)viewDidLoad
{
    [super viewDidLoad];
    TwitterDataLoad * data = [[TwitterDataLoad alloc] init];
    [data loadData];
    NSArray * temp = dataToDisplay;
}

我知道我以错误的方式返回值,但我尝试将它通过loadData消息本身返回到视图控制器,但它也没有工作,所以我只是尝试这个。请不要在乎。

由于

2 个答案:

答案 0 :(得分:2)

好吧我弄明白了这个问题。 dispatch_sync正在做它应该做的事情,问题在于调用dispatch_sync的其他两个语句(其他块)

[_accountStore requestAccessToAccountsWithType:accountTypeTwitter
                                         withCompletionHandler:^(BOOL granted, NSError *error)

所以这是一个异步调用,当程序控制回到主队列时调用调度同步,因为我们已经定义了这样的:dispatch_sync(dispatch_get_main_queue()) 并且该方法在控制返回主队列之前返回,因此该数组不会获得任何值。 所以为了解决这个问题,我在我的调用类中写了一个块,一旦这个数据调用结束,它就会得到一个返回调用。如果你想要整个代码@ ghostsmitm @ gmail.com

,请给我发电子邮件

答案 1 :(得分:0)

数据加载后,您应在reloadData上致电UITableView。您可以在致电loadData后执行此操作。