Teama se instalează încet, întrucât mi-am dat seama că încep să rămân fără aceste fotografii stock

Swift + inițializare cu închideri

Închideri F.T.W.

O notă rapidă - toate postările mele viitoare vor fi publicate pe site-ul meu dedicat, iar această publicație nu mai este actualizată. Multumesc pentru citit!

Încep să săpat cu adevărat întregul dans de inițializare din Swift. Am scris despre asta. Am scris despre motivul pentru care funcționează chiar așa. Am vorbit peste asta. Am citit despre asta (multe). Dar hei, mă întorc pentru încă un act în această privință.

Dintre toate numeroasele, frumoase și variate moduri, se poate inițializa ceva în Swift - utilizarea închiderilor nu este în mod obișnuit prezentată ca metodă de a face acest lucru. Dar, din păcate, poate face codul boilerplatey ™ init () mult mai puțin dureros și puțin mai ușor de gestionat.

Pentru interfața utilizatorului programatic devs acolo - acestea pentru tine !

UIKit == UIHugeSetupCode ()

Uite, nu este vina UIKits. Componentele cu care un utilizator trebuie să interacționeze se împrumută pe un munte de cod de configurare, deoarece preferințele. În mod obișnuit, o mulțime de acestea se regăsesc în viewDidLoad sau loadView:

Anulează funcția loadView ()
{
    let helloWorldLbl = UILabel ()
    helloWorldLbl.text = NSLocalizedString („controller.topLbl.helloWorld”, comentariu: „Hello World!”)
    helloWorldLbl.font = UIFont.preferredFontForTextStyle (UIFontTextStyleBody)
    helloWorldLbl.textColor = UIColor.whiteColor ()
    helloWorldLbl.textAlignment = .Center
    self.view.addSubview (helloWorldLbl)
}

Acest lucru este destul de standard pentru cei dintre noi care aventuram apele Cocoa Touch fără un .xib sau .storyboard la vedere. Deși, dacă împărtășești dragostea mea pentru metodele minuscule ViewDidLoad sau loadView, poți pune asta în altă parte.

Spune, o proprietate:

let helloWorldLbl: UILabel = {
    let lbl = UILabel ()
    lbl.text = NSLocalizedString („controller.topLbl.helloWorld”, comentariu: „Hello World!”)
    lbl.font = UIFont.preferredFontForTextStyle (UIFontTextStyleBody)
    lbl.textColor = UIColor.whiteColor ()
    lbl.textAlignment = .Center
    intoarce lbl
} ()

Frumos. În propria carte Apple despre Swift, se observă că „dacă valoarea implicită a proprietății dvs. necesită o anumită personalizare sau configurare, puteți utiliza o închidere sau o funcție globală pentru a oferi o valoare implicită personalizată pentru proprietatea respectivă.” După cum am menționat, UIKit controlează randamentul. multă personalizare și configurare.

Totuși, unul dintre cele mai frumoase produse secundare este aspectul loadView acum:

anulează funcția loadView
{
    self.view.addSubview (self.helloWorldLbl)
}

Atenție, totuși, la „()” de la sfârșitul închiderii din declarația de proprietate. Aceasta înseamnă că micii vrăjitori Swift care compun codul dvs. știu că instanța este atribuită tipului de returnare a închiderii. Dacă omitem acest lucru, este posibil să putem atribui chiar închiderea propriu-zisă instanței.

Și în acest caz, asta este .

Regulile sunt reguli

Chiar dacă avem o jucărie nouă strălucitoare, este imperativ să ne amintim de regulile terenului. Deoarece atribuim o proprietate unei închideri, este posibil ca restul instanței care conține să nu fi fost inițializate încă. Din acest motiv, atunci când închiderea se execută - nu este posibil să faceți referință la alte valori ale proprietății sau la sine.

De exemplu:

let helloWorldLbl: UILabel = {
    let lbl = UILabel ()
    lbl.text = self.someFunctionToDetermineText () // Eroarea compilatorului
    lbl.font = UIFont.preferredFontForTextStyle (UIFontTextStyleBody)
    lbl.textColor = self.myAppTheme.textColor () // O altă eroare
    lbl.textAlignment = .Center
    intoarce lbl
} ()

