简体   繁体   English

来自equatable协议的func ==不适用于自定义对象,swift

[英]func == from equatable protocol does not work for custom object, swift

My goal is to show a user list of history logins ( such as username ) if there are any. 我的目标是显示历史登录的用户列表(例如用户名)(如果有)。 In order to do that, I am doing 为了做到这一点,我正在做

1. Create an custom object named User like below

 class User: NSObject
    {
        var login: String

        init(login: String)
        {
            self.login = login
        }
        required init(coder aDecoder: NSCoder) {
            login = aDecoder.decodeObjectForKey("login") as! String
        }

        func encodeWithCoder(aCoder: NSCoder) {
            aCoder.encodeObject(login, forKey: "login")
        }
    }

    // This conform to make sure that I compare the `login` of 2 Users
    func ==(lhs: User, rhs: User) -> Bool
    {
        return lhs.login == rhs.login
    }

At UserManager, Im doing save and retrieve an User . 在UserManager,我正在saveretrieve User Before saving, I'm doing a check if the the list of history logins contains a User , I wont add it in, otherwise. 在保存之前,我正在检查历史记录登录列表是否包含User ,我不会添加它,否则。

class UserManager : NSObject
{
    static let sharedInstance   =   UserManager()
    var userDefaults            =   NSUserDefaults.standardUserDefaults()

    func saveUser(user:User)
    {
        var users = retrieveAllUsers()

        // Check before adding
        if !(users.contains(user))
        {
            users.append(user)
        }


        let encodedData =   NSKeyedArchiver.archivedDataWithRootObject(users)
        userDefaults.setObject(encodedData, forKey: "users")
        userDefaults.synchronize()
    }

    func retrieveAllUsers() -> [User]
    {
        guard let data  =   userDefaults.objectForKey("users") as? NSData else
        {
            return [User]()
        }
        let users   =   NSKeyedUnarchiver.unarchiveObjectWithData(data) as! [User]
        // Testing purpose
        for user in users
        {
            print(user.login)
        }
        return users
    }
}

At first time trying, I do 在第一次尝试时,我做到了

UserManager.sharedInstance.saveUser(User(login: "1234"))

Now it saves the first login. 现在它保存了第一次登录。 At second time, I also do 第二次,我也这样做

UserManager.sharedInstance.saveUser(User(login: "1234"))

UserManager still adds the second login into nsuserdefault . UserManager仍然将第二次登录添加到nsuserdefault That means the function contains fails and it leads to 这意味着该函数contains失败并导致

func ==(lhs: User, rhs: User) -> Bool
{
    return lhs.login == rhs.login
}

does not work properly. 不能正常工作。

Does anyone know why or have any ideas about this. 有谁知道为什么或有任何想法。

The problem is that User derives from NSObject. 问题是User派生自NSObject。 This means that (as you rightly say) your == implementation is never being consulted. 这意味着(正如你所说)你的==实现永远不会被咨询。 Swift's behavior is different for objects that derive from NSObject; 对于从NSObject派生的对象,Swift的行为是不同的; it does things the Objective-C way. 它以Objective-C的方式做事。 To implement equatability on an object that derives from NSObject, override isEqual: . 要在从NSObject派生的对象上实现可公平性,请覆盖isEqual: . That is what makes an NSObject-derived object equatable in a custom way, in both Objective-C and Swift. 这就是使得NSObject派生的对象在Objective-C和Swift中以自定义方式相同的原因。

Just paste this code right into your User class declaration, and contains will start working as you wish: 只需将此代码粘贴到您的User类声明中,并且contains将按您的意愿开始工作:

override func isEqual(object: AnyObject?) -> Bool {
    if let other = object as? User {
        if other.login == self.login {
            return true
        }
    }
    return false
}

What's going on? 这是怎么回事?

As @matt already said, the problem is about equality. 正如@matt所说,问题在于平等。

Look

var users = [User]()
users.append(User(login: "1234"))
users.contains(User(login: "1234")) // false

Look again 再看一遍

var users = [User]()
let user = User(login: "1234")
users.append(user)
users.contains(user) // true <---- THIS HAS CHANGED

contains 包含

The contains function is NOT using the logic you defined here contains函数使用您在此处定义的逻辑

func ==(lhs: User, rhs: User) -> Bool {
    return lhs.login == rhs.login
}

Infact it is simply comparing the memory addresses of the objects. 实际上,它只是比较对象的内存地址。

Solution

You can solve the issue passing your own logic to contains , just replace this 您可以解决将您自己的逻辑传递给contains ,只需替换它即可

if !(users.contains(user)) {
    users.append(user)
}

with this 有了这个

if !(users.contains { $0.login == user.login }) {
    users.append(user)
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM