2016-06-29 14 views
8

czytam blok kodu zamknięty w nawiasach klamrowych po słowie kluczowym else w kontekście przepływu guard-else, należy wywołać funkcję oznaczoną kontrolą noreturn atrybutu lub z przeniesieniem z użyciem return, break, continue lub throw.Kiedy i jak korzystać z atrybutu @noreturn w Swift?

Ostatnia część jest całkiem jasna, podczas gdy ja nie rozumiem dobrze tego pierwszego.

Po pierwsze, każda funkcja zwraca coś (co najmniej jest pustą krotką), nawet jeśli nie zadeklarowano żadnego typu zwracanego. Po drugie, kiedy możemy użyć funkcji noreturn? Czy dokumenty sugerujące niektóre podstawowe, wbudowane metody są oznaczone jako noreturn?

Klauzula else oświadczenia straży jest wymagane, i musi albo zadzwonić funkcją oznaczone noreturn atrybutu lub programu transferu kontrola zewnętrznego otaczającego zakresu rachunku strażnika za pomocą jednego z następujących stwierdzeń:

return 

break 

continue 

throw 

Oto source.

+1

Zobacz: http: // stos overflow.com/questions/27829132/convincing-swift-that-a-function-will-never-return-due-to-a-thrown-exception –

Odpowiedz

9

Po pierwsze, każda funkcja zwraca coś (co najmniej jest pustą krotką), nawet jeśli nie zadeklarowano żadnego typu zwrotu.

(@noreturn jest przestarzała; patrz Aktualizacja Swift 3 poniżej). Nie istnieją funkcje, które natychmiast zakończyć proces i zrobienia nie powrót do rozmówcy. Są one oznaczone Swift z @noreturn, jak

@noreturn public func fatalError(@autoclosure message:() -> String = default, file: StaticString = #file, line: UInt = #line) 
@noreturn public func preconditionFailure(@autoclosure message:() -> String = default, file: StaticString = #file, line: UInt = #line) 
@noreturn public func abort() 
@noreturn public func exit(_: Int32) 

i nie może być więcej.

(Uwagi: podobne adnotacje istnieją w innych językach programowania lub kompilatorów, takich jak [[noreturn]] w C++ 11, __attribute__((noreturn)) jako rozszerzenie GCC lub _Noreturn dla kompilatora dzyń.)

Można oznaczyć własną funkcję za pomocą @noreturn, jeśli to również bezwarunkowo kończy proces , , np., np. wywołując jedną z wbudowanych funkcji, takich jak

@noreturn func myFatalError() { 
    // Do something else and then ... 
    fatalError("Something went wrong!") 
} 

Teraz można korzystać z funkcji w klauzuli else z guard stwierdzeniem:

guard let n = Int("1234") else { myFatalError() } 

@noreturn funkcje mogą być również używane do oznaczania przypadki to "nie powinno być" "i wskazywać błąd programowania.Prostym przykładem (wyciąg z Missing return UITableViewCell)

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 
    let cell: MyTableViewCell 

    switch (indexPath.row) { 
    case 0: 
     cell = tableView.dequeueReusableCellWithIdentifier("cell0", forIndexPath: indexPath) as! MyTableViewCell 
     cell.backgroundColor = UIColor.greenColor() 
    case 1: 
     cell = tableView.dequeueReusableCellWithIdentifier("cell1", forIndexPath: indexPath) as! MyTableViewCell 
     cell.backgroundColor = UIColor.redColor() 
    default: 
     myFatalError() 
    } 
    // Setup other cell properties ... 
    return cell 
} 

bez myFatalError() oznaczone @noreturn, kompilator skarżą o brakującym powrotu w przypadku domyślnego.


Update: Swift 3 (Xcode 8 beta 6) atrybutu @noreturn zastąpiono przez typ Never powrotnej, tak w powyższym przykładzie będzie teraz zapisana jako

func myFatalError() -> Never { 
    // Do something else and then ... 
    fatalError("Something went wrong!") 
} 
+1

Istnieje również 'UIApplicationMain', który nigdy nie wraca (mimo że nie jest tak oznaczony prawdopodobnie ze względu na kompatybilność wsteczną). W Obj-C problem polegał na tym, że wywołania takie jak "[Wyjątek NSException]" nie zostały rozpoznane przez kompilator i nadal musiał być po nich "return". – Sulthan

+1

@Sulthan: Prawdopodobnie. I nie nazwałbyś UIApplicationMain() w oświadczeniu straży :) –

+0

@MartinR: Wiem, że mogę go użyć do niestandardowej funkcji, próbowałem przed wysłaniem :-) Moje pytanie brzmiało: ma sens dla programisty funkcja oznaczona w ten sposób? Szukałem przypadku użycia :-) –

2

prosty plac zabaw, aby zobaczyć, jak to działa ...

//: Playground - noun: a place where people can play 

import Foundation 
@noreturn func foo() { 
    print("foo") 
    exit(1) 
} 

var i: Int? 

guard let i = i else { 
    foo() 
} 

print("after foo") // this line will never executed 

//prints foo and finish 
+1

Jak to działa, dziękuję, ale to, czego szukałem, było konkretnym, rzeczywistym przykładem, w którym ten atrybut może być bardzo przydatny :-) –

+1

@IanBell, więc widzisz przykład ... :-). spróbuj wyobrazić sobie, że foo() robi jakieś czyszczenie przed wyjściem, lub nawet przenosi niektóre dane na serwer lub cokolwiek chcesz. Zadanie może być bardzo złożone, to zależy od ciebie. – user3441734

+0

to samo tutaj ... w jaki sposób @noreturn (teraz "nigdy") może być użyteczny ... naprawdę, w prawdziwym przykładzie ... – zumzum

Powiązane problemy