2012-06-04 7 views
51

Ich versuche, geparste Daten in Zellen zu laden, aber das Problem ist, dass es synchron passiert und UitableView wird nicht angezeigt, bis die Daten geladen sind. Ich habe versucht, das Problem mit performSelectorInBackground zu lösen, aber jetzt werden Daten nicht in den Zellen geladen, bis ich mit dem Scrollen anfange. Hier ist mein Code:Daten werden nicht in UITableView geladen, bis ich blättern

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 
    // Do any additional setup after loading the view, typically from a nib. 

    [self performSelectorInBackground:@selector(fethchData) withObject:nil]; 


} 


- (void)viewDidUnload 
{ 
    [super viewDidUnload]; 
    // Release any retained subviews of the main view. 
self.listData = nil; 
    self.plot=nil; 
} 


-(void) fethchData 

{ 
    NSError *error = nil; 
    NSURL *url=[[NSURL alloc] initWithString:@"http://www.website.com/"]; 
    NSString *strin=[[NSString alloc] initWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil]; 

    HTMLParser *parser = [[HTMLParser alloc] initWithString:strin error:&error]; 

    if (error) { 
     NSLog(@"Error: %@", error); 
     return; 
    } 

    listData =[[NSMutableArray alloc] init]; 
    plot=[[NSMutableArray alloc] init]; 

    HTMLNode *bodyNode = [parser body]; 
    NSArray *contentNodes = [bodyNode findChildTags:@"p"]; 


    for (HTMLNode *inputNode in contentNodes) { 
      [plot addObject:[[inputNode allContents] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]];  
     } 


    NSArray *divNodes = [bodyNode findChildTags:@"h2"]; 

    for (HTMLNode *inputNode in divNodes) { 

      [listData addObject:[[inputNode allContents] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]];   

     } 
    } 


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 

    static NSString *CellIdentifier = @"Cell"; 
    //here you check for PreCreated cell. 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 
    if (cell == nil) { 
     cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier]; 
     cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; 

    } 

    //Fill the cells... 


    cell.textLabel.text = [listData objectAtIndex:indexPath.row]; 
    cell.textLabel.font = [UIFont boldSystemFontOfSize:14]; 
    cell.textLabel.numberOfLines=6; 
    cell.textLabel.textColor=[UIColor colorWithHue:0.7 saturation:1 brightness:0.4 alpha:1]; 


    cell.detailTextLabel.text=[plot objectAtIndex:indexPath.row]; 
    cell.detailTextLabel.font=[UIFont systemFontOfSize:11]; 
    cell.detailTextLabel.numberOfLines=6; 

    return cell; 


} 
+0

nur sichtbare Zellen geladen werden Rest Zellen sein geladen, sobald sie nach dem Scrollen erscheinen. – rishi

Antwort

123

dies irgendwo Setzen, nachdem die Daten erfolgreich geladen wird:

dispatch_async(dispatch_get_main_queue(), ^{ 
    [self.tableView reloadData]; 
}); 

ein GUI-Update , während Sie nicht im Hauptthread dieses Problem zu beheben, das Problem des Aufrufs sind.

Dieser Code verwendet die GCD-Technologie von Apple, um zu erzwingen, dass die Funktion zum erneuten Laden von Daten im Hauptthread ausgeführt wird. Lesen Sie mehr über Concurrency Programming Guide für mehr Verständnis (es ist ziemlich großes Feld, so dass es schwer ist, in dem Kommentar zu erklären) Wie auch immer, es ist nicht sehr empfehlenswert, wenn Sie es nicht gut verstehen, weil es das Programm zum Absturz bringt.

+0

Danke. Ich hatte hastig einige Dinge bewegt und nicht bemerkt, dass mein Laden der Daten in einem anderen Thread war und daher auch meine reloadData. Danke, dass du mir geholfen hast, zurück zu gehen und Dinge zu analysieren. – chadbag

+0

Danke! Das hat einen wirklich nervigen Fehler gelöst, den ich hatte. –

+1

RIESIGE HILFE! danke – Greg

9

Alles, was Sie wirklich tun müssen, ist jedes Mal, wenn ein Update auf Back-End-Daten haben, rufen

[tableView reloadData]; 

Da dies geschieht synchron, sollten Sie wahrscheinlich eine Funktion wie

