Xcode 14.0: Publishing changes from within view updates is not allowed, this will cause undefined behavior.

Bug oder Feature?

Seit dem Release von Xcode 14.0 seid auch ihr möglicherweise auf jene Runtime-Warnung gestoßen, die den Titel dieses Artikels ziert. Es würde mich nicht wundern. Diese Meldung führt aktuell zu einiger Irritation innerhalb der Apple Developer-Community (siehe https://developer.apple.com/forums/thread/711899).

Um diese Warnung zu erhalten, müsst ihr nicht allzu viel tun. Der folgende Code ist zu Demonstrationszwecken vollkommen ausreichend. Ihr seht darin eine als ObservableObject deklarierte Klasse Person mit einer Published-Property namens name. Abschließend folgt eine ContentView, die eine Person-Instanz als StateObject enthält und deren Namen einen Standardwert nach Betätigung eines Buttons zuweist.

class Person: ObservableObject {
    @Published var name = ""
}

struct ContentView: View {
    @StateObject private var person = Person()
    
    var body: some View {
        NavigationView {
            Form {
                Text("Name: \(person.name)")
                Button("Max Mustermann") {
                    person.name = "Max Mustermann"
                }
            }
        }
    }
}

So weit, so gut – oder eben auch nicht. Das Problem ist, dass Xcode nach Betätigung des Buttons die Änderung des Namens mit jener Runtime-Warnung quittiert:

Publishing changes from within view updates is not allowed, this will cause undefined behavior.

Das ist deshalb irritierend, da das skizzierte Vorgehen

  1. in der Vergangenheit nie ein Problem war und
  2. eine Änderung einer Published-Property beispielsweise aus einer Button-Action heraus eigentlich überhaupt nichts ungewöhnliches oder kritisches darstellt (oder darstellen sollte).

Mit Xcode 14.0 aber weist uns Xcode darauf hin, dass dieses Vorgehen nicht okay ist. Und natürlich könnte es sein, dass uns Apple hier auf eine Nutzungsart von SwiftUI stößt, die eigentlich nicht gern gesehen oder sogar problematisch ist. Dumm nur, dass das (sollte diese Annahme tatsächlich der Wahrheit entsprechen) bisher niemand von Apple mal so recht kommuniziert hat, auch nicht jüngst auf der WWDC 2022 im Juni.

Wie also dieses Problem umgehen, die Warnung auflösen? Das hängt natürlich immer ein wenig vom Kontext ab, in dem die gezeigte Meldung genau auftritt (die Button-Action ist nur eins von mehreren potentiellen Beispielen). Im Falle der Button-Action ist die Lösung aber erfreulich simpel: Ihr verzögert schlicht die Button-Action, beispielsweise ganz simpel mittels Timer. Fertig.

Button("Max Mustermann") {
    Timer.scheduledTimer(withTimeInterval: 1, repeats: false) { _ in
        person.name = "Max Mustermann"
    }
}

Ist euch nicht recht? Wirkt nach einer stupiden und alles andere als vernünftigen Lösung? Ja, da habt ihr nicht ganz unrecht. Zum Glück hilft es auch, einen anderen Button-Style zu verwenden. Denn View-Styles haben bekanntlich explizite Auswirkungen auf das Verhalten von Action-Closures. In diesem Sinne hier die Layout-Lösung, tada!

Button("Max Mustermann") {
    person.name = "Max Mustermann"
}
.buttonStyle(.plain)

Ihr habt die Ironie vielleicht bemerkt. Gerade die letzte „Lösung“ mutet recht seltsam an, erlaubt ein Style-Wechsel doch plötzlich eine Model-Änderung, die zuvor eine Warnung ausgelöst hat. Einzige Erklärung (in meinen Augen): Die Animation des Buttons selbst löst den Konflikt aus, den die Änderung des Namens und damit einhergehend eine weitere View-Aktualisierung mit sich bringt. Doch auch in diesem Fall müssten wir wissen, wie mit solchen View-Animationen wie dem von Button korrekt umzugehen ist.

Doch generell machen mich jene beschriebenen „Lösungswege“ auch durchaus Glauben, dass wir es hier mit einem Bug in Xcode 14.0 beziehungsweise SwiftUI zu tun haben. Und ein Stück weit hoffe ich das auch. Denn wenn Apple es zukünftig unterbindet, Published-Properties beispielsweise direkt aus Button-Actions heraus zu ändern, wird das für viel Arbeit in allen möglichen bisherigen SwiftUI-Projekten sorgen. Einfach weil das bisher nie als „Problem“ kommuniziert wurde – sofern es überhaupt eines ist.

Darum hoffe ich persönlich auf den Oktober und den Release von macOS 13 und iPadOS 16 – mitsamt einer neuen Xcode-Version, die hoffentlich Licht in dieses Dunkel bringt. Denn im Prinzip erwarte ich jetzt eines von zwei Ereignissen:

  1. Es handelt sich bei der Runtime-Warnung tatsächlich um einen Bug, der zeitnah behoben wird (Stichwort Oktober).
  2. Es handelt sich bei der Runtime-Warnung um ein wirkliches Problem, demzufolge SwiftUI-Projekte in ihrer Logik zwingend angepasst werden müssen, um eine korrekte Funktionsweise auch in Zukunft zu gewährleisten. Dann glaube ich aber nicht, dass eine einfache Style-Änderung eines Buttons die Lösung darstellt, und die Runtime-Warnung entsprechend öfter getriggert werden muss. Ja, durch die Style-Änderung wird die Animation des Buttons in dem gezeigten Kontext zwar deaktiviert, aber nicht immer sind solche Animationen in Views ersichtlich und lassen sich daher kaum bei der Implementierung von beispielsweise Button-Actions berücksichtigen (da müsste eigentlich die Button-View selbst aktiv werden und die Action korrekt steuern, damit sie nicht mit einer Animation korreliert). So oder so wäre es in diesem Fall schön, von Apple höchstselbst zu erfahren, wie man zukünftig korrekt Aktualisierungen an Published-Properties in SwiftUI durchführt (und wie man mögliche Animationen von Standard-Views wie Button korrekt in der eigenen Logik umgeht).

Falls ihr aktuell also auch über diese Runtime-Warnung stolpert, dann … nun ja, kann ich euch leider auch nicht konkret sagen, was ihr tun solltet. Ich persönlich werde Stand heute einmal abwarten, wie sich diese Problematik mit den nächsten Xcode-Versionen verhält (zumindest so lange keine kritischen Probleme in den zugrundeliegenden Apps auftreten, doch das ist bisher bei mir nicht der Fall gewesen). Wer weiß, vielleicht erleuchtet uns Apple ja auch noch mit einem passenden Feedback zu dem Thema, sei es in den Xcode Release-Notes oder in den Apple Developer-Foren.

Es bleibt spannend.

Euer Thomas

Weiterführende Links zum Artikel


Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert