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())

1 Answer 1

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
}
Sign up to request clarification or add additional context in comments.

6 Comments

Hi! Thank for your quick response. I tried but the Self._printChanges() still display two lines when I change one score.
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.
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 Take a look at this , I think this is what you are looking for stackoverflow.com/a/67891839/14871052
This solution did not work for me either
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.