5

Dostaję dane wiersza czasu twitter z niestandardowej klasy NSObject i ta klasa ma wszystkie cale do wywoływania interfejsu API i analizowania danych. Wywołuję tę klasę z kontrolera widoku, który ma widok tabeli i należy wypełnić tabelę danymi pochodzącymi ze strony twitter. Ale z powodu pewnych problemów z dispatch_sync mój kontroler widoku wywołuje klasę twitter i kontrolka wraca do kontrolera widoku, zanim tablica (której używam do zapełnienia widoku tabeli) jest wypełniona danymi.Jak poprawnie używać dispatch_sync?

Oto niektóre kodu:

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

Klasa ta została nazwana tak:

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

wiem Wracam wartość w niewłaściwy sposób, ale starałem wpuszczeniem go za pośrednictwem wiadomości loaddata do kontrolera widoku, ale nie działało, więc próbowałem tego. Proszę, nie przejmuj się tym.

Dzięki

+0

Co masz na myśli "kontrola wraca do kontrolera widoku przed tablicą"? Co to jest kontrola? – yeesterbunny

+0

Mam na myśli NSArray * temp = dataToDisplay; linia zostanie wywołana przed wykonaniem całego kodu w klasie twitterDataLoad. – Ashutosh

+0

To dziwne. Czy możesz ustawić punkt przerwania w 'tmpView.dataToDisplay = complete;' i sprawdzić, czy rzeczywiście ma wartość? Jeśli tak, to musisz ustawić punkt przerwania w '[data loadData]' i wkroczyć do niego, aby zobaczyć, jak twoja 'NSArray * temp = dataToDisplay' zostaje wywołana przed' [data loadData] '. – yeesterbunny

Odpowiedz

2

W porządku, znalazłem problem z tym. dispatch_sync robi to, co ma zrobić, problem jest z dwóch pozostałych sprawozdań na podstawie których dispatch_sync jest nazwano (pozostałe bloki)

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

więc jest to wywołanie asynchroniczne i wysyłka synchronizacja zostanie wywołana, gdy program sterowanie powraca do głównej kolejki, tak jak ją zdefiniowaliśmy w następujący sposób: dispatch_sync (dispatch_get_main_queue()) , a metoda zwraca przed powrotem do głównej kolejki, przez co tablica nie otrzymuje żadnej wartości. Aby rozwiązać ten problem, napisałem blok w mojej klasie wywołania, który otrzymuje wywołanie zwrotne po zakończeniu tej transmisji danych. wyślij mi e-mail, jeśli chcesz cały kod @ ghostsmitm @ gmail.com

0

należy zadzwonić reloadData na własną UITableView raz dane zostały załadowane. Możesz to zrobić po zadzwonieniu pod numer loadData.

+0

Robię to po tym, ale to się nazywa przed tym całym świergotem. – Ashutosh

Powiązane problemy