Problème OHAlertView

Bonjour  


 


J'ai un souci avec OHAlertView :  




[OHAlertView showAlertWithTitle:NSLocalizedString(@title.leverAlert.confirm,nil) message:NSLocalizedString(@mess.leverAlert.confirm, nil) cancelButton:@Cancel otherButtons:@[;@Ok] onButtonTapped:^(OHAlertView *alert, NSInteger buttonIndex) {
                if (buttonIndex == 1) {
                    TMAEvent * event = [[TMAEvent alloc] init];
                    event.courseStatus = TMACourseStatusRunning;
                    event.timeStamp = [NSDate date];
                    [self.course addEvent:event];
                    [self.course save];
                    [self majStatus];
                }
            }];

 

 

Si je mets un point d'arrêt sur TMA Event, un 'PO' dans la console me dit : 

 

(lldb) po self

error: warning: Stopped in a context claiming to capture an Objective-C object pointer, but 'self' isn't available; pretending we are in a generic context

error: use of undeclared identifier 'self'

error: 1 errors parsing expression

 

 


Comment faire pour avoir le self svp ? 


 


Alex. 


Réponses

  • AliGatorAliGator Membre, Modérateur

    Hello


     


    Ce n'est pas un problème avec OHAlertView en particulier, c'est un "problème" dus au fonctionnement des blocks. Ou plutôt une incompréhension de ta part sur le fonctionnement réel des blocks en Objective-C.


     


    Un block n'est en fait pas grand chose d'autre qu'un pointeur de fonction (vers une fonction C, pas une méthode) associée à  un contexte (une structure contenant les variables capturées et que tu utilises à  l'intérieur de ton block). Dans ce cadre, les mots clés comme "self" n'ont pas de sens, puisque dans le code à  l'intérieur du block tu es un peu comme dans une fonction C. C'est donc normal que si tu fais "po self" il ne le trouve pas. Le "self" en question a été capturé par le block (par le compilateur qui l'a passé dans le contexte du block) pour que le code du block, utilisant self, puisse s'exécuter, mais le débuggeur ne connais pas de variable interne "self" directement.


    (A la limite il y a sans doute accès via un truc genre blockcontext.self, en imaginant que blockcontext représente la structure contenant tout le contexte nécessaire au block et les variables capturées, mais bon après je ne me rappelle plus dans les détails comment sont implémentés les blocks sous le capot pour savoir où sont accessibles ces variables)


     


    Le plus simple si tu veux vraiment avoir "self", c'est de le copier dans une variable interne au block. De toute façon en général ce n'est pas plus mal en particulier pour du code dans un block qui se trouve être retenu par self (car si le block est retenu par self " directement ou indirectement via un objet qui retient le block et qui est retenu par self par exemple " tu auras un retain cycle avec self retenant le block et le block retenant self par capture de variable...) de s'assurer d'éviter un retain cycle ou de retenir inutilement trop longtemps certains objets, en stockant self dans une variable "__weak typeof(self) weakSelf = self;" (une weak reference, référence faible), et utiliser weakSelf plutôt que self pour éviter que le block ne retienne self et d'avoir un retain cycle.


     


    Que tu fasses une weak reference de self et l'utilise dans ton block pour éviter que le block ne retienne self, ou que tu utilises self directement car tu n'as pas cette problématique de retain cycle (et à  mon avis dans ton cas tu n'as pas le pb donc c'est bon), le débuggeur ne saura t'afficher avec la commande "po" que les variables internes au block, voyant le block comme une fonction C, avec des paramètres et des variables locales. Donc il n'est pas assez intelligent pour que si tu fasses un "po self", il aille chercher "self" dans le contexte passé implicitement sous le capot au block. Il y a peut-être un moyen d'accéder à  la structure interne du block contenant les variables capturées, genre pour pouvoir faire "capturedvariables.self" mais si ça existe je ne l'ai pas en tête. Donc le plus simple si tu veux accéder à  la variable via le debuggeur, c'est de créer une variable locale dans ton block à  qui tu affectes self (genre "typeof(self) localself = self;" et d'accéder à  cette variable localself, car ça le débogueur saura te l'afficher ensuite.


  • al33eral33er Membre

    Merci beaucoup Ali, 


     


    Mon problème venait du fait que je ne voyais pas le self avec po et donc je pensais qu'il n'était pas renseigné or il l'est bien. Or mon problème venait en fait que j'appelai un fonction dans le block qui devait absolument fonctionner dans le mainThread. 


     


    Je fais donc un self performSelectorOnMainThread dans le block. 


     


    Merci. 


  • AliGatorAliGator Membre, Modérateur
    mai 2013 modifié #4

    C'est bizarre, normalement si tu as appelé ton "showAlertWithTitle:..." dans le main thread, comme tu dois le faire car tout ce qui touche à  l'UI doit être appelé sur le main thread absolument, normalement il me semble que le block est appelé sur le même thread " et donc le main (puisqu'il est appelé dans la méthode de delegate "alertView:clickedButtonAtIndex:" de UIAlertViewDelegate qui normalement est appelée sur le même thread que celui sur lequel tu as appelé le "show", il ne me semble pas qu'il y ait de cas spécial ici).


     


    Du coup ce n'est pas normal si ton show et/ou block n'est pas appelé sur le main thread (tu as essayé de faire un NSLog(@thread: %@ (main?%d)", [NSThread currentThread], [NSThread isMainThread]) pour vérifier ?)


     


    Bon et sinon si tu as vraiment besoin de forcer l'exécution sur le main thread, perso je préfère l'usage de GCD avec "dispatch_async(dispatch_get_main_queue(), ^{ /* ton code */ })" plutôt que performSelectorOnMainThread (qui impose de mettre le code dans une méthode séparée)


  • Tant qu'on y est je voulais te dire merci pour les 2 classes que j'utilise tous les jours. Je comprends pas pourquoi Apple ne propose toujours pas un truc aussi simple.


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