Cannot find ... in scope - swift

I want the string in text field take the values of name of Player [0]. I try this and I have this error "Cannot find '$PlayerList' in scope".
import SwiftUI
class PlayerList : ObservableObject {
#Published var Players = [
Player(name: ""),
Player(name: ""),
]
init() {
}
}
struct Player : Identifiable {
var name : String
var id = UUID()
}
struct ViewJouer: View {
#StateObject var viewModel: PlayerList = PlayerList()
var body: some View {
VStack {
TextField("Player 1", text: $PlayerList.Players[0].name)
}
}
}
struct ViewJouer_Previews: PreviewProvider {
static var previews: some View {
ViewJouer()
}
}

You don't have the PlayerList variable in the view, you called it viewModel.
Moreover, please use the Swift notation: variables start with lowercase letters.
Here's the corrected code:
import SwiftUI
class PlayerList : ObservableObject {
// Variables start with lowercase letter
#Published var players = [
Player(name: ""),
Player(name: ""),
]
}
struct Player : Identifiable {
var name : String
// If you don't change the id, make it a constant
let id = UUID()
}
struct ViewJouer: View {
// Better make your local variables private
#StateObject private var viewModel = PlayerList()
var body: some View {
// The player list is part of the view model
VStack {
TextField("Player 1", text: $viewModel.players[0].name)
}
}
}
struct ViewJouer_Previews: PreviewProvider {
static var previews: some View {
ViewJouer()
}
}

Related

How to observer a property in swift ui

How to observe property value in SwiftUI.
I know some basic publisher and observer patterns. But here is a scenario i am not able to implement.
class ScanedDevice: NSObject, Identifiable {
//some variables
var currentStatusText: String = "Pending"
}
here CurrentStatusText is changed by some other callback method that update the status.
Here there is Model class i am using
class SampleModel: ObservableObject{
#Published var devicesToUpdated : [ScanedDevice] = []
}
swiftui component:
struct ReviewView: View {
#ObservedObject var model: SampleModel
var body: some View {
ForEach(model.devicesToUpdated){ device in
Text(device.currentStatusText)
}
}
}
Here in UI I want to see the real-time status
I tried using publisher inside ScanDevice class but sure can to use it in 2 layer
You can observe your class ScanedDevice, however you need to manually use a objectWillChange.send(),
to action the observable change, as shown in this example code.
class ScanedDevice: NSObject, Identifiable {
var name: String = "some name"
var currentStatusText: String = "Pending"
init(name: String) {
self.name = name
}
}
class SampleViewModel: ObservableObject{
#Published var devicesToUpdated: [ScanedDevice] = []
}
struct ReviewView: View {
#ObservedObject var viewmodel: SampleViewModel
var body: some View {
VStack (spacing: 33) {
ForEach(viewmodel.devicesToUpdated){ device in
HStack {
Text(device.name)
Text(device.currentStatusText).foregroundColor(.red)
}
Button("Change \(device.name)") {
viewmodel.objectWillChange.send() // <--- here
device.currentStatusText = UUID().uuidString
}.buttonStyle(.bordered)
}
}
}
}
struct ContentView: View {
#StateObject var viewmodel = SampleViewModel()
var body: some View {
ReviewView(viewmodel: viewmodel)
.onAppear {
viewmodel.devicesToUpdated = [ScanedDevice(name: "device-1"), ScanedDevice(name: "device-2")]
}
}
}

Add a button to refresh a element in a list

