WWDC24 SALE: Save 50% on all my Swift books and bundles! >>

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      

Save 50% in my WWDC sale.

SAVE 50% To celebrate WWDC24, all our books and bundles are half price, so you can take your Swift knowledge further without spending big! Get the Swift Power Pack to build your iOS career faster, get the Swift Platform Pack to builds apps for macOS, watchOS, and beyond, or get the Swift Plus Pack to learn advanced design patterns, testing skills, and more.

Save 50% on all our books and bundles!

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.