cellForRowAtIndexPath: nicht aufgerufen

72

Meine App hat zwei Status: angemeldet und nicht angemeldet, und ich habe die folgende Architektur (stark vereinfacht):
- ViewController A, der ein Suchfeld und eine Tabellenansicht enthält.
- ViewController B, der zum Anmelden in der App verwendet wird.

Der Ablauf ist wie folgt:
- Der Benutzer ist nicht angemeldet.
- A wird auf den Stapel geschoben. In viewWillAppearIch überprüfe, ob der Benutzer angemeldet ist und wenn ja, wird eine asynchrone Netzwerkanforderung gestellt, und sobald dies erledigt ist, wird die Tabelle mit den Daten aus dem Netzwerk geladen. Da der Benutzer zu diesem Zeitpunkt jedoch nicht angemeldet ist, ist die Tabellenansicht leer.
- Der Benutzer tippt auf das Suchfeld. weil er nicht eingeloggt ist, wird B gedrückt (nach einer Bestätigung);
- er meldet sich erfolgreich in B an, drückt dann eine Taste, die B öffnet und A wieder anzeigt;
- zu diesem Zeitpunkt, weil er angemeldet ist, viewWillAppearmache ich die asynchrone Anfrage;
- Wenn das erledigt ist, rufe ich reloadDatadie Tabellenansicht auf.

Was mir auffällt ist, dass numberOfRowsInSection:es aufgerufen wird und das richtige Ergebnis zurückgibt, danach jedoch cellForRowAtIndexPath:NICHT aufgerufen wird und die Tabelle leer bleibt.

Ich habe geprüft und reloadDatawird im Haupt-Thread aufgerufen.

Irgendeine Idee was kann es sein? Weil es mich verrückt macht!

Danke,
S.

EDIT: Hier ist das asynchrone Codebit aus viewWillAppearA.

