Vous pouvez créer une extension de chaîne comme ceci:
extension String {
func someFunc -> Bool { ... }
}
mais que faire si vous voulez qu'il s'applique à une chaîne facultative?
var optionalString :String? = ""
optionalString!.someFunc() /* String? does not have a member someFunc */
Dans Swift 3.1, vous pouvez également ajouter une extension à des valeurs facultatives:
extension Optional where Wrapped == String {
var isBlank: Bool {
return self?.isBlank ?? true
}
}
Optional
qui retournent une String
À partir de Swift 3, vous ne pouvez pas contraindre directement une méthode d’extension à une variable String
facultative. Vous pouvez obtenir un résultat équivalent avec des protocoles, comme l'explique la réponse de Daniel Shin.
Vous pouvez cependant créer une méthode d'extension sur un type facultatif Facultatif et j'ai trouvé des méthodes utiles qui ont une valeur de retour String
. Ces extensions sont utiles pour consigner des valeurs dans la console. J'ai utilisé asStringOrEmpty () sur un String
facultatif lorsque je souhaite remplacer un nil possible par une chaîne vide.
extension Optional {
func asStringOrEmpty() -> String {
switch self {
case .some(let value):
return String(describing: value)
case _:
return ""
}
}
func asStringOrNilText() -> String {
switch self {
case .some(let value):
return String(describing: value)
case _:
return "(nil)"
}
}
}
Exemple d'utilisation:
var booleanValue: Bool?
var stringValue: String?
var intValue: Int?
print("booleanValue: \(booleanValue.asStringOrNilText())")
print("stringValue: \(stringValue.asStringOrNilText())")
print("intValue: \(intValue.asStringOrNilText())")
booleanValue = true
stringValue = "text!"
intValue = 41
print("booleanValue: \(booleanValue.asStringOrNilText())")
print("stringValue: \(stringValue.asStringOrNilText())")
print("intValue: \(intValue.asStringOrNilText())")
Sortie de la console:
booleanValue: (nil)
stringValue: (nil)
intValue: (nil)
booleanValue: true
stringValue: text!
intValue: 41
Optional
différent du pointeur nulCes extensions illustrent le fait qu'une Optional
est différente d'un pointeur nil. Optional
est une enum
d'un type spécifié (Wrapped
) indiquant qu'elle contient ou non une valeur. Vous pouvez écrire une extension sur le "conteneur" Optional
même s'il ne contient pas de valeur.
Extrait de la déclaration facultative de Swift
enum Optional<Wrapped> : ExpressibleByNilLiteral {
/// The absence of a value.
case none
/// The presence of a value, stored as `Wrapped`.
case some(Wrapped)
...
}
Dans le code, l'absence de valeur est généralement écrite à l'aide du littéral nil
plutôt que du cas d'énumération explicite .none
.
extension Optional where Wrapped == String {
var isNil: Bool {
return self == nil
}
La réponse ci-dessus (écrite par @Vlad Hatko) fonctionne bien, mais dans Swift 4, certains problèmes ont été résolus.
Mise à jour: Pour une solution de contournement qui fonctionne avec Swift 2 et supérieur, voir Réponse de Daniel Shin
Une chaîne facultative n'est pas en elle-même un type et vous ne pouvez donc pas créer une extension sur un type facultatif. Dans Swift, une Optional
est simplement une énumération (plus un peu de sucre syntaxique) qui peut être soit None
, soit Some
qui englobe une valeur. Pour utiliser votre méthode String, vous devez décompresser votre optionalString
. Vous pouvez facilement utiliser le chaînage optionnel pour réaliser ceci:
optionalString?.someFunc()
Si optionalString
n'est pas nil
, someFunc
sera appelé. Une autre solution (moins concise) consiste à utiliser une liaison facultative pour déterminer si optionalString
a ou non une valeur avant d'essayer d'appeler la méthode:
if let string = optionalString {
string.someFunc() // `string` is now of type `String` (not `String?`)
}
Dans votre exemple tiré des commentaires ci-dessous, vous n'avez pas besoin d'imbriquer plusieurs instructions if
. Vous pouvez vérifier si la chaîne facultative est une chaîne vide dans une seule variable if
:
if optionalString?.isEmpty == true {
doSomething()
}
Cela fonctionne parce que l'expression optionalString?.isEmpty
renvoie un booléen facultatif (c'est-à-dire true
, false
ou nil
). Donc, doSomething()
ne sera appelé que si optionalString
est nonnil
, et _ si cette chaîne est vide.
Une autre alternative serait:
if let string = optionalString where string.isEmpty {
doSomethingWithEmptyString(string)
}
Dans Swift 4.1, j'avais une erreur de compilation Optional is ambiguous for type lookup in this context
. Pour résoudre ce problème, vous devez explicitement ajouter l'espace de noms Swift au type:
extension Swift.Optional where Wrapped == String {
var isBlank: Bool {
return self?.isBlank ?? true
}
}
Depuis Xcode 9.3, vous pouvez utiliser cette légère modification de la réponse de @ Vladyslav:
extension Optional where Wrapped == String {
var isEmpty: Bool {
return self?.isEmpty ?? true
}
}
trouvé une astuce Swift 3
class A{
var name:String!;
init(_ name:String?){
self.name = name;
}
}
extension Optional where Wrapped == String {
func compareText(_ other:String?)->Bool{
switch (self,other){
case let(a?,b?):
return a < b;
case (nil,_):
return true;
default:
return false;
}
}
}
let words:[A] = [A("a"),A(nil),A("b"),A("c"),A(nil)];
// let sorted = words.sorted{ 0.name.compareText($1.name) }
// trick
let sorted = words.sorted{ ($0.name as String?).compareText($1.name) }
print(sorted.map{$0.name});