Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use dispatch_sync correctly?

I am getting twitter time line data from a custom NSObject class and this class has all the coe for calling the API and parse the data. I am calling this class from my view controller which has a table view and need to populate the tableview with the data coming from twitter. But due to some issues with the dispatch_sync my view controller calls the twitter class and control comes back to the view controller before the Array (which i am using to populate the tableview) is populated with the data.

Here's some code :

#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;
}

This class has been called like this:

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

I know I am returning the value in a wrong way but i tried returning it through the loadData message itself to the view controller but it didn't work either so i was just trying this. Please don't care about that.

Thanks

like image 489
Ashutosh Avatar asked Nov 03 '22 12:11

Ashutosh


1 Answers

Alright i figured out the problem with this. dispatch_sync is doing what it is supposed to do the problem is with the other two statements under which dispatch_sync is been called (the other blocks )

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

so this is an asynchronous call and dispatch sync gets called when the program control is back on the main queue as we have it defined like this : dispatch_sync(dispatch_get_main_queue()) and the method returns before the control is back on the main queue and hence the array doesn't gets any value. So to solve this i wrote a block in my calling class which gets the return call once this data call is over. email me if you want the whole code @[email protected]

like image 94
Ashutosh Avatar answered Nov 14 '22 16:11

Ashutosh