if ([User isLoggedIn]) {
    [self.asyncRequest fetchDataWithCompletionHandler:^(id response, NSError *error) {
        [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
        if (error) {
            [Utils displayError:error];
        } else {
            self.array = response;

            self.isLoaded = YES;
            [self.tableView reloadData];
            [self.tableView setContentOffset:CGPointMake(0.0f, 0.0f) animated:NO];
        }
    }];
}

Ich habe überprüft, ob die asynchrone Anforderung erfolgreich abgeschlossen wurde und responsedie richtigen Daten enthält (dies ist das Array , das zum Sichern der Anforderung verwendet wird UITableView).

Danach reloadDatahabe ich einen Haltepunkt eingefügt tableView:numberOfRowsInSection:und dieser stoppt dort und gibt die richtige Anzahl von Elementen zurück array. Danach wird der Haltepunkt in tableView:cellForRowAtIndexPath:jedoch nie mehr erreicht.

Stelian Iancu
quelle
Der richtige Methodenwähler ist tableView:cellForRowAtIndexPath:nicht cellForRowAtIndexPath:.
Ole Begemann
Wenn numberOfRowsInSection: korrekte Daten zurückgibt, liegt möglicherweise ein Problem beim Festlegen des Delegaten und der Datenquelle vor. Kannst du einen Code posten?
Shri
Ja, ich weiß, das ist es. Ich habe hier die Kurzversion eingefügt.
Stelian Iancu
Der Delegat und die Datenquelle werden im Interface Builder auf den Eigentümer der Datei (dh A) festgelegt.
Stelian Iancu
Ein weiterer Punkt: Dies funktioniert gut, wenn ich nach dem Anmelden von A wechsle und darauf zurückkomme, wird die Tabelle korrekt ausgefüllt. Nur wenn ich von B darauf zurückkomme, funktioniert es nicht.
Stelian Iancu

Antworten:

272

Ein gültiges Szenario dafür, warum numberOfRowsInSectionaufgerufen, aber cellForRowAtIndexPathnicht aufgerufen wird, ist, wenn für die Größe oder Positionierung der Tabelle keine Zeilen angezeigt werden müssen.

Angenommen, Sie hatten eine Tabelle mit einer Höhe von 20 Pixel, aber der Header für den ersten Abschnitt war 30 Pixel hoch, und Sie haben für den Header null zurückgegeben (oder nicht implementiert viewForHeaderInSection). In diesem Fall werden keine Zeilen angezeigt und es sieht so aus, als ob die Tabelle einfach nicht vorhanden ist.

Ich sehe, Sie verwenden IB. Die Größe der Tabelle kann in IB irreführend sein, da Kopf- und Fußzeilengrößen angenommen werden. Ich würde den Frame für die Tabelle protokollieren, damit Sie verstehen, wo er sich befindet, wenn die Anwendung ausgeführt wird (und wo er in IB angezeigt wird). Ich würde auch sicher sein, den Rahmen der Tabelle manuell zu dimensionieren und zu positionieren, bevor ich reloadData aufrufe. Dies löst diesen gültigen Fall, in dem cellForRowAtIndexPathnicht aufgerufen wird.

Joel
quelle
70
Dieser Typ weiß wovon er spricht.
Akaru
Was für eine großartige Antwort hier, @joel hat gerade eine sehr gute Erklärung gegeben. Ich bin tatsächlich auf ein ähnliches Problem gestoßen und habe fast einen Tag für das Debuggen gebraucht. In meinem Fall wird die Funktion cellForRowAtIndexPath nicht aufgerufen. Mit dieser Antwort fand ich heraus, dass das AutoLayout die Höhe für die Tabelle mit 0 berechnet hat. Und das ist die Hauptursache. App hat beschlossen, die Zelle überhaupt nicht zu rendern.
Leon Guan
2
Ich habe es so satt, dass Xcode die Einschränkungen für Ansichten vorschlägt. Meine Tabellenansicht wurde aufgrund einiger $ #! Tty-Einschränkungen, die vorgeschlagen wurden, nie angezeigt. Die Einschränkungen wurden geändert und alles hat perfekt funktioniert.
RyJ
Ich hatte eine leichte Variation davon. Ich habe ein UITavleView mit IB platziert, ohne das automatische Layout zu verwenden. Der Rahmen der Tabellenansicht wurde so eingestellt, dass er sich automatisch auf die Höhe der Zelle erstreckt. In der .m-Datei habe ich die Höhe des Rahmens der Zelle und die Höhe des Rahmens der Tabellenansicht festgelegt. XCode ignorierte meinen Codesatzrahmen beim ersten Anzeigen der Tabellenansicht, respektierte jedoch den Aufruf von setFrame beim zweiten Mal. Als ich die automatische Dehnung in der Y-Achse deaktivierte, verschwand mein Problem und die setFrame-Methoden funktionierten wie erwartet. XCode-Einschränkungen sind an manchen Tagen schmerzhaft. Danke für diese Antwort!
JasonD
Wie kann der Header 30 sein, aber dann sind Sie dafür zurückgekehrt nil? Sprechen Sie darüber, ob einer implementiert hat heightForHeaderInSectionund 30 zurückgibt, aber dann für den viewForHeaderInSectionzurückgekehrt ist nil?
Honig
44

Stellen Sie sicher, dass das numberOfSectionsInTableViewnicht 0 zurückgibt.

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    // Return the number of sections.
    return 1;
}
Peter Kelly
quelle
2
Ich habe das gleiche Problem wie der ursprüngliche Autor. Diese Methode gibt 1 zurück, wie in Ihrer Antwort gezeigt, und wird aufgerufen ... cellForRowAtIndexPath wird jedoch nicht aufgerufen. Die Datenquelle und der Delegat werden über den Interface Builder auf den Eigentümer der Datei festgelegt. Ich habe sogar versucht, es per Code festzulegen (tableView.delegate = self) und es wird immer noch nicht aufgerufen. Ich dachte nur, ich würde diese Faktoren einbringen, da der Autor keine Antwort akzeptiert hat, aber Sie scheinen auf dem richtigen Weg zu sein. Hoffe, jemand kann das herausfinden!
Danny
6
Laut Apple "Der Standardwert ist 1." Diese Methode wird nicht benötigt.
Peter DeWeese
4
Zum Zeitpunkt der Beantwortung dieser Frage war dies unbedingt erforderlich.
Peter Kelly
Ich kann bestätigen, dass diese Methode 0 zurückgegeben hat und Probleme verursacht hat. Ich habe es implementiert, um 1 in meinem Table View Controller zurückzugeben, und alles wurde behoben.
Kann Poyrazoğlu
Es gibt 3 für mich zurück.
ScottyBlades
27

