2017-07-23 90 views
12

我正在创建一个简单的聊天应用来学习Swift和Firebase。我有一个查询来检查聊天室的消息加载到tableView中。查询返回快照,但我无法正确地存储和加载数据。我创建从快照一本字典,所以我可以得到各个子值,但他们返回nil:在断点处Firebase查询快照为零?

query.observeSingleEvent(of: .childAdded, with: { snapshot in 

      print(snapshot) 

      let indexPaths = self.messages.enumerated().map { 
       IndexPath(row: $0.0, section: 0) 
      } 

      guard let messagesDict = snapshot.value as? [String:AnyObject] else { return } 
      guard let sender = messagesDict["sender"] as? String else { return } 
      guard let text = messagesDict["text"] as? String else { return } 
      guard let timestamp = messagesDict["timestamp"] as? Int else { return } 

      let message = Message.init(key: snapshot.key, sender: sender as! String, text: text as! String, timestamp: timestamp) 

      self.messages.append(message) 

      self.tableView.reloadData() 
     }) 

po messagesDict返回数据:

▿ 1 element 
    ▿ 0 : 2 elements 
    - key : "-KotqLUUucaRagTRt967" 
    ▿ value : 3 elements 
     ▿ 0 : 2 elements 
     - key : sender 
     - value : eGTYRSo81JefgasYLRHUFHUTnEC3 
     ▿ 1 : 2 elements 
     - key : text 
     - value : test 
     ▿ 2 : 2 elements 
     - key : timestamp 
     - value : 1499914135546 

的应用到达下一个断点哪里我设置了guard let sender,但应用程序命中返回并停止执行代码块的其余部分。如何正确访问发件人,文本和时间戳记元素,以便我可以将它们设置为变量并将它们存储在我的表格的数组中?

任何帮助将不胜感激。我一直坚持这一段时间,我可以用另一双眼睛!

谢谢!

附加信息:

查询:

let query = rootRef.child("chat-messages/\(chatKey)")

数据库结构:

