1

I'm trying to migrate to iOS 17 using @Observable.

I have a global view model of the app where I call an Exam model with all the values ​​I need inside.

According to Apple guidelines I'm using my view model like this

import Foundation
import Observation

struct Exam: {
    var title: String = ""
}


@Observable
final class Global {
    var exam = Exam()
}

import SwiftUI

@main
struct TestApp: App {
    @State private var model = Global()
    var body: some Scene {
        WindowGroup {
            InfoView()
                .environment(model)
                
        }
    }
}

Next I use my model within the InfoView like this

struct InfoView: View {
   // @Bindable private var model = Global()
    @Environment(Global.self) private var model

    var body: some View {
         VStack {
             TitledField(text: $model.exam.title, isMandatory: true, descriptionLabel: "", placeholder: "")
             .submitLabel(.continue)

          }
     }
}

As you can see in the first custom textField I use $model.exam.title but it doesn't seem to work because it gives me this error

Cannot find '$model' in scope

So I tried with @Bindable but the value that the user inserts in the textField is not read and always returns an empty string where am I going wrong? Has anyone started working on iOS 17?

HangarRash
  • 7,314
  • 5
  • 5
  • 32
kAiN
  • 2,559
  • 1
  • 26
  • 54

3 Answers3

1

The following example code with @Bindable works for me on iOS17. When the $model.exam.title is changed in the TextField, the UI is refreshed and displays the changed value.

import SwiftUI
import Observation

 @main
 struct TestApp: App {
     @State private var model = Global()
      var body: some Scene {
          WindowGroup {
              InfoView(model: model) // <-- here
          }
      }
 }
 
 struct InfoView: View {
     @Bindable var model: Global // <-- here
     var body: some View {
          VStack {
              TextField("", text: $model.exam.title).border(.red)
                  .submitLabel(.continue)
              
              Text(model.exam.title) // <-- for testing
           }
      }
 }

struct Exam {
    var title: String = "exam-title"
}

@Observable
final class Global {
    var exam = Exam()
}
0

If you are using @Environment you need to convert to @Bindable, e.g.

@Bindable var exam = model.exam
TitledField(text: $exam.title, isMandatory: true, descriptionLabel: "", placeholder: "") 

@Bindable isn't a DynamicProperty so it can be used inside body like any other struct.

malhal
  • 26,330
  • 7
  • 115
  • 133