-3

Modified to answer concerns appearing in comments.

Have the following code:

import SwiftUI
import SwiftData

@main
struct Fu: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        //.modelContainer(for: Bar.self)
    }
}

@Model
class Bar{
    var a: String
    var b: String

    init(a: String = "", b: String = "") {
        self.a = a
        self.b = b
    }
}

struct ContentView: View {
    //@Environment(\.modelContext) var modelContext
    //@Query var fu: Bar
    var fu = Bar()
    var body: some View {
        NavigationStack {
            if (fu.a.isEmpty) {
                NavigationLink("Lucy! I'm home.") {
                    StartScreen()
                }
            } else {
                Text("whatever")
            }
        }
    }
}
 
struct StartScreen: View {
    var body: some View {
        Text("Hello, World!")
    }
}

The above compiles and runs. In "ContentView," uncomment the '@Query...' and comment 'var fu = ....' on the next line. The editor shows no error. Now click 'run.' The build fails, but no indicataion in the editor. The issues frame shows 'Element is not a member type of class 'example.Bar' - click on the message and the 'private(set)' line appears beneath the @Query.

7
  • Well a @Query gives you an array containing all the Bars in the model container. Which one do you want to be edited by the text field? Commented Jul 3 at 1:33
  • What exactly are you trying to achieve here? And what is the point of the line private(set) var _fu: SwiftData.Query<Bar.Element, Bar> = .init(). If you have no idea what that line means, why is it there? Commented Jul 3 at 3:48
  • I'm NOT putting it there. It shows up during the build and is not removable. I'm just trying access the persistent data across multiple views. I actually only want one Bar. Commented Jul 3 at 3:53
  • @Cuse70 What do you mean it "shows up". If you remove the line, it just reappears? Commented Jul 3 at 3:57
  • exactly as stated. The error pops on in the "issues" but no indication in the editor of a problem. .Click on the error and that line appears beneath the Query statement Commented Jul 3 at 4:00

1 Answer 1

2

With the code as provided, your XCode should light up like a Xmas tree even before building.

Firstly, a @Query returns all instances of the respective model type, so it forcibly needs to be an array - it cannot just return "one Bar", without the proper filtering syntax.

@Query private var bars: [BarModel] // <- needs to be an array type (and private)

Consequently, if bars is an array, something like bars.a.isEmpty makes no sense, because bars is not an instance of a BarModel.

Secondly, a TextField requires a Binding for its text parameter and @Query does not give you any binding. So the error makes sense, because the approach is simply wrong.

Anyway, here's some working code, to show a basic example of how to use @Query, display views conditionally and insert objects into model context:

import SwiftUI
import SwiftData

@Model
class BarModel {
    var a: String
    var b: String
    
    init(a: String = "", b: String = "") {
        self.a = a
        self.b = b
    }
}

struct FooContentView: View {
    
    //Queries
    @Query private var bars: [BarModel]
    
    //Body
    var body: some View {
        
        VStack {
            
            AddBarView()
            
            if bars.isEmpty {
                EmptyBarsView()
            }
            else {
                ForEach(bars) { bar in
                    Text(bar.a)
                }
            }
        }
        .padding()
    }
}

struct EmptyBarsView: View {
    
    //Body
    var body: some View {
        
        VStack {
            Text("There are no bars to show.")
        }
    }
}

struct AddBarView: View {
    
    //Environment
    @Environment(\.modelContext) private var modelContext

    //State values
    @State private var barName: String = ""
    
    //Body
    var body: some View {
        
            TextField("Add a bar...", text: $barName)
                .onSubmit {
                    let newBar = BarModel(a: barName)
                    modelContext.insert(newBar)
                    try? modelContext.save()
                    
                    //Reset input field
                    barName = ""
                }
                .textFieldStyle(.roundedBorder)
    }
}

#Preview {
    FooContentView()
        .modelContainer(for: BarModel.self, inMemory: true)
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks. I'll play with it. Used to Futter, and the design concepts are different. I'm assuming singletons are somehow supported. Seems like every example out there assumes arrays.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.