Swift with Majid

the power of Delegate design pattern

29 May 2019

Last week before WWDC and everybody so excited about new features which we will have just in a few days. Kuitenkin, Let ’ s pitää postaukset liittyvät WWDC ensi viikolla. Tällä viikolla puhumme suosikkimuotoilijastani. Delegointi on suoraviivaisin ja tehokkain kuvio.

ohjelmistotekniikassa delegaatiokuvio on oliokeskeinen suunnittelukuvio, jonka avulla oliokoostumus voi saavuttaa saman koodin uudelleenkäytön perintönä. Delegoinnissa objekti käsittelee pyynnön delegoimalla toiselle objektille (delegoidulle). Delegaatti on auttaja-objekti, mutta alkuperäisellä asiayhteydellä.

protokollat

käytämme Delegointikuviota joka päivä, ja iOS SDK käyttää sitä monissa paikoissa. Esimerkiksi UITableView valtuutetut uitableviewdatasource täyttää taulukon soluilla, se myös siirtää solun valinta ja muut toimet UITableViewDelegate. Toinen erinomainen esimerkki delegaateista on FlowController tai Koordinaattorit. View controllers delegoi navigointilogiikan koordinaattorille. Olen erotettu post noin talteen navigointilogiikka osaksi FlowControllers.

sukelletaan koodinäytteisiin. Oletetaan, että työskentelet pelin parissa. Olet purettu pelin logiikan osaksi erotettu luokan peli, ja haluat siirtää pelin tilan muutokset UIViewController joka tekee tämän pelin.

protocol GameDelegate: AnyObject { func stateChanged(from oldState: Game.State, to newState: Game.State)}class Game { private var state: State = .notStarted { didSet { delegate?.stateChanged(from: oldValue, to: state) } } weak var delegate: GameDelegate? private(set) var value: Int = 0 func start() { state = .started } func generateNextValue() { value = Int.random(in: 0..<1000) state = generateState(using: value) }}extension Game { enum State { case notStarted case started case right case win case lost }}

tässä on yksinkertaisen pelin lähdekoodi, joka luo satunnaisia arvoja. Pelimoottori luo tilan satunnaisten arvojen perusteella. Jokainen valtion muutos kutsua valtuutettu siirtää vanhoja ja uusia valtioita. Määrittelemme delegointiprotokollamme laajennettuna AnyObject-projektista, mikä tarkoittaa, että ainoa luokka-instanssi voi hyväksyä sen. Käytän myös heikko avainsana määritellä muuttuja holding delegaatti. Sen piti katkaista delegaatin ja peliluokan välinen palautuskierre. Katsotaanpa GameViewController nyt.

class GameViewController: UIViewController { private let game: Game init(game: Game) { self.game = game super.init(nibName: nil, bundle: nil) } @IBAction func play() { game.start() } @IBAction func next() { game.generateNextValue() } override func viewDidLoad() { super.viewDidLoad() game.delegate = self }}extension GameViewController: GameDelegate { func render(_ state: Game.State) { switch state { case .lost: renderLost() case .right: renderRight() case .win: renderWin() case .started: renderStart() case .notStarted: renderNotStarted() } } func stateChanged(from oldState: Game.State, to newState: Game.State) { render(newState) }}

Tässä Meillä on GameViewController luokka, joka syöttää pelin käyttäjän toimia ja tehdä tilan muutoksia. GameViewController noudattaa Gamedelegatea ja toteuttaa kaiken tarvittavan renderöinnin laajennuksessa. Tämän seurauksena meillä on kompostoitava codebase avulla delegoida suunnittelukuvio.

sulkemiset

joskus kun valtuutetussa on vain yksi menetelmä, sen voi korvata sulkemisella. Idea on sama, mutta nyt soitetaan sulkemiselle ja ohitetaan valtio sen sijaan, että soitetaan menetelmää protokollan mukaan. Katsotaanpa katsomaan esimerkki sulkeminen.

class Game { typealias StateHandler = (State) -> Void var handler: StateHandler? private var state: State = .notStarted { didSet { handler?(state) } }}class GameViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() game.handler = { state in self?.render(state) } }}

kuten näette, siirrämme sulkemisen peliluokan instanssiin, joka käsittelee valtion muutoksia. Käytämme heikkoa katkaisemaan säilyttämissyklin sulkemisen kontekstikaappauksen aikana. Toinen vaihtoehto tässä voi olla käyttö siitä, että mikä tahansa Swift-toiminto on sulkeminen. Joten sen sijaan, että luodaan erotettu sulkeminen, voimme siirtää funktion nimi. Kuitenkin olla varovainen tämä menetelmä luo säilyttää ympyrä. Tässä on esimerkki siitä, miten voimme tehdä sen.

class GameViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() game.handler = render }}extension GameViewController { func render(_ state: Game.State) { switch state { case .lost: renderLost() case .right: renderRight() case .win: renderWin() case .started: renderStart() case .notStarted: renderNotStarted() } }}

johtopäätös

tänään keskustelimme iOS-kehityksen tehokkaimmasta ja suoraviivaisimmasta suunnittelukuviosta. Nautin siitä, kuinka yksinkertainen se on ja kuinka hyödyllistä se voi olla säveltäminen kappaletta tehdä codebase irrotettu. Voit vapaasti seurata minua Twitterissä ja kysyä kysymyksiä, jotka liittyvät tähän viestiin. Kiitos lukemisesta ja nähdään ensi viikolla!



+