{ 
    "chat-messages" : { 
    "-KotqKI4zF9cS5XMR9WU" : { 
     "-KotqLUUucaRagTRt967" : { 
     "sender" : "eGTYRSo81JefgasYLRHUFHUTnEC3", 
     "text" : "test", 
     "timestamp" : 1499914135546 
     } 
    }, 
    "-KotqvBoFFzOTY6Q1fO7" : { 
     "-KotqwGAJ85NuAp-Lh3Z" : { 
     "sender" : "eGTYRSo81JefgasYLRHUFHUTnEC3", 
     "text" : "test", 
     "timestamp" : 1499914290279 
     } 
    }, 
    "-KotsNgF0ou5MIDn2l5K" : { 
     "-KotsOSXw7OS_3xuXZgP" : { 
     "sender" : "eGTYRSo81JefgasYLRHUFHUTnEC3", 
     "text" : "test", 
     "timestamp" : 1499914671997 
     }, 
     "-KotsPqrCpipMLulNNFl" : { 
     "sender" : "eGTYRSo81JefgasYLRHUFHUTnEC3", 
     "text" : "test44", 
     "timestamp" : 1499914677715 
     } 
    }, 
    "-Kotsv1Vv19dEF2q7XQu" : { 
     "-KotsvYO9JvLY8gdTnA0" : { 
     "sender" : "eGTYRSo81JefgasYLRHUFHUTnEC3", 
     "text" : "test", 
     "timestamp" : 1499914811675 
     }, 
     "-KotsvxKXzIwbyvbwLPp" : { 
     "sender" : "eGTYRSo81JefgasYLRHUFHUTnEC3", 
     "text" : "test", 
     "timestamp" : 1499914813335 
     }, 
     "-Kotsw9vLiEf6KquU__e" : { 
     "sender" : "eGTYRSo81JefgasYLRHUFHUTnEC3", 
     "text" : "test", 
     "timestamp" : 1499914814205 
     }, 
     "-KotswHnzmfkEXih1O7y" : { 
     "sender" : "eGTYRSo81JefgasYLRHUFHUTnEC3", 
     "text" : "test", 
     "timestamp" : 1499914814709 
     }, 
     "-KotszHKBt254jZnUMAl" : { 
     "sender" : "eGTYRSo81JefgasYLRHUFHUTnEC3", 
     "text" : "test46456", 
     "timestamp" : 1499914826967 
     } 
    }, 
    "-KoyheS01YxWExSNxl_H" : { 
     "-Koyhf3G-FPEDrxQOcpU" : { 
     "sender" : "eGTYRSo81JefgasYLRHUFHUTnEC3", 
     "text" : "test", 
     "timestamp" : 1499995746607 
     } 
    }, 
    "-Koyjc_aBaF1kFE-8Bll" : { 
     "-Koyjd9PnO6sPOhS7P27" : { 
     "sender" : "eGTYRSo81JefgasYLRHUFHUTnEC3", 
     "text" : "test", 
     "timestamp" : 1499996263096 
     }, 
     "-KoyjdzSEi5twTVQMGOu" : { 
     "sender" : "eGTYRSo81JefgasYLRHUFHUTnEC3", 
     "text" : "test", 
     "timestamp" : 1499996266491 
     }, 
     "-Koyje2C9E524kV7nhLY" : { 
     "sender" : "eGTYRSo81JefgasYLRHUFHUTnEC3", 
     "text" : "test", 
     "timestamp" : 1499996266730 
     } 
    }, 
    "-KpfUGw45F1FU2IrR87A" : { 
     "sender" : "eGTYRSo81JefgasYLRHUFHUTnEC3", 
     "text" : "test", 
     "timestamp" : 1500746948396 
    }, 
    "-KpfUHQGuTDi4yZutS5K" : { 
     "sender" : "eGTYRSo81JefgasYLRHUFHUTnEC3", 
     "text" : "test", 
     "timestamp" : 1500746950368 
    }, 
    "-KpfUHdSXeTzauATsDAP" : { 
     "sender" : "eGTYRSo81JefgasYLRHUFHUTnEC3", 
     "text" : "test", 
     "timestamp" : 1500746951277 
    }, 
    "-Kpfia0fXsoqpRtIr1kU" : { 
     "sender" : "eGTYRSo81JefgasYLRHUFHUTnEC3", 
     "text" : "gerg", 
     "timestamp" : 1500750962815 
    } 
    }, 
    "chat-participants" : { 
    "-KotqKI4zF9cS5XMR9WU" : { 
     "eGTYRSo81JefgasYLRHUFHUTnEC3" : { 
     "username" : "tester" 
     } 
    }, 
    "-KotqvBoFFzOTY6Q1fO7" : { 
     "eGTYRSo81JefgasYLRHUFHUTnEC3" : { 
     "username" : "tester" 
     } 
    }, 
    "-KotsNgF0ou5MIDn2l5K" : { 
     "eGTYRSo81JefgasYLRHUFHUTnEC3" : { 
     "username" : "tester" 
     } 
    }, 
    "-Kotsv1Vv19dEF2q7XQu" : { 
     "eGTYRSo81JefgasYLRHUFHUTnEC3" : { 
     "username" : "tester" 
     } 
    }, 
    "-KoyheS01YxWExSNxl_H" : { 
     "eGTYRSo81JefgasYLRHUFHUTnEC3" : { 
     "username" : "tester" 
     } 
    }, 
    "-Koyjc_aBaF1kFE-8Bll" : { 
     "eGTYRSo81JefgasYLRHUFHUTnEC3" : { 
     "username" : "tester" 
     } 
    }, 
    "-KpfLBjQdPiX2kSrl1yF" : { 
     "eGTYRSo81JefgasYLRHUFHUTnEC3" : { 
     "username" : "tester" 
     } 
    } 
    }, 
    "chats" : { 
    "-KotqKI4zF9cS5XMR9WU" : { 
     "currentName" : "test", 
     "date" : 1499914130657 
    }, 
    "-KotqvBoFFzOTY6Q1fO7" : { 
     "currentName" : "test", 
     "date" : 1499914285904 
    }, 
    "-KotsNgF0ou5MIDn2l5K" : { 
     "currentName" : "test", 
     "date" : 1499914668844 
    }, 
    "-Kotsv1Vv19dEF2q7XQu" : { 
     "currentName" : "test", 
     "date" : 1499914809570 
    }, 
    "-KoyheS01YxWExSNxl_H" : { 
     "currentName" : "test", 
     "date" : 1499995744095 
    }, 
    "-Koyjc_aBaF1kFE-8Bll" : { 
     "currentName" : "test", 
     "date" : 1499996260740 
    }, 
    "-KpfLBjQdPiX2kSrl1yF" : { 
     "currentName" : "test3222", 
     "date" : 1500744567786 
    } 
    }, 
    "user-chats" : { 
    "eGTYRSo81JefgasYLRHUFHUTnEC3" : { 
     "-KotqKI4zF9cS5XMR9WU" : { 
     "chatKey" : "-KotqKI4zF9cS5XMR9WU", 
     "currentName" : "test" 
     }, 
     "-KotqvBoFFzOTY6Q1fO7" : { 
     "chatKey" : "-KotqvBoFFzOTY6Q1fO7", 
     "currentName" : "test" 
     }, 
     "-KotsNgF0ou5MIDn2l5K" : { 
     "chatKey" : "-KotsNgF0ou5MIDn2l5K", 
     "currentName" : "test" 
     }, 
     "-Kotsv1Vv19dEF2q7XQu" : { 
     "chatKey" : "-Kotsv1Vv19dEF2q7XQu", 
     "currentName" : "test" 
     }, 
     "-KoyheS01YxWExSNxl_H" : { 
     "chatKey" : "-KoyheS01YxWExSNxl_H", 
     "currentName" : "test" 
     }, 
     "-Koyjc_aBaF1kFE-8Bll" : { 
     "chatKey" : "-Koyjc_aBaF1kFE-8Bll", 
     "currentName" : "test" 
     }, 
     "-KpfLBjQdPiX2kSrl1yF" : { 
     "chatKey" : "-KpfLBjQdPiX2kSrl1yF", 
     "currentName" : "test3222" 
     } 
    } 
    }, 
    "user-friends" : { 
    "36HDn5XyxjMCcMluJJ9KPBOCDMm1" : { 
     "eGTYRSo81JefgasYLRHUFHUTnEC3" : { 
     "username" : "tester" 
     } 
    }, 
    "eGTYRSo81JefgasYLRHUFHUTnEC3" : { 
     "36HDn5XyxjMCcMluJJ9KPBOCDMm1" : { 
     "username" : "tester2" 
     } 
    } 
    }, 
    "user-invites" : { 
    "eGTYRSo81JefgasYLRHUFHUTnEC3" : { 
     "36HDn5XyxjMCcMluJJ9KPBOCDMm1" : { 
     "username" : "tester2" 
     } 
    } 
    }, 
    "users" : { 
    "36HDn5XyxjMCcMluJJ9KPBOCDMm1" : { 
     "email" : "[email protected]", 
     "username" : "tester2" 
    }, 
    "eGTYRSo81JefgasYLRHUFHUTnEC3" : { 
     "email" : "[email protected]", 
     "username" : "tester" 
    } 
    } 
} 
+0

