web-dev-qa-db-fra.com

Comment renvoyer nil dans Swift dans un initialiseur personnalisé?

J'essaie d'écrire un initialiseur personnalisé dans Swift. J'ai quelque chose comme ça:

convenience init(datasource:SomeProtocol) {
    assert(datasource != nil, "Invalid datasource")
    if(datasource == nil) {
        return nil
    }
    self.init()
}

La ligne "return nil" me donne cette erreur: "impossible de trouver une surcharge pour '__conversion' qui accepte les arguments fournis"

Donc, tout ce que j'essaie d'accomplir, c'est que cet initialiseur de commodité renvoie zéro si l'appelant ne fournit pas une source de données valide.

Qu'est-ce que je fais mal ici?

Merci

14
zumzum

C'est parce que initializers n'a en réalité pas de retour de valeur. Vous ne pouvez pas retourner nil si une méthode ne s'attend pas à un type de retour.

Pour réussir ce que vous essayez d’essayer (c’est-à-dire de forcer votre classe à avoir une source de données), il suffit de faire de votre source de données pas un facultatif. Les variables qui ne sont pas facultatives doivent ont une valeur (elles ne peuvent donc pas être nulles) et doivent être initialisées.

3
Emilie

Mise à jour: À partir de Xcode 6.1 beta 1 (disponible dans le Centre de développement Mac) , les initialiseurs Swift peuvent être déclarés pour renvoyer une valeur facultative:

convenience init?(datasource:SomeProtocol) {
    if datasource == nil {
        return nil
    }
    self.init()
}

ou une option implicitement non déballée:

convenience init!(datasource:SomeProtocol) {
    if datasource == nil {
        return nil
    }
    self.init()
}
41
user102008

Je pense que cela fonctionnerait, bien que votre article n'indique pas clairement où vous travaillez avec DataSource:

class func instOrNil(datasource:A) -> Self? {
    // do something with datasource
    if datasource.isValid() {
        return self()
    } else {
        return nil
    }
}

Mise à jour Swift 3

Vous pouvez, bien sûr, maintenant renvoyer nil depuis une init?(...):

init?(datasource: A){
    if datasource.isValid() {
        // initialise your properties from datasource
    } else {
        return nil
    }
}
8
Grimxn

Si la superclasse de cette classe est une classe Objective-C et que vous savez qu'il y a une entrée qui fera que son initialiseur renvoie nil, vous pouvez simplement transmettre cette entrée à l'initialiseur de la superclasse, ce qui fera que votre initialiseur renvoie nil:

import Foundation
class Foo : NSURL {
  convenience init(x: Int) {
    if x == 42 {
      self.init(string: "http://www.google.com/")
    } else {
      self.init(string: "not a url") // returns nil
    }
  }
}

let a: Foo? = Foo(x: 42)
println(a) // prints "Optional(http://www.google.com/)"
let b: Foo? = Foo(x: 17)
println(b) // prints "nil"

Bien sûr, cela ne fonctionne que si vous avez la chance d’avoir une super-classe dont l’initialiseur renverra zéro. Donc, ce n'est pas une solution générale.

1
user102008