Domanda

Ecco una pratica comune che vedo spesso (anche da un libro per sviluppatori iPhone molto popolare)

Nel file .h:

@interface SomeViewController : UIViewController
{
  UIImageView *imgView;
}

Da qualche parte nel file .m:

imgView = [[UIImageView alloc] initWithFrame:[[UIScreen mainScreen]
applicationFrame]];
[imgView setImage:[UIImage imageNamed:@"someimage.png"]];
[self addSubview:imgView];
[imgView release];

E più tardi, vediamo questo ...

- (void) dealloc
{
  [imgView release];
  [super dealloc];

} 

Poiché imgView ha allocazione e rilascio corrispondenti, è necessario il rilascio di imgView in dealloc?

Dove viene tenuto conto di imgView dalla chiamata addSubview?

È stato utile?

Soluzione

Sì, quel codice ha problemi. rilascia l'imgView troppo presto, il che potrebbe potenzialmente causare arresti anomali in rare circostanze memorizza un oggetto in una variabile di istanza senza conservarlo, e in genere si occupa solo della gestione della memoria nel modo sbagliato.

Un modo corretto per farlo sarebbe:

@interface SomeViewController : UIViewController
{
    UIImageView *imgView;
}
@property (nonatomic, retain) UIImageView *imgView;

E nell'implementazione;

@synthesize imgView;

Da qualche parte nel modulo:

//Create a new image view object and store it in a local variable (retain count 1)
UIImageView *newImgView = [[UIImageView alloc] initWithFrame:self.view.bounds];
newImgView.image = [UIImage imageNamed:@"someimage.png"];

//Use our property to store our new image view as an instance variable,
//if an old value of imgView exists, it will be released by generated method,
//and our newImgView gets retained (retain count 2)
self.imgView = newImgView;

//Release local variable, since the new UIImageView is safely stored in the
//imgView instance variable. (retain count 1)
[newImgView release];

//Add the new imgView to main view, it's retain count will be incremented,
//and the UIImageView will remain in memory until it is released by both the
//main view and this controller. (retain count 2)
[self.view addSubview:self.imgView];

E il dealloc rimane lo stesso:

- (void) dealloc
{
    [imgView release];
    [super dealloc];
}

Altri suggerimenti

Il codice non è corretto. Alla fine rilascerai imgView dopo che è stato deallocato.

Nel tuo file .m, tu:

  1. alloc it - > lo possiedi
  2. aggiungilo come sottoview - > tu e UIView lo possiede
  3. release it - > non lo possiedi

Quindi in dealloc , rilasci anche se, come stabilito al passaggio 3 sopra, non lo possiedi. Quando chiami [super dealloc] , la vista rilascerà tutte le sue visualizzazioni secondarie e immagino che otterrai un'eccezione.

Se vuoi mantenere un ivar di imgView , ti suggerisco di non chiamare rilasciare dopo averlo aggiunto come sottoview e mantenere il tuo dealloc lo stesso. In questo modo, anche se imgView viene ad un certo punto rimosso dalla gerarchia della vista, avrai comunque un riferimento valido ad esso.

Il codice non è corretto, non dovresti rilasciarlo nel metodo init, proprio quando viene chiamato dealloc (questo è se vuoi tenerlo come un ivar, non è necessario a meno che tu non abbia bisogno di un puntatore ad esso altrove da addSubview: manterrà la vista per te).

Credo che il motivo per cui non si sta effettivamente arrestando è perché è ancora trattenuto dalla superclasse (dalla chiamata ad addSubview :), quindi quando viene rilasciato in dealloc è effettivamente bilanciato. La vista probabilmente si rimuove dalla superview quando viene deallocata immediatamente dopo, quindi quando viene chiamato [super dealloc] non viene sovrascritto. Questo è il mio sospetto, in affitto.

Il rilascio in init non è corretto.

Hai citato " pratica comune " e un libro senza nome. Suggerisco di guardare gli esempi canonici di Apple: ViewTransitions è un buon esempio per questo caso (e 2 viste per l'avvio;)

http://developer.apple.com/iphone/library /samplecode/ViewTransitions/index.html

(Non ho abbastanza reputazione per aggiungere commenti ).

@bentford: correggimi se sbaglio, ma credo che per usare il setter sintetizzato della proprietà imgView, devi usare " self.imgView " ;:

self.imgView = [[UIImageView alloc] initWithFrame:[[UIScreen mainScreen]

Se non hai sé. , sta solo usando l'ivar e non sta ottenendo il mantenimento aggiuntivo.

La risposta di base è che dovrebbe esserci un solo [imgView release] nel codice di esempio ( sia dopo addSubview che in dealloc ). Tuttavia, rimuoverei [imgView release] da dealloc e lo lascerei dopo addSubview .

C'è un problema con l'iPhone; con didReceiveMemoryWarning , potresti avere oggetti ( inclusa un'intera vista ) rilasciati da sotto di te. Se si dispone di un set di conservazione a livello di applicazione e non si rispetta la memoria, è possibile che l'applicazione venga semplicemente uccisa.

Un buon esempio è:
se pensi a un set nidificato di 3 visualizzazioni, Visualizza 1- > Visualizza 2- > Visualizza 3 Quindi, considera le chiamate ' viewDidLoad ' e ' viewDidUnload '. Se l'utente è attualmente in "Visualizza 3", è possibile che View1 sia scaricato ed è qui che diventa brutto.
 Se hai allocato un oggetto all'interno di viewDidLoad e non lo hai rilasciato dopo averlo aggiunto alla sottoview, il tuo oggetto non viene rilasciato quando view1 viene scaricato, ma view1 viene comunque scaricato.
  viewDidLoad verrà eseguito di nuovo e il codice verrà eseguito di nuovo, ma ora hai due istanze dell'oggetto invece di una; un oggetto sarà nell'entroterra con la vista precedentemente scaricata e il nuovo oggetto sarà per la vista attualmente visibile. Risciacqua, insapona e ripeti e trovi l'applicazione che si blocca da perdite di memoria.

In questo esempio, se il blocco di codice specificato è volatile e ha la possibilità di essere eseguito nuovamente ( sia a causa della memoria o di una vista non caricata ), rimuoverei [imgView release ]; da dealloc e lasciarlo dopo addSubView.

Ecco un link sui concetti base di conservazione / rilascio: http://www.otierney.net/objective-c.html#retain

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