Marek H Marek H - 4 months ago 13
Swift Question

"Better" way to write equality for optionals

I am trying to find a better way to test equality. What I dislike is the part with profileImage.

Is there a nicer way to write it?

class CustomObject : NSObject , NSCoding {
var pattern : String
var name : String
var id : String
var profilePicture : NSImage?

override func isEqual(object: AnyObject?) -> Bool {
if let other = object as? CustomObject {
if (id == other.id &&
name == other.name &&
pattern == other.pattern) {
if (profilePicture == nil && other.profilePicture == nil) {
return true
} else {
return profilePicture!.isEqual(other.profilePicture)
}
}
}
return false
}
}


Just to be complete

extension NSImage {
override public func isEqual(object: AnyObject?) -> Bool {
if let other = object as? NSImage {
guard let data1 = self.TIFFRepresentation,
let data2 = other.TIFFRepresentation else {return false}

return data1.isEqual(data2)
}
return false
}

}

Answer

If you want to implement nearly the same as you have shown, my best recommendation is using == operator. (Not ===, don't be confused.)

== has an overload for Optionals with this signature: (in Swift 2)

@warn_unused_result
public func ==<T : Equatable>(lhs: T?, rhs: T?) -> Bool

And its detailed behaviour is as follows:

(1) if lhs == nil && rhs == nil, return true

(2) if lhs == nil && rhs != nil, return false

(3) if lhs != nil && rhs == nil, return false

(4) if lhs != nil && rhs != nil, return (lhs! == rhs!)

And in case #4, non-Optional version of == operator for two NSObject arguments, just calls isEqual: method internally.

So, CustomObject.isEqual(_:) can be written as something like this:

override func isEqual(object: AnyObject?) -> Bool {
    if let other = object as? CustomObject {
        return id == other.id &&
            name == other.name &&
            pattern == other.pattern &&
            profilePicture == other.profilePicture
    }
    return false
}

(Assuming your NSImage.isEqual(_:) works as expected.)


By the way, your original code may crash in a certain condition.

                if (profilePicture == nil && other.profilePicture == nil) {
                    return true
                } else {
                    return profilePicture!.isEqual(other.profilePicture)
                }

When profilePicture == nil && other.profilePicture != nil, the control goes through to the else part and profilePicture! will crash.