Frykt kom bare sakte inn da jeg skjønte at jeg begynner å bli tom for disse arkivbildene

Swift + Initialisering med lukkinger

Lukkinger F.T.W.

En rask merknad - alle mine fremtidige innlegg vil bli publisert på min dedikerte webside, og denne publikasjonen blir ikke lenger oppdatert. Takk for at du leste!

Jeg begynner å grave hele initialiseringsdansen i Swift. Jeg skrev om det. Jeg skrev om hvorfor det til og med fungerer slik det gjør. Jeg snakket om det. Jeg leste om det (mye). Men hei, jeg er tilbake for en ny handling i saken.

Av alle de mange, vakre og varierte måtene man kan initialisere noe i Swift - bruk av nedleggelser er ikke vanligvis ført opp som en metode å gjøre det på. Men akk, det kan gjøre at boilerplatey ™ init () -koden er mye mindre smertefull og litt mer håndterbar.

For det programmatiske brukergrensesnittet som finnes der ute - dette for deg !

UIKit == UIHugeSetupCode ()

Se, det er ikke UIKits feil. Komponenter som må samhandles med en bruker, låner seg til et fjell med oppsettkode, fordi preferanser. Vanligvis finner mye av dette seg enten i viewDidLoad eller loadView:

overstyre func loadView ()
{
    la helloWorldLbl = UILabel ()
    helloWorldLbl.text = NSLocalizedString (“controller.topLbl.helloWorld”, kommentar: “Hello World!”)
    helloWorldLbl.font = UIFont.preferredFontForTextStyle (UIFontTextStyleBody)
    helloWorldLbl.textColor = UIColor.whiteColor ()
    helloWorldLbl.textAlignment = .Center
    self.view.addSubview (helloWorldLbl)
}

Dette er ganske standard for de av oss som våger Cocoa Touch-vannet uten .xib- eller .storyboard i sikte. Skjønt, hvis du deler min kjærlighet til minuscule viewDidLoad- eller loadView-metoder, kan du legge dette fra et annet sted.

Si en eiendom:

la helloWorldLbl: UILabel = {
    la lbl = UILabel ()
    lbl.text = NSLocalizedString (“controller.topLbl.helloWorld”, kommentar: “Hello World!”)
    lbl.font = UIFont.preferredFontForTextStyle (UIFontTextStyleBody)
    lbl.textColor = UIColor.whiteColor ()
    lbl.textAlignment = .Center
    retur lbl
} ()

Ganske. I Apples egen bok om Swift bemerker den at “hvis eiendommens standardverdi krever tilpasning eller oppsett, kan du bruke en nedleggelse eller en global funksjon for å gi en tilpasset standardverdi for den egenskapen.” Som vi nettopp nevnte, kontrollerer UIKit avkastningen mye tilpasning og oppsett.

Et av de vakre biproduktene er imidlertid hvordan loadView ser ut nå:

overstyre func loadView
{
    self.view.addSubview (self.helloWorldLbl)
}

Vær imidlertid oppmerksom på “()” på slutten av nedleggelsen i eiendomserklæringen. Dette gir beskjed til de små Swift-veiviserne som kompilerer koden din om at forekomsten blir tilordnet returtypen for lukkingen. Hvis vi skulle utelate dette, er det mulig vi kunne ha tildelt selve stengingen til forekomsten.

Og i dette tilfellet er det .

Regler er regler

Selv om vi har et skinnende nytt leketøy, er det viktig å huske landets regler. Siden vi tilordner en eiendom til en nedleggelse, kan det hende at resten av den inneholder forekomsten ikke er blitt initialisert ennå. På grunn av dette er det ikke mulig å henvise til andre eiendomsverdier eller meg selv fra nedleggelsen.

For eksempel:

la helloWorldLbl: UILabel = {
    la lbl = UILabel ()
    lbl.text = self.someFunctionToDetermineText () // Kompilatorfeil
    lbl.font = UIFont.preferredFontForTextStyle (UIFontTextStyleBody)
    lbl.textColor = self.myAppTheme.textColor () // Nok en feil
    lbl.textAlignment = .Center
    retur lbl
} ()

