[Swift] Accéder à  UITableViewController depuis la classe UITableViewCell

CusmarCusmar Membre
juillet 2015 modifié dans API UIKit #1

Bonjour,


 


J'ai l'impression d'abuser sur les questions, mais à  mon avis c'est un truc tout simple mais impossible de trouver la réponse sur Google, et débutant, je maà®trise pas trop les superview, superclass, etc.. Mes recherches m'orientent vers l'utilisation de NSNotification pour passer de ma classe contenant ma cellule à  la classe UITableViewController.


 


Pour donner mon exemple, j'ai un bouton dans ma classe UITableViewCell, et je voudrais que lorsqu'il est cliqué, il recharge toute la classe UITableViewController (je modifie des éléments de d'autres cellules), à  l'aide de reloadData() entre autre.


 


J'ai tout essayé avec ce que je trouvais sur Stackoverflow, et c'est là  que j'ai vu une solution de passer par NSNotification. Mais je voulais m'assurer qu'il n'y ait pas quelque chose d'aussi simple que :


l



self.tableView.reloadData()

l


J'ai essayé de remplacer self par le nom de ma classe UITableViewController et j'ai fait toutes sortes d'essais, dont entre autres :


l



NomDeMaClasse.tableView.reloadData()

UITableView.reloadData(NotesTableViewController)

var parentTable = self.superview
parentTable.reloadData()

l


Merci beaucoup !


Réponses

  • jpimbertjpimbert Membre
    juillet 2015 modifié #2



    NomDeMaClasse.tableView.reloadData()



     


    tableView est une propriété d'instance, alors que NomDeMaClasse.tableView va chercher une propriété tableView pour la classe NomDeMaClasse, et pas pour une instance.


     


    Pour UITableView.reloadData(), c'est pareil. Tu lui demandes d'appeler une méthode de classe alors que reloadData() est une méthode d'instance.


     


    Pour l'appel à  la superVue, y'a de l'idée. Mais le problème est que Cocoa va générer tout un tas de vues intermédiaires entre la tableView et la cellView.


     


    Une notification devrait résoudre le problème.


     


    Une autre solution en peu plus complexe est de dériver UITableViewCell et de lui mettre un outlet vers la vue en table.  


  • AliGatorAliGator Membre, Modérateur
    La solution de la notification est quand même de l'overkill car ça va crier sur tous les toits qu'il faut recharger, dans toute ton appli. Ce n'est pas vraiment adapté à  ton usage local.


    Les solutions envisageables seraient plutôt :

    1) soit au lieu d'appeler directement cell.superview une seule fois, l'appeler jusqu'à  ce que cette superview soit de type UITableView, au cas où iOS insère des vues intermédiaires entre la tableview et ses cells. Et caster le résultat en UITableView pour pouvoir avoir le droit d'appeler reloadData() dessus sinon évidemment ça ne va pas marcher.

    // code dans ta sous-classe de UITableViewCell
    var parentTableView : UITableView? {
    var parentView : UIView? = self
    while (parentView = parentView.superview) != nil {
    if let tableView = parentView as? UITableView {
    return tableView
    }
    }
    return nil
    }

    ça reste un peu archaà¯que et violent comme solution pour accéder à  la tableView parente d'une cell quand même.


    2a) soit de sous-classe UITableViewCell pour lui rajouter un IBOutlet ou même une simple propriété (var) vers ta tableView. Et quand tu crées ta cellule dans tableView(_:cellForRowAtIndexPath:) tu affectes cette propriété. Jouable, mais pas idéal quand même car liaison un peu trop forte entre les 2 objets


    2b) Pareil que 2a mais avec une propriété vers ton UIViewController au lieu de vers ta tableView. Pas beaucoup mieux que 2a voire pire en terme de dépendance forte


    3) au lieu de 2a ou 2b, tu fais un delegate, c'est à  dire que comme pour 2a ou 2b, tu rajoutes une propriété à  ta sous-classe de UITableViewCell... mais cette propriété sera de type "MyTableViewCellDelegate", que tu déclares auparavant comme étant un "protocol" qui va définir une fonction genre "didUpdateData". Tu fais conformer ton UITableViewController à  ce protocole dans sa déclaration, tu implémentes la méthode "didUpdateData" de sorte qu'elle fasse le "self.tableView.reloadData()", et quand tu crées tes cells tu affectes leur propriété delegate à  ton UITableViewController. Et quand tu fais ton action qui nécessite de mettre ajout toute ta table, tu appelles self,delegate?.didUpdateData() pour déclencher le refresh.


    Cette solution 3 pourrait presque ressembler à  la solution 2b mais avec une différence majeure c'est qu'en passant par un protocole tu fais un couplage faible entre tes cellules et ton UITableViewController. Ce qui change tout côté flexibilité, séparation des responsabilités et architecture de ton code.


    Tu es aussi avec cette dernière solution plus proche d'un modèle MVC, où ca ne doit pas être la vue (UITableViewCell) qui met à  jour le modèle (les données) mais plutôt le Controlleur (UIViewController).


    En fait la bonne solution serait même plutôt une solution 4 qui ferait comme la solution 3 mais où la méthode déclarée dans le protocole MyTableViewCellDelegate s'appellerait plutôt "didTapOnButton(indexPath : NSIndexPath)", et l'IBAction liée au bouton de ta cellule se contenterait d'appeler "self.delegate?.didTapOnButton(self.indexPath)" et rien d'autre. C'est alors de la responsabilité du delegate de la cellule, qui sera en l'occurrence ton UIViewController, de faire " dans son implémentation de "didTapOnButton()" " les modifications nécessaires correspondantes dans le modèle (tes données) et d'appeler sel.tableView.reloadData() dans la foulée. Ainsi c'est bien MVC avec le ViewController qui modifie le modèle (les données) puis rafraà®chit la vue – et non pas la vue qui modifie le modèle.
  • CusmarCusmar Membre
    juillet 2015 modifié #4

    Merci beaucoup pour vos réponses.


     


    Je comprends un peu mieux pourquoi ça ne marchait pas, et j'avais testé quelque chose de semblable à  la solution 3 mais sans aller jusqu'au bout.


     


    Dans ma classe UITableViewController, j'avais mis :


    l



    func reloadTable() {
        self.tableView.reloadData()
    }

    l


    Et dans UITableViewCell, j'avais appelé cette fonction :


    ll



    NomDeMaClasse().reloadTable()

    l


    Mais bon maintenant je ne m'étonne plus que ça n'ait pas fonctionné.


     


    Je vais tester la dernière solution que tu as proposé.


Connectez-vous ou Inscrivez-vous pour répondre.