web-dev-qa-db-fra.com

Comment "fortifier" l'auto optionnel en utilisant guard dans Swift 2.0

Il y a question similaire sur la façon de weakify/strongify self, qui est répondu, mais je me demande comment utiliser "self" sans dérive vers la droite causée par if let:

Welcome to Apple Swift version 2.0 (700.0.59 700.0.72). Type :help for assistance.
  2> import Foundation
  3> class Foo {
  4.     func guardOptSelf() -> () throws -> Void {
  5.         return { [weak self] in
  6.             guard let self = self else { throw NSError(domain: "I was destroyed!", code: 1, userInfo: nil) }
  7.             self.doSomethingNonOptionalSelf()         
  8.         }
  9.     }
  10. }
repl.Swift:6:19: error: pattern matching in a condition requires the 'case' keyword
            guard let self = self else { throw NSError(domain: "I was destroyed!", code: 1, userInfo: nil) }
                  ^
                  case
repl.Swift:6:23: error: binary operator '~=' cannot be applied to two 'Foo?' operands
            guard let self = self else { throw NSError(domain: "I was destroyed!", code: 1, userInfo: nil) }
27
Brian Gerstle

Vous pouvez shadow self; vous avez juste besoin de backticks pour indiquer que "vous savez ce que vous faites". Par exemple:

foo.doSomethingAsyncWithBar(bar) { [weak self] result in
    guard let `self` = self else { return }
    self.receivedResult(result)
}

Ou, dans votre exemple:

2> import Foundation
3> class Foo {
4.     func guardOptSelf() -> () throws -> Void {
5.         return { [weak self] in
6.             guard let `self` = self else { throw NSError(domain: "I was destroyed!", code: 1, userInfo: nil) }
7.             self.doSomethingNonOptionalSelf()         
8.         }
9.     }
10. }
37
Jason

Swift 4.2

Depuis Swift 4.2, vous pouvez utiliser la syntaxe suivante:

{ [weak self] in
    guard let self = self else { return }

    // self is not an optional anymore, it is held strongly
}

Pour plus d'informations, voir la proposition d'évolution Swift SE-0079 .

Parfois, d'autres approches que l'utilisation de guard let pourrait également être utile (par exemple, plus court ou plus lisible). Voir aussi la section suivante, remplacez simplement strongSelf par self dans quelques exemples.

Swift 4.1 et versions antérieures

Car guard let `self` = self est un bogue du compilateur comme indiqué par Chris Lattner J'essaierais de l'éviter. Dans votre exemple, vous pouvez utiliser un simple chaînage facultatif simple:

return { [weak self] in
    self?.doSomethingNonOptionalSelf()         
}

Parfois, vous devrez peut-être utiliser self comme paramètre. Dans ce cas, vous pouvez utiliser flatMap (sur un type facultatif):

{ [weak self] in
    self.flatMap { $0.delegate?.tableView($0, didSelectRowAt: indexPath) }
}

Si vous devez faire quelque chose de plus compliqué, vous pouvez utiliser if let construction:

{ [weak self] in
    if let strongSelf = self {
        // Do something more complicated using strongSelf
    }
}

ou guard let construction:

{ [weak self] in
    guard let strongSelf = self else { return }

    // Do something more complicated using strongSelf
}

ou vous pouvez créer une méthode privée:

{ [weak self] in
    self?.doSomethingMoreComplicated()
}

...

private func doSomethingMoreComplicated() {
    // Do something more complicated
}
25
Marián Černý

Depuis Swift 4.2 vous n'avez plus besoin d'utiliser self avec des backticks (bug du compilateur) ou des noms de variables étranges comme strongSelf. Vous pouvez utiliser guard let self = self else { return } pour déballer weak self:

class Example {

    var closure: (() -> Void)?

    init() {
        self.closure = { [weak self] in
            guard let self = self else {
                return
            }
            // ...
        }
    }
}

Vous pouvez en savoir plus à ce sujet dans la Proposition d'évolution rapide .

6
Amer Hukic