Forekomsten av meg selv er kanskje ikke trygt å bruke ennå, eller det er muligens ikke gjennomført med Swifts tofase initialiseringsprosess. Det samme er tilfelle for noen forekomstegenskaper, som kanskje eller ikke kan tildeles og initialiseres siden nedleggelsen utføres umiddelbart.

Dette er en distinkt, men berettiget ulempe med å bruke lukkinger for initialisering. Det er imidlertid fullstendig fornuftig - og det stemmer overens med et av de tre designmålene til Swift: sikkerhet.

Gettin 'Cute with Collections

Et område der jeg har funnet denne teknikken spesielt nyttig, er tilfeller som representerer en av de mange forskjellige formene for en samling i Swift. Av Swifts mange talenter, skiver og siler gjennom samlinger med kraften fra tusen titaner, er en av mine mest favoritt.

Tenk på følgende eksempel, hentet fra en initialisator i et prosjekt jeg for tiden jobber med. Klassen som huser denne koden har en [Developer] -egenskap. På en ny lansering satte jeg de første verdiene fra en .plist-fil. Etterpå blir disse lagret via NSKeyedArchiver.

vakt la devs = NSKeyedUnarchiver.unarchiveObjectWithFile (DevDataManager.ArchiveURL.path!) som? [Utvikler] annet
{
    self.developers = {
        la pListData = // Få plistdata
        var devArray: [Developer] = [Developer] ()
        // Sett opp devArray fra plistdata
        return devArray.map {$ 0.setLocation ()}
                       .filter {$ 0.isRentable}
                       .sort {$ 0.name <$ 1.name}
     } ()
    komme tilbake
}
self.developers = devs

Jeg liker ganske godt denne tilnærmingen, for selv om vi ikke bruker den utenfor en initialiserer, er intensjonen med koden veldig tydelig på at den bare er ansvarlig for å sette en eiendom.

Etter hvert som initialisatorer og viewDidLoad-overstyringer blir større, er seksjonering av ting som dette (i det minste) en kjærkommen gave når det gjelder lesbarhet.

Å få NSCute

Hvis du virkelig digger å initialisere ting med en nedleggelse, men lider av en alvorlig mangel på å bruke de funksjonelle $-ene i koden din, kan du muntre opp. Ved å bruke noen dyktige Swiftery, kan man forfattere noen kode som angir typen i selve lukkingen, noe som gir en viss pro stilkonfigurasjon. Tenk på denne koden, som jeg først kom over på den alltid informative NSHipster:

@warn_unused_result
public func Init  (verdi: Type, @noescape-blokk: (objekt: Type) -> Void) -> Type
{
    blokk (objekt: verdi)
    returverdi
}

Jeg liker hvor dette går. En offentlig funksjon som tar nedleggelse med et maskinskrevet objekt ved hjelp av generiske data, som deretter returnerer den typen. Dette betyr at du kan snu og initialisere ting med mer type informasjon. Vår første kodeeksempel ville da på sin side se slik ut:

let helloWorldLbl = Init (UILabel ()) {
    $ 0.text = NSLocalizedString (“controller.topLbl.helloWorld”, kommentar: “Hello World!”)
    $ 0.font = UIFont.preferredFontForTextStyle (UIFontTextStyleBody)
    $ 0.textFarge = UIColor.whiteColor ()
    $ 0.textAlignment = .Center
}

Selv om det kan virke fancy, dreper det virkelig behovet for forekomstvariabelen innen lukkingen, og den blir kvitt "()" -kravet. Veldig hyggelig .

Siste tanker

Det kan sies at bruk av en slik teknikk er seks i den ene hånden, og et halvt dusin i den andre. Selv om det stemmer at kodelinjene som er skrevet av programmereren forblir stort sett de samme, vil jeg hevde at plasseringen og fleksibiliteten gjør den ideell for mange scenarier.

Det er en morsom måte å gjøre ting på, og det er til og med noen få måter å gjøre det samme i vår gamle venn Objekt-C. Men hei, jo mer vet du, amiritt?

Inntil neste uke = {la uke = uke () uke.advancedBy (dager: 7)} ()

Jordan Morgan er en iOS-programvareingeniør som driver Dreaming In Binary

Hvis du lærte om bruk av stenginger for initialisering, kan du gjerne gå foran og NSR anbefaler (dette, hvor: nedenfor);