S-ar putea ca instanța de sine să nu fie încă sigură de utilizat sau s-ar putea să nu se întâmple cu procesul de inițializare în două faze a lui Swift. Același lucru este valabil pentru orice proprietăți de instanță, care pot fi sau nu alocate și inițializate, deoarece închiderea se execută imediat.

Acesta este un dezavantaj distinct, dar justificat, cu utilizarea închiderilor pentru inițializare. Cu toate acestea, are sens complet - și este în concordanță cu unul dintre cele trei obiective de proiectare ale Swift: siguranța.

Gettin 'Drăguț cu colecții

Un domeniu în care am găsit această tehnică deosebit de utilă este cu situațiile care reprezintă una dintre numeroasele forme diferite ale unei colecții din Swift. Dintre numeroasele talente ale lui Swift, felierea și cernerea colecțiilor cu puterea a o mie de titani este unul dintre cei mai preferați ai mei.

Luați în considerare următorul exemplu, preluat de la un inițiator într-un proiect în care lucrez în prezent. Clasa care găzduiește acest cod are o proprietate [Dezvoltator]. La o nouă lansare, am setat valorile inițiale dintr-un fișier .plist. Ulterior, acestea sunt stocate prin NSKeyedArchiver.

guard let devs = NSKeyedUnarchiver.unarchiveObjectWithFile (DevDataManager.ArchiveURL.path!) as? [Dezvoltator] altceva
{
    self.developers = {
        let pListData = // Obțineți date despre plist
        var devArray: [Dezvoltator] = [Dezvoltator] ()
        // Configurați devArray din datele de plist
        return devArray.map {$ 0.setLocation ()}
                       .filter {$ 0,isRentable}
                       .sort {$ 0.name <$ 1.name}
     } ()
    întoarcere
}
self.developers = devs

Îmi place foarte mult această abordare, deoarece, deși nu o folosim în afara unui inițializator, intenția codului este foarte clară, întrucât este responsabilă doar de setarea unei proprietăți.

Pe măsură ce inițializatoarele și suprasolicitările ViewDidLoad devin mai mari, secționarea lucrurilor astfel (cel puțin) este un cadou binevenit în termeni de lizibilitate.

Obținerea NSCute

Dacă săpați cu adevărat inițializarea lucrurilor cu o închidere, dar suferiți de o lipsă severă de a folosi acele funcționale $ în codul dvs., încercați-vă. Folosind unii Swiftery adepți, se poate crea un anumit cod care încorporează tipul în cadrul închiderii în sine, ceea ce produce o configurație de stil pro. Luați în considerare acest cod, pe care l-am întâlnit pentru prima dată pe NSHipster mereu informativ:

@warn_unused_result
public func Init  (valoare: Type, @noescape bloc: (obiect: Type) -> Void) -> Type
{
    bloc (obiect: valoare)
    valoare returnată
}

Îmi place unde merge asta. Funcție publică care ia o închidere cu un obiect tastat folosind generice, care apoi returnează acel tip. Aceasta înseamnă că puteți să vă întoarceți și să inițiați lucrurile cu mai multe informații de tip. Primul nostru eșantion de cod ar arăta, la rândul său, astfel:

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

Deși ar părea fantezist, chiar elimină nevoia variabilei de instanță din interiorul închiderii și scapă de cerința „()”. Foarte frumos .

Gânduri finale

S-ar putea spune că folosirea unei astfel de tehnici înseamnă șase într-o mână, și o jumătate de duzină în cealaltă. Deși este adevărat că liniile de cod autorizate de programator rămân în mare parte aceleași, am susținut că plasarea și flexibilitatea acestuia îl fac ideal pentru multe scenarii.

Este o modalitate distractivă de a duce la bun sfârșit lucrurile și există chiar câteva moduri de a face același lucru în vechiul nostru prieten Obiectiv-C. Dar hei, cu cât știi mai mult, amirite?

Până la nextWeek = {let week = Week () week.advancedBy (zile: 7)} ()

Jordan Morgan este un inginer software iOS care conduce Dreaming In Binary

Dacă ați aflat despre utilizarea închiderilor pentru inițializatori, vă rugăm să nu ezitați să mergeți mai departe și NSRecommend (aceasta, unde: mai jos);