J'ai deux champs de texte, affectés à:
@State private var emailAddress: String = ""
@State private var password: String = ""
Maintenant, chaque fois que je tape dessus, l'application semble bloquée et me donne cette erreur:
'La modification de l'état lors de la mise à jour de la vue entraînera un comportement indéfini.'
J'ai une StartView()
:
class UserSettings: ObservableObject {
var didChange = PassthroughSubject<Void, Never>()
@Published var loggedIn : Bool = false {
didSet {
didChange.send(())
}
}
}
struct StartView: View {
@EnvironmentObject var settings: UserSettings
var body: some View {
if settings.loggedIn {
return AnyView(TabbarView())
}else {
return AnyView(ContentView())
}
}
}
J'ai créé une classe ObservableObject de UserSettings qui a une valeur booléenne loggedIn
. Lorsque l'utilisateur appuie sur le bouton "Connexion" dans LogInView()
, cette valeur booléenne devient true
et une nouvelle vue apparaît (TabbarView()
)
C'est LogInView ():
struct LogInView: View {
@EnvironmentObject var settings: UserSettings
@State private var emailAddress: String = ""
@State private var password: String = ""
var body: some View {
GeometryReader { geometry in
VStack (alignment: .center){
HStack {
Image("2")
.resizable()
.frame(width: 20, height: 20)
Text("Social App")
.font(.system(size: 12))
}.padding(.top, 30)
.padding(.bottom, 10)
Text("Log In to Your Account")
.font(.title)
.font(.system(size: 14, weight: .bold, design: Font.Design.default))
.padding(.bottom, 50)
TextField("Email", text: self.$emailAddress)
.frame(width: geometry.size.width - 45, height: 50)
.textContentType(.emailAddress)
.padding(EdgeInsets(top: 0, leading: 5, bottom: 0, trailing: 0))
.accentColor(.red)
.background(Color(red: 242 / 255, green: 242 / 255, blue: 242 / 255))
.cornerRadius(5)
TextField("Password", text: self.$password)
.frame(width: geometry.size.width - 45, height: 50)
.padding(EdgeInsets(top: 0, leading: 5, bottom: 0, trailing: 0))
.foregroundColor(.gray)
.background(Color(red: 242 / 255, green: 242 / 255, blue: 242 / 255))
.textContentType(.password)
.cornerRadius(5)
Button(action: {
self.settings.loggedIn = true
}) {
HStack {
Text("Log In")
}
.padding()
.frame(width: geometry.size.width - 40, height: 40)
.foregroundColor(Color.white)
.background(Color.blue)
.cornerRadius(5)
}
.padding(.bottom, 40)
Divider()
Button(action: {
print("Take to forget password VC")
}) {
Text("Forgot your password?")
}
Spacer()
}
.padding(.bottom, 90)
}
}
}
Je sais que cette erreur apparaît si je mets à jour la vue pendant la modification de l'état (lors de la saisie dans le champ de texte). Mais je ne mets à jour la vue nulle part dans l'écran de connexion. Alors pourquoi cette erreur se produit. Votre aide sera appréciée!
Je suppose que c'est un bug. Ce message que vous avez reçu se produit également sur cette vue simple qui filtre les entrées de liste par entrée utilisateur. Une simple saisie rapide dans le champ de texte provoque ce problème. Si vous entrez le premier caractère dans le champ de texte, l'interface utilisateur est restée bloquée pendant un certain temps.
struct ContentView: View {
@State private var list: [String] = (0..<500).map { "Text \($0)" }
@State private var searchText: String = ""
var filteredList: [String] {
guard !searchText.isEmpty else { return list }
return list.filter({ $0.contains(self.searchText) })
}
var body: some View {
VStack {
TextField("Search", text: $searchText)
List(filteredList, id: \String.self) { t in Text(t) }
}
.padding()
}
}
Une solution de contournement consiste à déplacer les variables @State dans un modèle. Cela semble donc être un problème avec @State:
class Model: ObservableObject {
@Published var list: [String] = (0..<500).map { "Text \($0)" }
@Published var searchText: String = ""
var filteredList: [String] {
guard !searchText.isEmpty else { return list }
return list.filter({ $0.contains(self.searchText) })
}
}
struct ContentView: View {
@ObservedObject var model: Model
var body: some View {
VStack {
TextField("Search", text: $model.searchText)
List(model.filteredList, id: \String.self) { t in Text(t) }
}
.padding()
}
}
Cela peut ne pas être lié à votre problème, mais dans Xcode 11 Beta 4, Apple a changé "didset" en "willset" et "didChange" en "willChange" Dans Xcode 11 Beta 5, Apple a changé " willChange "en" objectWillChange ".
Ainsi, StartView () devrait être:
class UserSettings: ObservableObject {
var objectWillChange = PassthroughSubject<Void, Never>()
@Published var loggedIn : Bool = false {
willSet {
objectWillChange.send(())
}
}
}