Alternative al modello di delega che consente i messaggi ciechi tra i componenti

3

Esistono delegati e delegazioni per consentire il passaggio di messaggi specifici a un osservatore, indipendentemente dal tipo di tale osservatore. In un'architettura di tipo coordinatore, in cui i coordinatori gestiscono e gestiscono il flusso di un'applicazione (invece di dire il livello dell'interfaccia utente, iOS e UIKit), la delega funge da principale mezzo di comunicazione tra i coordinatori figlio ei loro genitori. Il problema è che queste chiamate delegate sono in genere piuttosto specifiche dell'applicazione in questione.

Un esempio tipico potrebbe essere:

protocol AuthenticationCoordinatorDelegate {
    func coordinatorDidPressLoginButton()
    func coordinatorDidPresentAuthenticationPage()
}

Questo protocollo si applica solo al coordinatore dell'autenticazione e viene sempre implementato dal suo proprietario. È un caso d'uso molto specifico usato in un posto e perché ogni altro coordinatore ha bisogno di un modo per comunicare, l'esecuzione di un piano di lavoro dilagante. Più un'applicazione cresce, più i coordinatori esisteranno e più interfacce di delega una tantum dovranno essere create, tutte non generiche.

Quali sono alcune possibili alternative al modello di delega che consente il passaggio di messaggi ciechi tra i componenti? Un pensiero che avevo era un'architettura in stile Redux dove invece di informare un delegato qualcosa è successo, un'azione viene inviata a un negozio centrale e il coordinatore genitore reagisce in modo appropriato. Esistono, naturalmente, gravi limitazioni a questo schema, come il modo in cui modellare azioni come premere un pulsante nell'albero dello stato e come mantenere tale albero di stato (in particolare sul cellulare).

Qualcuno ha suggerimenti o idee?

    
posta barndog 18.08.2016 - 09:01
fonte

2 risposte

2

Un modo semplice per fornire un collegamento anonimo tra i componenti consiste nell'utilizzare le proprietà di chiusura per "notifiche".

Un oggetto con una proprietà name , ad esempio, potrebbe anche avere:

var didChangeName: ((old: String, new: String) -> Void)?

Su name in fase di modifica, chiamerebbe self.didChangeName?(old: oldName, new: newName) .

Il proprietario o un altro oggetto interessato alla modifica, ad esempio una vista in un'impostazione MVVM, avrebbe dovuto impostare questa proprietà in precedenza per eseguire qualsiasi azione fosse appropriata:

viewModel.didChangeName = { [weak self] (old, new) in
    self?.reactToNameChange(old, new)
}

Questo è abbastanza flessibile in quanto a) qualsiasi altro oggetto può fare qualunque cosa vogliano con le notifiche; b) tale oggetto non deve occuparsi di notifiche a cui non interessa *; e c) anche se probabilmente sono raramente necessari, gli oggetti separati possono registrarsi liberamente per diverse parti del set di notifiche: ciò è impossibile con l'impostazione tradizionale dei delegati.

D'altra parte, è un po 'meno flessibile di una soluzione come KVO / Rx perché solo un oggetto può "iscriversi" ad ogni chiusura. Inoltre, passare notifiche su una catena di controllo è completamente esplicito, richiedendo di collegare i callback a mano a ogni livello. Ad esempio:

// Parent object
viewModel.modelDidChange = { [weak self] in
    self?.handleModelChange()
}

// Child object
subViewModel.didChangeName = { [weak self] (old, new) in
    // Do things...
    self?.modelDidChange()
}

Un secondo vantaggio è che è estremamente testabile, perché non c'è alcun requisito per un client diverso da quello che ha impostato la chiusura:

func testNotifiesViewOnNameChange()
{
    let newName = Model.dummy.name
    var viewModel = ViewModel(model: Model.dummy)
    var sentDidUpdate = false
    viewModel.didUpdate = { sentDidUpdate = true }

    viewModel.name = newName

    XCTAssertTrue(sentDidUpdate)
}

Se sei interessato a vederlo in modo più approfondito, dovresti dare un'occhiata a L'articolo di Ian Keen su MVVM non reattivo e il progetto di accompagnamento su GitHub . È lì che ho imparato questa tecnica, e penso che sia una spiegazione eccellente.

* Non possibile con un protocollo rigorosamente Swift

    
risposta data 26.08.2016 - 00:08
fonte
1

Bene, un semplice "schema" che viene in mente è usare NSNotificationCenter , qualcosa che può tornare utile quando è necessario aggiornare i controller di visualizzazione non direttamente connessi o nei casi in cui è necessario aggiornare più osservatori contemporaneamente. Assicurati di rimuovere gli osservatori per impedire i cicli di conservazione.

    
risposta data 25.08.2016 - 23:14
fonte

Leggi altre domande sui tag