Objective-C: reparación de la gestión de memoria en un método

votos
5

Casi estoy entendiendo la administració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.

- (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;
}
Publicado el 26/02/2009 a las 23:32
fuente por usuario
En otros idiomas...                            


3 respuestas

votos
5

Aquí hay una reescritura equivalente de tu 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;
}

Note que solo hice referencia contando theXMLDocument. Eso es porque las matrices y diccionarios viven más allá del alcance de este método. Los métodos arrayy dictionaryclase crean instancias NSArrayy NSMutableDictionaryobjetos liberados automáticamente . 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é el código que nunca se iba a ejecutar. El CXMLNode namemétodo dice que devuelve una cadena, por lo que la prueba siempre será cierta.
  • Si mutableDictes así nil, tienes problemas más grandes. Es mejor que arroje una excepción que silenciosamente fallar, así que también terminé con esa prueba.
  • También utilicé la forsintaxis de enumeración relativamente nueva , 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 hiciste nada con theError. Debería verificarlo e informar el error, o bien pasar nilsi no lo va a verificar. 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.

Respondida el 27/02/2009 a las 00:18
fuente por usuario

votos
1

Bueno, liberar mutableDict realmente no debería estar causando ningún problema porque la línea de arriba (agregando mutableDict a mutableArray) lo retendrá automáticamente. Si bien no estoy seguro de qué es exactamente lo que está pasando con tu código (no especificaste qué significa "cosas malas"), sugiero algunas cosas generales:

  1. No libere de forma automática mutableArray de inmediato. 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 liberarlo antes de regresar. 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 lanzado automáticamente, ya que no se garantiza que esté disponible cuando lo necesite, a menos que lo retenga o lo libere explícitamente en alguna parte.

De lo contrario, este código debería funcionar. 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.

Respondida el 26/02/2009 a las 23:49
fuente por usuario

votos
0

En Guía de Programación de la administración de memoria en el tema Volviendo 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.

Respondida el 08/09/2010 a las 22:48
fuente por usuario

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more