Updater la tableView d'un UIViewController à  partir d'une autre classe

CoolsinusCoolsinus Membre
mai 2013 modifié dans API UIKit #1

Bonjour à  tous ! 


 


Voici le premier message que je post sur ce forum qui m'a l'air fort plaisant ma foi ! 


 


Alors voilà  : je suis en train de créer une application telle que Contacts, sauf que j'ai un petit problème. J'ai une subclass d'un UIViewController qui s'appelle CreateContactViewController (j'importe le UITableViewDelegate&DataSource), et jai un outlet pour ma tableView qui s'appelle..tableView !  :D


 


Ensuite, dans cette classe, j'ai d'autres properties, et notamment des arrays qui servent de DataSource pour ma tableView. J'ai crée une subclass de UITableViewCell que j'ai nommée CreateContactCell, qui est la classe des cellules de ma tableView. Cette classe a en entre autres deux outlets : un Label, et un TextField (pour que l'utilisateur entre ses informations).


 


Ce que je veux faire, c'est que dès que l'utilisateur commence à  entrer des données dans une cellule (= dès qu'il commence à  écrire), une autre cellule apparaisse. 


J'ai donc ajouté le UITextFieldDelegate à  CreateContactCell pour être en mesure d'ajouter une cellule dès que l'utilisateur commence à  éditer.


 


Voici le problème : dans les IBAction whatever qui réagissent aux évènements, je dois pouvoir ajouter les nouvelles cellules à  ce moment là . Or, le problème est que je dois pouvoir accéder au DataModel conservé dans les properties de mon CreateContactViewController, sauf qu'avec les Class Methods, c'est impossible, et que si je crée une instance de CreateContactViewController, les properties n'aura pas de données, car c'est une nouvelle instance...


 


J'ai donc cherché sur internet, et là  j'ai vu sur stackoverflow que je pouvais créer une property navigationController dans mon AppDelegate, et utiliser la property visibleViewController. J'ai donc fait comme cela : 


 


AppDelegate.m :



- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.navigationController = (UINavigationController *)self.window.rootViewController;
return YES;
}


-(CreateContactViewController *)visibleViewController
{
CreateContactViewController *controller = nil;

if ([self.navigationController.visibleViewController isKindOfClass:[CreateContactViewController class]]) {
CreateContactViewController *controller = (CreateContactViewController *)self.navigationController.visibleViewController;
} else {
CreateContactViewController *controller = nil;
}

return controller;
}


CreateContactCell.m : 



-(void)textFieldDidBeginEditing:(UITextField *)textField
{
NSLog(@editingBegan:);

[CreateContactViewController checkIfDeletingRowsIsNeededAtSection:self.indexPath.section]; // check if other blank cells are out there : if yes : needs to be deleted

if ([textField.text isEqualToString:@""]) {
self.blankCell = YES;
self.firstEdition = YES;
} else {
self.blankCell = NO;
self.firstEdition = NO;
}
}

- (IBAction)editingChanged:(UITextField *)sender
{
NSLog(@editingChanged:);

if (self.isBlankCell && self.isFirstEdition) {
self.blankCell = NO;
self.firstEdition = NO;

[CreateContactViewController insertRowAtSection:self.indexPath.section]; // call methode to add new cell and check if no other is blank
}
}


CreateContactViewController.m



+(void)insertRowAtSection:(NSInteger)section
{
CreateContactViewController *controller = nil;
id deletage = [[UIApplication sharedApplication] delegate];
if ([deletage performSelector:@selector(visibleViewController)]) {
controller = (CreateContactViewController *)[deletage visibleViewController];
}

NSLog(@%@", [[[[controller.arrayOfCellsWithTextValues.cells objectAtIndex:section] objectAtIndex:0] field] text]);
}



Le problème c'est que cette dernière ligne de code me renvoi (null).


 


Ainsi donc je vous demande, quelle est la meilleur approche pour pouvoir modifier le Data Model d'une autre classe pour ensuite pouvoir updater ma tableView en y ajoutant une cellule ? 


 


Merci d'avoir pris le temps de me lire.


 


Hugo  :D


Réponses

  • CéroceCéroce Membre, Modérateur


     


    Ainsi donc je vous demande, quelle est la meilleur approche pour pouvoir modifier le Data Model d'une autre classe pour ensuite pouvoir updater ma tableView en y ajoutant une cellule ? 




    La bonne méthode est de passer l'objet nécessaire, c'est à  dire lui transmettre un pointeur sur l'objet nécessaire, par exemple en déclarant une propriété dans le contrôleur destinataire.


     


    Ta question sous-jacente est " Comment accéder au contrôleur 2 depuis le contrôleur 1 ?" et la réponse est qu'en général on n'y accède pas. En effet, si on respecte bien le MVC, les changements sont appliqués au modèle.


     


    Reste donc une question: " comment savoir que le modèle a changé " ? Je ne vais pas trop m'étendre sur le sujet, évoqué maintes fois, mais en gros, voici les techniques par ordre de préférence:


     


    1. Délégation


    2. Key-Value Observing


    3. Notifications

  • Am_MeAm_Me Membre
    mai 2013 modifié #3

    Comme explique par ceroce il faut essayer de respecter le modele MVC ou IHM


     


    Pour le 2.Key-Value Observing 


     


    utilise cette fonction 



    -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context

    keyPath est la string que tu envoi genre ca peut etre : creerContact , supprimerContact en fait ca depend ce que tu veux faire faire a la vue avec l'observeur 


  • Bonjour,


     


    Désolé de répondre si tardivement, mais j'ai eu les épreuves anticipées du bac donc pas eu le temps de programmer...mais merci pour vos réponses !


     


    @Céroce : Vous voilà  en gros je veux accéder à  un viewController à  partir d'une autre classe, mais le problème c'est que la seule manière de modifier une tableView est à  partir du ViewController lui même et non pas du Model. 


     (et à  @Am_Me) : Donc vous me proposez d'attendre de voir si le Model est modifier pour ensuite à  l'interieur du Controller remarquer ce changement et faire des modifications de la View en conséquence ?


     


    C'est bien ça ? Et donc pouvez-vous me donner un exemple d'implémentation de la méthode ci-dessus ? :)


     


    Merci !


  • AliGatorAliGator Membre, Modérateur
    Il y a des exemples d'implémentations (et les explocations détaillées) dans le Programming Guide qui parle du KVO dans la doc Apple ;)
  • Am_MeAm_Me Membre
    juillet 2013 modifié #6

    Dans ta fonction init :



    [self->objetDeMaClasse addObserver:self forKeyPath:@maMission options:NSKeyValueObservingOptionNew context:NULL];

    le petit truc magique c'est NSKeyValueObservingOptionNew qui comme sont nom l'indique detecte les changements. Alors je sais pas si c'est du MVC Push ou Pull (Je dirais plus pull). 


     


    Dans ton observer 



    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
    {
        if ([@maMission isEqualToString:keyPath] && object == self->objetDeMaClasse) {
            //update ta table
        }
    }

    J'ai été gentil et encore (ce n'est peut etre pas la meilleur facon de faire qui sait :P ) ;D. Va faire un tour sur le Programme guide que te conseil Aligator.


  • CoolsinusCoolsinus Membre
    juillet 2013 modifié #7

    Okay, donc j'ai lu l'intro du programming guide du KVO, et en gros le KVO dans mon cas : 


     


    Dès que on commence à  remplir une Cell, j'incrémente une property quelconque (disons numberOfCellsNeeded). Je set ma TableViewController comme étant observer de ma property, et des que y'a un changement, je suis à  même de modifier mon Data contenu dans une property de mon TableViewController et ainsi d'update ma tableView en conséquence ?


     


    :)


     


    EDIT : autre petite question hors contexte mais qui me tracasse : quelle est la différence entre self.myProperty et _myProperty ? 




  •  


    EDIT : autre petite question hors contexte mais qui me tracasse : quelle est la différence entre self.myProperty et _myProperty ? 




     


    Aucune si je ne dis pas de bêtises :D

  • Plop.


    Une p'tite case sur le forum de présentation pour connaà®tre ton background ?


  • AliGatorAliGator Membre, Modérateur
    juillet 2013 modifié #10


    Aucune si je ne dis pas de bêtises  :D




    Si, une grosse bétise !


     


    x = self.myProperty est l'équivalent de x = [self myProperty]


    self.myProperty = x est l'équivalent de [self setMyProperty:x]


     


    Or [self setMyProperty:] appelle donc la méthode setter de ta propriété


    • Si cette propriété est synthétisée par le compilateur (et que ce n'est pas toi qui l'écrit mais le compilo), ça va certes modifier la variable d'instance _myProperty associée, mais ça va aussi générer les évènements de KVO (willChangeValueForKey:/didChangeValueForKey:) permettant d'utiliser le mécanisme de KVO justement (sans ça les observeurs ne seraient pas notifiés), gérer l'atomicité de l'accès (mutex pour protéger les accès concurrents à  la variable) si ta propriété n'est pas marquée comme nonatomic, et si tu n'es pas en ARC mais que ta propriété est retain ou copy, ça va se charger du release de l'ancienne valeur et du retain ou copy de la nouvelle valeur.

       


    • Si cette méthode de setter est implémentée par tes soins, bah ça va l'appeler tout pareil, et de la même manière bah ça dépend de ce que tu fais dans cette méthode, mais y'a des chances que tu ne vas pas te contenter de juste faire un _myProperty = nouvellevaleur mais faire d'autres choses (sinon aucun intérêt de l'implémenter toi-même plutôt que laisser le compilo le faire pour toi)
  • Tiens :/


    Belle explications comme quoi s'était une grosse bêtise mais tant mieux


  • @Am_Me : Apparemment si ! :D


    @Larme : Ouai je vais poster un message de présentation dans la section appropriée, sinon tu as pu me voir sur les forums MacG ;)


    @AliGator : D'accord, bon j'ai pas tout compris en ce qui concerne les évènement de KVO, mais certes il est inutile d'écrire ses propres setter si au final c'est le même code que lorsque le compilateur le fait ;) 


    Donc en gros dans le cas self.myProperty = x, on peut utiliser _myProperty = x, mais pas dans le cas x = self.myProperty, est-ce bien cela ? 


    Mais pourquoi lorsque le compilateur synthesize les properties, pourquoi utilise t-il _myProperty et non self.myProperty ? Est-ce une bonne pratique de programmation en Objective-C ?


     


    :)


  • AliGatorAliGator Membre, Modérateur


    Donc en gros dans le cas self.myProperty = x, on peut utiliser _myProperty = x, mais pas dans le cas x = self.myProperty, est-ce bien cela ?

    Hein ?! Heu non ca serait plutôt tout l'inverse (et encore si le getter n'émet pas de notif de KVO puisque la valeur ne change pas, il gère quand même l'atomicité de l'accès à  la variable don pour une variable atomic c'est quand même pas la même chose d'utiliser le getter plutot qu'un accès direct à  l'ivar !!)

    Mais pourquoi lorsque le compilateur synthesize les properties, pourquoi utilise t-il _myProperty et non self.myProperty ? Est-ce une bonne pratique de programmation en Objective-C ?

    pas compris la question.


    Ceci dit ces questions sur propriété vs ivar etc c'est du grand classique on en a déjà  parlé plusieurs fois sur les forums, je t'invite à  faire une recherche parce que j'ai un peu la flemme de répéter mon explication détaillée de 3km et les liens vers la doc Apple :P
  • Ouai j'ai trouvé dans choses sur le forum mais tout le monde se contredit... :p Pourrais-tu me donner le lien de la doc Apple stp ? 


    Sinon qu'est ce qu'une variable d'instance ? Est-ce : 



    @interface Foo : NSObject
    {
    Object *instanceVariable;
    Object2 *instanceVariable2;
    }

    Parce que je cherche sur internet et les forums mais c'est juste pas clair..


  • AliGatorAliGator Membre, Modérateur
    juillet 2013 modifié #15
    T'as déjà  ça DevPedia, Cocoa Core Competencies : Declared Property
    qui mène (lien tout en bas) vers le Programming Guide bien plus complet "Programming with Objective-C" : Encapsulating Data
  • Okay merci :)


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