0
votes

I'm getting this error on the line let itemToAdd = snapshot.childSnapshot(forPath: "Shopa function that retrieves data from Firebase. the output of the console in Could not cast value of type 'NSNull' (0x1118c8de0) to 'NSString' (0x10dda45d8).. What I'm trying to do is to filter database ordering by one value opening Timeand than get another value Shop Namefrom the returned entries in the snapshot.

here's the function:

func filterOpenShops(enterDoStuff: @escaping (Bool) -> ()) {
    ref = Database.database().reference().child("Continent").child("Europe").child("Country").child("Italy").child("Region").child("Emilia-Romagna").child("City").child("Bologna").child("Shops").child("Shops Opening Times")
let query = ref?.queryOrdered(byChild: "Opening Time").queryStarting(atValue: openingTimeQueryStart).queryEnding(atValue: openingTimeQueryEnd)
query?.observe(.value, with: { (snapshot) in
    for childSnapshot in snapshot.children {
        // new modification
        if childSnapshot is DataSnapshot {
            let itemToAdd = snapshot.childSnapshot(forPath: "Shop Name").value as! String // gets the open shop from snapshot
        self.availableShopsArray.append(itemToAdd)
        print(snapshot.children)
         print(" Open Shops are \(self.availableShopsArray)")


        }
    }
    // still asynchronous part
    enterDoStuff(true)
    // call next cascade function filterClosedShops only when data
})

// Sychronous part

print("opening query start is \(openingTimeQueryStart) and opening query end is \(openingTimeQueryEnd)")


} // end of filterOpenShops()

EDIT:

I rewrote the function as:


    func filterOpenShops(enterDoStuff: @escaping (Bool) -> ()) {
        // get from Firebase snapshot all shops opening times into an array of tuples
        //shopOpeningTimeArray:[(storeName: String, weekdayNumber: String, opening1: Sring, closing1: String, opening2:String, closing2: String)]

        ref = Database.database().reference().child("Continent").child("Europe").child("Country").child("Italy").child("Region").child("Emilia-Romagna").child("City").child("Bologna").child("Shops").child("Shops Opening Times")
        let query = ref?.queryOrdered(byChild: "Opening Time").queryStarting(atValue: String(describing: openingTimeQueryStart)).queryEnding(atValue: String(describing :openingTimeQueryEnd))
        query?.observe(.value, with: { (snapshot) in // original is ok
//            guard let data = snapshot.value as? [String:String] else { return }



            for childSnapshot in snapshot.children {

                print("snapshot is: \(childSnapshot)")
                print("snapshot.childrend is: \(snapshot.children)")
                guard let data = snapshot.value as? [String:String] else { return }

                let itemToAdd = data["Shop Name"]
                self.availableShopsArray.append(itemToAdd!)
                print("Open Shop is: \(String(describing: itemToAdd))")
                print(" Open Shops are \(self.availableShopsArray)")



            }
            // still asynchronous part
            enterDoStuff(true)
            // call next cascade function filterClosedShops only when data
            print(" Open Shops are \(self.availableShopsArray)")
        })

        print("opening query start is \(openingTimeQueryStart) and opening query end is \(openingTimeQueryEnd)")


    } // end of filterOpenShops()

but I still get a null object and not a [String:String] as expected.

The function that created the entries in Firebase is:

    func postOpeningTime() {

//        if shopNameTextfield.text != nil && openingTimeTextfield.text != nil && closingTimeTextfield.text != nil {
            let shopName = shopNameTextfield.text!
            let openingTime = openingTimeTextfield.text!
            let closingTime = closingTimeTextfield.text!
//        } else {return}

        let post: [String:String] = [
            "Shop Name" : shopName ,
            "Opening Time" : openingTime ,
            "Closing Time" : closingTime
            ]
        var ref: DatabaseReference!
        ref = Database.database().reference()

        ref?.child("Continent").child("Europe").child("Country").child("Italy").child("Region").child("Emilia-Romagna").child("City").child("Bologna").child("Shops").child("Shops Opening Times").childByAutoId().setValue(post)

    }

Now I have two behaviours:

1st: When querying for entries and finds values that are Int: completion get called but I get no snapshot print. 2nd: When querying for entries and find values that are String: completion doesn't get called but snapshot prints the right entries with values.

Can anyone please spot what's going on here?

1
Your shop name is null somewhere. So instead of using 'as!' try using 'if let' - Sanman
I'm using values for the search that should give me results. how do I check what's in the snapshot I get? - Vincenzo
Try logging snapshot.children before running for loop. You might get to see values - Sanman
I printend childSnapshot and it has a result: `childSnapshot is: Snap (Arma Wed Mor) { "Closing Time" = 41230; "Opening Time" = 40830; "Shop Name" = Armaroli; }ยด so the query is finding the right data. I just want to get the shop name from it - Vincenzo
@sanman. Interestingly enough I repeated the search to a value that should return 2 shops but still I only get the same as before. can it be because I'm printing childSnapshotfrom inside the for in loop? I'll try and print snapshot.children instead before the loop - Vincenzo

1 Answers

0
votes

I found the problem to bee the way I was casting query result. Casting it as [String:String] produced to return because upshot was actually [String[String:String]] when all the values for entry's parameter were String, but as I changed Opening Time and Closing time to be Int, than I have to read the snapshot as [String[String:Any]]. So the final function is:

func filterOpenShops(setCompletion: @escaping (Bool) -> ()) {
        // Empty the array for beginning of the search
        self.availableShopsArray.removeAll()
        var ref = Database.database().reference()

        ref.child("Continent").child("Europe").child("Country").child("Italy").child("Region").child("Emilia-Romagna").child("City").child("Bologna").child("Shops").child("Shops Opening Times").queryOrdered(byChild: "Opening Time").queryStarting(atValue: openingTimeQueryStart).queryEnding(atValue: openingTimeQueryEnd).observe(.value) { (snapshot) in
            print(snapshot)
            if let data = snapshot.value as? [String : [String : Any]] {
                for (_, value) in
                    data {
                        let shopName = value["Shop Name"] as! String
                        let active = value["Active"] as! String
                        if active == "true" {
                            self.availableShopsArray.append(shopName)
                            print("Shop_Name is :\(shopName)")
                            print("self.availableShopsArray is: \(self.availableShopsArray)")
                        }
                }

            } else {
                print("No Shops")
            }
            // still asynchronous part
            setCompletion(true)
            // call next cascade function filterClosedShops only when data retrieving is finished
            self.filterClosedShops(setCompletion: self.completionSetter)

            print("  1 Open Shops are \(self.availableShopsArray)")
        }
    } // end of filterOpenShops()