skip to Main Content

When I update the isDisabled state variable in my view, it updates the .disabled modifier of my text field as expected, but it then causes about 40 instances of the following error to appear in the console (with varying attribute numbers at the end):
=== AttributeGraph: cycle detected through attribute 200472 ===

And then it says: AttributeGraphError[59460:4808136] [SwiftUI] Modifying state during view update, this will cause undefined behavior.

Here is a minimal version of the code producing the error:

struct ContentView: View {
  @State var isDisabled = false
  @State var text = ""
  
  var body: some View {
    VStack {
      TextField("", text: $text)
        .textFieldStyle(.roundedBorder)
        .disabled(isDisabled)

      Button("Disable text field") { isDisabled = true }
    }
  }
}

How do I fix this error?

2

Answers


  1. Chosen as BEST ANSWER

    After a couple hours of painful debugging, I figured out the solution!

    It turns out the problem was that you can't disable the text field while the user is still editing the field. Instead, you must first resign the text field (i.e. close the keyboard), and then disable the text field.

    Here's my updated code:

    struct ContentView: View {
      @State var isDisabled = false
      @State var text = ""
      
      var body: some View {
        VStack {
          TextField("", text: $text)
            .textFieldStyle(.roundedBorder)
            .disabled(isDisabled)
    
          Button("Disable text field") {
            closeKeyboard()
            isDisabled = true
          }
        }
      }
    
      func closeKeyboard() {
        UIApplication.shared.sendAction(
          #selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil
        )
      }
    }
    

  2. Here is an iOS 15+ solution.

    struct ContentView: View {
        
        enum Field: Hashable {
            case text
        }
        @FocusState private var focusedField: Field?   // available iOS 15+
        
        @State var isDisabled = false
        @State var text = ""
        
        var body: some View {
            VStack {
                TextField("", text: $text)
                    .focused($focusedField, equals: .text)
                    .textFieldStyle(.roundedBorder)
                    .disabled(isDisabled)
                
                Button("Disable text field") {
                    focusedField = nil
                    isDisabled = true
                }
            }
        }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search