2010-04-22 5 views
0

J'ai créé une application graphique qui appelle un service Web. L'utilisateur peut zoomer & se déplacer dans le graphique, et le programme prend parfois la décision d'appeler le service Web pour plus de données en conséquence. Ceci est réalisé par le processus suivant:Problème de gestion de mémoire Objective-C

Le graphe a une boucle de rendu qui restitue en permanence le graphe, et une certaine logique de décision qui ajoute des informations d'appel de service Web à une pile. Un thread séparé extrait les informations d'appel de service Web les plus récentes de la pile et l'utilise pour effectuer l'appel de service Web. Les autres objets de la pile sont regroupés. L'idée est de réduire le nombre d'appels de service Web uniquement aux appels appropriés, et un seul à la fois.

droit, avec la longue histoire de la route (pour laquelle je présente mes excuses), voici mon problème de gestion de la mémoire:

Le graphique a le caractère persistant (et convenablement verrouillé) NSDate * objets pour le début affiché & les temps de fin du graphique. Ceux-ci sont passés dans les initialisers pour mes objets de demande de service Web. Les objets d'appel de service Web conservent alors les dates. Une fois les appels de service Web terminés (ou annulés s'ils étaient obsolètes), ils libèrent le NSDate *.

Le graphique lui-même libère et réaffecte de nouveaux NSDates * sur l'événement 'touches terminées'. S'il n'y a qu'un seul objet d'appel de service Web sur la pile lorsque removeAllObjects est appelé, EXC_BAD_ACCESS se produit dans la méthode de désallocation de l'objet d'appel de service Web lorsqu'il tente de libérer les objets date (même s'ils semblent exister et sont dans la portée dans le débogueur). Si, cependant, je commente les messages de sortie du destructeur, aucune fuite de mémoire ne se produit pour un objet sur la pile libérée, mais des fuites de mémoire se produisent s'il y a plus d'un objet sur la pile.

Je n'ai absolument aucune idée de ce qui ne va pas. Les variables de stockage que j'utilise pour les objets d'appel du service Web ne sont pas différentes car elles sont assignées dans l'initialiseur et ne sont ensuite lues que (par souci d'exactitude, elles sont définies sur readonly).

Cela ne semble pas non plus faire de différence si je conserve ou copie les dates dans l'initialiseur (bien que toute autre chose soit évidemment hors de portée ou soit publiée ailleurs de façon indésirable et provoque un plantage). Je suis désolé que cette explication soit longue, j'espère que c'est suffisamment clair mais je ne suis pas en train de jouer sur ça non plus j'ai peur. Grand merci à tous ceux qui peuvent aider, même suggérer tout ce que j'ai peut-être manqué?

Pour nous espérons éclaircir les choses un peu, voici un code pseudo (ish) ... des choses (à l'exclusion des serrures et initialiseurs):

NSMutableArray* requests; 
NSDate* start, end; 

-(void)webServiceThread 
{ 
    if([requests count] > 1) 
    { 
     [self doRequestWithParams:[requests lastObject]]; 
     [requests removeAllObjects]; 
    } 
} 

-(void)render 
{ 
    if(conditions for another web service call are met) 
    { 
     WebServiceRequest* new = [[WebServiceRequest alloc] initWithDates:start :end]; 
     [requests addObject:new]; 
     [new release]; 
    } 

    [self doRendering]; 
} 

-(void)touchesEnded 
{ 
    [start release]; 
    [end release]; 
    start = [[NSDate dateSinceTimeInterval:chartLeft] retain]; //Ficticious NSDate Method names for example. 
    end = [[NSDate dateSinceTimeInterval:chartRight] retain]; 
} 

Et puis dans l'objet d'appels de service Web:

NSDate* startDate; 
NSDate* endDate; 

-(void)initWithDates:start :end 
{ 
    startDate = [start retain]; 
    endDate = [end retain]; 
} 

-(void)dealloc 
{ 
    [super dealloc]; 

    //The following two lines cause EXC_BAD_ACCESS if this is the only object on the request stack. If they are commented, however, memory is leaked if this is not the only object on the request stack. 
    [startDate release]; 
    [endDate release]; 
} 
+0

Il me semble que il y a une version à beaucoup. D'après votre explication, il semble que ce n'est pas évident où cette version supplémentaire se produit. Je pense que quelque part sur le chemin, une autorelease doit s'être faufilé, ce qui vous a manqué. Il serait utile si vous pouviez afficher le code pertinent - toutes les affectations, conserver et les versions des dates. –

+0

Pour une petite note, il est généralement plus sûr d'appeler '[super dealloc]' dernier dans 'dealloc', mais pas obligatoire. http://stackoverflow.com/questions/909856/why-do-i-have-to-call-super-dealloc-last-and-not-first –

+0

Merci pour votre réponse, le pseudocode a été ajouté (le code actuel est massivement plus long, pourrait également faire partie du problème). L'idée d'Autorelease ne m'est pas venue à l'esprit, mais tout a une méthode de stockage (actuellement retenue) spécifiée le cas échéant. – Tobster

Répondre

0

Problème résolu en mettant [super dealloc]; à la fin du descacheur. Crédit à Toon Van Acker.

Pas d'intérêt; anypne peut-il dire si le même principe s'applique à d'autres méthodes telles que [super init]?

+0

Vous devez appeler [super dealloc] dernier. Dès qu'il est appelé, vous ne pouvez plus garantir que l'un de vos ivars est valide car [super dealloc] finit par appeler [NSObject dealloc] qui libère la mémoire et la rend disponible pour une réutilisation. [super init] doit être fait avant tout code de votre propre initialisation et sa valeur de retour affectée à self. – JeremyP