【问题标题】:func == from equatable protocol does not work for custom object, swift来自 equatable 协议的 func == 不适用于自定义对象,swift
【发布时间】:2016-07-14 20:59:00
【问题描述】:

我的目标是显示历史登录的用户列表(例如 username )(如果有的话)。为了做到这一点,我正在做

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
    }

在 UserManager,我在做 saveretrieveUser。在保存之前,我正在检查历史登录列表是否包含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
    }
}

第一次尝试,我愿意

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

现在它保存了第一次登录。第二次,我也这样做了

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

UserManager 仍将第二次登录添加到nsuserdefault。这意味着函数contains 失败并导致

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

无法正常工作。

有谁知道原因或对此有任何想法。

【问题讨论】:

标签: ios swift equatable


【解决方案1】:

问题是 User 派生自 NSObject。这意味着(正如您正确地说的)您的 == 实现永远不会被咨询。对于从 NSObject 派生的对象,Swift 的行为是不同的;它以 Objective-C 的方式做事。要在派生自 NSObject 的对象上实现相等性,请覆盖 isEqual:。这就是使 NSObject 派生对象能够以自定义方式在 Objective-C 和 Swift 中相等的原因。

只需将此代码粘贴到您的 User 类声明中,contains 就会开始按您的意愿工作:

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

【讨论】:

  • 谢谢。有用。但是,我想完全理解。我知道other 是新的Userself 将是以前的User,它们是列表中的。我不确定如何将self 引用到列表中以前的User
  • 别担心。毕竟,您不必为== 担心。您只需要知道contains 依赖于此。
【解决方案2】:

发生了什么事?

正如 @matt 已经说过的,问题在于平等。

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

再看一遍

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

包含

包含函数使用您在此处定义的逻辑

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

实际上它只是比较对象的内存地址。

解决方案

您可以解决将自己的逻辑传递给contains 的问题,只需替换此

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

有了这个

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

【讨论】:

  • 我也试过了,效果也不错。我很惊讶contains 逻辑用于比较内存地址。你能解释一下$0.login == user.login 这一行吗?$0是什么意思更进一步,似乎我不需要在我的代码中再符合func ==了。
  • @tonytran:问题是你继承了NSObject,所以调用isEqual方法来检查是否相等。
  • @tonytran: { $0.login == user.login } 这里$0users 的第n 个元素。这个闭包应用于数组的每个元素,直到它是true。在这种情况下,contains 返回true。否则contains 会执行false
  • @tonytran: YES users.contains { $0 == user } 可以正常工作。
  • @tonytran: 没问题 :D 这个=== 总是比较内存地址
猜你喜欢
  • 2017-06-27
  • 1970-01-01
  • 1970-01-01
  • 2017-12-09
  • 2015-11-02
  • 1970-01-01
  • 2016-09-29
  • 1970-01-01
相关资源
最近更新 更多