I have a list of questions and when the app is launched one randomly pops up. Now I want when a button is clicked it shows another random question in the list. Any ideas?
This is my view
import SwiftUI
struct ViewJouer2: View {
#EnvironmentObject var data : DefisList
var body: some View {
List {
if let randomDefi = data.defis.randomElement() {
DefiRow(Defi: randomDefi)
}
}
}
}
struct ViewJouer2_Previews: PreviewProvider {
static var previews: some View {
ViewJouer2()
.environmentObject(DefisList())
}
}
This is my Data
import SwiftUI
class DefisList : ObservableObject {
#Published var defis = [
Defi(question: "How old are you?"),
Defi(question: "How are you"),
Defi(question: "What is your name?"),
]
}
struct Defi : Identifiable {
var question : String
var id = UUID()
}
Make randomDefi a #Published variable of your ObservedObject. Add a method called randomize() to choose a random one and call that from your button.
import SwiftUI
struct ViewJouer2: View {
#EnvironmentObject var data : DefisList
var body: some View {
List {
DefiRow(defi: data.randomDefi)
}
Button("random") {
data.randomize()
}
}
}
class DefisList : ObservableObject {
#Published var randomDefi = Defi(question: "")
private var defis = [
Defi(question: "How old are you?"),
Defi(question: "How are you?"),
Defi(question: "What is your name?"),
]
init() {
randomize()
}
func randomize() {
randomDefi = defis.randomElement()!
}
}
struct Defi : Identifiable {
var question : String
var id = UUID()
}
struct DefiRow: View {
let defi: Defi
var body: some View {
Text(defi.question)
}
}

SwiftUI: Model doesn't work with the TextField view

I have this simple code for my model:
import Foundation
class TaskListModel: ObservableObject
{
struct TodoItem: Identifiable
{
var id = UUID()
var title: String = ""
}
#Published var items: [TodoItem]?
//MARK: - intents
func addToList()
{
self.items!.append(TodoItem())
}
}
Then I use it in this view:
import SwiftUI
struct TasksListView: View {
#ObservedObject var model = TaskListModel()
var body: some View {
List {
Button("Add list", action: {
model.addToList()
})
ForEach(model.items!) { item in
TextField("Title", text: item.title)
}
.onMove { indexSet, offset in
model.items!.move(fromOffsets: indexSet, toOffset: offset)
}
.onDelete { indexSet in
model.items!.remove(atOffsets: indexSet)
}
}
}
}
struct TasksListView_Previews: PreviewProvider {
static var previews: some View {
TasksListView()
}
}
I can't seem to make this code work, I suspect the items array needs to be wrapped in #Binding property wrapper, but it already wrapped in #Published, so it puzzles me even more. Any help would be appreciated!
You have forgotten to create array for items
class TaskListModel: ObservableObject
{
struct TodoItem: Identifiable
{
var id = UUID()
var title: String = ""
}
#Published var items: [TodoItem] = [] // << here !!
// ...
}
and remove everywhere force-unwrap (!!)

SwiftUI Sharing model data between views

