Home > Back-end >  Comparing An Object to Itself Returning False
Comparing An Object to Itself Returning False

Time:10-29

I have a class that implements the Equatable protocol, and it uses a UUID field for comparison:

class MemberViewModel {
    private static var entities: [MemberViewModel] = []
    private var entity: Member

    let id = UUID()

    init(_ entity: Member) {
        self.entity = entity
    }

    static func members() -> [MemberViewModel] {
        entities.removeAll()

        try? fetch().forEach { member in
            entities.append(MemberViewModel(member))
        }

        return entities
    }
}

extension MemberViewModel: Equatable {
    static func == (lhs: MemberViewModel, rhs: MemberViewModel) -> Bool {
        return lhs.id == rhs.id
    }
}

I then have a view that creates icons that when tapped should display a stroke to denote it was "selected":

struct MyView: View {
    @State var selectedMember: MemberViewModel? = nil

    var body: some View {
        let members = MemberViewModel.members()

        ScrollView(.horizontal, showsIndicators: true) {
            HStack(alignment: .top, spacing: 4) {
                ForEach (members, id: \.id) { member in
                    var isSelected: Bool = selectedMember == member

                    Circle()
                        .fill(Color(.red))
                        .frame(width: 48, height: 48)
                        .overlay() {
                            if isSelected {
                                Circle()
                                    .stroke(Color(.black), lineWidth: 2)
                            }
                        }
                        .onTapGesture { selectedMember = member }
                }
            }
        }
    }
}

I have tried setting isSelected multiple ways, including the following from another SO question:

let isSelected = Binding<Bool>(get: { self.selectedMember == member }, set: { _ in })

When debugging using breakpoints, the value of isSelected is always false.

I'm using XCode Version 14.0.1 (14A400), and Swift 5.7.

CodePudding user response:

Put let members = MemberViewModel.members() just before var body: some View {...}, not inside it, like this:

let members = MemberViewModel.members()  // <-- here 

var body: some View {
  ...
} 

Due to your weird code structure, let members = MemberViewModel.members() gets re-done evey time the body is refreshed. And since the UUID is re-generated .... you can guess that the ids now are all over the place and not equal to the selectedMember.

In other words, the object comparison is working, but you are not comparing what you think.

CodePudding user response:

Use the sample below hope you get the idea.

Model

struct Member {
    
    let id = UUID()
    
}

extension Member: Equatable {
    static func == (lhs: Member, rhs: Member) -> Bool {
        return lhs.id == rhs.id
    }
}

class MemberViewModel: ObservableObject {
    // each time you update the entities, view vill be updated
    @Published var entities: [Member] = []
    
    func fetchMembers() {
        entities.removeAll()

        // your code to fetch members
        try? fetch().forEach { member in
           entities.append(member)
        }
        
    }
}

MyView

struct MyView: View {
    
    @StateObject private var modelData = MemberViewModel()
    @State private var selectedMember: Member? = nil

    var body: some View {
        
        ScrollView(.horizontal, showsIndicators: true) {
            HStack(alignment: .top, spacing: 4) {
                ForEach (modelData.entities, id: \.id) { member in

                    Circle()
                        .fill(Color(.red))
                        .frame(width: 48, height: 48)
                        .overlay() {
                            if selectedMember == member {
                                Circle()
                                    .stroke(Color(.black), lineWidth: 2)
                            }
                        }
                        .onTapGesture { selectedMember = member }
                }
            }
        }.onAppear {
            modelData.fetchMembers()
        }
    }
}
  • Related