notes descargar apple app actualizar iphone memory-management uiviewcontroller nib dealloc

iphone - descargar - itunes



aplicación para iPhone con múltiples vistas/subvistas: la memoria no está siendo desasignada (2)

¿Intentó establecer las variables de salida en nulo en dealloc? Está implementando correctamente el método setView, pero está configurando las variables de salida en nil en el método viewDidUnload en lugar de dealloc. Como se discutió aquí , debe implementar dealloc de la siguiente manera:

- (void)setView:(UIView *)aView { if (!aView) { // view is being set to nil // set outlets to nil, e.g. self.anOutlet = nil; } // Invoke super''s implementation last [super setView:aView]; } - (void)dealloc { // release outlets and set outlet variables to nil [anOutlet release], anOutlet = nil; [super dealloc]; }

EDITAR : si los puntos de venta son UIImageViews, entonces puede ser el caso que necesites hacer

anOutlet.image = nil;

porque establecer la propiedad de la imagen de instancia del UIImage debería aumentar el recuento de retención de la instancia del UIImage en 1.

Tengo una aplicación de iPhone que carga vistas exitosas en un marco basado en el explicado en este enlace (básicamente un ViewController principal que carga / elimina vistas adicionales con un método displayView ). En mi aplicación , estoy usando NIB (el enlace de ejemplo usa vistas codificadas), así que cada uno de mis ViewControllers tiene su plumín de acompañamiento.

La depuración en Instrumentos no muestra fugas, pero si ingreso / abandono una sección (ViewController con su View.xib), la plumilla permanece en la memoria, por lo tanto, después de que comienza a acumularse un poco de memoria de entrada / salida.

Sé que el plumín no está siendo descargado porque uno está casi creado programáticamente (nada en IB) mientras que otro tiene imágenes y botones creados en IB. El grande se carga primero y el pequeño se carga a continuación. Esperaría una reducción en la asignación en Instrumentos.

¿Cómo puedo prevenir esto?

Mi estructura es la siguiente, con algunos comentarios a continuación:

`MyAppDelegate.h` #import <UIKit/UIKit.h> @class RootViewController; @interface MyAppDelegate : NSObject <UIApplicationDelegate> { UIWindow *window; RootViewController *viewController; } @property (nonatomic, retain) IBOutlet UIWindow *window; @property (nonatomic, retain) IBOutlet RootViewController *viewController; -(void) displayView:(int)intNewView; @end `MyAppDelegate.m` #import "MyAppDelegate.h" #import "RootViewController.h" @implementation MyAppDelegate @synthesize window; @synthesize viewController; - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [window addSubview:viewController.view]; [window makeKeyAndVisible]; return YES; } - (void)applicationDidReceiveMemoryWarning:(UIApplication *)application { } -(void) displayView:(int)intNewView { [viewController displayView:intNewView]; } - (void)dealloc { [viewController release]; [window release]; [super dealloc]; } @end

Este controlador maneja la subvista carga / elimina:

`RootViewController.h` #import <UIKit/UIKit.h> @interface RootViewController : UIViewController { } - (void) displayView:(int)intNewView; @end `RootViewController.m` #import "RootViewController.h" #import "ViewController.h" @implementation RootViewController UIViewController *currentView; - (void) displayView:(int)intNewView { NSLog(@"%i", intNewView); [currentView.view removeFromSuperview]; [currentView release]; switch (intNewView) { case 1: currentView = [[ViewController alloc] initWithNibName:@"View" bundle:nil]; break; } [self.view addSubview:currentView.view]; } - (void)viewDidLoad { currentView = [[ViewController alloc] initWithNibName:@"View" bundle:nil]; [self.view addSubview:currentView.view]; [super viewDidLoad]; } - (void)dealloc { [currentView release]; [super dealloc]; } @end

Habría tantos case como ViewControllers "detalles" que tengo (ahora tengo 3 case pero esto crecerá a 10 o más). El propósito de esta estructura es pasar fácilmente de una "sección" de la aplicación a otra (el controlador NavBar o el controlador TabBar no se ajustan a mis necesidades específicas).

`ViewController.h` // Generic View Controller Example #import <UIKit/UIKit.h> @interface ViewController : UIViewController { UIImageView *_image1; UIImageView *_image2; NSTimer *_theTimer; } @property (nonatomic, retain) IBOutlet UIImageView *image1; @property (nonatomic, retain) IBOutlet UIImageView *image2; @property (nonatomic, retain) NSTimer *theTimer; @end `ViewController.m` #import "ViewController.h" #import "MyAppDelegate.h" @synthesize image1 = _image1, image2 = _image2, theTimer = _theTimer; - (void)loadMenu { [self.theTimer invalidate]; self.theTimer = nil; MyAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate]; [appDelegate displayView:2]; } -(void)setView:(UIView*)aView { if (!aView){ self.image1 = nil; self.image2 = nil; } [super setView:aView]; } - (void)viewDidLoad { //some code [super viewDidLoad]; } - (void)viewDidUnload { self.image1 = nil; self.image2 = nil; } - (void)dealloc { NSLog(@"dealloc called"); [self.theTimer invalidate]; [self.theTimer release]; [self.image1 release]; [self.image2 release]; [super dealloc]; }

Observe el NSLog en dealloc . Se está llamando (puedo verlo en la consola) pero la memoria necesaria para el plumín no se libera (Instruments muestra un aumento en la asignación de memoria al salir de una sección, porque se carga un plumín nuevo).

Cualquier ayuda será apreciada. He intentado un millón de cosas diferentes y no puedo descargar las puntas.


Después de un millón de intentos diferentes, finalmente me encontré con este foro .

Afirma:

Aparentemente, las imágenes asignadas en IB se cargan en vistas de imagen usando imageNamed . imageNamed almacena en caché las imágenes de una manera que las hace descargables. Puede cargar las imágenes en viewDidLoad con initWithContentsOfFile y luego asignarlas a las vistas.

En otro lugar, había leído que imageNamed es el diablo, así que preferiría que mis imágenes no se cargaran de esa manera.

(Por cierto, este es el iPhone OS 3.1 que estoy usando)

Lo que terminé fue dejar el UIImageView intacto en IB pero con un valor vacío de .image . El código modificado es algo así como:

- (void)viewDidLoad { NSString *path = [NSString stringWithFormat:@"%@/%@", [[NSBundle mainBundle] resourcePath], @"myImageThatBeforeWasAValueinIB.jpg"]; UIImage *image = [UIImage imageWithContentsOfFile:path]; outlet.image = image; // do the rest of my stuff as it was [super viewDidLoad]; } - (void)dealloc { outlet.image = nil; [outlet release], outlet = nil; [super dealloc]; }

¡Y ahora todo funciona como un encanto! La memoria se recupera cuando descargo una punta y cuando recibo advertencias de memoria.

Así que más o menos si tienes IBOutlets para UIImageView y la memoria es una preocupación (siempre lo es, supongo), puedes diseñar todo lo que quieras en IB y cuando llegue el momento de conectarlos a los puntos de venta, elimina la referencia de imagen en IB y crea desde el código. IB es realmente bueno para diseñar tu aplicación. Sería desagradable tener que hacer todo eso por código, pero también encontré esta buena utilidad que convierte las puntas en código objetivo c aunque todavía no lo he probado.