-(void) updateTable 
{ 
    [tableView reloadData]; 
} 

und nach den Daten in Ihrem Download-Gespräch hinzugefügt

[self performSelectorOnMainThread:@selector(updateTable) withObject:nil waitUntilDone:NO]; 
+0

Es heißt "unbekannter Empfänger tableView" – Benjamen

+0

Der Code ist als Beispiel gemeint, ich kenne nicht die genaue Struktur Ihrer Klasse oder Ansicht Layout. Der Punkt ist, dass Sie einen Verweis auf Ihre Tabellenansicht erhalten müssen (wenn Ihre Klasse eine Instanz oder Unterklasse von UITableViewController ist, sollten Sie einfach self.tableView haben) und rufen Sie die Methode 'reloadData' darauf auf –

+0

In einem UITabbleviewController es wird ** self.tableView ** – LavaSlider

1

Ich hatte genau das gleiche Problem! Ich wollte, dass das UITableView vollständig gefüllt war, bevor der View-Controller erschien. Envils Post gab mir die Informationen, die ich brauchte, aber meine Lösung endete anders.

Hier ist, was ich getan habe (umgebaut, um den Kontext der Frage Asker passen).

- (void)viewDidLoad { 
    [super viewDidLoad]; 
    [self performSelectorInBackground:@selector(fethchData) withObject:nil]; 
} 

- (void)viewWillAppear { 
    [tableView reloadData]; 
} 
2

U kann [Zelle setNeedsDisplay]; zum Beispiel:

dispatch_async(dispatch_get_main_queue(), ^{ 
      [cell setNeedsDisplay]; 
      [cell.contentView addSubview:yourView]; 
     }); 
1

hatte ich dieses Problem und ich war mit ihm den ganzen Tag zu tun.

Ich verwende statische Zellen und reloadData verursacht das falsche Laden, es zeigt nur die sichtbaren Zellen und entfernen Sie die anderen. Was ich bemerkte ist, dass, wenn ich scrollte (y im negativen Wert) die Zellen richtig geladen wurden, also schrieb ich diesen Code und es funktionierte, obwohl ich es nicht so lassen möchte.

Schießen Sie, wenn Sie eine bessere Lösung finden.

-(void)reloadTableView{ 
     CGPoint point = self.tableSettings.tableView.contentOffset; 
     [self.tableSettings.tableView reloadData]; 

     [UIView animateWithDuration:.001f animations:^{ 
      [self.tableSettings.tableView setContentOffset:CGPointMake(point.x, -10)]; 
     } completion:^(BOOL finished) { 
      [UIView animateWithDuration:.001f animations:^{ 
       [self.tableSettings.tableView setContentOffset:point]; 
      } completion:^(BOOL finished) { 

      }]; 
     }]; 
} 
+0

Das hat bei mir funktioniert. Lassen Sie mich wissen, wenn Sie das eigentliche Problem herausgefunden haben –

13

Für schnellen 3:

DispatchQueue.main.async(execute: {() -> Void in 
       self.tableView.reloadData() 
      }) 

Für das schnelle 2:

dispatch_async(dispatch_get_main_queue(), {() -> Void in 
       self.tableView.reloadData() 
      }) 
+0

bro swift 3 funktioniert gut !! ... Danke –

+0

@MayPhyu Gern geschehen :) – Hamid

0

Erstens, dieses halb löste mein verwandtes Problem. Ich möchte Ecken eines Bildes in einer Tabellenzelle runden. Das asynchrone Dispatching behebt das Problem für einige, aber nicht für alle Bilder. Irgendwelche Ideen?

Zweitens, ich glaube, Sie sollen einen starken Referenzzyklus zu vermeiden, zu schaffen, indem ein Verschlussaufnahmeliste wie folgt aus:

DispatchQueue.main.async(execute: { [weak weakSelf = self]() -> Void in 
      weakSelf!.tableView.reloadData() 
     }) 

See: sind https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html#//apple_ref/doc/uid/TP40014097-CH20-ID52

+0

Das hat mein Problem behoben: DispatchQueue.main.async (ausführen: {[weak weakCell = Zelle]() -> Void in weakCell! .imageView! .layer.cornerRadius = cell.imageView! .frame.width/4.0 weakCell! .imageView! .clipsToBounds = true }) – user3590685

Verwandte Themen