UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

SOLVED: Challenge Day 47 - Strange Equatable behaviour

Forums > 100 Days of SwiftUI

So I completed the app and it worked exactly how it is supposed to. I decided to play around to see if there were any parts I could change using knowledge I already knew, and that is when I ran into this weird problem.

struct Activity: Codable, Identifiable, Equatable {
    var id = UUID()
    let title: String
    let description: String
    var completedCount = 0

    static func ==(lhs: Activity, rhs: Activity) -> Bool {
        lhs.id == rhs.id
    }
}

The method that updates the count for each activity:

    func increment(activity: Activity) {
        var copy = activity
        copy.completedCount += 1
        if let index = activities.firstIndex(where: { $0 == activity }) {
            print("Index found at ", index)
            activities[index] = copy
        }
    }

See after adding my own method to check for equality it stopped working! when I increment the counter UI doesn't change, no matter how many times I increment it. But when I relaunch the app I see it has incremented by 1.

Does anybody have any idea what is going on? Because if I remove the static equality method it works again.

2      

Hi, The thing is that out of the box the == operation checks every property you have for equality (ie. id, title, description, ect...), when you override the function it no longer does that it only checks the ones you specify (ie. id, in this case) with the lhs.id == rhs.id, so when you change the Activity’s count the change is not published because it only checks the id, now the change still happens so when you restart the app you see the change, so one way of fixing this is adding " && lhs.completedCount == rhs.completedCount" to the == function.

static func ==(lhs: Activity, rhs: Activity) -> Bool {
        lhs.id == rhs.id && lhs.completedCount == rhs.completedCount
    }

2      

Thanks but I'm a little confused. I thought the Equatable conformance was just to to find the location of the item we want to edit in the array? so this line finds the item:

if let index = activities.firstIndex(where: { $0 == activity }) { ... } 

and this line changes the array which is marked with @Published which should trigger the UI to update.

activities[index] = copy

2      

Behind the scenes the activitties array is using the == to check for changes, you could also add a new UUID to the copy when you update the completedCount and it will update the view.

func increment(activity: Activity) {
        var copy = activity
        copy.completedCount += 1
        copy.id = UUID()
        if let index = activities.firstIndex(where: { $0 == activity }) {
            print("Index found at ", index)
            activities[index] = copy
        }
    }

3      

and this line changes the array which is marked with @Published which should trigger the UI to update.

Nope. You make a copy of one Activity and change its completedCount property and then add that back into the array at the same index as the original.

So nothing triggers the @Published property wrapper to notice that there have been changes because you didn't:

  1. add/remove anything from the array, or
  2. change an item in the array

You may think you did #2, but because your custom Equatable conformance only looks at the id when determining if two Activity items are the same and you didn't change the id property, @Published considers the two items to be the same and thus there was no change to the item.

In a case like this, you should not be using a custom conformance to Equatable; just let the default synthesized conformance do its thing and you'll be fine.

3      

Thank you both, that makes sense and I understand it now 👍

2      

TAKE YOUR SKILLS TO THE NEXT LEVEL If you like Hacking with Swift, you'll love Hacking with Swift+ – it's my premium service where you can learn advanced Swift and SwiftUI, functional programming, algorithms, and more. Plus it comes with stacks of benefits, including monthly live streams, downloadable projects, a 20% discount on all books, and free gifts!

Find out more

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.