如何从 Firebase 在 Swift 中存储和检索数据
How to store and retrieve data in Swift from Firebase
我有一个自己构建的消息传递应用程序,我想显示用户使用我的应用程序所在的城市。该应用程序可以很好地收集和显示位置数据,但它一次只存储一个位置数据实例。例如,如果我 post 来自西雅图的应用程序,应用程序会说我 post 来自西雅图。但是,如果其他人 post 从纽约访问该应用程序,西雅图的位置数据将被覆盖,就好像每个用户都在纽约一样。这显然是一个重大问题。
我想我可以使用 Firebase 数据库(我已经在使用它来处理消息传递)来存储每个唯一用户的位置数据,然后在我 posting 时从数据库中检索它,但是我一直在努力寻找解决问题的方法,但没有成功。
再一次,我在收集位置数据时没有问题,我只想为每个唯一用户存储一个唯一位置。
下面是我的一些代码(注意:很抱歉,它太长了,但我不想省略任何可能帮助别人回答我的问题的代码):
class ChatViewController: JSQMessagesViewController, CLLocationManagerDelegate {
// MARK: Properties
//Location
var city: String = ""
var state: String = ""
var country: String = ""
var locationManager = CLLocationManager()
func getLocation() -> String {
if country == ("United States") {
return (self.city + ", " + self.state)
}
else {
return (self.city + ", " + self.state + ", " + self.country)
}
}
//Firebase
var rootRef = FIRDatabase.database().reference()
var messageRef: FIRDatabaseReference!
var userLocation: FIRDatabaseReference!
//JSQMessages
var messages = [JSQMessage]()
var outgoingBubbleImageView: JSQMessagesBubbleImage!
var incomingBubbleImageView: JSQMessagesBubbleImage!
override func viewDidLoad() {
super.viewDidLoad()
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
if CLLocationManager.locationServicesEnabled() {
//collect user's location
locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers
locationManager.requestLocation()
locationManager.startUpdatingLocation()
}
title = "Group Chat"
setupBubbles()
// No avatars
collectionView!.collectionViewLayout.incomingAvatarViewSize = CGSizeZero
collectionView!.collectionViewLayout.outgoingAvatarViewSize = CGSizeZero
// Remove file upload icon
self.inputToolbar.contentView.leftBarButtonItem = nil;
messageRef = rootRef.child("messages")
userLocation = rootRef.child("locations")
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
observeMessages()
}
override func viewDidDisappear(animated: Bool) {
super.viewDidDisappear(animated)
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
//--- CLGeocode to get address of current location ---//
CLGeocoder().reverseGeocodeLocation(manager.location!, completionHandler: {(placemarks, error)->Void in
if let pm = placemarks?.first
{
self.displayLocationInfo(pm)
}
})
}
func displayLocationInfo(placemark: CLPlacemark?)
{
if let containsPlacemark = placemark
{
self.city = (containsPlacemark.locality != nil) ? containsPlacemark.locality! : ""
self.state = (containsPlacemark.administrativeArea != nil) ? containsPlacemark.administrativeArea! : ""
self.country = (containsPlacemark.country != nil) ? containsPlacemark.country! : ""
print(getLocation())
}
}
func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
print("Error while updating location " + error.localizedDescription)
}
override func collectionView(collectionView: JSQMessagesCollectionView!,
messageDataForItemAtIndexPath indexPath: NSIndexPath!) -> JSQMessageData! {
return messages[indexPath.item]
}
override func collectionView(collectionView: JSQMessagesCollectionView!,
messageBubbleImageDataForItemAtIndexPath indexPath: NSIndexPath!) -> JSQMessageBubbleImageDataSource! {
let message = messages[indexPath.item] // 1
if message.senderId == senderId { // 2
return outgoingBubbleImageView
} else { // 3
return incomingBubbleImageView
}
}
override func collectionView(collectionView: UICollectionView,
numberOfItemsInSection section: Int) -> Int {
return messages.count
}
override func collectionView(collectionView: JSQMessagesCollectionView!,
avatarImageDataForItemAtIndexPath indexPath: NSIndexPath!) -> JSQMessageAvatarImageDataSource! {
return nil
}
private func setupBubbles() {
let factory = JSQMessagesBubbleImageFactory()
outgoingBubbleImageView = factory.outgoingMessagesBubbleImageWithColor(
UIColor.jsq_messageBubbleBlueColor())
incomingBubbleImageView = factory.incomingMessagesBubbleImageWithColor(
UIColor.jsq_messageBubbleLightGrayColor())
}
func addMessage(id: String, text: String) {
let message = JSQMessage(senderId: id, displayName: "", text: text)
messages.append(message)
}
override func collectionView(collectionView: UICollectionView,
cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = super.collectionView(collectionView, cellForItemAtIndexPath: indexPath)
as! JSQMessagesCollectionViewCell
let message = messages[indexPath.item]
if message.senderId == senderId {
cell.textView!.textColor = UIColor.whiteColor()
} else {
cell.textView!.textColor = UIColor.blackColor()
}
return cell
}
override func didPressSendButton(button: UIButton!, withMessageText text: String!, senderId: String!,
senderDisplayName: String!, date: NSDate!) {
let itemRef = messageRef.childByAutoId() // 1
let messageItem = [ // 2
"text": text,
"senderId": senderId
]
itemRef.setValue(messageItem) // 3
// Start storing location data
let locRef = userLocation.childByAutoId()
let locItem = [
"location": getLocation()
]
// Set location data in Firebase
locRef.setValue(locItem)
// 4
JSQSystemSoundPlayer.jsq_playMessageSentSound()
// 5
finishSendingMessage()
}
private func observeMessages() {
// 1
let messagesQuery = messageRef.queryLimitedToLast(25)
// 2
messagesQuery.observeEventType(.ChildAdded) { (snapshot: FIRDataSnapshot!) in
// 3
let id = snapshot.value!["senderId"] as! String
let text = snapshot.value!["text"] as! String
// 4
self.addMessage(id, text: text)
// 5
self.finishReceivingMessage()
}
}
override func textViewDidChange(textView: UITextView) {
super.textViewDidChange(textView)
}
override func collectionView(collectionView: JSQMessagesCollectionView!, attributedTextForCellBottomLabelAtIndexPath indexPath: NSIndexPath!) -> NSAttributedString! {
let message = messages[indexPath.item] // 1
// This is where I need help retrieving the data from firebase
let text = "From: " + getLocation()
if message.senderId == senderId { // 2
return nil
} else { // 3
return NSAttributedString(string: text)
}
}
override func collectionView(collectionView: JSQMessagesCollectionView, layout collectionViewLayout: JSQMessagesCollectionViewFlowLayout, heightForCellBottomLabelAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return kJSQMessagesCollectionViewCellLabelHeightDefault
}
}
在 Firebase 中,分别存储每个用户的位置:这样他们就不会被其他用户覆盖。
向数据库结构添加一个新分支,例如地点
接下来,添加一个 child,例如人
Finally, add another child for each user with the attribute location.
接下来简单查询这个分支,获取用户信息。当您更新用户的位置时,它只会覆盖 他们 之前的位置。
请阅读有关查询 Firebase 的文档:
https://firebase.google.com/docs/database/ios/retrieve-data#read_data_once
以及与更新数据有关的文档:
https://firebase.google.com/docs/database/ios/save-data#basic_write
为了进一步了解 Firebase。
我有一个自己构建的消息传递应用程序,我想显示用户使用我的应用程序所在的城市。该应用程序可以很好地收集和显示位置数据,但它一次只存储一个位置数据实例。例如,如果我 post 来自西雅图的应用程序,应用程序会说我 post 来自西雅图。但是,如果其他人 post 从纽约访问该应用程序,西雅图的位置数据将被覆盖,就好像每个用户都在纽约一样。这显然是一个重大问题。
我想我可以使用 Firebase 数据库(我已经在使用它来处理消息传递)来存储每个唯一用户的位置数据,然后在我 posting 时从数据库中检索它,但是我一直在努力寻找解决问题的方法,但没有成功。
再一次,我在收集位置数据时没有问题,我只想为每个唯一用户存储一个唯一位置。
下面是我的一些代码(注意:很抱歉,它太长了,但我不想省略任何可能帮助别人回答我的问题的代码):
class ChatViewController: JSQMessagesViewController, CLLocationManagerDelegate {
// MARK: Properties
//Location
var city: String = ""
var state: String = ""
var country: String = ""
var locationManager = CLLocationManager()
func getLocation() -> String {
if country == ("United States") {
return (self.city + ", " + self.state)
}
else {
return (self.city + ", " + self.state + ", " + self.country)
}
}
//Firebase
var rootRef = FIRDatabase.database().reference()
var messageRef: FIRDatabaseReference!
var userLocation: FIRDatabaseReference!
//JSQMessages
var messages = [JSQMessage]()
var outgoingBubbleImageView: JSQMessagesBubbleImage!
var incomingBubbleImageView: JSQMessagesBubbleImage!
override func viewDidLoad() {
super.viewDidLoad()
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
if CLLocationManager.locationServicesEnabled() {
//collect user's location
locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers
locationManager.requestLocation()
locationManager.startUpdatingLocation()
}
title = "Group Chat"
setupBubbles()
// No avatars
collectionView!.collectionViewLayout.incomingAvatarViewSize = CGSizeZero
collectionView!.collectionViewLayout.outgoingAvatarViewSize = CGSizeZero
// Remove file upload icon
self.inputToolbar.contentView.leftBarButtonItem = nil;
messageRef = rootRef.child("messages")
userLocation = rootRef.child("locations")
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
observeMessages()
}
override func viewDidDisappear(animated: Bool) {
super.viewDidDisappear(animated)
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
//--- CLGeocode to get address of current location ---//
CLGeocoder().reverseGeocodeLocation(manager.location!, completionHandler: {(placemarks, error)->Void in
if let pm = placemarks?.first
{
self.displayLocationInfo(pm)
}
})
}
func displayLocationInfo(placemark: CLPlacemark?)
{
if let containsPlacemark = placemark
{
self.city = (containsPlacemark.locality != nil) ? containsPlacemark.locality! : ""
self.state = (containsPlacemark.administrativeArea != nil) ? containsPlacemark.administrativeArea! : ""
self.country = (containsPlacemark.country != nil) ? containsPlacemark.country! : ""
print(getLocation())
}
}
func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
print("Error while updating location " + error.localizedDescription)
}
override func collectionView(collectionView: JSQMessagesCollectionView!,
messageDataForItemAtIndexPath indexPath: NSIndexPath!) -> JSQMessageData! {
return messages[indexPath.item]
}
override func collectionView(collectionView: JSQMessagesCollectionView!,
messageBubbleImageDataForItemAtIndexPath indexPath: NSIndexPath!) -> JSQMessageBubbleImageDataSource! {
let message = messages[indexPath.item] // 1
if message.senderId == senderId { // 2
return outgoingBubbleImageView
} else { // 3
return incomingBubbleImageView
}
}
override func collectionView(collectionView: UICollectionView,
numberOfItemsInSection section: Int) -> Int {
return messages.count
}
override func collectionView(collectionView: JSQMessagesCollectionView!,
avatarImageDataForItemAtIndexPath indexPath: NSIndexPath!) -> JSQMessageAvatarImageDataSource! {
return nil
}
private func setupBubbles() {
let factory = JSQMessagesBubbleImageFactory()
outgoingBubbleImageView = factory.outgoingMessagesBubbleImageWithColor(
UIColor.jsq_messageBubbleBlueColor())
incomingBubbleImageView = factory.incomingMessagesBubbleImageWithColor(
UIColor.jsq_messageBubbleLightGrayColor())
}
func addMessage(id: String, text: String) {
let message = JSQMessage(senderId: id, displayName: "", text: text)
messages.append(message)
}
override func collectionView(collectionView: UICollectionView,
cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = super.collectionView(collectionView, cellForItemAtIndexPath: indexPath)
as! JSQMessagesCollectionViewCell
let message = messages[indexPath.item]
if message.senderId == senderId {
cell.textView!.textColor = UIColor.whiteColor()
} else {
cell.textView!.textColor = UIColor.blackColor()
}
return cell
}
override func didPressSendButton(button: UIButton!, withMessageText text: String!, senderId: String!,
senderDisplayName: String!, date: NSDate!) {
let itemRef = messageRef.childByAutoId() // 1
let messageItem = [ // 2
"text": text,
"senderId": senderId
]
itemRef.setValue(messageItem) // 3
// Start storing location data
let locRef = userLocation.childByAutoId()
let locItem = [
"location": getLocation()
]
// Set location data in Firebase
locRef.setValue(locItem)
// 4
JSQSystemSoundPlayer.jsq_playMessageSentSound()
// 5
finishSendingMessage()
}
private func observeMessages() {
// 1
let messagesQuery = messageRef.queryLimitedToLast(25)
// 2
messagesQuery.observeEventType(.ChildAdded) { (snapshot: FIRDataSnapshot!) in
// 3
let id = snapshot.value!["senderId"] as! String
let text = snapshot.value!["text"] as! String
// 4
self.addMessage(id, text: text)
// 5
self.finishReceivingMessage()
}
}
override func textViewDidChange(textView: UITextView) {
super.textViewDidChange(textView)
}
override func collectionView(collectionView: JSQMessagesCollectionView!, attributedTextForCellBottomLabelAtIndexPath indexPath: NSIndexPath!) -> NSAttributedString! {
let message = messages[indexPath.item] // 1
// This is where I need help retrieving the data from firebase
let text = "From: " + getLocation()
if message.senderId == senderId { // 2
return nil
} else { // 3
return NSAttributedString(string: text)
}
}
override func collectionView(collectionView: JSQMessagesCollectionView, layout collectionViewLayout: JSQMessagesCollectionViewFlowLayout, heightForCellBottomLabelAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return kJSQMessagesCollectionViewCellLabelHeightDefault
}
}
在 Firebase 中,分别存储每个用户的位置:这样他们就不会被其他用户覆盖。
向数据库结构添加一个新分支,例如地点
接下来,添加一个 child,例如人
Finally, add another child for each user with the attribute location.
接下来简单查询这个分支,获取用户信息。当您更新用户的位置时,它只会覆盖 他们 之前的位置。
请阅读有关查询 Firebase 的文档:
https://firebase.google.com/docs/database/ios/retrieve-data#read_data_once
以及与更新数据有关的文档:
https://firebase.google.com/docs/database/ios/save-data#basic_write
为了进一步了解 Firebase。