来自 equatable 协议的 func == 不适用于自定义对象,swift
Posted
技术标签:
【中文标题】来自 equatable 协议的 func == 不适用于自定义对象,swift【英文标题】:func == from equatable protocol does not work for custom object, 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,我在做 save
和 retrieve
和 User
。在保存之前,我正在检查历史登录列表是否包含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
无法正常工作。
有谁知道原因或对此有任何想法。
【问题讨论】:
相关:***.com/questions/33319959/… 【参考方案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
是新的User
和self
将是以前的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
这里$0
是users
的第n 个元素。这个闭包应用于数组的每个元素,直到它是true
。在这种情况下,contains
返回true
。否则contains
会执行false
。
@tonytran: YES users.contains $0 == user
可以正常工作。
@tonytran: 没问题 :D 这个===
总是比较内存地址以上是关于来自 equatable 协议的 func == 不适用于自定义对象,swift的主要内容,如果未能解决你的问题,请参考以下文章
如何根据实现该协议的两个实例的身份为一个协议实现 Equatable 协议?