Giovanni Trezzi Giovanni Trezzi - 5 months ago 27
Swift Question

Array.contains returns false

I have an array of users

[User]
called conversationUsers

User is defined as

public class User: NSManagedObject { ... }


and
currUser
is an User object

if I try

currUser == conversationUsers[0]


it results true

but

conversationUsers.contains(currUser)


results false

If instead I use

conversationUsers.contains({$0 == currUser})


it returns true

FYI I have also defined this:

public func ==(lhs: User, rhs: User) -> Bool {

let logicalExpression = lhs.email.lowercaseString == rhs.email.lowercaseString

return logicalExpression

}





Why contains returns false? Which is his default predicate?

Thank you for your help

Answer

UPDATE

In short, you should override NSObject.isEqual() method:

public class User: NSManagedObject { 
    ... 
    override func isEqual(object: AnyObject?) -> Bool {
        if let rhs = object as? User {
            return self == rhs
        }
        return false
    }
}

I made a little research. It seems that if class A is inherited from NSObject then collection methods like contains use NSObject.isEqual() method for determining equality of two objects. Class B is not inherited from NSObject so contains method is working as expected.

import Foundation

class A: NSObject {
    var value: Int

    init(_ value: Int) {
        self.value = value
    }
}

func ==(lhs: A, rhs: A) -> Bool {
    return lhs.value == rhs.value
}

var a = A(1)
var array: [A] = [a, A(2)]
array.contains(a) // true
array.contains(A(1)) // false
array.contains { $0 == A(1) } // true
array[0] == A(1) // true


class B: Equatable {
    var value: Int

    init(_ value: Int) {
        self.value = value
    }
}

func ==(lhs: B, rhs: B) -> Bool {
    return lhs.value == rhs.value
}

var b = B(1)
var array2: [B] = [b, B(2)]
array2.contains(b) // true
array2.contains(B(1)) // true
array2.contains { $0 == B(1) } // true
array2[0] == B(1) // true

So you need to override NSObject.isEqual() method:

class A: NSObject {
    var value: Int

    init(_ value: Int) {
        self.value = value
    }

    override func isEqual(object: AnyObject?) -> Bool {
        if let rhs = object as? A {
            return self == rhs
        }
        return false
    }
}

OLD ANSWER

User class should also conform to Equatable protocol:

extension User: Equatable {}

Or you can add it directly to class definition:

public class User: NSManagedObject, Equatable {}