2015-08-11 11 views
5

Nell'applicazione a cui sto lavorando, cerco di sfruttare la nuova funzione di estensione del protocollo in Swift. L'idea è che ho molte classi che implementano lo stesso protocollo. Poiché tutte queste classi dovrebbero avere le stesse proprietà calcolate e poiché le proprietà dovrebbero comportarsi in modo identico in classi diverse, ho pensato che sarebbe stato carino aggiungere la funzionalità una sola volta.Come si memorizzano i dati inviati alle proprietà calcolate in un'estensione di protocollo?

Il mio codice è strutturato come il seguente esempio

protocol SomeProtocol { ... } 

// There could potentially be unlimited different versions of "SomeClass" that implements "SomeProtocol" 
class SomeClass : SomeProtocol { ... } 

extension SomeProtocol { 
    var computedProperty1: Type? { 
     get { getData(SOME_ENUM) } 
     set { validateAndSave(newValue, atKey: SOME_ENUM) } 
    } 
    var computedProperty2: Type? { 
     get { getData(SOME_OTHER_ENUM) } 
     set { validateAndSave(newValue, atKey: SOME_OTEHR_ENUM) } 
    } 
    ... 

    func getData(atKey: ENUM_TYPE) -> Type? { 
     [NEED SOME WAY TO GET THE SAVED DATA AND RETURN IT] 
    } 
    func validateAndSave(value: Type?, atKey: ENUM_TYPE) { 
     [NEED SOME WAY TO SAVE DATA FOR LATER RETURNING] 
    } 
} 

// The properties needs to be visible to the client code like this: 
class ClientCode { 
    let someClassObject: SomeProtocol = SomeClass() 
    someClassObject.computedProperty1 = Type() 
    print(someClassObject.computedProperty1) 
} 

(Il codice sopra mostra segni di memorizzazione dei dati in diversi dizionari, che è stato il mio primo pensiero)

Il problema è che un'estensione fa non supporta le proprietà memorizzate. Ma dove/come posso archiviare i dati inviati alle proprietà calcolate allora?

posso pensare di 2 diverse soluzioni, ma nessuno di loro bene ..

  1. ho potuto trasformare l'estensione in una classe che implementa SomeProtocol invece, e poi fare SomeClass una sottoclasse di esso. Ciò mi permetterebbe di salvare i dati nelle proprietà archiviate. Ma mi richiederebbe anche di implementare tutti i metodi che il protocollo richiede nella nuova classe, il che non ha assolutamente senso, dal momento che sono le diverse versioni di SomeClass che dovrebbero fornire funzionalità diverse.
  2. Posso semplicemente eliminare l'intera estensione idea e sposta tutte le proprietà in SomeProtocol. Ma ciò richiederebbe l'implementazione di tutte le proprietà calcolate in tutte le diverse versioni di SomeClass con funzionalità identiche e l'intero scopo della mia idea di estensione era evitare di scrivere la stessa implementazione per le stesse proprietà più e più volte.

C'è qualche soluzione logica completamente semplice che ho trascurato?

... o un bel modo per salvare i dati in un'estensione di protocollo che non conosco?

... o un altro modo di ottenere la funzionalità desiderata?

... o dovrei semplicemente succhiarlo e usare una delle mie soluzioni non così carine?

risposta

-1

Estensione del protocollo? Perché?

A volte siamo così ossessionati da un'idea che ignoriamo una soluzione pratica che ci fissa direttamente in faccia.

1. Avete un insieme di proprietà calcolate? No, vuoi le proprietà memorizzate.

Poiché tutte queste classi dovrebbero avere le stesse proprietà calcolate, e poiché le proprietà devono comportarsi identicamente in de diverse classi ...

... ma poi

Il problema è che un'estensione non supporta le proprietà archiviate. Ma dove/come posso memorizzare i dati inviati alle proprietà calcolate allora?

2. Supponendo che si tratti di un insieme di proprietà memorizzate che si desidera, in pratica è stata fornita la soluzione! Fatto un cambiamento che avrà senso ora.

ho potuto trasformare l'estensione in una classe che implementa SomeProtocol invece, e poi fare SomeClass una sottoclasse di esso. Che mi consentirebbe di salvare i dati nelle proprietà memorizzate.

si estende la classe ogni volta che si desidera e poi confermate sue sottoclassi per SomeProtocol per ottenere le caratteristiche. Questo è più pulito.

Nota a margine, i protocolli di Swift che non sono in grado di memorizzare le proprietà sono di progettazione. I protocolli non hanno un'esistenza a sé stante e non ha senso aggiungere proprietà memorizzate in essi.

+0

Se i protocolli potevano memorizzare proprietà che avrebbero solo fatto loro classi e poiché i protocolli possono essere aggiunti a una classe che è sottoclasse che essenzialmente creerebbe un'ereditarietà multipla . Ma Swift by design non supporta l'ereditarietà multipla. – zaph

+0

Vedo il tuo punto e ciò che è in realtà anche qualcosa che ho preso in considerazione. Il problema è che questa "soluzione" interrompe il codice client, dal momento che le proprietà (memorizzate o calcolate) sono ora visibili solo nella sottoclasse. – MortenHC

+0

@ zaph, puoi avere una classe per confermare tutti i protocolli che vuoi. Non è un'eredità multipla. Un'alternativa praticabile a uno - ma non è tecnicamente uno. – avismara

0

Supponendo di comprendere correttamente la domanda per aggirare il fatto che le estensioni di protocollo non supportano le proprietà memorizzate, è possibile estendere NSObject e utilizzare il runtime C oggettivo per memorizzare le proprietà.

import ObjectiveC 

private var AssociationKey: UInt8 = 0 

class YourStoredObject { 
    // Whatever object your are persisting 
} 

extension NSObject { 
    var yourStoredObject: (YourStoredObject)! { 
    get { 
     return objc_getAssociatedObject(self, &AssociationKey) as? YourStoredObject 
    } 
    set(newValue) { 
     objc_setAssociatedObject(self, &AssociationKey, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN) 
    } 
    } 
} 

protocol YourProtocol { 
    var yourStoredObject: YourStoredObject! { get set } 
} 

extension YourProtocol { 

    func customYourStoredObjectGetter() -> YourStoredObject { 
    return yourStoredObject 
    } 

} 

extension UILabel : YourProtocol { 

    func myExtendedFunc() { 
    // Get (and print) your object directly 
    print(yourStoredObject) 
    // Get your object through a protocol custom getter 
    print(customYourStoredObjectGetter()) 

    // Set your object 
    yourStoredObject = YourStoredObject() 
    } 
} 

Non sto dicendo che questa sia la soluzione migliore ma questa è l'unica soluzione che riesco a pensare. Sto anche cercando alternative Swift più belle ma non ne ho ancora trovato.

+0

Sono d'accordo con te, le soluzioni non sono così pulite finora, Swift non è ancora pronto per questo tipo di comportamento attraverso i protocolli di estensione !!, spero che arriverà molto presto. –

+0

Dato l'errore che dice che le proprietà memorizzate non sono supportate sulle estensioni del protocollo, spero che venga implementata nelle versioni successive poiché è una caratteristica mancante molto utile di Swift. – lucianomarisi

+0

Sono d'accordo che questa soluzione potrebbe funzionare ... ma l'aggiunta di una proprietà a ogni singolo NSObject sembra un serio overkill. Diciamo solo se ho visto un PR con questa modifica, sarebbe un rifiuto;) –

Problemi correlati