Domanda

Ho un'applicazione iPhone che carica viste succesive in un quadro basato su quello spiegato in questo link (fondamentalmente un ViewController principale che carica / rimuove viste supplementari con un metodo displayView). Nella mia applicazione Sto usando ONA (il link esempio utilizza viste codificato), anche se in modo ognuno di mia ViewControllers ha il suo pennino accompagna.

Debug in strumenti spettacoli perdite , ma se entro / lasciare una sezione (ViewController con la sua View.xib), il pennino rimane in memoria in modo che dopo un paio di memoria in / out inizia ad accumularsi.

So che il pennino non viene scaricato perché uno è quasi a livello di codice creato (non roba in IB), mentre un altro ha le immagini e pulsanti creati in IB. Il grande viene caricato per la prima e la piccola uno carichi successivo. Ci si aspetterebbe una riduzione di allocazione in strumenti.

Come si può evitare questo?

La mia struttura è la seguente, con alcuni commenti qui sotto:

`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

Questo controller gestisce carico visualizzazione secondaria / rimuove:

`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

Ci sarebbero tanti case come ViewControllers "dettaglio" Ho (in questo momento ho 3 case ma questo crescerà a 10 o più). Lo scopo di questa struttura è quello di spostare facilmente da una "sezione" della domanda ad un altro (controllore NavBar o il controller TabBar non soddisfare le mie esigenze specifiche).

`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];
}

Si noti la NSLog in dealloc. Questo viene chiamato (posso vederlo nella console), ma la memoria necessaria per il pennino non viene liberato (Instruments mostra un aumento di allocazione della memoria al momento di lasciare una sezione, perché un nuovo pennino è caricato).

Ogni aiuto sarà molto apprezzato. Ho provato un milione di cose diverse e non posso ottenere i pennini per scaricare.

È stato utile?

Soluzione

Dopo un milione di diversi tentativi finalmente ho corse in questo forum .

Esso afferma:

  

A quanto pare immagini assegnate in IB vengono caricati in vista di immagine utilizzando imageNamed. imageNamed memorizza le immagini in un modo che li rende scarrabile. Si potrebbe caricare le immagini in viewDidLoad con initWithContentsOfFile e poi assegnarli ai punti di vista.

Da qualche altra parte avevo letto che imageNamed è il diavolo quindi preferirei non avere le mie immagini vengono caricate in questo modo.

(BTW questo è iPhone OS 3.1 che sto usando)

Quello che ho finito lascia il UIImageView intatta in IB, ma con un valore .image vuoto. Il codice modificato è qualcosa di simile:

- (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];
}

E ora tutto funziona come un fascino! La memoria è recuperato quando scaricare un pennino e quando ricevo avvisi di memoria.

Quindi, più o meno, se si dispone di IBOutlets per UIImageViews e la memoria è una preoccupazione (è sempre credo), è possibile progettare tutto quello che volete in IB, e quando arriva il momento di collegarli alle prese, rimuovere il riferimento immagine in IB e crearlo dal codice. IB è veramente buono per la posa fuori la vostra applicazione. E avrebbe fatto schifo di avere a che fare tutto ciò che cosa dal codice, ma ho anche trovato questa simpatica utility che converte pennini all'obiettivo codice C anche se non ho ancora testato.

Altri suggerimenti

Hai provato impostare le variabili di uscita a zero in dealloc? Si sono correttamente attuazione del metodo setview, ma si sta impostando le variabili di uscita a zero nel metodo viewDidUnload invece di dealloc. Come discusso qui , è necessario implementare dealloc come segue:

- (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];
}

Modifica : se le prese sono UIImageViews, allora potrebbe essere il caso che è necessario fare

anOutlet.image = nil;

perché l'impostazione proprietà immagine esempio del UIImage dovrebbe aumentare il conteggio di conservare esempio del UIImage di 1.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top