Ich hatte genau das gleiche Problem und das Problem war, dass ich versuchte, reloadData aufzurufen: von einem anderen Thread. Die Lösung wäre:

dispatch_async(dispatch_get_main_queue(), ^{
    [self.tableView reloadData];
});
Nikolay Dyankov
quelle
16

Wenn Sie wie ich eine andere dataSource verwenden, stellen Sie sicher, dass Sie die dataSource beibehalten. Es reicht nicht aus, nur die Klasse zu instanziieren, die die dataSource sein wird, und sie über zuzuweisen, tableView.dataSource = myDataClassda die dataSource-Eigenschaft einer tableView schwach ist und nach Abschluss von viewDidLoad freigegeben wird. Alle anderen Methoden wurden für mich aufgerufen - auch überraschenderweise heightForRowAtIndexPath-, so dass ich einige Zeit zum Debuggen brauchte.

avance
quelle
Danke für das Teilen. Denn heightForRowAtIndexPathes ist im Delegierten, deshalb wurde es sowieso aufgerufen.
Y.Bonafons
das ist so gültig
king_T
12
// For others showing up on this questions via Google, etc.
// Check and make sure you've set the table view's data source and delegate.
self.tableView.dataSource = self;
self.tableView.delegate = self;
John Erck
quelle
12

Wenn eine Tabellenansicht in einer Ansicht, die in Konflikt mit der Scrool-Ansicht steht, nicht aufgerufen wird. Sie sollten die Ansichten in Ihrem Storyboard oder Ihrer * .xib-Datei trennen.

// TrueView
        ► Table View
        ► Scrool View
        ► Constraints

// FalseView
        ► Scrool View
            ► Table View
        ► Constraints
behicsakar
quelle
5

Wir hatten das gleiche / ähnliche Problem. Der Code erreichte numberOfSectionsund numberOfRowsInSection(und gab sogar Werte zurück), konnte aber nicht erreichen cellForRowAt. Zu diesem Zeitpunkt gab es in der Tabellenansicht im Storyboard nur Einschränkungen für die rechte Seite, die linke Seite und die Oberseite, nicht jedoch für die Unterseite. Nachdem wir dem unteren Rand eine Einschränkung hinzugefügt hatten, funktionierte es wie ein Zauber.

Überprüfen Sie daher, ob Sie alle erforderlichen Einschränkungen für die Tabellenansicht angeben.

1johnnytheboy
quelle
4

Alle reden immer über Größe, aber meine TableView in einer StackViewmit führenden Ausrichtung endete mit 0 Breite.

Stellen Sie sicher, dass Sie mit überprüfen, ob Ihre TableViewGröße korrekt ist Debug View Hierarchy.

Jaroslaw
quelle
und was war deine lösung? Meins ist in einem StackView, aber ich sehe es immer noch nicht als Debugger
Honey
@Honey Vielleicht möchten Sie die Höhenbeschränkung auf eine Konstante setzen und das Scrollen deaktivieren.
Jaroslaw
Eigentlich habe ich es gerade aus der Stapelansicht entfernt, aber es machte immer noch keinen Unterschied. Andere Methoden werden getroffen, aber nichtcellforrowatindexpath . Zu Ihrer Information, es ist eine Tabellenansicht in einer UIView ...
Honey
@Honey nicht sicher, wie man mit dieser Menge an Informationen hilft, stellen Sie sicher, dass 0 in numberOfRows nicht zurückgegeben wird :)
Yaroslav
Das gleiche Problem Ich habe Tabellenansicht in Stapelansicht nicht verwendet cellForRowAt indexPath funktioniert nicht
Harshil Kotecha
3

