2017-08-20 1 views
0
func loadYelpComments(){ 
     guard let business = business else {return} 
     guard let _ = tableView else {return} 
     guard let businessID = business.id else {return} 
     let dateFormatter = DateFormatter() 
     dateFormatter.dateStyle = .full 

     HTTPHelper.getYelpComments(for: businessID, completionHandler: { data in 
      let json = JSON(data) 
      let reviews = json["reviews"].arrayValue.map({return $0.dictionaryValue}) 
      var commentDate: Date? 


      for (index, review) in reviews.enumerated(){ 
       let userDictionary = review["user"]?.dictionary 
       if let dateString = review["time_created"]?.stringValue{ 
        commentDate = dateFormatter.date(from: dateString) 
       } 

       let yelpComment = YelpComment(rating: review["rating"]?.intValue, userImageURL: userDictionary?["image_url"]?.stringValue, userName: userDictionary?["name"]?.stringValue, comment: review["text"]?.stringValue, commentDate: commentDate, commentPageURL: review["url"]?.stringValue) 

       self.comments.append(yelpComment) 
      } 

      print("Number of comments: \(self.comments.count)") //Prints: Number of comments: 3" 
      self.tableView.reloadData() 

     }) 

      print("Number of comments: \(self.comments.count)") //This prints firt "Number of comments: 0" 

    } 

Die Klassenmethode getYelpComments(for:completionHandler:) ist für das Abrufen von JSON-Daten von der Yelp-API zuständig. Zu meiner Überraschung, obwohl das comments Instanz-Array durch Hinzufügen neuer YelpComment Objekte aktualisiert wird, hat sein count unterschiedliche Werte innerhalb und außerhalb des Verschlusses.Warum hat eine Instanzvariable innerhalb eines Abschlusses einen anderen Wert?

Diese Kommentare sollen in einer Tabellenansicht angezeigt werden. Was mich weiter verwirrt ist die Tatsache, dass, wenn ich tableView.reloadData() innerhalb der Schließung hinzufügen, bekomme ich eine index out of bounds for an empty array Fehler, aber wenn ich die gleiche Codezeile hinzufügen: tableView.reloadData() außerhalb der Schließung bekomme ich keinen Fehler und comments.count gleich Null. Jede Hilfe würde sehr geschätzt werden!

P.S. Ich weiß nicht, ob das Erwähnen etwas bewirken wird, aber data ist @escaping. Ich verwende auch SwiftyJSON und Alamofire.

UPDATE:

Meine Tabellenansicht Datenquelle Methoden sind:

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 

     if section == 0 { 
      return super.tableView(tableView, numberOfRowsInSection: section) 
     } else { 
      return comments.count 
     } 

    } 

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

     if indexPath.section == 0 { 
      return super.tableView(tableView, cellForRowAt: indexPath) 
     } else { 
      let cell = tableView.dequeueReusableCell(withIdentifier: CustomCellTypeIdentifiers.YelpCommentCell, for: indexPath) as! YelpCommentCell 
      cell.configureYelpCell(with: comments[indexPath.row]) 
      return cell 
     } 
    } 
+0

'GetYelpComments' ist ein Async-Aufruf. Print-Anweisung außerhalb von courare wird ausgeführt, bevor der Code in Ihrer Closure ausgeführt wird. Veröffentlichen Sie Ihre 'cellforRow' und' noOfRowsInSection' Methoden, ich denke, diese Methoden verursachen den Absturz. – Bilal

+0

@Bilal aktualisiert meine Frage mit Tabellenansicht Datenquellmethoden. –

Antwort

0

Da die Aufgabe des completion Block ist Ihnen zu melden, wenn das Netzwerk Anruf erfolgt. HTTPHelper ruft einen Server an, was einige Zeit in Anspruch nehmen kann. Es stoppt nicht die Ausführung Ihres Programms und wartet nur auf diese Zeile: es geht sofort zur nächsten Zeile und ruft print("Number of comments: \(self.comments.count)"), und Sie erhalten 0, weil der Netzwerkaufruf noch nicht erledigt ist. Dann passiert etwas später der ganze Block completion.

Dies ist eine asynchrone Funktion, und es stolpert häufig Leute, die es vorher nicht gesehen haben, aber Sie sehen viel davon schließlich, so dass es sich lohnt, auf zu lesen.

Die Tatsache, dass Sie sagen, „wenn ich tableView.reloadData() innerhalb des Verschlusses hinzufügen Ich erhalte eine index out of bounds for an empty array Fehler“, klingt es wie eine Ihrer UITableViewDataSource Funktionen, die die Tabelle konfiguriert (cellForRowAt, numberOfRowsInSection), hat einen Fehler in es irgendwo.

+0

aktualisierte meine Fragen mit meiner Tabellenansicht Datenquellenmethoden. –

0

Verschlüsse werden nicht unbedingt sofort an dem Punkt ausgeführt, an dem Sie sie sehen.

In Ihrem Code wird die print außerhalb der Schließung vor der print innerhalb der Schließung ausgeführt werden. Dies liegt daran, dass getYelpComments eine sogenannte "asynchrone Methode" ist. Während Sie darauf warten, dass die Yelp-Server antworten, sitzt der Code nicht nur da und tut nichts. Es führt fort, den Code nach der Schließung auszuführen und druckt, dass die Zählung 0 ist.

Nachdem Yelp reagiert, wird die Schließung ausgeführt. Und zählen, 3 sein, wird gedruckt.

Warum das Setzen von tableView.reloadData() es zum Absturz bringt, ist wahrscheinlich etwas falsch in Ihren Tabellenansicht Datenquellen Methoden. Es ist höchstwahrscheinlich ein Off-by-1.

Edit:

Ich denke, die Tatsache, dass Sie

if section == 0 { 
    return super.tableView(tableView, numberOfRowsInSection: section) 

seltsam schreiben ist.Ich weiß nicht, warum Sie die super Implementierung zurückgeben möchten, wenn der Abschnitt 0 ist. Hat Ihre Tabellenansicht mehrere Abschnitte? Wenn nicht, sollten Sie den Check wahrscheinlich entfernen. Wenn ja, geben Sie einen Wert für den ersten Abschnitt korrekt zurück.

+0

aktualisierte meine Fragen mit meiner Tabellenansicht Datenquellenmethoden. –

+0

@ A.Jam Siehe die bearbeitete Antwort. – Sweeper

+0

Der erste Abschnitt besteht aus statischen Zellen, deshalb rufe ich super an. Der zweite Abschnitt soll dynamische Zellen enthalten, in denen die Kommentare stehen. –

Verwandte Themen