2

I'm using a ForEach to loop over an array of structures and display a View for each item of the array.
When I'm mutating a single item, the main view re-render every element of the array. Is there a way to avoid this when using structures? I'd like that only the view corresponding to my modified item to be re-rendered.

Is it achievable with structures or do I need to use classes with ObservedObjects ?

A simplified version would look like this (the real version uses the Defauts package with an array and the item view is way more expensive, but the idea is the same).

import SwiftUI
import PlaygroundSupport

struct Player {
    var name: String
    var score: Int
}

struct PlayerView: View {
    @Binding var player: Player
    
    var body: some View {
        let _ = Self._printChanges()
        return HStack(spacing: 12) {
            Text(player.name).font(.system(size: 20))
            Text("\(player.score)").font(.system(size: 20))
            Button("plus") { player.score += 1 }.font(.system(size: 20))
        }
    }
}

struct PlayersView: View {
    @State var players = [
        Player(name: "John", score: 12), 
        Player(name: "Jane", score: 15)
    ]
    
    var body: some View {
        VStack {
            ForEach($players, id: \.name) { player in
                PlayerView(player: player)
            }
            Button("inc", action: {players[0].score += 10})
        }
    }
}

PlaygroundPage.current.setLiveView(PlayersView())
Vincent
  • 356
  • 2
  • 8

1 Answers1

0

Just make model Equatable so rendering engine could detect if dependent property is really changed.

Tested with Xcode 13.4 / iOS 15.5

struct Player: Equatable {    // << here !!
    var name: String
    var score: Int
}
Asperi
  • 228,894
  • 20
  • 464
  • 690
  • Hi! Thank for your quick response. I tried but the `Self._printChanges()` still display two lines when I change one score. – Vincent Jun 19 '22 at 16:02
  • Test on Simulator or real device, that might be playground issue. As I mentioned I tested and only one is called, at least with provided example - your real code might have different additional affected areas. – Asperi Jun 19 '22 at 16:04
  • I did conformed everything to `Codable, Identifiable, Equatable, Hashable` but they are still re-rendered. I'm also getting a couple of `@440` when using `_printChanges` but I'm not sure what it means. – Vincent Jun 19 '22 at 16:29
  • @Vincent Take a look at this , I think this is what you are looking for https://stackoverflow.com/a/67891839/14871052 – fdvfarzin Jun 19 '22 at 18:14
  • This solution did not work for me either – John Mar 30 '23 at 00:00