2009-02-26 12 views
5

Casi estoy entendiendo la gestión simple de conteo/memoria de referencia en Objective-C, sin embargo, estoy teniendo dificultades con el siguiente código. Estoy lanzando mutableDict (comentado en el código a continuación) y está causando un comportamiento perjudicial en mi código. Si dejo escapar la memoria, funciona como se esperaba, pero esa no es la respuesta aquí. ;-) ¿Alguno de ustedes, gente más experimentada, sería tan amable de señalarme en la dirección correcta, ya que puedo volver a escribir cualquiera de estos métodos para manejar mejor la huella de mi memoria? Principalmente con la forma en que estoy manejando NSMutableDictionary * mutableDict, ya que ese es el gran culpable aquí. Me gustaría entender el problema, y ​​no solo copiar/pegar código, por lo que algunos comentarios/comentarios son ideales. Gracias a todos.Objective-C: Corregir la gestión de memoria en un método

- (NSArray *)createArrayWithDictionaries:(NSString *)xmlDocument 
           withXPath:(NSString *)XPathStr { 

    NSError *theError = nil; 
    NSMutableArray *mutableArray = [[[NSMutableArray alloc] init] autorelease]; 
    //NSMutableDictionary *mutableDict = [[NSMutableDictionary alloc] init]; 
    CXMLDocument *theXMLDocument = [[[CXMLDocument alloc] initWithXMLString:xmlDocument options:0 error:&theError] retain]; 
    NSArray *nodes = [theXMLDocument nodesForXPath:XPathStr error:&theError]; 
    int i, j, cnt = [nodes count]; 
    for(i=0; i < cnt; i++) { 
     CXMLElement *xmlElement = [nodes objectAtIndex:i]; 
     if(nil != xmlElement) { 
      NSArray *attributes = [NSArray array]; 
      attributes = [xmlElement attributes]; 
      int attrCnt = [attributes count]; 
      NSMutableDictionary *mutableDict = [[NSMutableDictionary alloc] init]; 
      for(j = 0; j < attrCnt; j++) { 
       if([[[attributes objectAtIndex:j] name] isKindOfClass:[NSString class]]) 
        [mutableDict setValue:[[attributes objectAtIndex:j] stringValue] forKey:[[attributes objectAtIndex:j] name]]; 
       else 
        continue; 
      } 
      if(nil != mutableDict) { 
       [mutableArray addObject:mutableDict]; 
      } 
      [mutableDict release]; // This is causing bad things to happen. 
     } 
    } 

    return (NSArray *)mutableArray; 
} 

Respuesta

5

He aquí un equivalente de reescritura de su código:

- (NSArray *)attributeDictionaries:(NSString *)xmlDocument withXPath:(NSString *)XPathStr { 
    NSError *theError = nil; 
    NSMutableArray *dictionaries = [NSMutableArray array]; 
    CXMLDocument *theXMLDocument = [[CXMLDocument alloc] initWithXMLString:xmlDocument options:0 error:&theError]; 
    NSArray *nodes = [theXMLDocument nodesForXPath:XPathStr error:&theError]; 

    for (CXMLElement *xmlElement in nodes) { 
     NSArray *attributes = [xmlElement attributes]; 
     NSMutableDictionary *attributeDictionary = [NSMutableDictionary dictionary]; 
     for (CXMLNode *attribute in attributes) { 
      [attributeDictionary setObject:[attribute stringValue] forKey:[attribute name]]; 
     } 

     [dictionaries addObject:attributeDictionary]; 
    } 

    [theXMLDocument release]; 
    return attributeDictionaries; 
} 

Aviso Yo sólo lo hizo el recuento de referencias en theXMLDocument. Eso es porque las matrices y diccionarios viven más allá del alcance de este método. Los métodos de clase array y dictionary crean instancias autorreleasadas de objetos NSArray y NSMutableDictionary. Si la persona que llama no los retiene explícitamente, se lanzarán automáticamente en la próxima ronda del ciclo de eventos de la aplicación.

  • También eliminé código que nunca se iba a ejecutar. El método CXMLNodename dice que devuelve una cadena, por lo que la prueba siempre será cierta.
  • Si mutableDict es nil, tiene problemas mayores. Es mejor que arroje una excepción que silenciosamente fallar, así que también terminé con esa prueba.
  • También utilicé la relativamente nueva sintaxis de enumeración for, que elimina las variables de contador.
  • Cambié el nombre de algunas variables y el método para ser un poco más Cocoa-ish.El cacao es diferente de la mayoría de los lenguajes, ya que generalmente se considera incorrecto usar un verbo como "crear", a menos que específicamente desee que el emisor sea responsable de liberar cualquier objeto que devuelva.
  • No hizo nada con theError. Debería verificarlo e informar el error, o bien pasar nil si no va a verificarlo. No tiene sentido hacer que la aplicación genere un objeto de error que no vas a usar.

Espero que esto ayude a apuntar en la dirección correcta.

+0

Alex, ahora estoy revisando el código, pero un problema que veo enseguida es que los atributos estarán fuera de alcance antes de que puedas devolverlos. –

+0

Creo que acaba de hacer un error tipográfico (y no tengo suficiente representante para editarlo) - Creo que la última línea debería ser "devolver diccionarios". La instancia attributeDictionary se agrega a esta matriz, por lo que no saldrá del alcance. – erikprice

+0

Sí. Erik tiene razón No lo entendí lo suficientemente pronto. – Alex

1

Bueno, liberando mutableDict realmente no debería estar causando ningún problema porque la línea por encima de ella (la adición de mutableDict a mutableArray) retendrá automáticamente. Aunque no estoy seguro de lo que está pasando exactamente mal con su código (no se especificó qué "cosas malas" significa), hay algunas cosas generales que sugeriría:

  1. No AutoRelease mutableArray derecha lejos. Deje que sea una instrucción alloc/init regular y vuelva a soltarla automáticamente cuando la devuelva ("return [mutableArray self release];").

  2. theXMLDocument está goteando, asegúrese de liberar eso antes de volver. Además, no es necesario que lo conserve como está. alloc/init hace el trabajo iniciando el recuento de retención de objetos en 1, reteniéndolo nuevamente solo asegura que gotea para siempre. Deshágase de la retención y libérela antes de regresar y no tendrá fugas.

  3. Solo un consejo: asegúrese de conservar el valor de retorno de este método cuando lo use en otro lugar: el resultado se ha liberado automáticamente ya que no se garantiza que esté disponible cuando lo necesite a menos que lo retenga o lo libere explícitamente .

De lo contrario, este código debe trabajo. Si todavía no lo hace, otra cosa que probaría es quizás hacer [mutableArray addObject: [mutableDict copy]] para asegurar que mutableDict no le cause ningún problema cuando se lance.

+0

"No libere automáticamente el archivo mutableArray ... vuelva a soltarlo automáticamente cuando lo devuelva ..." No estoy de acuerdo. Si no veo la liberación automática en la misma línea, tengo que buscarla para asegurarme de que no se filtró. –

0

En Memory Management Programming Guide con el tema de que vuelven objetos de Métodos ( desplazarse un poco), hay algunos ejemplos sencillos sobre cómo devolver los objetos a partir de un método con la Gestión de memoria correcta.

Cuestiones relacionadas