Reputation: 936
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" : "[email protected]",
"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 = "[email protected]";
name = Steve;
profileImageUrl =
"https://firebasestorage.googleapis.com";
})
This format works for the dictionary
data snapshot using print(room.members)
:
Optional({
K0tA3yTnxAWxCFBZoeyAjcr3yYy1 = {
email = "[email protected]";
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
Upvotes: 0
Views: 588
Reputation: 35657
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
Upvotes: 1
Reputation: 1090
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.
Upvotes: 0