Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I create a Set of custom objects (Swift)?

People also ask

What is set in swift IOS?

Sets are unordered collections of unique values. Dictionaries are unordered collections of key-value associations. Arrays, sets, and dictionaries in Swift are always clear about the types of values and keys that they can store. This means that you can't insert a value of the wrong type into a collection by mistake.

How do I store a custom object in defaults Swift?

To store them in UserDefaults, we need to implement or confirm Codable to the user-defined class or struct. Codable is a typealias of Decodable & Encodable protocols. It adds the functionality of Encoding and Decoding to the class or struct.


To make set of Person you need to make it conform to Equatable and Hashable protocols:

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
}

Then you can use set of persons like this:

var set = Set<Person>()
set.insert(Person(id: 1, name: "name"))

With Swift 2.0, Hashable and Equitable is a part of NSObject. All you need to do is to override "isEqual" and "var hash:" for the property of interest. In this case: "Id", Set will exclude Person-objects with identical Ids.

    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"}]

    }

UPDATE

Depretation warning when using hashValue:

'Hashable.hashValue' is deprecated as a protocol requirement; conform type 'Person' to 'Hashable' by implementing 'hash(into:)' instead

Following the object Person example, nowadays implementation would be:

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
    }
    
}

Note: As per documentation the components used for hashing must be the same as the components compared in your type’s == operator implementation.