Ich habe das Problem gelöst, weil meine Unteransicht, zu der ich die hinzugefügt habe, UITableViewnicht zugewiesen wurde, sodass sie nicht zurückgegeben wurde und die Tabellenansicht nicht anrief, cellForRowAtIndexPathsondern numberOfRowsInSectionaufgerufen wurde

user1039695
quelle
3

Wenn Sie wie ich das automatische Layout verwenden und der Ansicht Ihres View Controllers eine Tabellenansicht hinzufügen, stellen Sie sicher, dass Sie diese Zeile hinzugefügt haben, wenn Sie Ihre Tabellenansicht zuweisen.

tableView?.translatesAutoresizingMaskIntoConstraints = false

Dummer Fehler von meiner Seite.

Anuran Barmann
quelle
Hat mir Stunden gespart haha. Danke
Roi Mulia
2

Ich verwende eine Kundendatenquelle und sie wurde freigegeben. Weil es eine schwache Referenz der Tabellenansicht ist.

TK189
quelle
2

Das ist peinlich und verwirrend, aber hier ist meine Lösung.

Mein Code:

_scanResultTable.delegate = self;
_scanResultTable.dataSource = self; // self's lifecycle was fine, wasn't getting released
[_scanResultTable reloadData];

Der seltsame Teil ist also: Der Bezeichner _scanResultTable wurde in meinem Code nie irgendwo im Projekt deklariert. Ich habe keine Ahnung, wie dies kompiliert wurde (und ich habe es mehrmals neu kompiliert).

Meine Hauptursache war, dass ich meine Tabellenausgabe scanResultTablein meinem ViewController verknüpft hatte, sie aber als _scanResultTable bezeichnete. Sobald ich anfing, so zu verwenden, scanResultTablewie ich es hätte tun sollen, klärten sich die Dinge auf. Ich frage mich daher, ob Objective-C etwas Besonderes daran hat, Unterstriche in Bezeichnern zu führen ...

Edit: Das tut es ! Guter Herr, ich kann es kaum erwarten, diese Sprache nie wieder zu berühren.

ArtHare
quelle
Das Problem wurde auch für mich gelöst. <3
Pepper
2

Verschwendete Stunden und fand dann heraus, dass sich meine Tabellenansicht in einer Stapelansicht befand. Sobald ich die Stapelansicht entfernt hatte, funktionierte es wie ein Zauber. Für mich ist es Xcode 11.3.

Tripti Kumar
quelle
1
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    // Make sure self.data isn't nil!
    // If it is, you'll always return 0 and therefore
    // cellForRowAtIndexPath will never get called.
    return [self.data count]; 
}
John Erck
quelle
1

Ich benutze ReactiveCocoa. Also habe ich das Modell für die Tabellenansicht erstellt. Die Daten wurden für die Anzeige vorbereitet numberOfRowsund so weiter. Aber ich habe die Tabellenansicht nicht als Unteransicht hinzugefügt, daher cellForRowAtIndexPathwurde sie nicht aufgerufen)))

Naloiko Eugene
quelle
1

In meinem Fall hatte ich das TableViewInnere eines StackView. Wenn ich es außerhalb von StackView platzierte, funktionierte es.

el3ankaboot
quelle
0

Sind Sie sicher, dass nach dem Anmelden des Benutzers und dem Popup von B die viewWillAppearMethode in A aufgerufen wird, um die Aktualisierung durchzuführen?

Wenn Sie B als modalen Controller anzeigen, haben Sie den nicht, wenn Sie ihn schließen viewWillAppear Methode aufgerufen.