I have such a structure, this structure seems wrong to me as the approach I want to ask you. So when I want to use 2 models in 1 view, I have to put it in foreach in one view. This is what I want. Using the data I use in my user's profile on other pages I want. How should I do this? How do you guys do it?
Let me give an example for your better understanding:
I want to show my user's Username data on the Homepage, how should I do this?. In fact, after initializing my model once, I want to use it in other views. What is the right approach.
import SwiftUI
struct ContentView: View {
#StateObject var network = ProfileNetwork()
var body: some View {
TabView{
ProfileView().tabItem { Image(systemName: "house") }
ForEach(self.network.userprofile,id:\.id){a in
ShopView(profile_model: a)
}.tabItem { Image(systemName: "house") }
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
class ProfileNetwork : ObservableObject {
#Published var userprofile : [UserPRofile] = [UserPRofile(name: "Test", coin: 1, id: "dsa")]
}
struct ProfileView : View {
#StateObject var network = ProfileNetwork()
var body: some View {
ForEach(self.network.userprofile, id:\.id){ i in
ProfileViewModel(profile_model: i)
}
}
}
struct ProfileViewModel : View {
var profile_model : UserPRofile
var body: some View {
Text(self.profile_model.name)
}
}
struct UserPRofile : Decodable{
var name : String
var coin : Int
var id : String
}
class ShopeNetwork : ObservableObject {
#Published var shop : [ShopStore] = [ShopStore(id: "sda", image: "dasd", price: 100, name: "sda")]
}
struct ShopView : View {
#StateObject var network = ShopeNetwork()
var profile_model : UserPRofile
var body: some View {
ForEach(self.network.shop, id:\.id){ c in
ShopViewModel(shop_model: c, profile_model: profile_model)
}
}
}
struct ShopViewModel : View {
var shop_model : ShopStore
var profile_model : UserPRofile
var body: some View {
Text(profile_model.name)
Text(self.shop_model.name)
}
}
struct ShopStore : Decodable {
var id : String
var image : String
var price : Int
var name : String
}
A possible solution is to create an #EnvironmentObject and inject it at the root level:
class AppState: ObservableObject {
#Published var userProfile: UserPRofile?
}
#main
struct TestApp: App {
#StateObject private var appState = AppState()
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(appState)
}
}
}
struct ProfileView: View {
#EnvironmentObject private var appState: AppState // access as an `#EnvironmentObject`
#StateObject var network = ProfileNetwork()
var body: some View {
VStack {
ForEach(self.network.userprofile, id: \.id) { i in
ProfileViewModel(profile_model: i)
}
}
.onAppear {
appState.userProfile = network.userprofile.first // set `userProfile` globally
}
}
}
struct ShopView: View {
#EnvironmentObject private var appState: AppState // use it in any other view
...
Swift 5, iOS 14
Make the class a singleton so it becomes shareable easily.
class ProfileNetwork : ObservableObject {
#Published var userprofile : [UserPRofile] = [UserPRofile(name: "Test", coin: 1, id: "dsa")]
static var shared = ProfileNetwork()
}
And then refer to it with the shared handle.
struct ContentView: View {
#StateObject var network = ProfileNetwork.shared
var body: some View {
....
}
struct ProfileView : View {
#StateObject var network = ProfileNetwork.shared
var body: some View {
....
}

How to pass binding to subview with SwiftUI when the variable is nested in an object?

This works
import SwiftUI
struct ContentView : View {
#State var val1: Int = 0
var body: some View {
MySubview(val1: $val1)
}
}
#if DEBUG
struct ContentView_Previews : PreviewProvider {
static var previews: some View {
ContentView(val1: 0)
}
}
#endif
struct MySubview : View {
#Binding var val1: Int
var body: some View {
return Text("Value = \(val1)")
}
}
But when the variable is nested in an Object, this fails
import SwiftUI
struct MyStruct {
let number: Int
}
struct ContentView : View {
#State var val1 = MyStruct(number: 7)
var body: some View {
MySubview(val1: $val1.number)
}
}
#if DEBUG
struct ContentView_Previews : PreviewProvider {
static var previews: some View {
ContentView(val1: 0)
}
}
#endif
struct MySubview : View {
#Binding var val1: Int
var body: some View {
return Text("Value = \(val1)")
}
}
Error shown: Generic parameter 'Subject' could not be inferred
How do i pass nested variable as a binding to a subview?
The error is very misleading. Number must be a var, not a let:
struct MyStruct {
var number: Int
}
Change it and it will work fine.
Your code was good except for needing var number: Int as kontiki pointed out.
To help with understanding of passing bindings about between views I prepared the following code which shows use of #Binding in slightly different ways:
import SwiftUI
struct Zoo { var shed: Shed }
struct Shed { var animals: [Animal] }
struct Animal { var legs: Int }
struct ZooView : View {
#State var zoo = Zoo( shed: Shed(animals:
[ Animal(legs: 2), Animal(legs: 4) ] ) )
var body: some View {
VStack {
Text("Legs in the zoo directly:")
Text("Animal 1 Legs: \(zoo.shed.animals[0].legs)")
Text("Animal 2 Legs: \(zoo.shed.animals[1].legs)")
Divider()
Text("And now with nested views:")
ShedView(shed: $zoo.shed)
}
}
}
struct ShedView : View {
#Binding var shed: Shed
var body: some View {
ForEach(shed.animals.indices) { index in
VStack {
Text("Animal: \(index+1)")
AnimalView(animal: self.$shed.animals[index])
}
}
}
}
struct AnimalView : View {
#Binding var animal: Animal
var body: some View {
VStack {
Text("Legs = \(animal.legs)")
Button(
action: { self.animal.legs += 1 }) {
Text("Another leg")
}
}
}
}
In particular ShedView is given a binding to a shed and it looks up an animal in the array of animals in the shed and passes a binding to the animal on to AnimalView.