2010-09-26 16 views
1

J'ai reçu un rapport d'erreur d'Apple et j'essaie de déterminer ce qui s'est passé. Je n'ai pas été capable de recréer le crash en suivant leurs pas et je n'ai pas vu un crash similaire dans mes tests. Voici les parties importantes du rapport d'accident:Comment cet objet est-il prématurément publié?

9 libobjc.A.dylib     0x00004838 objc_exception_throw + 64 
10 CoreFoundation     0x000a167c -[NSObject(NSObject) doesNotRecognizeSelector:] + 96 
11 CoreFoundation     0x000491d2 ___forwarding___ + 502 
12 CoreFoundation     0x00048f88 _CF_forwarding_prep_0 + 40 
13 TheApp       0x0001cd28 -[Tumblelog initWithDictionary:] (Tumblelog.m:40) 
14 TheApp       0x0001ef8c -[TumblrEngine userFromRequest:] (TumblrEngine.m:589) 

Cela me semble que mon dictionnaire est libéré prématurément. Ce chemin de code est appelé plusieurs fois au cours de la plupart des exécutions de l'application et il n'a pas encore planté pour moi, donc je suis confiant que je ne vais pas envoyer accidentellement le mauvais objet à initWithDictionary.

Voici le code de TumblrEngine et Tumblelog.

// TumblrEngine.m 
- (TumblrUser *)userFromRequest:(ASIHTTPRequest *)request{ 
    NSData *data = [request responseData]; 
    NSError *parseError = nil; 
    NSXMLDocument *doc = [[[NSXMLDocument alloc] initWithData:data options:NSXMLDocumentTidyXML error:&parseError] autorelease]; 
    NSDictionary *dictionary = [doc toDictionary]; 
    NSDictionary *userDict = [dictionary valueForKeyPath:kParseKeyPathUserInfo]; 
    TumblrUser *user = [[TumblrUser alloc] initWithDictionary:userDict]; 
    NSArray *tumblelogs = [dictionary valueForKeyPath:kParseKeyPathTumblelogsInfo]; 
    NSMutableArray *userTumblelogs = [NSMutableArray array]; 
    for(NSDictionary *tumblelogDictionary in tumblelogs){ 
     Tumblelog *tumblelog = [[Tumblelog alloc] initWithDictionary:tumblelogDictionary]; //line 589 
     [userTumblelogs addObject:tumblelog]; 
     [tumblelog release]; 
    } 
    [user setTumblelogs:userTumblelogs]; 
    return [user autorelease]; 

} 

// Tumblelog.m 
- (id)initWithDictionary:(NSDictionary *)aDictionary{ 
    if((self = [super init])){ 
     [self setAvatarURL:[aDictionary restURLForKey:kParseKeyTumblelogAvatarURL]]; //line 40 
     // this was the line that started the crash 
    } 
    return self; 
} 

Ma principale question est la suivante: vous voyez comment il serait possible aDictionary d'être libéré à tout moment entre le moment où il est créé et quand je tente de l'utiliser dans Tumblelog.m?

Sinon, j'explore si un problème est survenu lors du chargement de la catégorie sur NSDictionary. Cela fonctionne bien lorsque je charge directement l'application sur mes trois téléphones de test (iPhone 4/iOS 4.1, iPhone 3GS/iOS 4.0.1, iPhone 3G/3.1.3). Le téléphone sur lequel l'application s'est écrasée était iPhone 4/iOS 4.1, identique à mon téléphone de test principal.

Seule une autre chose que je peux penser est peut-être quelque chose dans le binaire que j'ai envoyé Apple a été corrompu. Je doute que ce soit la réponse, puisque ces binaires sont vérifiés, mais je suis à court d'idées ici. Je ne veux pas juste resoumettre si ça va se bloquer à nouveau sur le téléphone du testeur.

+2

Dommage que vous ne puissiez pas recréer le crash. Il me semble à partir de la trace de la pile qu'il est plus probable que quoi que vous passiez - [Tumblelog initWithDictionary:] n'est pas réellement un NSDictionary. Ensuite, cette méthode appelle une méthode NSDictionary, provoquant une exception «ne reconnaît pas le sélecteur». Êtes-vous sûr que chaque objet du tableau tumblelogs est toujours un NSDictionary (c'est-à-dire que la valeur de la clé kParseKeyPathTumblelogsInfo dans doc toDictionary est toujours un tableau de NSDictionaries)? –

+0

Je ne suis pas familier avec NSXMLDocument toDictionary (et ne trouve pas docs?) Pour le savoir, mais est-il garanti que '[dictionary valueForKeyPath: kParseKeyPathTumblelogsInfo]' va retourner un NSArray d'instances NSDictionary? Vous ne faites AUCUNE détection d'erreur du tout que les données entrantes se conforme au XML que vous attendez. – imaginaryboy

+0

Très bons points. Recevoir des données de réponse formatées différemment de ce à quoi je m'attendais pourrait certainement être le problème. Je prévois d'ajouter une vérification d'erreur comme @imaginaryboy suggéré. Dans des circonstances normales, les réponses XML mal formées ne seront pas si profondes dans le code, elles auront été détectées beaucoup plus tôt. Ce qui me préoccupe, c'est que ce n'est pas le problème et je vais simplement soumettre à nouveau une application qui sera à nouveau rejetée. – kubi

Répondre

1

Cela pourrait être un problème de threading (où les objets sont publiés sur un autre thread), mais cela semble vraiment improbable avec le code ci-dessus.

Il est beaucoup plus probable (comme le dit @imaginaryboy) que vous n'ayez pas vraiment de dictionnaire.

Une boucle beaucoup plus sûre ressemblerait à ceci.

for(id tumblelogDictionary in tumblelogs){ 
    if ([tumblelogDictionary isKindOfClass:[NSDictionary class]]) { 
     Tumblelog *tumblelog = [[Tumblelog alloc] initWithDictionary:tumblelogDictionary]; //line 589 
     [userTumblelogs addObject:tumblelog]; 
     [tumblelog release]; 
    } else { 
     // Appropriate error handling and/or logging. 
    } 
} 

REMARQUE: je n'ai pas réellement essayé de compiler ceci. Il peut avoir une faute de frappe ou une erreur de syntaxe ou deux.

+0

Merci. Dans ce cas, il suffit de vérifier si j'ai un dictionnaire dans le tableau. À moins que quelqu'un d'autre ait des idées, la seule façon d'atteindre ce point sans recevoir un tableau de dictionnaires est d'obtenir du HTML mal formé à partir du serveur.Si c'est le cas, laisser le tumblelog vide serait un résultat acceptable. – kubi