objective c - Ogni ivar deve essere una proprietà?




objective-c ios (3)

Le proprietà sono solo zucchero sintattico che ti evita di scrivere sempre gli stessi metodi. Con una proprietà hai un setter che rilascia il vecchio oggetto e conserva quello nuovo gratuitamente.

Lo vedo raccomandato dappertutto quando si codifica per iOS che le proprietà dovrebbero essere utilizzate per accedere alle variabili di istanza a causa dei vantaggi che questo offre alla gestione della memoria, tra le altre cose.

Questo consiglio non si adatta molto bene a me. Trovo che l'utilizzo di proprietà al posto di semplici vecchi ivars richieda troppo codice e non vedo realmente i benefici se si ha dimestichezza con la gestione della memoria. È davvero così importante? Qual è il tuo approccio alla gestione delle variabili di istanza?


Mentre la risposta di Daniel è corretta, penso che manchi un punto importante. Vale a dire:

Trovo che l'utilizzo di proprietà al posto di semplici vecchi ivars richieda troppo codice e non vedo realmente i benefici se si ha dimestichezza con la gestione della memoria.

I benefici sono consistenza; gestione coerente della memoria e comportamento coerente.

In particolare, queste due righe di codice possono effettivamente avere un comportamento estremamente diverso in fase di esecuzione:

iVar = [foo retain];
self.iVar = foo;

Il primo è un'impostazione diretta della variabile di istanza e non ci saranno notifiche di modifica. Il secondo passa attraverso il setter e, quindi, conserva le eventuali personalizzazioni della sottoclasse sul set e garantisce che tutti gli osservatori della proprietà vengano informati della modifica .

Se stai usando ivars direttamente attraverso il tuo codice (internamente alla classe - se stai usando ivars di un'istanza direttamente dall'esterno di quell'istanza, beh ... qualsiasi appaltatore che lavora sulla tua base di codice dovrebbe raddoppiare le loro tariffe;), quindi devi o gestiscono manualmente la propagazione delle notifiche di modifica (in genere chiamando willChangeValueForKey: / didChangeValueForKey ) o ingegnerizzando esplicitamente la propria applicazione per evitare l'utilizzo di meccanismi basati didChangeValueForKey del valore-chiave.

Dici "prende troppo codice". Non lo vedo; nelle due righe di codice precedenti, la sintassi del punto è costituita da un numero inferiore di caratteri. Anche chiamare il metodo setter usando la sintassi tradizionale sarebbe meno codice.

E non sottovalutare il valore nella centralizzazione della gestione della memoria; un'omissione accidentale in una miriade di siti di chiamate e crash city.


Per i campi privati ​​- suggerisco che è sicuro usare ivars diretti solo per i tipi primitivi (BOOL / int / float ecc.). Trovo una buona pratica che avvolge tutto ciò che riguarda la gestione della memoria nelle proprietà, anche nei campi usati raramente. Un ulteriore vantaggio di questo approccio è che l'IDE evidenzia in genere l'accesso diretto a ivars in modo diverso, in modo da avere sempre una buona separazione tra campi scalari semplici e campi di tipo oggetto.

Contrariamente a ciò, sconsiglio vivamente tutti gli ivar diretti nell'interfaccia pubblica di classe . A causa della natura dinamica del linguaggio, può portare a errori di runtime estremamente difficili da trovare, localizzare e correggere. Considera la seguente gerarchia

@interface BaseControl
...
@end

@interface Label : BaseControl
...
@end

@interface Button : BaseControl {
  @public
    BOOL enabled;
}
@end

e uno snippet di codice

- (void)enableAllButtons {
    NSArray *buttons = [self getAllButtons];   // expected to contain only Button instances
    for (Button *button in buttons) {
        button->enabled = YES;
    }
} 

Ora immagina che ci sia un errore da qualche parte nella logica -getAllButtons e ottieni anche alcune etichette restituite in quell'array, quindi quelle istanze della classe Label mancheranno l'ivar mancante assegnato. Il fatto che possa essere sorprendente è che -enableAllButtons non si bloccherà in quel caso. Ma a quel punto quelle strutture interne delle istanze Label sono danneggiate e questo causerà comportamenti indefiniti e arresti anomali quando vengono utilizzati altrove.

Come alcuni problemi comuni con la gestione della memoria (e in generale - con puntatori penzolanti) - questo tipo di problemi è difficile da trovare e localizzare - perché l'aspetto dell'errore di solito è distante (in termini di tempo, codice o flusso di app) dal luogo, causando l'errore. Ma con quel particolare problema non hai nemmeno strumenti pratici (come gli analizzatori di perdite / zombi, ecc.) Per aiutarti a localizzarlo e correggerlo, anche quando impari come riprodurlo e puoi facilmente indagare su uno stato errato.

Ovviamente se si usa @property (assign) BOOL enabled; riceverai una facile diagnosi e correzione dell'eccezione di runtime in -enableAllButtons.





instance-variables