web-dev-qa-db-fra.com

Le moyen le plus élégant de comparer deux optionnels à Swift

J'ai deux variables AnyObject? que j'aimerais comparer pour l'égalité des références:

var oldValue: AnyObject?
var newValue: AnyObject?
...
if oldValue != newValue {
    changed = true
}

Cela ne fonctionne pas bien, car je ne peux apparemment pas comparer directement deux optionnels. Je veux le comportement comme si je comparais ids en Objective-C, c'est-à-dire:

  • true si les deux sont nil
  • true si les deux ont une valeur et que les valeurs sont également égales
  • false autrement

Existe-t-il un moyen élégant d’écrire cela dans Swift (idéalement sans écrire une extension personnalisée)?

C'est le meilleur que j'ai trouvé avec:

if !(oldValue != nil && newValue != nil && oldValue == newValue)

Pas très jolie. :(

13
devios1

Vous pouvez utiliser !== 

From Le langage de programmation Swift

Swift fournit également deux opérateurs d'identité (=== et !==), que vous utilisez pour vérifier si deux références d'objets se rapportent toutes deux à la même instance d'objet.

Quelques bons exemples et explications sont également à Différence entre == et ===

Sur le point @PEEJWEEJ, procédez comme suit: false

var newValue: AnyObject? = "String"
var oldValue: AnyObject? = "String"

if newValue === oldValue {
   print("true")
} else {
   print("false")
}
11
sbarow

En supposant que vous utilisez des entités comparables, cela fonctionnera sur n'importe quoi:

func optionalsAreEqual<T: Comparable>(firstVal: T?, secondVal: T?) -> Bool{

    if let firstVal = firstVal, secondVal = secondVal {
        return firstVal == secondVal
    }
    else{
        return firstVal == nil && secondVal == nil
   }
}

Ce n'est pas exactement court et agréable, mais c'est expressif, clair et réutilisable.

11
PeejWeej

J'ai aimé @ Keith's solution. Mais je pense qu'il n'est pas écrit dans Swift 4, car je ne peux pas le compiler avec le compilateur Swift 4.

J'ai donc converti son code en version Swift 4 ici.

N'oubliez pas que si vous utilisez une version de la langue Swift supérieure à Swift 4.1 , puis cette réponse n'est pas nécessaire car elle fournit cette fonctionnalité par défaut. Vous pouvez consulter ici pour plus de détails. 

Version Swift 4 du code de @ Keith:

infix operator ==? : ComparisonPrecedence

func ==? <T: Comparable>(lhs: T?, rhs: T?) -> Bool {
    if let lhs = lhs, let rhs = rhs {
        return lhs == rhs
    } else {
        return lhs == nil && rhs == nil
    }
}

func ==? <T: AnyObject>(lhs: T?, rhs: T?) -> Bool {
    if let lhs = lhs, let rhs = rhs {
        return lhs === rhs
    } else {
        return lhs == nil && rhs == nil
    }
}
4
Nitesh Borad

Je définis un opérateur d'infixe personnalisé avec une fonction pour les types de référence et les types de valeur.

func ==? <T: Comparable>(lhs: T?, rhs: T?) -> Bool {
    if let lhs = lhs, rhs = rhs {
        return lhs == rhs
    } else{ return lhs == nil && rhs == nil }
}
func ==? <T: AnyObject>(lhs: T?, rhs: T?) -> Bool {
    if let lhs = lhs, rhs = rhs {
        return lhs === rhs
    } else{ return lhs == nil && rhs == nil }
}
infix operator ==? { associativity left precedence 130 }

var aString: String? = nil
var bString: String? = nil
print(aString ==? bString) // true

aString = "test"
bString = "test"
print(aString ==? bString) // true

aString = "test2"
bString = "test"
print(aString ==? bString) // false

aString = "test"
bString = nil
print(aString ==? bString) // false

class TT {}
let x = TT()

var aClass: TT? = TT()
var bClass: TT? = TT()
print(aClass ==? bClass) // false

aClass = TT()
bClass = nil
print(aClass ==? bClass) // false

aClass = nil
bClass = nil
print(aClass ==? bClass) // true

aClass = x
bClass = x
print(aClass ==? bClass) // true
3
Keith

Vous pouvez surcharger l'opérateur == pour un type Comparable

public func ==<T: SomeType>(lhs: T?, rhs: T?) -> Bool {
    switch (lhs,rhs) {
    case (.some(let lhs), .some(let rhs)):
        return lhs == rhs
    case (.none, .none):
        return true
    default:
        return false
    }
}

Ou utilisez la comparaison === pour AnyObject, cependant, personnellement, je préférerais ne pas utiliser AnyObject en premier lieu.

0
nikans