您的查询是什么?和你的数据库结构? – Pipiks

+0

感谢您的帮助!我编辑了问题以包含查询和数据库结构。 – winston

+0

@freeman我前几天添加了一个建议的解决方案 - 解决问题还是有问题? – Yasir

回答

3

你的字典的样子:

▿ 1 element 
    ▿ 0 : 2 elements 
    - key : "-KotqLUUucaRagTRt967" 
    ▿ value : 3 elements 
     ▿ 0 : 2 elements 
     - key : sender 
     - value : eGTYRSo81JefgasYLRHUFHUTnEC3 
     ▿ 1 : 2 elements 
     - key : text 
     - value : test 
     ▿ 2 : 2 elements 
     - key : timestamp 
     - value : 1499914135546 

但实际上它应该看起来像(如果你想获得大辞典[ “发件人”):

▿ 2 elements 
    ▿ 0 : 2 elements 
    - key : sender 
    - value : eGTYRSo81JefgasYLRHUFHUTnEC3 
    ▿ 1 : 2 elements 
    - key : text 
    - value : test 
    ▿ 2 : 2 elements 
    - key : timestamp 
    - value : 1499914135546 

解决方案一:

您需要在查询中添加.child(“ - KotqLUUucaRagTRt967”)。

OR

解决方法二:

你需要做这样的事情:

query.observe(.childAdded, with: { snapshot in 
    for child in snapshot.children { 
     guard let value = child.value as? NSDictionary else { 
      return 
     } 

     guard let sender = value["sender"] as? String else { 
      return 
     } 

     // You can user the sender 
    } 
}) 

UPDATE:

query.observe(.childAdded, with: { snapshot in 
    for child in snapshot.children.allObjects as! [FIRDataSnapshot] { 
     if let value = child.value as? [String:Any], let sender = value["sender"] as? String { 
      // You can user the sender 
     } 
    } 
}) 

注意

我更换observeSingleEvent观察,为弗兰克面包车Puffelen说,它是一种罕见的组合。childAdded

+0

谢谢!我收到错误'任何类型的值没有成员值'。它在'value = child.value'上出错。有任何想法吗? – winston

+0

@freeman是否确保在'value = child.value'之前包含'guard let'? –

+0

@RajatKhare是的,它仍然在这条线上的错误'警卫让价值= child.value为? NSDictionary其他{return}'。 XCode建议将其更改为'guard let value =(child as AnyObject).value as? NSDictionary其他{返回}'但是然后抛出错误'暧昧的使用价值' – winston

4

我不认为你想要一个ChildAdded处理程序,所以我去一个observeSingleEvent示例,因为你想在没有触发器的情况下从数据库查询数据。当您使用observeSingleEvent时,保持数据库同步非常重要。我会建议使用下面的代码:

query.keepSynched(true) //keeps data in sync with database, if you have data persistince on in your appDelegate 
query.observeSingleEvent(of: .value, with: { (snapshot) in //notice the changed here 
      print(snapshot) 
      //Since you want to loop again because there could be multiple 
      //messages in that chatroom which all have a unique ID, do this loop: 
      let enumerator = snapshot.children 
      while let rest = enumerator.nextObject() as? FIRDataSnapshot { 
       //this is 1 single message here 
       let values = rest.value as? NSDictionary 
       for (key, value) in values{ 
       print("Key: \(key), value: \(value)") 
       } 
       //lets say you want to check if there is a value with a key named "text": 
      let textUser = values?["text"] as? String ?? "No text found" 
       //providing a default value if there is no text. You could leave it empty, than it is nil (not recommend) 
       //Not only is this a lot more readable, I do not use force unwrapping so your app 
       //cannot cause an exception. 

       //Get more values from the dictionary as I did with textUser 
       //Initialize message than here. You will see you do not need to force unwrap anything :D 
       } 

      } 

     }) 
