Hey there! I would like to tell you about a framework for building user interfaces on iOS and macOS. It is very convenient to use because it employs a declarative approach to programming. With SwiftUI, you can describe what your interface should do and look like, and the framework will take care of the rest. SwiftUI, One of the key elements of SwiftUI is the use of property wrappers. These are functional elements that allow you to provide additional logic for properties. SwiftUI has five main property wrappers: @State @Binding @ObservedObject @StateObject @EnvironmentObject They will become your best friends in development. @State allows you to create properties that can be changed and, if necessary, update the interface based on these changes. For example, if you want to create a button that changes its color when pressed, you can create a @State variable to store the color and add it to the button: @State struct MyButton: View { @State var buttonColor = Color.blue var body: some View { Button("Press me!") { buttonColor = Color.red } .background(buttonColor) } } @Binding allows you to use a value that It is typically used in SwiftUI to pass a value from one view to another, allowing them to interact with each other. For example, imagine we have two views - one with a text field and the other with a button. We want the text field to update when the user presses the button. To do this, we can use @Binding: @Binding is stored in one part of the code in another part of the code. struct ContentView: View { @State private var text = "" var body: some View { VStack { TextField("Enter text", text: $text) Button("Update text") { text = "New text" } SecondView(text: $text) } } } struct SecondView: View { @Binding var text: String var body: some View { Text(text) } } In this example, is used to pass the value from (which is in ) to (which is in ), so when the user presses the button, the text field will update and display the new text. @Binding $text ContentView text SecondView @ObservedObject is used to mark properties that are This property wrapper subscribes to changes in the object that conforms to the and automatically updates the relevant parts of the interface if the data has changed. Here's a brief example of using : @ObservedObject observed and can change depending on external data changes. ObservableObject protocol @ObservedObject class UserData: ObservableObject { @Published var name = "John" } struct ContentView: View { @ObservedObject var userData = UserData() var body: some View { VStack { Text("Hello, \(userData.name)!") TextField("Enter your name", text: $userData.name) } } } In this example, we create a class called UserData, which contains a @Published name. In the ContentView structure, we create a property called userData with the type UserData, We display the value of userData.name in a text field and output it on the screen. using @ObservedObject. When the user changes the value in the SwiftUI automatically updates the corresponding part of the interface, as the property is published and observed using This means we don't need our own code to update the interface, and we allow SwiftUI to do it for us. text field, name @Published. If you don't know, @Published is a property wrapper from the Combine framework that can be added to a class or structure property, which automatically sends notifications of any changes to the value of that property to anyone who has subscribed to it. In other words, it's a helper attribute for properties that can be tracked for changes. Note: @StateObject is a property wrapper used This means that the object is stored as long as the view exists and is destroyed along with it. Typically, using is more practical for class objects that are needed for views, not just For example: @StateObject to initialize a class object and store it in the view state in SwiftUI. @StateObject multiple one. class UserData: ObservableObject { @Published var name = "John" @Published var age = 30 } struct ContentView: View { @StateObject var userData = UserData() var body: some View { NavigationView { VStack { Text("Name: \(userData.name)") Text("Age: \(userData.age)") NavigationLink( destination: ProfileView(userData: userData), label: { Text("Edit Profile") }) } .navigationTitle("Home") } } } struct ProfileView: View { @ObservedObject var userData: UserData var body: some View { Form { TextField("Name", text: $userData.name) Stepper("Age: \(userData.age)", value: $userData.age) } .navigationTitle("Profile") } } In this example, is an object of a class that contains several properties that can be used in multiple views. The class is marked as so it can be used with and . UserData ObservableObject @StateObject @ObservedObject In we create a new object using to save state between transitions between different views. In this case, displays user data, visualizes it, and contains a link to another view that can be used to edit the user data. ContentView, UserData @StateObject ContentView (ProfileView) In , we get access to the same object using to modify user data. When the user changes data, it is automatically updated in because the same object is used. ProfileView UserData @ObservedObject ContentView UserData Use @ObservedObject if you need to observe changes in a class object from one view and @StateObject if you need to save the state of a class object that affects the display of multiple views. Note: If you use @ObservedObject instead of @StateObject for an object needed in multiple views, each view will have its own instance of the object, which can lead to problems with data synchronization between views. Therefore, in this case, it is better to use @StateObject. @EnvironmentObject is a property wrapper for p It allows access to the data object from any view in the SwiftUI hierarchy that belongs to the Environment container (e.g., Scene, View, App, etc.). For example, imagine we have a task list management app. We can have a root that contains a list of tasks and the ability to create new tasks. For this, we create a separate view that displays the list of tasks and a button to add new tasks. After adding a new task, the user should be redirected to the add task screen, so we create a separate view. @EnvironmentObject assing data objects through the SwiftUI view hierarchy. ContentView TaskListView AddTaskView To pass the object to all three views, we can create its instance in , and then pass it as a parameter to both and . However, this can become a problem if we decide to add even more nested views, as we will need to pass through many intermediate views. UserManager ContentView TaskListView AddTaskView UserManager Instead of this, we can use to pass down through the view hierarchy. This way, all views that need access to can simply declare it as an and use it as needed. @EnvironmentObject UserManager UserManager @EnvironmentObject struct TaskManagerApp: App { @StateObject var userManager = UserManager() var body: some Scene { WindowGroup { ContentView() .environmentObject(userManager) } } } struct ContentView: View { var body: some View { NavigationView { TaskListView() } } } struct TaskListView: View { @EnvironmentObject var userManager: UserManager var body: some View { List(userManager.tasks) { task in TaskRow(task: task) } .navigationBarTitle("Tasks") .navigationBarItems(trailing: Button(action: { // Navigate to AddTaskView }) { Image(systemName: "plus") } ) } } struct AddTaskView: View { @EnvironmentObject var userManager: UserManager var body: some View { // Add new task using userManager } } So, now the object will be automatically passed to and via . Note that we can modify the state of in one view, and the changes will automatically be reflected in the other view. UserManager TaskListView AddTaskView @EnvironmentObject UserManager The article covered the basic SwiftUI property wrappers: @State, @Binding, @ObservedObject, @StateObject, @EnvironmentObject. These property wrappers form the foundation of working with app state in SwiftUI. Use this article as a cheat sheet to have the basic property wrappers at your fingertips, necessary for developing apps with SwiftUI. By applying this knowledge, you will be able to build more complex user interfaces with dynamically changing states and integrate data from your models into SwiftUI.