如何创建一组自定义对象 (Swift)?
How do I create a Set of custom objects (Swift)?
对于我的 iOS 应用程序,我有一个类似
的模型
class Person {
var Id: Int
var Name: String
init(id: Int, name: String?) {
self.Id = id
self.Name = name ?? ""
}
}
然后稍后在我的 ViewController
中,当我从服务器加载数据时,我将一些人添加到数组中
class ViewController: UIViewController {
var people:[Person] = []
override func viewDidLoad() {
self.loadPeople()
}
func loadPeople() {
// This data will be coming from a server request
// so is just sample. It could have users which
// already exist in the people array
self.people.append(Person(id: "1", name: "Josh"))
self.people.append(Person(id: "2", name: "Ben"))
self.people.append(Person(id: "3", name: "Adam"))
}
}
我现在要做的是将 people
数组转换为 Set<Person>
,这样它就不会添加重复项。这可以做还是我需要改变我的逻辑?
要制作 Person
集,您需要使其符合 Equatable 和 Hashable 协议:
class Person: Equatable, Hashable {
var Id: Int
var Name: String
init(id: Int, name: String?) {
self.Id = id
self.Name = name ?? ""
}
var hashValue: Int {
get {
return Id.hashValue << 15 + Name.hashValue
}
}
}
func ==(lhs: Person, rhs: Person) -> Bool {
return lhs.Id == rhs.Id && lhs.Name == rhs.Name
}
那么你可以使用这样一组人:
var set = Set<Person>()
set.insert(Person(id: 1, name: "name"))
在 Swift 2.0 中,Hashable 和 Equitable 是 NSObject 的一部分。您需要做的就是为感兴趣的 属性 覆盖 "isEqual" 和 "var hash:"。在这种情况下:"Id",Set 将排除具有相同 ID 的 Person-objects。
class Person: NSObject {
var Id: Int
var Name: String
init(id: Int, name: String?) {
self.Id = id
self.Name = name ?? ""
}
override var hash: Int {
return Id.hashValue
}
override func isEqual(object: AnyObject?) -> Bool {
guard let rhs = object as? Person else {
return false
}
let lhs = self
return lhs.Id == rhs.Id
}
}
func mergeArrays(){
let person1 = Person(id: 1, name: "Tom")
let person2 = Person (id: 2, name: "John")
let person3 = Person(id: 3, name: "Adam")
let downloadedPeople = [person1,person2] //[{NSObject, Id 1, Name "Tom"}, {NSObject, Id 2, Name "John"}]
let peopleStoredLocally = [person1,person3] //[{NSObject, Id 1, Name "Tom"}, {NSObject, Id 3, Name "Adam"}]
let downloadedPeopleSet = Set(downloadedPeople) //{{NSObject, Id 2, Name "John"}, {NSObject, Id 1, Name "Tom"}}
let mergedSet = downloadedPeopleSet.union(peopleStoredLocally) //{{NSObject, Id 2, Name "John"}, {NSObject, Id 3, Name "Adam"}, {NSObject, Id 1, Name "Tom"}}
let mergedArray = Array(mergedSet)//[{NSObject, Id 2, Name "John"}, {NSObject, Id 3, Name "Adam"}, {NSObject, Id 1, Name "Tom"}]
}
更新
使用 hashValue 时的弃用警告:
'Hashable.hashValue' is deprecated as a protocol requirement; conform
type 'Person' to 'Hashable' by implementing 'hash(into:)' instead
以对象 Person 为例,现在的实现是:
class Person: Equatable, Hashable {
let id: Int
let countryId: Int
var name: String
init(id: Int, countryId: Int, name: String) {
self.id = id
self.countryId = countryId
self.name = name
}
func hash(into hasher: inout Hasher) {
hasher.combine(id)
hasher.combine(countryId)
}
static func == (lhs: Person, rhs: Person) -> Bool {
return lhs.id == rhs.id && lhs.countryId == rhs.countryId
}
}
注意:根据文档,用于散列的组件必须与您的类型的 == 运算符实现中比较的组件相同。
对于我的 iOS 应用程序,我有一个类似
的模型class Person {
var Id: Int
var Name: String
init(id: Int, name: String?) {
self.Id = id
self.Name = name ?? ""
}
}
然后稍后在我的 ViewController
中,当我从服务器加载数据时,我将一些人添加到数组中
class ViewController: UIViewController {
var people:[Person] = []
override func viewDidLoad() {
self.loadPeople()
}
func loadPeople() {
// This data will be coming from a server request
// so is just sample. It could have users which
// already exist in the people array
self.people.append(Person(id: "1", name: "Josh"))
self.people.append(Person(id: "2", name: "Ben"))
self.people.append(Person(id: "3", name: "Adam"))
}
}
我现在要做的是将 people
数组转换为 Set<Person>
,这样它就不会添加重复项。这可以做还是我需要改变我的逻辑?
要制作 Person
集,您需要使其符合 Equatable 和 Hashable 协议:
class Person: Equatable, Hashable {
var Id: Int
var Name: String
init(id: Int, name: String?) {
self.Id = id
self.Name = name ?? ""
}
var hashValue: Int {
get {
return Id.hashValue << 15 + Name.hashValue
}
}
}
func ==(lhs: Person, rhs: Person) -> Bool {
return lhs.Id == rhs.Id && lhs.Name == rhs.Name
}
那么你可以使用这样一组人:
var set = Set<Person>()
set.insert(Person(id: 1, name: "name"))
在 Swift 2.0 中,Hashable 和 Equitable 是 NSObject 的一部分。您需要做的就是为感兴趣的 属性 覆盖 "isEqual" 和 "var hash:"。在这种情况下:"Id",Set 将排除具有相同 ID 的 Person-objects。
class Person: NSObject {
var Id: Int
var Name: String
init(id: Int, name: String?) {
self.Id = id
self.Name = name ?? ""
}
override var hash: Int {
return Id.hashValue
}
override func isEqual(object: AnyObject?) -> Bool {
guard let rhs = object as? Person else {
return false
}
let lhs = self
return lhs.Id == rhs.Id
}
}
func mergeArrays(){
let person1 = Person(id: 1, name: "Tom")
let person2 = Person (id: 2, name: "John")
let person3 = Person(id: 3, name: "Adam")
let downloadedPeople = [person1,person2] //[{NSObject, Id 1, Name "Tom"}, {NSObject, Id 2, Name "John"}]
let peopleStoredLocally = [person1,person3] //[{NSObject, Id 1, Name "Tom"}, {NSObject, Id 3, Name "Adam"}]
let downloadedPeopleSet = Set(downloadedPeople) //{{NSObject, Id 2, Name "John"}, {NSObject, Id 1, Name "Tom"}}
let mergedSet = downloadedPeopleSet.union(peopleStoredLocally) //{{NSObject, Id 2, Name "John"}, {NSObject, Id 3, Name "Adam"}, {NSObject, Id 1, Name "Tom"}}
let mergedArray = Array(mergedSet)//[{NSObject, Id 2, Name "John"}, {NSObject, Id 3, Name "Adam"}, {NSObject, Id 1, Name "Tom"}]
}
更新
使用 hashValue 时的弃用警告:
'Hashable.hashValue' is deprecated as a protocol requirement; conform type 'Person' to 'Hashable' by implementing 'hash(into:)' instead
以对象 Person 为例,现在的实现是:
class Person: Equatable, Hashable {
let id: Int
let countryId: Int
var name: String
init(id: Int, countryId: Int, name: String) {
self.id = id
self.countryId = countryId
self.name = name
}
func hash(into hasher: inout Hasher) {
hasher.combine(id)
hasher.combine(countryId)
}
static func == (lhs: Person, rhs: Person) -> Bool {
return lhs.id == rhs.id && lhs.countryId == rhs.countryId
}
}
注意:根据文档,用于散列的组件必须与您的类型的 == 运算符实现中比较的组件相同。