+0

“你和Pipiks结合了一个observeSingleEvent与一个ChildAdded,这两个不会在一起”虽然这是一个不常见的组合,这些技术原因不能合并。 –

+0

同意,不明白为什么你不能结合单个事件和childAdded? – Yasir

+0

@Yasir我当然不知道,那就是为什么“我认为??!”。从我阅读的文档中可以看出,每次添加新的子项时都会触发childAdded。一个observeSingleEvent将读取当时的数据。我认为两个人不会一起工作,但弗兰克已经纠正了我,我会编辑这部分。 –

3

由于Pipiks解释,你的问题是,你正试图以比返回的数据更高一级访问个人信息的详细信息。

快照值为您提供了聊天消息字典,其中顶级的键是聊天消息键。为了您的返回数据映射到消息的数组,我会用下面的代码:

query.observeSingleEvent(of: .childAdded, with: { snapshot in 

    guard let messagesDict = snapshot.value as? [String: AnyObject] else { return } 

    self.messages = messagesDict.flatMap({ (messageId: String, messageData: Any) -> Message? in 
     guard 
      let sender = messageData["sender"] as? String, 
      let text = messageData["text"] as? String, 
      let timestamp = messageData["timestamp"] as? Int, 
      let message = Message(key: messageKey, sender: sender, text: text, timestamp: timestamp) else { 
       return nil 
     } 
     return message 
    }) 

    self.tableView.reloadData() 
}) 

这样做是你的地图信息的字典Message对象的数组。

我已经使用flatMap过滤掉没有发件人,文本或时间戳值的消息(因此flatMap返回一个[Message]对象)。

这是否解决了这个问题?

+0

我遗漏了indexPaths代码,因为它看起来不像它在任何地方使用:) – Yasir