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" 

    } 

La méthode de classe getYelpComments(for:completionHandler:) est chargée d'extraire les données JSON de l'API Yelp. À ma grande surprise, même si le tableau d'instance comments est mis à jour en y ajoutant de nouveaux objets YelpComment, son count a des valeurs différentes à l'intérieur et à l'extérieur de la fermeture.Pourquoi une variable d'instance a-t-elle une valeur différente à l'intérieur d'une fermeture?

Ces commentaires sont supposés être affichés dans une vue de tableau. Ce qui m'embarrasse encore, c'est que quand j'ajoute tableView.reloadData() dans la fermeture, j'obtiens une erreur index out of bounds for an empty array mais quand j'ajoute la même ligne de code: tableView.reloadData() de l'autre côté de la fermeture, je n'obtiens aucune erreur et comments.count équivaut à zéro. Toute aide serait très appréciée!

P.S. Je ne sais pas si mentionner cela va faire une différence, mais data est @escaping. J'utilise également SwiftyJSON et Alamofire.

MISE À JOUR:

Mon point de vue de la table des méthodes de source de données sont les suivantes:

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' est un appel asynchrone. L'instruction d'impression en dehors de cloure s'exécute avant que le code de votre fermeture s'exécute. Publiez vos méthodes 'cellforRow' et' noOfRowsInSection', je pense que ces méthodes causent l'accident .. – Bilal

+0

@Bilal mis à jour ma question avec les méthodes de source de données vue table. –

Répondre

0

Parce que le travail du bloc completion est à vous signaler lorsque l'appel du réseau est effectuée. HTTPHelper appelle un serveur, ce qui peut prendre beaucoup de temps. Cela n'empêche pas votre programme de s'exécuter, et attendez juste à cette ligne: il passe immédiatement à la ligne suivante et appelle print("Number of comments: \(self.comments.count)"), et vous obtenez 0, car l'appel réseau n'est pas encore terminé. Ensuite, quelque temps plus tard, ce bloc entier completion se produit.

Ceci est appelé une fonction asynchrone , et il fait souvent trébucher les gens qui ne l'ont pas vu auparavant, mais vous en voyez beaucoup à la fin, donc ça vaut le coup de lire.

Le fait que vous dites « quand j'ajoute tableView.reloadData() dans la fermeture, je reçois une erreur index out of bounds for an empty array », il sonne comme un de vos fonctions de UITableViewDataSource qui configure la table (cellForRowAt, numberOfRowsInSection), a une erreur quelque part.

+0

a mis à jour mes questions avec mes méthodes de source de données de vue de table. –

0

Les fermetures ne sont pas nécessairement exécutées immédiatement à l'endroit où vous les voyez.

Dans votre code, le print en dehors de la fermeture sera exécuté avant le print à l'intérieur de la fermeture. C'est parce que getYelpComments est ce qu'on appelle une "méthode asynchrone". Pendant que vous attendez que les serveurs de Yelp répondent, le code ne reste pas là à ne rien faire. Il continue à exécuter le code après la fermeture, en imprimant que le compte est 0.

Après que Yelp a répondu, la fermeture est exécutée. Et compte, étant 3, est imprimé. Pour ce qui est de savoir pourquoi mettre tableView.reloadData() provoque un plantage, il y a probablement quelque chose qui ne va pas dans les méthodes de la source de données de votre vue table. Il s'agit probablement d'un off-by-1.

Edit:

Je pense que le fait que vous écrivez

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

est bizarre.Je ne sais pas pourquoi vous souhaitez renvoyer l'implémentation super si la section est 0. Votre vue de table comporte-t-elle plusieurs sections? Sinon, vous devriez probablement supprimer la vérification. Si oui, alors renvoyez correctement une valeur pour la première section.

+0

a mis à jour mes questions avec mes méthodes de source de données de vue de table. –

+0

@ A.Jam Voir la réponse éditée. – Sweeper

+0

La première section est composée de cellules statiques, c'est pourquoi j'appelle super. La deuxième section est destinée à avoir des cellules dynamiques où les commentaires vont être. –