firebase json deserialization swift

痴心易碎 提交于 2019-12-12 03:35:28

问题


I have JSON data I need entered in a dictionary and then appended to an array.

Below is where that should take place, but I get the error

this class is not key value coding-compliant for the key K0tA3yTnxAWxCFBZoeyAjcr3yYy1.'

let room = rooms[indexPath.row]

if let dictionary = room.members {

    let user = User()

    user.setValuesForKeys(dictionary)

    liveCell.members.append(user)

}

Below are the classes

User

class User: NSObject {
    var email: String?
    var name: String?
    var profileImageUrl: String?
}

Room

class Room: NSObject {
    var rid: String?
    var owner: String?
    var groupChatName: String?
    var groupChatDescription: String?
    var members: NSDictionary?
}

Room object in database

"rooms" : {
    "B7C7E469-945E-4327-9473-AAE34FCB9B41" : {
      "groupChatDescription" : "123ae",
      "groupChatName" : "Test123",
      "members" : {
        "K0tA3yTnxAWxCFBZoeyAjcr3yYy1" : {
          "email" : "S@gmail.com",
          "name" : "Steve",
          "profileImageUrl" : "https://firebasestorage.googleapis.com"
        }
      },
      "owner" : "Steve"
    }
},

To recap, rooms is an array of rooms, room is the specific room object, members is an array of users, and member is the specific user.

I have used the dictionary method already to retrieve users from my database, but I found some differences between the datasnapshots.

snapshot.value from FireBase:

Optional({
    email = "S@gmail.com";
    name = Steve;
    profileImageUrl = 
"https://firebasestorage.googleapis.com";
})

This format works for the dictionary

data snapshot using print(room.members):

Optional({
    K0tA3yTnxAWxCFBZoeyAjcr3yYy1 =     {
        email = "S@gmail.com";
        name = Steve;
        profileImageUrl = 
"https://firebasestorage.googleapis.com";
    };
})

This format doesn't work for the dictionary I believe it's because of the key but I don't know how to get rid of it because that is essentially how I separate each member in the members array.

Any suggestions?

As for what liveCell is here is a screen shot that explains it well...

This is a liveCell and you can see where the data matches up. The yellow rectangle is another uicollectionview that houses the array of members profileimages in which each profile image will be inside the red square.

Hope this clears things up


回答1:


Instead of trying to fix all of that code, here's a clean, simple way to populate an array of rooms, where each room has an array of users.

Given a Firebase Structure similar to yours

  "rooms"
    "room_0"
      "groupChatName" : "Test123",
      "members"
        "user_0"
          "name" : "Barry"
        "user_1"
          "name" : "Maurice"
        "user_2"
          "name" : "Robin"

We start off with the RoomClass and UserClass. Note that I make those classes do the heavy lifting - they tear down the snapshot and store it's values.

Note that I treat the members child node as a snapshot so I can iterate over it while maintaining it's key: value pairs.

class RoomClass {
    var key = ""
    var groupChatName = ""
    var membersArray = [UserClass]()

    init(snapshot: DataSnapshot) {
        let dict = snapshot.value as! [String: Any]
        let membersSnap = snapshot.childSnapshot(forPath: "members")
        let snapKey = snapshot.key
        let groupName = dict["groupChatName"] as! String

        self.key = snapKey
        self.groupChatName = groupName

        for member in membersSnap.children {
            let memberSnap = member as! DataSnapshot
            let user = UserClass(snapshot: memberSnap)
            self.membersArray.append(user)
        }
    }
}

class UserClass {
    var key = ""
    var name = ""

    init(snapshot: DataSnapshot) {
        let dict = snapshot.value as! [String: Any]
        let snapKey = snapshot.key
        let userName = dict["name"] as! String
        self.key = snapKey
        self.name = userName
    }
}

We then define the array to store the rooms and the code to populate it

var roomsArray = [RoomClass]()

func doButton0Action() {
    let roomsRef = self.ref.child("rooms")
    roomsRef.observeSingleEvent(of: .value, with: { snapshot in

        for child in snapshot.children {
            let snap = child as! DataSnapshot
            let room = RoomClass(snapshot: snap)
            self.roomsArray.append(room)
        }

        //this just demonstrates the rooms and members are loaded
        for room in self.roomsArray {
            let groupChatName = room.groupChatName

            print(groupChatName)

            for user in room.membersArray {
                let userName = user.name
                print("  \(userName)")
            }
        }
    })
}

and the output

Test123
  Barry
  Maurice
  Robin



回答2:


Weird solution, but you shouldn't cast to [String:AnyObject] with firebase. It's never worked for me either, but doing:

snapshot.value as? [String:Any]

has worked. It's more the dev's responsibility to add custom classes to interprete the snapshot's value in custom use cases (class for rooms, cars, etc. etc.) by casting possible keys of snapshot.value appropriately.



来源:https://stackoverflow.com/questions/45494174/firebase-json-deserialization-swift

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!