SwiftUI function shows "Modifying state during view update, this will cause undefined behavior."

2k views Asked by At

The code works in that it brings up 5 random consonants and 2 vowels just like I want, but it is showing a warning message that "Modifying state during view update, this will cause undefined behavior."

I am fairly new to Swift and I don't understand the answers I am reading online when I search for swiftui and "Modifying state during view update, this will cause undefined behavior." At least I don't understand well enough to fix my own code. I am no closer to figuring out how to modify my code to get rid of the warning. Please help.

FYI - I want to keep my vowels and consonants in (sorted) arrays that are updated when the button is pressed to roll new random vowels and consonants.

import SwiftUI

struct ContentView: View {
  @State private var vowels = ["X","X"]
  @State private var consonants = ["X","X","X","X","X"]
  
  var body: some View {
    VStack {
      Spacer()
      Text(rollConsonants())
      Text(rollVowels())
      Spacer()
      Button("Reroll") {
        _ = rollVowels()
        _ = rollConsonants()
      }
    }
    .font(.largeTitle)
  }
  
  
  func rollVowels() -> String {
    vowels = ["A","E","I","O","U"].shuffled().prefix(2).sorted()   // message here
    let string = vowels.joined(separator:"   ")
    return string
  }
  
  func rollConsonants() -> String {
    let commonConsonants = ["C","D","L","N","R","S","T"].shuffled().prefix(2)
    var otherConsonants = ["B","F","G","H","K","M","P","V","W","Y","*"].shuffled().prefix(3)
    let rareConsonants = ["J","Q","X","Z"].shuffled()
    if let i = otherConsonants.firstIndex(of: "*") {
      otherConsonants[i] = rareConsonants[0]
    }
    consonants = (commonConsonants + otherConsonants).sorted()   // message here
    let string = consonants.joined(separator:"   ")
    return string
  }

  
}
1

There are 1 answers

0
Daniel Amarante On BEST ANSWER

It's because of this:

Text(rollConsonants())
Text(rollVowels())

You're modifying the state while SwiftUI is trying to render the text.

This change fixes the warning, by splitting up the act of updating the state from the act of reading from the state:

import SwiftUI

struct ContentView: View {
    @State private var vowels = ["X", "X"]
    @State private var consonants = ["X", "X", "X", "X", "X"]

    var formattedVowels: String {
        vowels.joined(separator: "   ")
    }

    var formattedConsonants: String {
        consonants.joined(separator: "   ")
    }

    var body: some View {
        VStack {
            Spacer()
            Text(formattedConsonants)
            Text(formattedVowels)
            Spacer()
            Button("Reroll") {
                rollVowels()
                rollConsonants()
            }
        }
        .font(.largeTitle)
    }

    func rollVowels() {
        vowels = ["A", "E", "I", "O", "U"].shuffled().prefix(2).sorted() // message here
    }

    func rollConsonants() {
        let commonConsonants = ["C", "D", "L", "N", "R", "S", "T"].shuffled().prefix(2)
        var otherConsonants = ["B", "F", "G", "H", "K", "M", "P", "V", "W", "Y", "*"].shuffled().prefix(3)
        let rareConsonants = ["J", "Q", "X", "Z"].shuffled()
        if let i = otherConsonants.firstIndex(of: "*") {
            otherConsonants[i] = rareConsonants[0]
        }
        consonants = (commonConsonants + otherConsonants).sorted() // message here
    }
}