swiftuixcode11.3

Canvas preview doesn't show when accessing environmentObject containing array of objects


Preview usually works fine with environment object but I'm having trouble when accessing within the object an array of objects.

The following view doesn't show in preview but works fine insimulator

import SwiftUI

struct ScoreCell: View {

    @EnvironmentObject var game : Game

    var player: Player

    var body: some View {
        VStack {  
            Text(String(self.game.playerScores[self.game.indexOfPlayerInScores(player: player)].totalScore()))
        }
    }
}

struct ScoreCell_Previews: PreviewProvider {
    static var previews: some View {
        ScoreCell(player: Player(name: "s", shortName: "Steph", photoURL: "steph", color: Color(.cyan)))
            .environmentObject(Game())
    }
}

If I replace by a hardcoded index it works just fine (like in the line below)

Text(String(self.game.playerScores[0].totalScore()))

Additional info:

struct PlayerScore {
    let player: Player
    var pointsList: [Int]     


    func totalScore() -> Int {
        return pointsList.reduce(0, +)
    }
}

I can definitely work without preview but I have the feeling it's hiding a more generic problem that will bite me later ... Thanks for the help.

Adding code of Game to provide potential info - Thanks

import SwiftUI
import Combine

class Game: ObservableObject {

    var players = [Player] ()
    @Published var playerScores = [PlayerScore] ()

    func addPlayer(player: Player) {
        players.append(player)
        playerScores.append(PlayerScore(player: player, pointsList: [0]))
    }

    func addPlayer(player: Player, score: Int) {
        players.append(player)
        playerScores.append(PlayerScore(player: player, pointsList: [score]))
    }

    func indexOfPlayerInScores(player: Player) -> Int {
        return  playerScores.firstIndex(where: {$0.player.id == player.id})!
    }

    init () {
        self.addPlayer(player: Player(name: "Stephane", shortName: "Steph", photoURL:"steph", color: Color(.sRGB,red: 90/255, green: 197/255, blue: 191/255)))
        self.addPlayer(player: Player(name: "Sophie", shortName: "Sof", photoURL:"sof", color: Color(.sRGB, red: 189/255, green: 0/255, blue: 82/255)))
        self.addPlayer(player: Player(name: "Chloe", shortName: "Chloe", photoURL:"chloe", color: Color(.sRGB,red: 251/255, green: 78/255, blue: 84/255)))
        self.addPlayer(player: Player(name: "Stephane", shortName: "Gaby", photoURL:"gaby", color: Color(.sRGB,red: 255/255, green: 195/255, blue: 11/255)))
    }


}

Solution

  • The issue is definitely here

    func indexOfPlayerInScores(player: Player) -> Int {
        return  playerScores.firstIndex(where: {$0.player.id == player.id})!
    }
    

    you Player does not have id in constructor, so it is autogenerated, so above method just does not find matches in run-time, because created player in preview and added by-default players in Game are different (independently of type, class or struct).

    The solution: to change logic of detecting equality of Players (maybe confirming explicitly to Equatable).