9

he configurado un nsurl que toma los datos de http. cuando ejecuto el instrumento, dice que tengo un objeto NSFNetwork de fuga.NSURLConnection leak?

y cómo se libera theConnection en (vacío) ButtonClicked? o será lanzado más tarde?

- (void)ButtonClicked { 
    NSURLRequest *theRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:KmlUrl] 
               cachePolicy:NSURLRequestUseProtocolCachePolicy 
              timeoutInterval:20.0f]; 

    NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self]; 
    if (theConnection) { 
     // receivedData is declared as a method instance elsewhere 
     NSMutableData *receivedData = [[NSMutableData data] retain]; 
     [self setKMLdata:receivedData]; 
    } else { 
     // inform the user that the download could not be made 
    } 
} 


- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data 
{ 
    // append the new data to the receivedData 
    // receivedData is declared as a method instance elsewhere 
    [KMLdata appendData:data]; 
    NSLog(@"didReceiveData"); 
} 


- (void)connectionDidFinishLoading:(NSURLConnection *)connection 
{ 
    // release the connection, and the data object 
    [connection release]; 
    [KMLdata release]; 
} 


- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error 
{ 
    // release the connection, and the data object 
    [connection release]; 
    // receivedData is declared as a method instance elsewhere 
    [KMLdata release]; 

} 

Respuesta

2

Esta es una pregunta común y se resuelve con la magia de [obturación automática de objetos]. En su código esta sería la siguiente:

NSURLConnection *theConnection = [[[NSURLConnection alloc] initWithRequest:theRequest delegate:self] autorelease]; 

De esta manera, el objeto se añade automáticamente a la "piscina autorelease" y dealloc'd en el inicio del siguiente bucle de ejecución después de que ya no se hace referencia.

Espero que ayude

Editar: Además, no veo por qué estás necesidad de llamar -retain en su variable de receivedData.

+0

Mientras autorelease llamando va a funcionar, se producirá un error en los casos en que el delegado se libera antes de que la conexión se libera. La mejor manera sería asignar la conexión a una variable de instancia y liberar + nil cuando no sea necesario. Si la conexión ivar todavía se asigna cuando el objeto se distribuye, el delegado debe establecerse en cero antes de liberar la conexión. – rpetrich

+0

@rpetrich Estoy de acuerdo con que su sugerencia es más exhaustiva, sin embargo, estaba claro que su pregunta mostraba un malentendido básico de la administración de memoria en el iPhone y por eso quería darle una solución conceptual más fácil – h4xxr

+0

@rpetrich, ¿puede proporcionar un ejemplo de código? Intenté resolver este problema de muchas maneras y todavía tengo una filtración. – Jordan

17

Finalmente encontré la respuesta para esto.

El error en el código anterior (que por cierto es la muestra casi exacta del SDK docs) no está en el código de gestión de memoria. Autorelease es una opción, la liberación manual es otra. Independientemente de cómo maneje su objeto NSURLConnection, obtiene fugas usando NSURLConnection.

Primero, aquí está la solución. Simplemente copie estas 3 líneas de código directamente en connectionDidFinishLoading, didFailWithError y en cualquier otro lugar donde libere el objeto NSURLConnection.

NSURLCache *sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:0 diskCapacity:0 diskPath:nil]; 
[NSURLCache setSharedURLCache:sharedCache]; 
[sharedCache release]; 

crédito a mpramodjain en http://forums.macrumors.com/showthread.php?t=573253 para el código.

El problema parece ser este: el SDK guarda en caché las solicitudes y las respuestas en el iPhone. Incluso parece que su NSMutableURLRequest cachePolicy está configurado para no cargar la respuesta de la caché.

Lo tonto es que parece almacenar en caché una gran cantidad de datos de manera predeterminada. Estoy transmitiendo una gran cantidad de datos (divididos en varias conexiones) y comencé a recibir advertencias de memoria, y finalmente mi aplicación murió.

Los documentos que necesitamos están en NSURLCache (no NSURLConnection), afirman:

NSURLCache implementa el almacenamiento en caché de respuestas a las solicitudes de carga de URL por mapeo de objetos a NSURLRequest objetos NSCachedURLResponse. Es un compuesto de una en memoria y una memoria caché en disco .

Se proporcionan métodos para manipular los tamaños de cada una de estas memorias caché, así como para controlar la trayectoria en el disco para usar para el almacenamiento persistente de datos de la caché.

Esas tres líneas tienen el efecto de deshabilitar totalmente el caché. Después de agregarlos a mi aplicación (GPS Log), mi recuento # de objetos vivos permanece estable.

+0

para el registro, cambié al autorrelease 'd [NSURLConnection connectionWithRequest: request delegate: self] pero no creo que debería importar. –

+0

Si su aplicación realiza cualquier otra solicitud de NSURL que _debe usar el almacenamiento en caché, esta solución los deshabilitará. Una mejor solución en este caso podría ser la de poner en práctica el delegado respuesta en caché (que tiene el mismo efecto): '- (NSCachedURLResponse *) Conexión: (NSURLConnection *) willCacheResponse conexión: (NSCachedURLResponse *) cachedResponse { \t retorno a cero; } ' –

+1

Un poco más adelante en lo que está sucediendo realmente: NSURLCache está almacenando en caché la respuesta a la solicitud, pero está utilizando la solicitud como clave. Por lo tanto, se mantendrá en la solicitud siempre que las respuestas estén en caché. Un caché de 0 bytes derrota esto, a expensas de hacer que todas las solicitudes realizadas por la aplicación no se guarden en caché; implementar el método de delegado es un enfoque más personalizado. Establecer la política de caché de la solicitud para ignorar el caché no es suficiente. –

5

Hola, ¿has probado este método delegado?

- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse 
{ 
    return nil; 
} 

Puede gestionar la memoria caché de forma más precisa.

"restablecer" NSURLCache * sharedCache puede causar problemas en otra parte de su código?

1

estoy usando el método de enfoque estático/autoreleased y parece funcionar bien:

[NSURLConnection connectionWithRequest:theRequest delegate:self]; 

De esta manera usted ni siquiera tiene que preocuparse acerca de la liberación de las devoluciones de llamada de delegado. Resulta que el recuento retenido de la conexión es en realidad 2 (no 1) después de que se haya asignado en los ejemplos anteriores, lo que cambia la forma en que pensé acerca de esta "fuga" de memoria.

@rpetrich De hecho, no creo que deba preocuparse por la liberación del delegado antes de que se libere la conexión. La conexión conserva su delegado y la conexión en sí es retenida por algún tipo de cola abierta de conexiones. Me escribió una entrada de blog en mis experimentos con NSURLConnection en mi blog:

"Potential leak of object" with NSURLConnection