j.iese
j.iese

Reputation: 181

error retrieving data from an object array swift

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

Answers (1)

Nirav D
Nirav D

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

Related Questions