来自 equatable 协议的 func == 不适用于自定义对象,swift
func == from equatable protocol does not work for custom object, swift
我的目标是显示历史登录(例如用户名)的用户列表(如果有的话)。为了做到这一点,我正在做
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
}
无法正常工作。
有谁知道为什么或对此有任何想法。
问题是 User 派生自 NSObject。这意味着(正如您所说的那样)您的 ==
实现从未被咨询过。 Swift 的行为对于派生自 NSObject 的对象是不同的;它以 Objective-C 的方式做事。要在派生自 NSObject 的对象上实现等同性,请覆盖 isEqual:
。这就是使 NSObject 派生对象以自定义方式相等的原因,在 Objective-C 和 Swift.
中
只需将这段代码直接粘贴到您的用户 class 声明中,contains
就会开始工作:
override func isEqual(object: AnyObject?) -> Bool {
if let other = object as? User {
if other.login == self.login {
return true
}
}
return false
}
怎么回事?
正如@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
包含
contains 函数 NOT 使用您在此处定义的逻辑
func ==(lhs: User, rhs: User) -> Bool {
return lhs.login == rhs.login
}
其实就是比较对象的内存地址。
解决方案
您可以解决将您自己的逻辑传递给 contains
的问题,只需替换此
if !(users.contains(user)) {
users.append(user)
}
有了这个
if !(users.contains { [=14=].login == user.login }) {
users.append(user)
}
我的目标是显示历史登录(例如用户名)的用户列表(如果有的话)。为了做到这一点,我正在做
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
}
无法正常工作。
有谁知道为什么或对此有任何想法。
问题是 User 派生自 NSObject。这意味着(正如您所说的那样)您的 ==
实现从未被咨询过。 Swift 的行为对于派生自 NSObject 的对象是不同的;它以 Objective-C 的方式做事。要在派生自 NSObject 的对象上实现等同性,请覆盖 isEqual:
。这就是使 NSObject 派生对象以自定义方式相等的原因,在 Objective-C 和 Swift.
只需将这段代码直接粘贴到您的用户 class 声明中,contains
就会开始工作:
override func isEqual(object: AnyObject?) -> Bool {
if let other = object as? User {
if other.login == self.login {
return true
}
}
return false
}
怎么回事?
正如@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
包含
contains 函数 NOT 使用您在此处定义的逻辑
func ==(lhs: User, rhs: User) -> Bool {
return lhs.login == rhs.login
}
其实就是比较对象的内存地址。
解决方案
您可以解决将您自己的逻辑传递给 contains
的问题,只需替换此
if !(users.contains(user)) {
users.append(user)
}
有了这个
if !(users.contains { [=14=].login == user.login }) {
users.append(user)
}