In Swift, you can either use class or struct to define your custom class. Most likely in the later development, you would need to have an array of such custom modelsomewhere in the project, and each of the custom model in the array are unique, in other words, you want an array/dictionary/set only includes non-duplicated custom model objects. So the following are the complete guide of some examples showing how to do compare your own custom model:

In Swift, you can either use class or struct to define your custom class. Here are some examples.

Struct Model

// Struct
struct NoteModel {
    let userName: String
    let latitude: Double
    let longitude: Double
    let text: String
    let createDateTime: String
}

In the case above, we are assuming if two notes have different username, latitude, longitude and text, they are two different notes, so if you want to make two of above objects can be comparable, add the following code:

struct NoteModel: Equatable {
    let userName: String
    let latitude: Double
    let longitude: Double
    let text: String
    let createDateTime: String
    
    // compare whether two notes are same
    static func == (lhs: NoteModel, rhs: NoteModel) -> Bool {
        return lhs.createDateTime == rhs.createDateTime &&
            lhs.text == rhs.text &&
            lhs.userName == rhs.userName &&
            lhs.latitude == rhs.latitude &&
            lhs.longitude == rhs.longitude
    }
}

Class Model

Sometimes we are using class for the model, see the following code for the same functionality:

class NoteModel: Equatable {
    
    let userName: String
    let latitude: Double
    let longitude: Double
    let text: String
    let createDateTime: String
    
    init(userName: String, latitude: Double, longitude: Double, text: String, createDateTime: String) {
        self.userName = userName
        self.latitude = latitude
        self.longitude = longitude
        self.text = text
        self.createDateTime = createDateTime
    }
    
    static func == (lhs: NoteModel, rhs: NoteModel) -> Bool {
        return lhs.createDateTime == rhs.createDateTime &&
            lhs.text == rhs.text &&
            lhs.userName == rhs.userName &&
            lhs.latitude == rhs.latitude &&
            lhs.longitude == rhs.longitude
    }
}

Class Model inherited from NSObject

Sometimes we have the special requirements that model class must inherited from NSObject, so you have to override the isEqual. See the following code for the same functionality:

class NoteModel: NSObject {
    
    let userName: String
    let latitude: Double
    let longitude: Double
    let text: String
    let createDateTime: String
    
    init(userName: String, latitude: Double, longitude: Double, text: String, createDateTime: String) {
        self.userName = userName
        self.latitude = latitude
        self.longitude = longitude
        self.text = text
        self.createDateTime = createDateTime
    }
    
    override func isEqual(_ object: Any?) -> Bool {
        guard let _object = object else { return false }
        guard let rhs = _object as? NoteModel else { return false }
        return (self.createDateTime == rhs.createDateTime &&
            self.text == rhs.text &&
            self.userName == rhs.userName &&
            self.latitude == rhs.latitude &&
            self.longitude == rhs.longitude
        )
    }
}

Why do we need to override?

With overriding isEqual or ==, you can make use a lot of inner-built methods such as contains, filter etc, an example of showing contains:

let note1 = NoteModel(userName: "testing user 2", latitude: 0.0, longitude: 0.0, text: "testing notes", createDateTime: "04/12/2020 18:12:03")
let note2 = NoteModel(userName: "testing user 2", latitude: 0.0, longitude: 0.0, text: "testing notes", createDateTime: "04/12/2020 18:12:03")
let array = [note1]
XCTAssertEqual(array.contains(note2), true)  // true

Conclusion

  • Custom Struct/Class: need to extend Equatable and override the operand ==.
  • Custom Class inherited from NSObject: need to override isEqual.