0

Why is my SwiftUI Swipe Action behaving like this?

I don't now how to add a GIF in stack overflow so here is a imagur link https://i.stack.imgur.com/VCKEE.jpg. If you don't want to click on external links here is a image from the GIF:

This bug is only for the row 2, 3 and 4. Not for 1 and 5. If I add more items, the first and the last row wont have this bug

My View:

struct MyView: View {
@State var shops = [Shop.empty(), Shop.empty(), Shop.empty(), Shop.empty(), Shop.empty()]

var body: some View {
    NavigationView {
        List($shops) { $shop in
            Text(shop.name)
                .swipeActions {
                    Button {
                        shop.toggleFavourite()
                    } label: {
                        Image(systemName: "star")
                    }
                }
        }
    }
}
}

the shop struct:

struct Shop: Hashable, Identifiable {

var id: UUID

var favourite: Bool

init(id: UUID){
    self.id = id
    self.favourite = UserDefaults.standard.bool(forKey: id.uuidString)
}

mutating func toggleFavourite() {
    favourite.toggle()
    UserDefaults.standard.set(favourite, forKey: id.uuidString)
}

static func empty() -> Shop{
    Shop(id: UUID())
}
}

But I can't sadly I can't give you a working example, because I tried to run this code in a fresh app and it worked, without the Bug. On the same device. And I don't understand why, because I also put this view in the root of my old project, just for testing, and the bug stayed there.

I was able to figure out, that if I commented out this line:

UserDefaults.standard.set(favourite, forKey: id.uuidString)

my code would work. But unfortunately I can't just leave out this line of code. I tried several things, including wrapping this line into DispatchQueue.main.async {} and DispatchQueue.main.sync {}, same with the DispatchQueue.global(). I also added delays. Short delays wouldn't work at all (under .5 seconds) and longer delays would just delay the view bug. Of course I also tried wrapping this line into a separate function, and so on.

There are two mayor points, why I'am so confused:

  1. Why is the line, that sets this to the Userdefaults even influencing the view? I mean I checked with a print statement, that the initializer, which is the only section in my code that checks this Userdefaultvalue, only gets called when the view gets initialized.
  2. Why does the code work in a different project?

I know since I can't provide a working example of my bug it's hard for you to figure out whats wrong. If you have any ideas, I would be very happy!

Boothosh81
  • 387
  • 1
  • 5
  • 24
  • When you are able to produce a working example you will find the error. There is no way to help if we can’t see code with the issue. UserDefaults is a terrible solution for this type of work. You should be using another type of persistence – lorem ipsum Aug 23 '22 at 11:51
  • What type would you recommend for this? – Boothosh81 Aug 23 '22 at 13:17
  • CoreData, Firebase, AWS, files, etc. UserDefaults is for inconsequential things like volume settings, etc. – lorem ipsum Aug 23 '22 at 13:19

0 Answers0