Domanda

Questo è un piccolo dettaglio ma ogni volta che carico pigro qualcosa mi beccano su di esso. Sono entrambi questi metodi accettabili? O è meglio? Si supponga che la variabile ha la proprietà conservano.

Metodo # 1

(AnObject *)theObject{
    if (theObject == nil){
        theObject = [[AnObject createAnAutoreleasedObject] retain];
    }
    return theObject;
}

Metodo # 2

(AnObject *)theObject{
    if (theObject == nil){
        self.theObject = [AnObject createAnAutoreleasedObject];
    }
    return theObject;
}

In primo luogo, non sono sicuro se è OK per accedere a un altro funzione di accesso all'interno di una funzione di accesso (non vedo perché no, però). Ma sembra che l'impostazione della variabile di classe senza passare attraverso il setter potrebbe essere altrettanto male, se il setter fa qualcosa di speciale (o se la proprietà è cambiato in qualcosa oltre trattenere e il getter non è selezionata).

È stato utile?

Soluzione

Entrambi sono in realtà molto fragile e non a tutti identici, a seconda di ciò che i clienti della classe stanno facendo. Rendendoli identico è abbastanza facile - vedi sotto - ma che lo rende meno fragile è più difficile. Tale è il prezzo di inizializzazione differita (e perché in genere cercano di evitare l'inizializzazione differita in questo modo, preferendo trattare inizializzazione di sottosistemi come parte di gestione generale stato dell'applicazione).

Con 1 #, si sta evitando il setter e, quindi, nulla osservando il cambiamento non vedrà il cambiamento. Per "osservazione", sto specifico riferimento all'osservazione di valori-chiave (tra cui cacao Associazioni, che utilizza KVO per aggiornare l'interfaccia utente automaticamente).

Con 2 #, si attiverà la notifica di modifica, l'aggiornamento dell'interfaccia utente e altro esattamente come se il setter è stato chiamato.

In entrambi i casi, si ha un potenziale di ricorsione infinito se l'inizializzazione dell'oggetto chiama il getter. Ciò include eventuali osservatore chiede il vecchio valore come parte della notifica cambiamento. Non farlo.

Se avete intenzione di utilizzare entrambi i metodi, considerare attentamente le conseguenze. Si ha la possibilità di lasciare l'applicazione in uno stato incoerente, perché un cambiamento di stato di un immobile non ha notificato e l'altro ha il potenziale per la situazione di stallo.

Meglio evitare il problema del tutto. Vedi sotto.


Si consideri (garbage collection on, strumento da riga di comando di cacao di serie:

#import <Foundation/Foundation.h>

@interface Foo : NSObject
{
    NSString *bar;
}
@property(nonatomic, retain) NSString *bar;
@end
@implementation Foo
- (NSString *) bar
{
    if (!bar) {
        NSLog(@"[%@ %@] lazy setting", NSStringFromClass([self class]), NSStringFromSelector(_cmd));
        [self willChangeValueForKey: @"bar"];
        bar = @"lazy value";
        [self didChangeValueForKey: @"bar"];
    }
    return bar;
}

- (void) setBar: (NSString *) aString
{
    NSLog(@"[%@ %@] setting value %@", NSStringFromClass([self class]), NSStringFromSelector(_cmd), aString);
    bar = aString;
}
@end

@interface Bar:NSObject
@end
@implementation Bar
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context;
{
    NSLog(@"[%@ %@] %@ changed\n\tchange:%@", NSStringFromClass([self class]), NSStringFromSelector(_cmd), keyPath, change);
}
@end

int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    Foo *foo = [Foo new];
    Bar *observer = [Bar new];
    CFRetain(observer);
    [foo addObserver:observer forKeyPath:@"bar"
             options: NSKeyValueObservingOptionPrior | NSKeyValueObservingOptionNew
             context:NULL];
    foo.bar;
    foo.bar = @"baz";
    CFRelease(observer);

    [pool drain];
    return 0;
}

Questo non appendere. Si sputa:

2010-09-15 12:29:18.377 foobar[27795:903] [Foo bar] lazy setting
2010-09-15 12:29:18.396 foobar[27795:903] [Bar observeValueForKeyPath:ofObject:change:context:] bar changed
    change:{
    kind = 1;
    notificationIsPrior = 1;
}
2010-09-15 12:29:18.397 foobar[27795:903] [Bar observeValueForKeyPath:ofObject:change:context:] bar changed
    change:{
    kind = 1;
    new = "lazy value";
}
2010-09-15 12:29:18.400 foobar[27795:903] [Bar observeValueForKeyPath:ofObject:change:context:] bar changed
    change:{
    kind = 1;
    notificationIsPrior = 1;
}
2010-09-15 12:29:18.400 foobar[27795:903] [Foo setBar:] setting value baz
2010-09-15 12:29:18.401 foobar[27795:903] [Bar observeValueForKeyPath:ofObject:change:context:] bar changed
    change:{
    kind = 1;
    new = baz;
}

Se si dovesse aggiungere NSKeyValueObservingOptionOld alla lista delle opzioni per l'osservazione, lo fa molto blocco.

Per tornare a un commento che ho fatto in precedenza; la soluzione migliore è quella di non fare l'inizio pigro come una parte del vostro getter / setter . E 'troppo a grana fine. Tu sei molto meglio gestire il tuo stato oggetto grafico a un livello superiore e, come una parte di questo, avere una transizione di stato che è fondamentalmente dell ' "Yo! Ho intenzione di utilizzare questo sottosistema ora! Caldi che cattivo ragazzo in su! " che fa l'inizializzazione pigra.

Altri suggerimenti

Questi metodi non sono mai identici. Il primo è a destra, mentre il secondo è sbagliato ! Un getter non può mai chiamare will/didChangeValueForKey: e quindi anche non il setter. Questo porterà ad infinito ricorsione se si osserva che la proprietà.

E poi, non v'è alcun cambiamento di stato da osservare quando il membro viene inizializzato. Chiedete al vostro oggetto per il theObject e lo si ottiene. Quando questo viene creato è un dettaglio di implementazione e nessuna preoccupazione per il mondo esterno.

Se si conosce il metodo di proprietà setter è un setter di fissaggio standard, sono identici. In caso contrario, è necessario decidere se altri comportamenti del palleggiatore deve essere richiamato durante tale operazione. Se non si sa, è più sicuro di usare il setter, dal momento che il suo comportamento può essere importante. Non preoccuparti.

Sia di coloro che sono fondamentalmente identiche, la sua realtà solo a voi scegliere quale è meglio per il vostro caso. È già realtà ha descritto il pro / contro sull'utilizzo della sintassi di proprietà.

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