Passing Variables between Views SwiftUI
Create & pass in an environment object at the root view of your app, or where any 'children' views may need access to anytext
. Store anytext
as a @Published
property in that ObservedObject
.
That's a pointer, but there will be lots of similar questions and stuff. Here is a HWS article which may help.
Here is an example:
class MyModel: ObservableObject {
@Published var anytext = ""
}
struct ContentView: View {
@StateObject private var model = MyModel()
var body: some View {
Entry().environmentObject(model)
}
}
struct Entry: View {
@EnvironmentObject private var model: MyModel
var body: some View {
VStack {
TextField("Enter text here", text: $model.anytext)
.padding()
.border(Color.black, width: 1)
.padding()
TextDisplayer()
}
}
}
struct TextDisplayer: View {
@EnvironmentObject private var model: MyModel
var body: some View {
Text(model.anytext)
}
}
Result:
All three views have model
which they can access, to get the anytext
property.
To answer your questions:
You use
@Published
becauseString
,Float
,Double
etc are all value types.Using environment objects, as shown here.
They are not persisted, see
@AppStorage
for saving that.
SwiftUI - pass data to different views
You should use @EnvironmentObject
. It allows an object to be shared, which is very important for sharing data to other views.
I am using a Shopping
object in this example. This app will act like a shopping list. This whole project is available of GitHub here.
I really hope this is useful, as it took quite a while. This is just a general example of how to use @EnvironmentObject
effectively between View
s.
The app looks like this:
Creating the project
(can be downloaded through GitHub, see above link)
1: First, in your SceneDelegate.swift
, replace:
let contentView = ContentView()
with:
let contentView = ContentView().environmentObject(Shopping())
2: Xcode will be complaining for now about Shopping
not being made yet, so we will fix that next:
class Shopping: ObservableObject {
@Published var list = [
ShoppingItem("Bread", quantity: 1),
ShoppingItem("Milk", quantity: 2),
ShoppingItem("Eggs", quantity: 12)
]
func addItem(_ item: ShoppingItem) {
list.append(item)
}
}
class ShoppingItem: Identifiable {
var name: String
var quantity: Int
init(_ name: String, quantity: Int) {
self.name = name
self.quantity = quantity
}
}
3: Next, we want the main content, ContentView
:
struct ContentView: View {
@EnvironmentObject private var shopping: Shopping
@State private var newItem: String?
var body: some View {
NavigationView {
List {
ForEach(shopping.list) { item in
NavigationLink.init(destination: EditView(currentItem: item)) {
HStack {
Text(item.name)
Spacer()
Text(String(item.quantity))
Spacer().frame(width: 10)
}
}
}
if newItem != nil {
TextField("New Item", text: $newItem.bound, onCommit: {
if !self.newItem!.isEmpty {
self.shopping.addItem(ShoppingItem(self.newItem!, quantity: 1))
}
self.newItem = nil
})
}
}
.navigationBarTitle("Shopping List")
.navigationBarItems(trailing: Button(action: {
self.newItem = ""
}, label: {
Image(systemName: "plus.circle.fill")
.resizable()
.frame(width: 25, height: 25)
}))
}
}
}
4: Along with this extension
to let optional @State
s work (credit here, although this has been simplified):
extension Optional where Wrapped == String {
var bound: String {
get {
return self ?? ""
}
set {
self = newValue
}
}
}
5: And then finally - the EditView
, to allow you to edit the name of the item in the shopping list:
struct EditView: View {
let currentItem: ShoppingItem
@EnvironmentObject private var shopping: Shopping
@State private var name = ""
var body: some View {
TextField("Item", text: $name, onCommit: saveName)
.padding()
.background(Color.gray)
.onAppear(perform: setName)
}
private func saveName() {
shopping.objectWillChange.send()
currentItem.name = name
}
private func setName() {
name = currentItem.name
}
}
How to pass data between SwiftUI views using NavigationLink
remove the second navigation view
struct SecondView: View {
var message: String
var body: some View {
VStack(spacing: 100 ) {
Text("\(message)")
NavigationLink(destination: ThirdView(message: self.message)) {
Text("Go to Third View")
}
}
}
}
struct ThirdView: View {
var message: String
var body: some View {
Text("\(message)")
}
}
SwiftUI Question passing a variable to another view
This is easily done with Bindings. Because mhzValue
is marked with the @State
property wrapper, it has an associated Binding. You can therefore declare a @Binding
variable in your second view, and initialize it with the Binding to the original variable.
struct NextView : View {
@Binding var mhzValue: Float
...
}
When you specify NextView
as the destination for your navigation button, pass it a Binding to mhzValue
. (The dollar-sign syntax is a shorthand way to refer to the binding.)
struct ContentView : View {
@State private var mhzValue : Float = 0
...
NavigationButton(destination: NextView(mhzValue: self.$mhzValue)){...}
...
}
You can then use mhzValue
inside NextView
:
struct NextView : View {
@Binding var mhzValue: Float
var body: some View {
VStack{
Text("Display Slider Value Here:")
Text("\(Int(mhzValue)) Value")
.font(.title)
.fontWeight(.semibold)
.color(.blue)
}
}
}
Any changes you make to mhzValue
within NextView
will effectively be changes to ContentView.mhzValue
.
SwiftUI: How to pass a data from one view and use it in the viewModel of another view
Use init
and StateObject(wrappedValue:)
. Here is the possible solution.
Your view model
final class SubViewModel: ObservableObject {
@Published var phone = ""
init(phone: String) {
self.phone = phone
}
}
Your subview
struct SubView: View {
@StateObject private var viewModel: SubViewModel
private let phone: String
init(phone: String) {
self.phone = phone
_viewModel = StateObject(wrappedValue: SubViewModel(phone: phone))
}
var body: some View {
ZStack {
Color.background
VStack {
Spacer()
// textfield default text should be the phone number passed from main view
TextField("type here...", text: $viewModel.phone)
Spacer()
}
}
}
}
Related Topics
Swift: Hashable Struct with Dictionary Property
Xcode Error - Undefined Symbols for Architecture X86_64
How to Replace Limited Number of Occurrences in String
How to Subclass a Class Which Doesn't Have Any Designated Initializers
Xcode UI Test:Accessibility Query Fail on Uitableviewcell
Anyobject Try Cast to Equatable
Drawing a Gradient Color in an Arc with a Rounded Edge
How to Create a Nsmutabledictionary in Swift
Callback Url Not Approved Despite Being Provided Twitter API
Xcode Takes Long Time to Print Debug Results
How to Add Custom Init for String Extension
Swift Protocol Defining Class Method Returning Self
How to Convert Tuple to Anyobject in Swift
Alamofire with Custom Parameter Encoding for Swift Application