[Résolu] XMLParser Delegate Crash sur iOS 8

Am_MeAm_Me Membre
septembre 2014 modifié dans API UIKit #1

J'était sur le point de commencer la démarche pour publier mon appli que survint un problème : le problème de dernière minute :


 


Voilà  j'ai voulu tester mon application sur iOS 8 (simulator) tout marche sauf 1 chose : je ne sais pas pourquoi un de mes custom class implémentant XMLParserDelegate (je dis un car je ne sais pas si les autres fonctionne à  100% du coup car je n'ai pas eu le temps de tester : mais ils suivent tous le même modèle) me fait crasher l'application.


 


Pourtant iOS 7 ça marche super bien. J'ai vu que d'autres personnes rencontraient ce problème sur iOS 8 lien et d'autres qui parlent d'ARC qui est la cause de la chose.


 


Pourtant ARC+iOS 7+ParserDelegate = 0 problème chez moi mais avec iOS 8 j'ai l'impression qu'il y a un bog. Voilà  une personne qui remet en cause ARC et trouve la solution : mais j'ai l'impression que la personne a relativement abandonné ARC du coup cela implique que si je veux faire la même chose je vais devoir me taper tout les free() ou plutôt release en Obj-C ???


 


Voilà  l'image du EXC_BADACCESS quand ça crash : 

