Pytanie Swift: metody wywołania zmiennej opcjonalnej


Tak więc znam różnicę między "!" i "?", chcę tylko wiedzieć, jaki jest najlepszy sposób ich użycia podczas wywoływania metody zmiennej opcjonalnej

var bar: Bar? = nil

bar?.doSomething()  // this will be valid, but wouldn't call doSomething
bar!.doSomething() // Given error: EXC_BAD_INSTRUCTIONS (Obviously)

Ale gdy 'bar' nie jest zerowy, te dwa wywołania metod są poprawne.

bar = Bar()
bar?.doSomething()  // Valid
bar!.doSomething()  // Valid

Moje pytanie brzmi: jaki jest najlepszy sposób wywoływania metod zmiennej opcjonalnej, ja osobiście używam:

if bar != nil {
    bar!.doSomething()
}

lub będzie pasek? .doSomething () zrobić dokładnie to samo?


11
2018-03-13 08:57


pochodzenie


Zasada: za każdym razem możesz uniknąć pisania !, zrób to (z wyjątkiem negowania a Bool). Obejmuje to np. przymusowy downcast as!. ! znaczy Hey! Don't do it! It's dangerous! I warned you! - Jean-Philippe Pellet
! znaczy I know exactly what I am doing! I am the developer and I decide how my program should run! It's not up to some variable to decide if a method should be called!. Moim zdaniem twórcy Objective-C mają tendencję do nadużywania ?. Jeśli opcjonalnie scalisz rzeczy, które nie powinny być opcjonalne (z punktu widzenia projektowania oprogramowania), emulujesz przyjazne zero z Objective-C. - Matthias Bauch
@ MatthiasBauch ! znaczy I am the developer and I never make mistakes! My program always runs exactly as! I decided! W mojej opinii ! oznacza po prostu this should never be nil, do not continue if it does. - Krzak


Odpowiedzi:


Myślę, że to jest zła rada, której należy unikać bar?.doSomething() i zawsze używaj if let bar = bar { ... } zamiast.

Istnieją dwa główne powody:

Pierwszy, bar?.doSomething() po prostu jest bardziej zwięzły. Jeśli piszesz if let używając tylko jednego wyrażenia warunkowego, powinieneś zadać sobie pytanie, czy nie chcesz umieszczać tego kodu w jednym wierszu z krótszą wersją.

Chociaż jest to całkowicie legalny kod.

if let thing = thing {
    thing.bar()
}

.. Poniższy jest tak samo legalny, tylko o wiele krótszy ..

thing?.bar()

Po drugie, ważniejsze i kluczowe dla tego problemu, nie są one takie same! The if let jest połączonym testem, opcjonalnym rozpakowaniem i przypisaniem podczas bar? robi coś, co nazywa Opcjonalne połączenie.

Ta ostatnia jest bardzo przydatna w wielu przypadkach, która pozwala napisać znacznie ładniejszy kod. Na przykład:

Może być użyty do zastąpienia tego ..

var imageGenerator: ImageGenerator?

if let generator = imageGenerator {
    myView.image = generator.generateImage()
} else {
    myView.image = nil
}

.. po prostu z:

myView.image = self.imageGenerator?.generateImage()

Powodem tego jest, ponieważ Opcjonalne połączenie zwraca nil jak tylko się pojawi nil w łańcuch. I od tego czasu UIImageView ma image: UIImage?, przyjmuje tę zerową wartość. Nawet jeśli pochodzi z ImageGenerator?

Jest jeszcze bardziej przydatny w połączeniu z Operator koalescencji zerowej, ??.

Teraz możesz włączyć ten kod ...

var imageGenerator: ImageGenerator?

if let generator = imageGenerator {
    myView.image = generator.generateImage()
} else {
    myView.image = DefaultImage
}

.. w ..

myView.image = generator?.makeImageGenerator() ?? DefaultImage

.. co jest bardziej zwięzłe.

I ponieważ Opcjonalne połączenie działa dalej Więzy ... możesz nawet zrobić coś takiego:

myView.image = delegate?.makeImageGenerator()?.generateImage() ?? DefaultImage

Które stanie się ...

if let delegate = delegate {
    if let generator = delegate.generatorForImage() {
        if let image = generator.generateImage() {
            myView.image = image
        } else {
            myView.image = DefaultImage
        }
    } else {
        myView.image = DefaultImage
    }
} else {
    myView.image = DefaultImage
}

.. jeśli nie używałeś Opcjonalne połączenie i Operator koalescencji zerowej.

(Tak myView.image = DefaultImage można to zrobić tylko warunkowo na końcu, ale to oznacza, że ​​nadal musisz wprowadzić dodatkowy kod, aby sprawdzić, czy został ustawiony. To nie będzie dużo krótsze.)

Tam są dwie nowe sztuczki :-)


23
2018-03-13 13:30





Kiedy to zrobisz

bar?.doSomething() 

nazywa się Opcjonalne łańcuchy: https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/OptionalChaining.html

Oznacza to, że w przypadku, gdy pasek jest zerowy, nie będzie kontynuował wykonywania tej samej metody, ale zwróci zero. Jeśli chcesz obsłużyć przypadki, w których jest zerowe, powinieneś sprawdzić, czy obiekt zawiera zero, czy nie. Możesz również zrobić to w ten sposób, opcjonalnie wiążąc:

if let unwrappedBar = bar {
    unwrappedBar.doSomething()
} else {
    doSomeOtherThing() // In case it's nil
}

To sprawia, że ​​wartość jest dostępna w instrukcji if let jako stała tymczasowa o nazwie unwrappedBar (możesz nadać jej dowolną inną nazwę, jeśli chcesz), jeśli nie jest zerowa.

Możesz także użyć krótszej składni z opcjonalnym operatorem łączenia i łączenia:

bar?.doSomething() ?? doSomeOtherThing()

Oto więcej informacji o różnych sposobach uzyskiwania dostępu do opcjonalnych wartości: https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-ID330


4
2018-03-13 09:04



Świetnie, powinienem użyć jeśli pozwolisz częściej - Youri Nooijen
To nie jest właściwie zamknięcie. - Stefan Arentz
@StefanArentz to prawda, dziękuję. Mam nadzieję, że teraz jest poprawna. :) - Aleksi Sjöberg


bar?.doSomething() 

to najlepszy sposób wywołania metody zmiennej opcjonalnej. Wywołuje tylko coś, jeśli pasek nie jest zerowy. Piszesz najmniejszy kod i jest dokładnie taki jak implementacja if let czek

if let bar = bar {
    bar.doSomething()
}

2
2018-03-13 09:13



Myślę, że to jest lepsza rada niż "zawsze używaj if let". Ta forma istnieje z jakiegoś powodu: jest zwięzła. The if let jest nadal przydatny, ale nie w przypadku pojedynczych wywołań metod, moim zdaniem - jeśli używasz bar więcej niż raz if let jest prawdopodobnie lepszy. - Stefan Arentz