2011-02-21 11 views
6

Piuttosto un sacco di persone sembrano utilizzare una macro comeAbbiamo davvero bisogno di una macro di rilascio sicura?

#define SAFE_RELEASE(X) [X release]; X = nil; 

(me compreso).

Mi è stato rivalutato il motivo per cui lo sto usando e ho voluto dare un parere.

Lo scopo (credo) per l'utilizzo di questa macro è in modo che se si dovesse accidentalmente utilizzare il vostro oggetto dopo aver rilasciato allora non sarà possibile ottenere un'eccezione accesso male perché Objective-C sarà tranquillamente ignorarlo quando l'oggetto è nullo.

Mi sembra che questo abbia il potenziale per mascherare alcuni bug oscuri. Forse sarebbe effettivamente preferibile che il programma si arresti in modo anomalo quando tenti di usare di nuovo X. In questo modo durante i test puoi trovare il problema e migliorare il codice.

Questa macro incoraggia la programmazione pigra?

Pensieri?

+1

La sezione della [FAQ] (http://stackoverflow.com/faq) per le domande che non dovrebbero essere poste qui. - "Non c'è nessun problema da risolvere:" Sono curioso di sapere se gli altri si sentono come me. "" – Abizern

+0

Abbastanza giusto, ma è un problema che sto affrontando. Il problema è che dovrei continuare ad usare questa macro? Ci sono buone ragioni per usarlo di cui non sono a conoscenza? – Ian1971

risposta

6

Penso che discutiate di tutti i pro e contro nella vostra domanda, quindi non ho una grande quantità da aggiungere. Personalmente non uso il costrutto. Come suggerisci, è possibile utilizzare per stampare su aree in cui le persone non comprendono correttamente la gestione della memoria. La mia preferenza è di correggere l'errore e non il sintomo.

Tuttavia, un compromesso che ho visto di volta in volta è:

  • Make it incidente durante lo sviluppo
  • fare il var = nil; nel codice di produzione

In questo modo forza essere più affidabili con i clienti paganti e si blocca ancora presto durante lo sviluppo.

Non sono entusiasta di questo, dato che stai usando codice diverso per i tuoi utenti e solo perché la versione buggy continua a funzionare non significa che stia facendo la cosa giusta. Non bloccare, ma danneggiare il tuo database non è un comportamento desiderabile ...

+0

Sono d'accordo Non mi piace avere un codice diverso sulla produzione – Ian1971

+0

Perché il down-vote? –

1

Non si necessario esso, ma è utile avere. Uso qualcosa di simile nelle mie app. Puoi considerarlo "pigro", ma quando hai circa 20 oggetti, scrivendoli manualmente diventa noioso.

+1

Suppongo che non si tratti tanto della macro in sé, quanto della teoria di impostare un oggetto su zero dopo averlo rilasciato. Se hai finito con l'oggetto allora forse non dovresti provare ad accedervi di nuovo, e se riesci ad accedere di nuovo allora potrebbe essere meglio avere l'arresto in modo da poter risolvere quel particolare problema di codice. Ad esempio, perché stai tentando di accedervi di nuovo? – Ian1971

2

Penso che, o un equivalente come self.myVar = nil dove applicabile, è un bene. Ci sono molti casi in cui semplicemente non puoi semplicemente assegnare nil e supporre che qualsiasi accesso successivo sia un bug.

Ad esempio in UIKit è un buon comportamento liberare quante più risorse possibile quando il sistema operativo lo richiede. Per esempio.

- (void)didReceiveMemoryWarning 
{ 
    [myCachedData release]; 
    [super didReceiveMemoryWarning]; 
} 

Ora, quando verrà utilizzata la mia classe, come faccio a sapere che myCachedData non è più valido? L'unico modo (a corto di avere una variabile ANOTHER come flag) è di impostare myCachedData su zero dopo averlo rilasciato. E condensare queste due noiose linee in una è esattamente ciò che SAFE_RELEASE è per.

+0

Penso che tu abbia ragione, è corretto impostare a zero se applicabile. Penso che la trappola in cui sono caduto sia stata usare ciecamente la macro e non averla pensata troppo. – Ian1971

1

Stavo esaminando la stessa domanda.Con il bit di lettura ho fatto devo solo qualcosa di simile:

#define DEBUGGING 
    //#define PRODUCTION 

#ifdef DEBUGGING 
#define SAFE_RELEASE(X) [X release]; 
#else 
#define SAFE_RELEASE(X) [X release]; X = nil; 
#endif 

Quindi, in questo modo se sto sviluppando, mi vengono i crash. In produzione non lo faccio.

Scott < -

+0

Questo potrebbe portare a una difficile individuazione dei bug nella produzione - vedere la mia risposta per i dettagli. – Sebastian

1

Come Andrew ha sottolineato, ci sono casi in cui l'assegnazione nil non è solo evitano gli insetti, ma necessario. Basti pensare tipico UIViewController codice

- (void)viewDidLoad { 
    button = [UIButton buttonWithType:UIButtonTypeRoundedRect]; // autoreleased 
    [button retain]; // keep alive 
} 

- (void)viewDidUnload { // view has been removed 
    [button release]; 
} 

- (void)dealloc {  // destroying the view controller 
    [button release]; // <-- problem 
} 

Se viene caricato il controllore, successivamente scaricato (perché un altro controller di vista viene visualizzata una memoria si sta esaurendo) e infine distrutta, il [button release] in dealloc sarebbe eccessivo rilasciare il pulsante (invio un messaggio a un oggetto rilasciato). Pertanto è necessario assegnare nil. La soluzione sicura sarebbe:

- (void)viewDidUnload { // view has been removed 
    [button release]; 
    button = nil; 
} 

- (void)dealloc {  // destroying the view controller 
    [button release]; // <-- safe 
} 

Per questi casi una macro è piacevole e utile. Per essere più espliciti su quello che fa, meglio lo chiama RELEASE_AND_NIL

#define RELEASE_AND_NIL(X) [X release]; X = nil; 
Problemi correlati