5

Sto ricevendo i dati della linea temporale di Twitter da una classe NSObject personalizzata e questa classe ha tutto il coe per chiamare l'API e analizzare i dati. Sto chiamando questa classe dal mio controller di visualizzazione che ha una vista tabella e ho bisogno di compilare la tabella con i dati provenienti da Twitter. Ma a causa di alcuni problemi con dispatch_sync il mio controller di visualizzazione chiama la classe twitter e il controllo ritorna al controller di visualizzazione prima che l'array (che sto usando per popolare la tabella) sia popolato con i dati.Come usare dispatch_sync correttamente?

Ecco po 'di codice:

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

Questa classe è stata chiamata in questo modo:

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

so che sto tornando il valore in modo sbagliato, ma ho cercato di tornare attraverso il messaggio loadData stesso al controller della vista, ma non ha funzionato, quindi stavo solo provando questo. Per favore non ti preoccupare di questo.

Grazie

+0

Cosa intendi con "il controllo torna al controller della vista prima della matrice"? Cos'è un controllo? – yeesterbunny

+0

Intendo il NSArray * temp = dataToDisplay; questa linea viene chiamata prima che l'intero codice venga eseguito in esecuzione nella classe twitterDataLoad. – Ashutosh

+0

Questo è strano. Puoi impostare breakpoint su 'tmpView.dataToDisplay = complete;' e vedere se ha effettivamente un valore? Se lo fa, allora devi impostare breakpoint su '[data loadData]' e passarci dentro per vedere come il tuo 'NSArray * temp = dataToDisplay' viene chiamato prima di' [data loadData] '. – yeesterbunny

risposta

2

OK ho capito il problema con questo. dispatch_sync sta facendo quello che dovrebbe fare il problema è con le altre due affermazioni in base alle quali dispatch_sync è stato chiamato (gli altri blocchi)

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

quindi questa è una chiamata asincrona e la sincronizzazione spedizione viene chiamato quando il programma il controllo ritorna sulla coda principale come lo abbiamo definito in questo modo: dispatch_sync (dispatch_get_main_queue()) e il metodo ritorna prima che il controllo ritorni sulla coda principale e quindi l'array non ottiene alcun valore. Quindi per risolvere questo ho scritto un blocco nella mia classe chiamante che riceve la chiamata di ritorno una volta che questa chiamata dati è finita. scrivimi se vuoi l'intero codice @ ghostsmitm @ gmail.com

0

si dovrebbe chiamare reloadData sul UITableView volta che i dati sono stati caricati. È possibile farlo dopo aver chiamato loadData.

+0

Lo sto facendo dopo, ma questo viene chiamato prima dell'intera cosa su Twitter. – Ashutosh

Problemi correlati