Soweit ich weiß, viewWillAppear/viewDidAppear(und ähnliche) sind Ereignisse, die vom UINavigationController bei Navigationsereignissen (Push / Pop-Viewcontroller) generiert werden. Vielleicht erhalten Sie deshalb irgendwann Ihre Aktualisierung, wenn Sie A verlassen und zurückkehren ... alles hängt davon ab, wie der nächste Viewcontroller angezeigt wird.

Andrei Stanescu
quelle
Ja, ich bin sicher, ich habe Haltepunkte in den Code eingefügt und sehe, dass sie getroffen wurden. Alles funktioniert einwandfrei bis zu dem Punkt, an dem tableView: cellForRowAtIndexPath: aufgerufen werden sollte.
Stelian Iancu
Dann habe ich keine Ideen mehr. Wenn Sie mehr Code veröffentlichen, können wir möglicherweise einen möglichen Fehler erkennen. Aber etwas ist definitiv faul.
Andrei Stanescu
0

Versuchen Sie, neue Zeilen manuell einzufügen, anstatt [self.tableView reloadData]:

[self.tableView beginUpdates];
    for (int i = 0; i < responseArray.count; i++) {
        _rowsNumber += 1;
        NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i inSection:0];
        [self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationBottom];
    }
[self.tableView endUpdates];

In der dataSource-Methode wird die Rückgabe inkrementiert int _rowsNumber:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return _rowsNumber;
}
Aleh
quelle
0

Ich habe das gleiche Problem gelöst, indem ich die tableViewCell-ID überprüft habe. Gehen Sie zu Attributes Inspector und sehen Sie sich den Abschnitt mit den Bezeichnern an. Vermutlich fehlt. Schreiben Sie also die Zellenkennung.

Emre Gürses
quelle
0

Gleicher Fall hier, aber es war ein Fehler:

Ich habe eine Bildlaufansicht mit 2 Tabellenansichten in einen ViewController eingefügt (Entwurfsanforderungen), im Bildlaufansicht-Controller habe ich die ViewController (die die Tabellenansichten enthalten) programmgesteuert erstellt und eine schwache Variable zum Speichern verwendet, schlechte Idee da sie am Ende von veröffentlicht wurden viewDidLoad-Methode.

Wenn Sie den Inhalt Ihrer Tabellenansicht nicht sehen, überprüfen Sie bitte, ob er veröffentlicht wurde.

Mein Fehler war für mich sehr hirnschmerzhaft, da alle Methoden (Delegat & Datenquelle) außer viewForCell aufgerufen wurden ...

ucotta
quelle
0

Ich habe das gleiche Problem, ich habe die Tabellenansicht in der StackView und der Tabellenansicht verwendet, um die Bildlaufbeschränkung zu deaktivieren und festzulegen, aber danach

tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell

Nicht funktioniert, hören Sie auf, diese Methode alle Data Sourceund aufzurufenDelegate stellen Sie sie richtig ein.

Wenn Sie dasselbe Problem haben wie Lösung, wird die Tabellenansicht unten als führende, nachfolgende Einschränkung festgelegt

Geben Sie hier die Bildbeschreibung ein

Harshil Kotecha
quelle
0

Keine der Antworten hier hat mir geholfen.

Ich habe meine Einschränkungen programmgesteuert ausgeführt, aber vergessen zu schreiben:

myTableView.translatesAutoresizingMaskIntoConstraints = false
Honig
quelle
0

Stellen Sie sicher, dass Ihre Einschränkungen korrekt sind und keine davon beim Erstellen entfernt wird.

rs7
quelle
0

Dies ist vielleicht zu offensichtlich, aber in meinem Fall habe ich ein Element (Label) gelöscht, das programmgesteuert auf den oberen Rand meiner Tabelle verweist. Es war also kein Problem mit dem Delegaten / der Quelle, sondern mit der Tabelle, die einige Probleme mit dem Inhalt hatte. Größe / Höhe, dieser Konflikt verursachte ein seltsames Verhalten und rief numberOfRowsInSection auf, aber nicht cellForRowAt indexPath

Wilson Muñoz
quelle