Fast app prototyping with SwiftUI & ChatGPT
Everything that follows from this point forward is my input prompts, followed by ChatCGP’s responses, complete with sample code in Swift.
Hey ChatGPT, can you make a SwiftUI registration form with name, address and city fields?
import SwiftUI
struct RegistrationForm: View {
@State private var name: String = ""
@State private var address: String = ""
@State private var city: String = ""
var body: some View {
Form {
TextField("Name", text: $name)
TextField("Address", text: $address)
TextField("City", text: $city)
}
}
}
The RegistrationForm
struct conforms to the View
protocol and defines a body
property that returns a Form
view. The Form
view contains TextField
views for each of the form fields, and the @State
property wrapper is used to manage the state of each field.
Can you move the fields to a view model?
Move the form fields to a separate view model in order to better manage the state and logic of the form.
import SwiftUI
struct RegistrationForm: View {
@ObservedObject var viewModel: RegistrationFormViewModel
var body: some View {
Form {
TextField("Name", text: $viewModel.name)
TextField("Address", text: $viewModel.address)
TextField("City", text: $viewModel.city)
}
}
}
class RegistrationFormViewModel: ObservableObject {
@Published var name: String = ""
@Published var address: String = ""
@Published var city: String = ""
}
The RegistrationForm
struct has an @ObservedObject
property that references an instance of the RegistrationFormViewModel
class. This allows the RegistrationForm
view to bind to the properties of the view model using the $
prefix, just as it did with the @State
properties in the previous example.
The RegistrationFormViewModel
class defines @Published
properties for each of the form fields, which allows the view to be notified when the values of these properties change. This allows the view to update automatically when the user changes the form fields.
This approach helps to keep the view logic and state management separate from the view itself, making the code easier to understand and maintain.
What if I need to validate that none of the fields are empty?
If you need to validate that none of the fields in the form are empty, you can add a method to the RegistrationFormViewModel
class that checks the values of the form fields and returns a Bool
indicating whether the form is valid or not.
class RegistrationFormViewModel: ObservableObject {
@Published var name: String = ""
@Published var address: String = ""
@Published var city: String = ""
var isValid: Bool {
return !name.isEmpty && !address.isEmpty && !city.isEmpty
}
}
The isValid
property uses the isEmpty
property of each of the form fields to determine whether the form is valid or not. If all of the fields are not empty, the isValid
property will return true
, otherwise it will return false
.
You can then use this property in the view to enable or disable a submit button or to display an error message if the form is not valid.
struct RegistrationForm: View {
@ObservedObject var viewModel: RegistrationFormViewModel
var body: some View {
Form {
TextField("Name", text: $viewModel.name)
TextField("Address", text: $viewModel.address)
TextField("City", text: $viewModel.city)
if !viewModel.isValid {
Text("All fields are required")
.foregroundColor(.red)
}
}
}
}
The RegistrationForm
view checks the value of the isValid
property and, if the form is not valid, it displays an error message using a Text
view. This allows the user to know which fields need to be filled out in order to make the form valid.
Can we add a Save button to that form?
Add a Save button to the form by using a Button
view in the RegistrationForm
struct.
struct RegistrationForm: View {
@ObservedObject var viewModel: RegistrationFormViewModel
var body: some View {
Form {
TextField("Name", text: $viewModel.name)
TextField("Address", text: $viewModel.address)
TextField("City", text: $viewModel.city)
if !viewModel.isValid {
Text("All fields are required")
.foregroundColor(.red)
}
Button(action: {
// Save the form data here
}) {
Text("Save")
}
.disabled(!viewModel.isValid)
}
}
}
The RegistrationForm
view includes a Button
view with an action closure that is called when the button is tapped. This closure can be used to save the form data to a database or other storage location.
The Button
view also has a disabled
modifier that disables the button if the isValid
property of the RegistrationFormViewModel
is false
. This ensures that the form must be filled out correctly before the user can save the data.
Can you create a User struct based on the form information?
A User
struct that could be used to represent the data from the form:
struct User {
var name: String
var address: String
var city: String
}
This User struct defines properties for each of the form fields, such as name
, address
and city
. These properties can be used to store the values entered by the user in the form.
Create an instance of the User
struct using the values from the form:
let user = User(
name: viewModel.name,
address: viewModel.address,
city: viewModel.city
)
The user
constant is initialized with the values from the RegistrationFormViewModel
instance. You can then use this User
instance to save the data to a database or other storage location, or to pass the data to another part of your app for further processing.
And how do I populate the fields on the view model from the struct?
class RegistrationFormViewModel: ObservableObject {
@Published var name: String = ""
@Published var address: String = ""
@Published var city: String = ""
var isValid: Bool {
return !name.isEmpty && !address.isEmpty && !city.isEmpty
}
func populate(with user: User) {
name = user.name
address = user.address
city = user.city
}
}
Use this method to populate the form fields:
let user = User(
name: "Oliver Doe",
address: "100 Main St",
city: "Anytown"
)
viewModel.populate(with: user)
The user
constant is initialized with some sample data, and then the populate(with:)
method is called on the viewModel
instance, passing in the user
instance as a parameter. This will set the values of the view model's properties to match the values of the User
instance, which will in turn populate the form fields with the data from the User
instance.