Wednesday, August 8, 2018

Swift Equatable Protocol


In this tutorial, let’s see what is like confirming to Equatable protocol and where exactly it fits in app development.


It’s quite often we compare things/objects.

       
        let currentAddress = "New York, America"
        let selectedAddress = "New York, America"
        
        if currentAddress == selectedAddress {
            print("Deliver to current address.")
        } else {
            print("Deliver to selected address.")
        }




As these are strings, directly we can use equal to(==) operator.

What If thy are custom objects ?

       
  let currentAddress = Address(city: "Amsterdam", 
                                              state: "New York", 
                                              country: "America")

  let selectedAddress = Address(city: "Amsterdam", 
                                                state: "New York", 
                                                country: "America")
        
  if currentAddress == selectedAddress { 
            
  }




If you compare two custom objects, We get below build error,

// Binary operator '==' cannot be applied to two 'Address' operands

Here what we can do is to write a method in Address struct.

       
 struct Address {
    
    let city: String
    let state: String
    let country: String
    
    func isEqual(to address: Address) -> Bool {
        if city == address.city && 
           state == address.state && 
           country == address.country {

            return true
        }
        return false
    }
    
 }

  let currentAddress = Address(city: "Amsterdam", 
                                              state: "New York", 
                                              country: "America")

  let selectedAddress = Address(city: "Amsterdam", 
                                                state: "New York", 
                                                country: "America")
        
   if selectedAddress.isEqual(to: currentAddress) {
            
   }




This solves the scenario for now.

What if we have an array of addresses and we need to find a address in that?

And we can not directly use contains by passing element like below.

       
  var countries = ["Canada", "Australia", "India", "America"]


   let country = "India"
        
   if countries.contains(country) {
            
   }



We have to use the Array’s contains(where) closure.




       
  let addresses = [
                             Address(city: "Amsterdam", state: "New York", country: "America"), 
                             Address(city: "Belmont", state: "California", country: "America"),  

                             Address(city: "Hartford", state: "Connecticut", country: "America")
                          ]
        
  let selectedAddress = Address(city: "Hartford", state: "Connecticut", country: "America")
        
        let contains = addresses.contains { (address) -> Bool in

            return (selectedAddress.city == address.city &&
                selectedAddress.state == address.state &&
                selectedAddress.country == address.country)
        }



We need to check with the Array contains method with the same condition we used in Address struct method isEqual()


       
     func isEqual(to address: Address) -> Bool {
        if city == address.city && 
           state == address.state && 
           country == address.country {

            return true
        }
        return false
    }

    let contains = addresses.contains { (address) -> Bool in

            return (selectedAddress.city == address.city &&
                selectedAddress.state == address.state &&
                selectedAddress.country == address.country)
     }




Isn’t it a tedious job?


So, This is the use case of Equatable protocol, where it gives the easy solution/way for comparing two objects and finding an object in a collection.

It is as simple as shown below.

Let our Address structure confirm to Equatable protocol.

Earlier, prior to Swift 4.1 version, we need to implement below == static method where we can write equality logic.

       
 struct Address: Equatable {
    
    let city: String
    let state: String
    let country: String
    
    public static func == (lhs: Address, rhs: Address) -> Bool {
        return lhs.city == rhs.city &&
        lhs.state == rhs.state &&
        lhs.country == rhs.country
    }
    
 }




From Swift 4.1 onwards, we don’t need to write the boilerplate code for Equatable protocol unless we need to change the logic.

       
 struct Address: Equatable {
    
    let city: String
    let state: String
    let country: String    
    
 }



By default, boilerplate code compares all the stored properties.

       
 public static func == (lhs: Address, rhs: Address) -> Bool {


        return lhs.city == rhs.city &&
                  lhs.state == rhs.state &&
                  lhs.country == rhs.country
  }



If you want to customise you can implement the == method. In this case, If you want to compare just city and state.

       
 struct Address: Equatable {
    
    let city: String
    let state: String
    let country: String
    
    public static func == (lhs: Address, rhs: Address) -> Bool {

        return lhs.state == rhs.state &&
                  lhs.country == rhs.country
    }
    
 }



Now, we can compare objects like native things.


       
    let currentAddress = Address(city: "Amsterdam", 
                state: "New York", country: "America")


    let selectedAddress = Address(city: "Amsterdam", 
                state: "New York", country: "America")

    if currentAddress == selectedAddress {
            
    }




And also below. When we call !=, It takes the reverse of == method. No need to write extra code for !=
        
       
   if currentAddress != selectedAddress {
            
    }




So, comparing objects became easy with Equatable protocol. Let’s see finding an element in a collection if all the objects in the collection confirm to Equatable protocol.

       
 let addresses = [

          Address(city: "Amsterdam", state: "New York", country: "America"), 


          Address(city: "Belmont", state: "California", country: "America"), 


          Address(city: "Hartford", state: "Connecticut", country: "America")


  ]


  let selectedAddress = Address(city: "Hartford", state: "Connecticut", country: "America")




I want to check whether addresses collection contains selected address or not. As Address confirm to Equatable protocol and addresses array is a collection of Address objects. We get another useful and simple contains() method now.





             
 let addresses = [

          Address(city: "Amsterdam", state: 

                 "New York", country: "America"), 

          Address(city: "Belmont", state: 

                 "California", country: "America"), 

          Address(city: "Hartford", state: 

               "Connecticut", country: "America")

  ]


  let selectedAddress = Address(city: 

                            "Hartford", state: 
               "Connecticut", country: "America")


  if addresses.contains(selectedAddress) {
            
  }




We can simply find objects now using contains.

That’s how Equatable makes it easy of comparing custom objects and finding custom objects in a collection.

Hope this post is useful. Feel free to comment in case of any queries.



No comments:

Post a Comment