2013-02-22 9 views
14

Sto scrivendo app iOS utilizzando ARC e targeting per iOS 5+.Impostare i delegati su zero sotto ARC?

Supponiamo di scrivere un oggetto di visualizzazione personalizzato con una proprietà delegata. Nel dichiarare la proprietà delegato, faccio un riferimento debole per evitare un ciclo trattengono, in modo che quando l'oggetto delegato effettivo (controllore) è distrutta, ritengo ordinazione inoltre essere distrutto, come segue:

@interface MyCustomView : UIView 

@property (nonatomic, weak) id<MyCustomViewDelegate> delegate; 

@end 

Va tutto bene.

Ok, quindi sto scrivendo l'oggetto controller e ha riferimenti a due oggetti vista: la mia vista personalizzata e una vista UIKit fornita da Apple, che dichiarano entrambe le proprietà delegate e il controller è il delegato per entrambi i punti di vista. Forse è simile a questa:

@interface MyViewController : UIViewController <MyCustomViewDelegate, UITableViewDataSource, UITableViewDelegate> 

@property (nonatomic, strong) MyCustomView *customView; 
@property (nonatomic, strong) UITableView *tableView; 

@end 

@implementation MyViewController 

- (void)viewDidLoad 
{ 
    self.customView.delegate = self; 
    self.tableView.dataSource = self; 
    self.tableView.delegate = self; 
} 

@end 

mia domanda è questa: Ho bisogno di ignorare dealloc per impostare uno o entrambi i delegati a zero?

Cioè, come risulta, la proprietà delegato della vista UIKit (in questo caso, tableView) non è effettivamente dichiarata come riferimento debole, ma piuttosto un riferimento __unsafe_unretained, per la compatibilità con i non-ARC versione di iOS. Quindi forse ho bisogno di scrivere

- (void)dealloc 
{ 
    _tableView.dataSource = nil; 
    _tableView.delegate = nil; 
} 

Ora, se devo ignorare dealloc, io ancora non dover impostare _customView.delegate = nil, giusto? Perché è stato dichiarato (da me) come riferimento debole, quindi dovrebbe essere impostato su zero automaticamente alla distruzione di MyViewController.

Ma d'altra parte, non sto prendendo di mira versioni non ARC di iOS, né ho intenzione di farlo. Quindi forse non ho bisogno di sovrascrivere dealloc?

+0

Potrebbe non esserne a conoscenza, ma la raccomandazione corrente è che IBOutlets * contenuto in una gerarchia di viste * dovrebbe essere debole. In altre parole, se tableView è contenuto in una vista, la vista viene mantenuta dal riferimento forte e non è necessario che TableView sia. Ciò rende il tuo caso un po 'artificiale, anche se è ancora una domanda legittima per quel caso (che ha altre istanze più reali). –

+0

@StevenFisher Grazie, Steven. Ne ero a conoscenza, ma nel mio esempio non ho dichiarato che le proprietà della vista fossero IBOutlet; forse li sto generando programmaticamente piuttosto che tramite IB. –

+0

@StevenFisher Immagino che la cosa più curiosa sia la differenza tra le dichiarazioni di proprietà '__weak' e '__unsafe_unretained', e quale sia la mia responsabilità rispetto a quelle dichiarazioni diverse quando scelgo come target le versioni post-ARC di iOS. –

risposta

30

Impostazione delegati non deboli a zero è generalmente una buona idea a meno che non sapere non avete a. Per UITableView e UIScrollView, ho sperimentato incidenti sulle versioni precedenti di iOS con le seguenti operazioni (che può aiutare a correre con zombie abilitati):

  1. Scroll veramente veloce.
  2. Premere Fine o il pulsante Indietro o altro per eliminare il VC.

Questo sembra accadere perché l'animazione a scorrimento mantiene un riferimento alla vista, quindi la vista sopravvive al VC. Si blocca quando si invia l'evento di scorrimento.

Ho anche riscontrato arresti anomali dopo aver chiuso un VC contenente uno UIWebView durante il caricamento di una richiesta, in cui semplicemente l'impostazione del delegato su nil non era sufficiente (penso che la soluzione alternativa fosse chiamare [webView loadRequest:nil]).

+0

Avete trovato questo solo nei casi in cui non si utilizza UITableViewController come l'OP? –

+0

@BobSpryn Non so; Non ho tenuto traccia (ma generalmente ho usato un VC personalizzato perché "UITableViewController' non è * abbastanza * abbastanza flessibile). È assolutamente possibile che 'UITableViewController' disattivi l'origine dati/delegato della vista tabella in' -dealloc'. –

0

L'unica ragione per cui si vorrebbe impostare in modo esplicito il delegate e dataSource-nil è se il customView o tableView fuori potrebbe vivere il controller della vista. Impostandoli su nil si guarderebbe dallo delegate o dataSource facendo riferimento a un oggetto deallocato.

Se il customView e tableView saranno deallocato insieme al controller della vista, non è necessario a zero il delegate e dataSource.

2

Se l'unico riferimento forte a detto tableView è il vostro unico controllore MyViewController, non è necessario impostare manualmente UITableViewDelegate o UITableViewDataSource-nil.

La ragione è che una volta che il metodo dealloc sul MyViewController viene chiamato, tableView sarà anche distrutta insieme con il controllore (cioè, ancora una volta, a patto che l'unico riferimento ad esso è l'unico regolatore MyViewController classe) .

Se si hanno altri riferimenti forti a questa vista tabella, come ad esempio altri controllori, sarebbe quindi possibile che la vista tabella possa quindi esistere più a lungo della classe MyViewController.In tal caso, si sarebbe essere necessario impostare il UITableViewDelegate e UITableViewDataSource-nil nel metodo dealloc di MyViewController perché, come lei ha ricordato, queste proprietà non sono riferimenti deboli e non verranno automaticamente impostate su nil.

Tuttavia, questo tipo di situazione è piuttosto rara nella mia esperienza però.

La maggior parte delle volte, non mi preoccupo di impostarle su nil in modo onesto, ma è una pratica di programmazione difensiva.

vedi questo post anche:

In dealloc method set any delegate to nil is needed or not needed

+0

Abbiamo una piccola app con solo un paio di centinaia di utenti, e vedo 3-4 incidenti al giorno correlati a questo. CoreAnimation è nello stack, quindi sospetto che un'animazione stia trattenendo un forte riferimento alla tabella dopo che il suo controller (delegato e dataSource) è stato liberato. Non sono riuscito a riprodurre questo, tuttavia. Questo potrebbe non essere un problema se utilizzi UITableViewController e il delegato e dataSource sono impostati su UITableViewController. In questo caso, Apple li elimina nel metodo dealloc. – Steve

Problemi correlati