2009-06-03 8 views
7

Dopo aver letto il valore-chiave Guida Coding programmazione, il valore-chiave Osservando Guida alla programmazione e la Modello Guida Object Attuazione, così come la lettura molte voci StackOverflow sul tema e la sperimentazione di diversi scenari di modellazione, ho sento di avere una buona conoscenza di come modellare i miei dati.Le relazioni "to-many" dovrebbero essere modellate come proprietà?

Finisco per utilizzare le proprietà dichiarate per tutti i miei attributi e le relazioni a uno, supportate da ivars privati. Per gli attributi di sola lettura che devono essere scrivibili privatamente, utilizzo l'attributo readonly nella dichiarazione dell'interfaccia .h, quindi ripeto la proprietà con l'attributo readwrite in un'estensione di classe dichiarata nel file .m. All'interno dei metodi di classe, utilizzo sempre gli accessor della proprietà con la sintassi del punto e non accedo mai direttamente agli ivars privati.

C'è tuttavia un aspetto che mi lascia ancora perplesso: come modellare correttamente a-molte relazioni, specialmente quando la raccolta deve essere pubblicamente immutabile, ma in privato mutabile (cioè i consumatori dell'oggetto modello non possono aggiungere o rimuovere oggetti a la raccolta, ma il contenuto della raccolta è gestito privatamente dalla classe).

Capisco come implementare i metodi di accesso KVC per le relazioni to-many (countOf<Key>, objectsIn<Key>AtIndex, ecc.) E questa è la strada che ho seguito fino ad ora.

Tuttavia, ho visto alcuni codice di esempio che utilizza le proprietà dichiarate per esporre le relazioni, non implementare i metodi di accesso KVC, ma sono ancora visibili valore-chiave. Ad esempio:

@interface MyModel : NSObject 
{ 
    // Note that the ivar is a mutable array, 
    // while the property is declared as an immutable array. 
    @private NSMutableArray *transactions_; 
} 

@property (nonatomic, retain, readonly) NSArray transactions; 

@end 

-------------------- 

@implementation MyModel 

@synthesize transactions = transactions_; 

- (void)privateMethodThatManagesTransactions 
{ 
    [[self mutableArrayValueForKey:@"transactions"] addObject:t]; 
} 

@end 

Se un oggetto di consumo si aggiunge come osservatore di un'istanza MyModel per il percorso della chiave "transactions", esso sarà notificato quando vengono aggiunti o rimossi operazioni dalla collezione transactions (purché le mutazioni sono fatto tramite il metodo mutableArrayValueForKey:).

Per me, questo sembra il modo più pulito per esporre a molte relazioni in quanto non è necessario codificare manualmente gli accessori KVC della raccolta e mantiene il codice pulito.

Tuttavia, non sembra essere il modo in cui viene promosso dalla documentazione Apple e non posso fare a meno di chiedermi se il fatto che funzioni è solo un effetto collaterale inaffidabile.

Quindi prima di dedicarmi a una tecnica o l'altra nelle mie classi di modelli di vita reale per un progetto su cui sto iniziando a lavorare, mi piacerebbe avere l'opinione e il consiglio degli esperti sviluppatori di Cocoa.

Quindi la domanda è: se utilizzo le proprietà per modellare su molte relazioni, devo ancora implementare i metodi di accesso/mutatore KVC?

Aggiornamento

Anche quando dichiaro una proprietà a-molti come readonly, come nell'esempio di cui sopra, il codice esterno può ancora chiamare mutableArrayValueForKey:@"transactions" sul modello a oggetti e mutare la collezione. Questo sembra indicare che usare le proprietà dichiarate per molte relazioni non è la strada da percorrere, ma mi sembra ancora di non averlo capito ...

+0

Mi sono appena reso conto che anche per le proprietà semplici che rappresentano gli attributi o le relazioni uno, dichiarare la proprietà come readonly in .H e riaffermarlo come readwrite in .M consente al codice esterno di modificare il valore della proprietà utilizzando KVC setValue: forKey: ... Quindi sembra che KVC permetta di bypassare la semantica espressa nella dichiarazione di proprietà in tutti i casi, quindi suppongo che non dovrei essere sorpreso di poter mutare una raccolta in sola lettura usando mutableArrayValueForKey: .. –

risposta

6

Sì.

C'è tuttavia un aspetto che mi lascia ancora perplesso: come modellare correttamente a-molte relazioni, specialmente quando la raccolta deve essere pubblicamente immutabile, ma in privato mutabile ....

Facile: Dichiarare la proprietà come readonly nell'intestazione, quindi redeclare it as readwrite, copy in a class extension nel file di implementazione.

capisco come implementare i metodi di accesso KVC per a-molti (countOf<Key>, objectsIn<Key>AtIndex, ecc) e questo è il percorso ho seguito finora.

Ci sono anche dei mutativi. Con questi, non è necessario utilizzare mutableArrayValueForKey:; invece, è possibile utilizzare direttamente gli accessori mutativi. Riceverai comunque notifiche KVO, perché KVO avvolge quei metodi la prima volta che qualcosa si aggiunge come osservatore per la proprietà.

Ho il a list of the accessor selector formats, compresi gli accessori di accesso mutativo, sul mio blog.

Edit:

Anche quando dichiaro una proprietà a-molti in sola lettura, come nell'esempio di cui sopra, il codice esterno può ancora chiamare mutableArrayValueForKey:@"transactions" sul modello a oggetti e mutare la collezione.

Questa è una buona ragione per prendere l'abitudine di utilizzare le opzioni di accesso mutative ed evitare mutableArrayValueForKey:. Non invierai messaggi di mutazione dall'esterno della classe se ricevi un avvertimento sul compilatore (nessun metodo [pubblico]) ogni volta che lo provi.

Nonostante la disponibilità di mutableArrayValueForKey: e il rischio che qualcuno lo utilizzi, le proprietà conformi allo standard KVO sono il modo per andare qui.

+0

Grazie per la risposta rapida. Ho modificato la mia domanda per renderla più precisa: se uso le proprietà per modellare su molte relazioni, devo ancora implementare i metodi di accesso/mutatore KVC? –

+0

Sì. Puoi sintetizzare il getter, ma il setter sarà sbagliato se vuoi un oggetto mutabile nella tua ivar (@property (copy) ti dà * copie immutabili *) e @synthesize non ti darà alcuno dei precisi accessor (come objectIn AtIndex :). Quindi devi ancora implementare * almeno * il setter da solo. –

+0

Sono ancora confuso ... Se devo implementare i metodi KVC (accessori e mutatori), qual è il valore aggiunto di dichiarare una proprietà su di essi? –

Problemi correlati