Reputation: 181
I am trying to code a message chat log between users. so I want to retrieve only specific data from my message array. For example when a person sends a text message I only want to retrieve from my message array fromId,toId, and text. when a person sends an image I want to only retrieve fromId,toId and imageUrl. At the moment the app crashes because when a person sends a text "imageUrl" is nil and vice versa sending an image where "text" is nil. Is there a way around this? Or do I have to create 2 separate arrays? Thanks in advance
message array
class Message {
var fromId: String
var text: String
var toId: String
var timeStamp: NSNumber?
var imageUrl: String
init(fromId: String, text: String, toId: String, timeStamp: NSNumber, imageUrl: String){
self.fromId = fromId
self.text = text
self.toId = toId
self.imageUrl = imageUrl
}
init(snapshot:FIRDataSnapshot) {
self.fromId = (snapshot.value! as! NSDictionary)["fromId"] as! String!
self.toId = (snapshot.value! as! NSDictionary)["toId"] as! String!
self.text = (snapshot.value! as! NSDictionary)["text"] as! String!
self.imageUrl = (snapshot.value! as! NSDictionary)["imageUrl"] as! String!
}
firebase structure
{ "messages": {
"KkGAWnQhqnOx525vv2W": {
"fromId": tvyT6UF6mWZeewAJXt076qqt7ek2,
"toId": USk3w8ZPYlRhfDmEwWwtkMhzUNX2,
"text": "Hello"
},
"hujU6UF6mWZeewAJXt0": {
"fromId": tvyT6UF6mWZeewAJXt076qqt7ek2,
"toId": USk3w8ZPYlRhfDmEwWwtkMhzUNX2,
"imageUrl": "https://firebasestorage.googleapis.com/v0/b.."
}
method used to retrieve data
var message = [Message]()
func observeMessages(){
let ref = FIRDatabase.database().reference().child("user-messages").child(uid)
ref.observe(.childAdded, with: { (snapshot) in
let messageId = snapshot.key
let messageReference = FIRDatabase.database().reference().child("messages").child(messageId)
messageReference.observe(.value, with: { (snapshot) in
for posts in snapshot.children{
let message = Message(snapshot: posts as! FIRDataSnapshot )
let chatPartnerId = message.chatPartnerId()
self.messagesDictionary[chatPartnerId!] = message
self.messageTableView.reloadData()
})
}
}, withCancel: nil)
}
Upvotes: 1
Views: 127
Reputation: 72460
The reason it is crashing is because you are forcefully wrapping value when you subscript with dictionary. You need to use if let
or guard let
to wrapped the optional or you can use Nil-Coalescing Operator
with default value empty and later check which one is non empty text
or image
.
init(snapshot:FIRDataSnapshot) {
let dictionary = snapshot.value as! [String:Any]
self.fromId = dictionary["fromId"] as! String
self.toId = dictionary["toId"] as! String
self.text = dictionary["text"] as? String ?? ""
self.imageUrl = dictionary["imageUrl"] as? String ?? ""
}
Also the batter option is to add one more key with your message object as type
and with value either text
or image
. Make your structure like this.
{
"messages": {
"KkGAWnQhqnOx525vv2W": {
"fromId": tvyT6UF6mWZeewAJXt076qqt7ek2,
"toId": USk3w8ZPYlRhfDmEwWwtkMhzUNX2,
"type" "text"
"text": "Hello"
},
"hujU6UF6mWZeewAJXt0": {
"fromId": tvyT6UF6mWZeewAJXt076qqt7ek2,
"toId": USk3w8ZPYlRhfDmEwWwtkMhzUNX2,
"type" "image"
"imageUrl": "https://firebasestorage.googleapis.com/v0/b.."
}
}
}
After that get the value of type and compare is it text
or image
init(snapshot:FIRDataSnapshot) {
let dictionary = snapshot.value as! [String:Any]
self.fromId = dictionary["fromId"] as! String
self.toId = dictionary["toId"] as! String
//Make one more property with name type of String
self.type = dictionary["type"] as! String
self.text = dictionary["text"] as? String ?? ""
self.imageUrl = dictionary["imageUrl"] as? String ?? ""
}
Now when you access this object check its type and access its property text and imageUrl according to it.
Upvotes: 1