2

I use the new @FirestoreQuery property wrapper and it's working with the code below. But i need to use it/initialize it with variables, how can i do it (see below what I am trying to do)?

import SwiftUI
import FirebaseFirestoreSwift

struct TestFirestoreQuery: View {
    @State var itemLimit: Int = 5
    let increment: Int = 5
    
    @FirestoreQuery(collectionPath: "/discussions/blablabal/messages",
                    predicates: [
                        .order(by: "dateCreated", descending: true),
                        .limit(to: 5)
                    ]
    ) fileprivate var MessageResults: Result<[Message_M], Error>
    
    var body: some View {
        VStack {
            if case let .success(Messages) = MessageResults {
                List(Messages.reversed()) { message in
                    Text("\(message.msg)")
                }
                .refreshable{
                    itemLimit += increment
                    $MessageResults.predicates = [
                        .order(by: "dateCreated", descending: true),
                        .limit(to: itemLimit)
                    ]
                }
            }
            else if case let .failure(error) = MessageResults {
                // Handle error
                Text("Couldn't map data: \(error.localizedDescription)")
            }
            Button {
                itemLimit += increment
                $MessageResults.predicates = [
                    .order(by: "dateCreated", descending: true),
                    .limit(to: itemLimit)
                ]
            } label: {
                Text("Tap me!")
                    .padding()
                    .foregroundColor(.white)
                    .background(.red)
            }
        }
    }
}

what I want to do but it doesn't work :

...
    @State var itemLimit: Int = 5
    let increment: Int = 5
    let path: String = "/discussions/blablabal/messages"
    
    @FirestoreQuery(collectionPath: path,
                    predicates: [
                        .order(by: "dateCreated", descending: true),
                        .limit(to: itemLimit)
                    ]
    ) fileprivate var MessageResults: Result<[Message_M], Error>

...

I got these errors :

  • Cannot use instance member 'path' within property initializer; property initializers run before 'self' is available...

  • Cannot use instance member 'itemLimit' within property initializer; property initializers run before 'self' is available

Flincorp
  • 751
  • 9
  • 22
  • It seems you are having the similar issue mentioned in this [stackoverflow thread](https://stackoverflow.com/questions/68533137/cannot-use-instance-member-videoname-within-property-initializer-property-ini). Can you try out the answer mentioned in the [accepted answer](https://stackoverflow.com/a/68533583)? – Prabir Nov 15 '21 at 12:42
  • 1
    If you make the path variable a static constant on its encapsulating type, then you can use `TypeName.path` instead of `path` in the FirestoreQuery. – Noah Wilder Dec 08 '22 at 22:35

3 Answers3

2

Ok you can initialize them in the onAppear :

.onAppear {
           $MessageResults.path = path

           $MessageResults.predicates = [
                          .order(by: "dateCreated", descending: true),
                          .limit(to: itemLimit)
                          ]

}
Flincorp
  • 751
  • 9
  • 22
  • The GitHub repo contains a sample app that shows a typical example (changing the predicates): https://github.com/firebase/firebase-ios-sdk/blob/master/Example/FirestoreSample/FirestoreSample/Views/FavouriteFruitsView.swift#L56 – Peter Friese Apr 06 '23 at 10:55
0

At the point where the @FirestoreQuery is created the path variable isn't available yet.

Why do you need the path to be a separate variable? Wouldn't it be easier to directly pass the String into the @FirestoreQuery?

@FirestoreQuery(collectionPath: "/discussions/blablabal/messages",
                predicates: [
                    .order(by: "dateCreated", descending: true),
                    .limit(to: itemLimit)
                ]

This way you don't have to add an onAppear modifier.

Florian S
  • 552
  • 3
  • 15
0

onAppear has its problems, so you can use init instead:

  1. First declare the property which store the firebase query result:
     let messageResults: FirestoreQuery<Result<[Message_M], Error>>
  1. In your init:
init(path: String, itemLimit: Int, ...) {
     self.messageResults = .init(collectionPath: path, 
     predicates: [ .order(by: "dateCreated", descending: true), 
    .limit(to: itemLimit)])
}
  1. Now you can use your property like this:
    messageResult.wrappedValue