aplicación para el iPhone con múltiples puntos de vista / subvistas: La memoria no se cancela la asignación

StackOverflow https://stackoverflow.com/questions/1482934

Pregunta

Tengo una aplicación de iPhone que carga vistas sucesivas en un marco basado en la rel="noreferrer"> href="http://www.pushplay.net/blog_detail.php?id=27" uno (básicamente un ViewController principal que carga / elimina vistas adicionales con un método displayView). En mi aplicación Estoy utilizando ONE (el enlace de ejemplo se utiliza vistas codificado) a pesar de que cada uno de mis ViewControllers tiene su punta de acompañamiento.

Depuración de los instrumentos se visualizan no hay fugas , pero si entro / dejar una sección (ViewController con su View.xib), la punta se mantiene en la memoria para después de unos pocos memoria entradas / salidas comienza a acumularse.

Sé que la punta no está siendo descargada debido a que uno se crea casi programación (sin materia en IB), mientras que otro tiene imágenes y botones creados en IB. El grande se carga primero y el pequeño uno cargas siguiente. Que se puede esperar una reducción en la asignación de un instrumento.

¿Cómo puedo evitar esto?

Mi estructura es la siguiente, con unos pocos 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

maneja Este controlador de carga subvista / quita:

`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

No habría tantos case como ViewControllers "detalle" que tengo (ahora tengo 3 case pero esto aumentará a 10 o más). El propósito de esta estructura es mover fácilmente de "sección" uno de la aplicación a otra (controlador de barra de navegación o controlador TabBar no satisfacer 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];
}

Note la NSLog en dealloc. Esto se llama (lo puedo ver en la consola), pero la memoria necesaria para la punta no se libera (Instrumentos muestra un aumento en la asignación de memoria al salir de una sección, ya que se carga una nueva mina).

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

¿Fue útil?

Solución

Después de un millón de diferentes intentos que finalmente se topó este foro .

Se afirma:

  

Al parecer, las imágenes asignadas en IB se cargan en vistas de imágenes utilizando imageNamed. imageNamed almacena en caché las imágenes de una manera que los hace descargable. Se podía cargar las imágenes en viewDidLoad con initWithContentsOfFile y luego asignarlos a los puntos de vista.

En otro lugar había leído que imageNamed es el demonio por lo que preferiría no tener mis imágenes se cargan de esa manera.

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

Lo que terminé abandona el UIImageView intacto en IB, pero con un valor .image vacía. El código modificado es algo 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 me descargo una punta y cuando llego a las advertencias de memoria.

Así que más o menos si tiene IBOutlets para UIImageViews y la memoria es una preocupación (que siempre es, supongo), se puede diseñar todo lo que quiere en IB y cuando llegue el momento de conectarse a puntos de venta, quitar la imagen de referencia en el IB y crear desde el código. IB es realmente bueno para la disposición de su aplicación. Sería aspirar a tener que hacer todo eso por el código, pero también encontrados esta utilidad agradable que convierte nibs de código c objetivo aunque no he probado todavía.

Otros consejos

¿Usted intentó establecer las variables de salida a cero en dealloc? Está implementando correctamente el método setView, pero está configurando las variables de salida a cero en el método viewDidUnload en lugar de dealloc. Como se discutió aquí , se deben 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 las salidas son UIImageViews, entonces puede ser el caso de que usted tiene que hacer

anOutlet.image = nil;

debido establecer la propiedad de imagen del ejemplo UIImage debería aumentar la cuenta de retención de la instancia del UIImage en 1.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top