Réponses

  • Bon visiblement le problème a disparu ... allez savoir pourquoi. Pourtant je n'ai presque rien touché ...


     


    Bon je croise les doigts en attendant.

  • Am_MeAm_Me Membre
    septembre 2014 modifié #3

    Le crash se reproduit de tps à  autres sur iOS 8. Mais c'est pas systématique donc rassurant déjà  ...


     


    Si qqun a une idée en tout cas j'utilise NSURLSessionDataTask et pour passer de string à  NSURL j'utilise urlWithString


  • AliGatorAliGator Membre, Modérateur
    Heu je dirais pas que c'est rassurant, au contraire, les crashs aléatoires sont les moins rassurants, car les plus difficiles à  tracker et donc à  débuguer. Alors que quand ça crash systématiquement et que tu sais exactement comment reproduire le bug, c'est 100x plus facile de le tracker et l'éradiquer.
  • Am_MeAm_Me Membre
    septembre 2014 modifié #5

    Comme décris ci-dessus l'erreur me dit que le XML que je charge a un problème à  la fin ....


    Alors soit NSXMLParser est devenu plus "stricte" sur iOS 8 soit je deviens fou  :o


     


    Bah justement je sais reproduire le problème mais quand j'essaie toujours la même erreur : et l'erreur se produit 1 fois sur 2 sur iOS 8 par exemple et 0 fois sur 10^10^10 sur iOS 7 


     


    J'ai l'impression que ce problème est inresolvable ...


     


    J'ai cru lire sur un site que l'erreur pouvait venir de UrlWithString de NSURL et qu'il faudrait utilise fileWithUrl bref mais bon je n'ai pas fait confiance à  la chose car ce n'est pas logique


  • Am_MeAm_Me Membre
    septembre 2014 modifié #6

    Le truc le plus fou c'est que le problème ne se produit que sur le simulateur iphone 5s iOS 8 et iphone 6 Plus et pas sur les autres ...


     


    Ce n'était qu'une impression au final ... ça crash bien sur tout appareil IOS 8


  • Am_MeAm_Me Membre
    septembre 2014 modifié #7

    Voilà  ce matin j'ai essayé de creuser le problème :


     


    Ce que je ne comprend pas du coup là  c'est que mon 



    - (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError

    et 



    - (void) parserDidEndDocument:(NSXMLParser *)parser

    s'execute quand même et fini bien ce qu'il a à  faire


     


    Donc meme si l'erreur arrive alors parserDidEndDocument s'execute quand même ? ..


    Je comprends toujours pas le pb d'ailleurs j'ai l'IMPRESSION que Xcode me mène vers la mauvaise voie car le XML est correcte ... et j'ai regardé les problèmes similaire en Obj-C, PHP les gens qui ont ça ont leur xml mal formé : il n'ont pas de rootelement (en gros un truc qui englobe tout les autres balises : moi c'est bon de ce côté la ...


     


     


    PS : J'ai l'impression que je le seuil dans le MONDE à  avoir ce problème haha quel chance !


  • Am_MeAm_Me Membre
    septembre 2014 modifié #8

    Si quelqu'un a un parser (asynchrone si possible et qui supporte HTTP) à  me proposer qui soit simple d'utilisation :)


     


    J'ai essayé TBXML : je l'ai inclus dans mon projet : les fichier TBXML font crasher mon appli alors ... j'ai vite abandonné. 


     


    J'utilise ARC


     


    Ou y a-t-il moyen de dire à  NSXMLParser d'être plus coopératif xd : de lui dire d'être moins stricte du coup ... ? (ce problème n'est que sur iOS 8 je signal. je me repète mais iOS 7 il n'y a pas de problème)


    Et sur iOS 8 ça marche mais certaine fois il me retourne cette erreur ... Du coup sur iOS 7 je ne sais pas si c'est fiable à  100% : est-ce que j'ai eu de la "chance" que ça ne crash pas jusque là 


     


     


    _______


     


    MAJ : je ne fait que des tests depuis ce matin et là  je me suis retrouvé avec un file empty ... bref j'ai bien l'impression qu'il a du mal à  faire les requêtes ... pourtant tout est en asynchrone et parfois c'est seulement une petite requête sur iOS qui crash ..


  • Tu devrais essayer de lire un autre xml pour voir ou à  retirer quelques éléments de ton xml afin de t'assurer que ton parser fonctionne correctement. 


  • Lire un autre xml ? Bah en fait je lis des xml sous le mêmes formats mais avec différentes valeurs quoi (c'est pas moi qui les créer mais j'utilise l'api d'un site connu dans le domaine).


     


    Bah il fonctionne pour pas mal de requêtes mais il arrive qu'un requête saute ...


  • Je prépare un fichier xml et je vais le mettre ici pour voir si qqun y voit une erreur 


  • Am_MeAm_Me Membre
    septembre 2014 modifié #12

    #import "MonXmlDelegate.h"

    @implementation MonXmlDelegate

    - (void)setDictionnary:(NSMutableDictionary*)dicF
    {
    groupeObjetDictionnaire = dicF;
    }

    - (void) parserDidStartDocument:(NSXMLParser *)parser {
    currentElement = @noting ....;
    malisteObjets = [[NSMutableArray alloc] init];
    objetCourant = [[CustomObject alloc] init];
    initialiserNouvelObjet = NO;//me permet de savoir si je dois creer un nouvel
    //objet ou non
    if(groupeObjetDictionnaire==nil)
    {
    groupeObjetDictionnaire = [[NSMutableDictionary alloc] init];
    }
    }

    - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
    currentElement = [[NSString alloc] initWithString:elementName];
    }

    -(void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
    if((![currentElement isEqualToString:@""] && [currentElement isEqualToString:@CustomObject]) || initialiserNouvelObjet==YES)
    {
    initialiserNouvelObjet = YES;
    if([currentElement isEqualToString:@id])
    {
    [objetCourant setIdentification:string];
    }
    else if([currentElement isEqualToString:@name])
    {
    [objetCourant setName:string];
    }
    else if ([currentElement isEqualToString:@periodeNumber])
    {
    [objetCourant setPeriodeNumber:string];
    }
    else if([currentElement isEqualToString:@rating])
    {
    [objetCourant setRating:string];
    }
    else if ([currentElement isEqualToString:@lastupdated]) {
    [objetCourant setLastUpdate:string];
    }
    //.... bien entendu j'ai une plus grosse liste de else if
    }
    }

    - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {

    currentElement = @"";
    if([elementName isEqualToString:@CustomObject] && initialiserNouvelObjet==YES)
    {
    if([malisteObjets firstObject]==nil)
    {
    [malisteObjets addObject:objetCourant];
    }
    else if([malisteObjets firstObject]!=nil && [[[malisteObjets firstObject] periodeNumber] isEqualToString:[objetCourant periodeNumber]])
    {
    [malisteObjets addObject:objetCourant];
    }
    else
    {
    [groupeObjetDictionnaire setObject:malisteObjets forKey:[[malisteObjets firstObject] periodeNumber]];
    malisteObjets = [[NSMutableArray alloc] init];
    [malisteObjets addObject:objetCourant];
    }
    //J'en ai fini avec l'objet courant : je me prépare pour le suivant.
    objetCourant = [[CustomObject alloc] init];
    }
    }

    - (void) parserDidEndDocument:(NSXMLParser *)parser {
    NSLog(@parserDidEndDocument);

    //Ca c'est le fait dans le cas ou il y a un dernier objet qui a été stocker :
    //et c'est super important sinon ça ne me l'enregistre pas avant de quitter
    if([malisteObjets firstObject]!=nil)
    [groupeObjetDictionnaire setObject:malisteObjets forKey:[[malisteObjets firstObject] periodeNumber]];

    //JE TIENS à  SIGNALER : que je ne détruit pas l'objet objetCourant ... est-ce la cause du problème ?
    NSLog(@Je passe ici meme 1);
    }

    - (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError {
    NSLog(@MON PARSER : %@",parser);
    NSLog(@ERROR : %@",parseError);
    }

    - (NSMutableDictionary*)getMygroupeObjetDictionnaire
    {
    return groupeObjetDictionnaire;
    }

    @end


  • Am_MeAm_Me Membre
    septembre 2014 modifié #13

    Un petit "image" de à  quoi ressemble mon résultat arrive de suite : 



    <?xml version="1.0" encoding="UTF-8" ?>
    <Data><Toto>
    // la dans la balise il y a des donnees que je ne traite pas ... enfin pas dans ce cas la
    </Toto>
    <Objet>
    <id>42</id>
    <name>Hello</name>
    <periodeNumber>1</periodeNumber>
    <rating></rating>
    <lastupdated>12239392</lastupdated>
    </Objet>
    <Objet>
    <id>54</id>
    <name>Hola</name>
    <periodeNumber>1</periodeNumber>
    <rating></rating>
    <lastupdated>42429392</lastupdated>
    </Objet>
    <Objet>
    <id>89</id>
    <name>Bonjour</name>
    <periodeNumber>2</periodeNumber>
    <rating></rating>
    <lastupdated>12239112</lastupdated>
    </Objet>
    </Data>

    Voila le but est d'avoir un dictionnaire qui ressemble à  ca (la clé est la periodeNumber)


     


    Dico : 



    "1" {
    Objet avec identifiant 42
    Objet avec identifiant 54
    }
    "2" {
    Objet avec identifiant 89
    }


    Mon raisonnement marche mais j'ai peut-être négligé quelques chose


  • Bon j'y suis aller à  la "bourrin" dans la méthode pour récupérer l'erreur j''ai fait appelé la méthode abortParsing du NSXmlParser.


    En même temps elle n'est pas la pour rien ...


     


    Ca ne gene pas l'utilisation de mon application car à  la prochaine ouverture la requête sera renvoyée et vu qu'elle marche 10 fois sur 15 par exemple l'utilisateur verra ses données mise à  jour un moment ou un autre. Et puis la requête je ne la fait que quand lastupdate change dans le xml et il change pas toutes les secondes non plus donc me voilà  un peu plus rassuré du faite que mon application ne crash plus au démarrage quoi ...


     


    Je marque ce problème en Non_Résolu en attendant peut-être que quand tout le monde se sera mis à  iOS 8 peut-être que le problème pourra être corrigé même si ça m'étonne énormément .


     


    En tout cas Merci à  ceux qui m'ont répondu 


  • Am_MeAm_Me Membre
    septembre 2014 modifié #15

    De plus je rajouterai que récemment là  je me tape des document empty document (document vide) sur une requête sur 10 alors qu'il ne l'est pas : vérifié sur Firefox en executant la même URL 



    NSXMLParserErrorColumn=1, NSXMLParserErrorLineNumber=1, NSXMLParserErrorMessage=Document is empty

    De plus je ne peux gérer le XML car il n'est pas fait par moi mais par une API que j'utilise , de plus le XML n'est pas incorrecte mais je pense que le serveur parfois renvoi quelque chose d'incorrect donc voilà  : c'était pour justifier mon abortParsing 


     


    MAJ : abortParsing ne m'aide pas trop au final car ça crash quand même quelques fois ! ...


     


    Je vais migrer vers une API full JSON et plus récente, dans un futur proche


  • Alors j'ai résolu mon problème sans le vouloir  :o    :D    <3    :o </p>

     


    JE suis passé du NSUrlSession + NSUrlSessionDataTask a l'ancienne façon de faire : "ancienne" mais qui marche correctement allez savoir pourquoi ... du coup j'hésite à  passer mes NSUrlSession en NSUrlConnection


    NSString *url = [[NSString alloc] initWithFormat:@"http://www/%@/ficher.xml",API];

    ////NSLog(@Je lance la requete : %@",url);

    NSURLRequest *request = NSURLRequest alloc] initWithURL:[NSURL URLWithString:url;


    NSOperationQueue *queue = [[NSOperationQueue alloc] init];

    [NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {


    //methode qui appel le parseur // sans intérêt ...

    [self updateMyObjectswithData:data];


    completion();

    }];

     


    Ca c'était avant : trouvez l'erreur s'il y en a une. Vous n'êtes pas obligé hein  :P


    NSURLSession *session = [NSURLSession sharedSession];

    NSURLSessionDataTask *task = [session dataTaskWithRequest:request

    completionHandler:

    ^(NSData *data, NSURLResponse *response, NSError *error) {

    [self updateMyObjectswithData:data];


    completion();

    }];

    [task resume];


  • Alors j'ai compris le pourquoi du comment : Cf une thread que j'ai créer sur le forum de dev apple : https://devforums.apple.com/message/1047727#1047727


     


    En fait apparemment des développeurs n'arrive pas à  lancer des connexion HTTP sur Safari carrément du coup c'est peut-être le simulateur qui est buggé :/


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