swift - 如何在 Swift 中从 Firebase 存储和检索数据

标签 swift firebase firebase-realtime-database jsqmessagesviewcontroller

我有一个自己构建的消息传递应用程序,我想显示用户使用我的应用程序时所在的城市。该应用程序可以很好地收集和显示位置数据,但它一次只存储一个位置数据实例。例如,如果我从西雅图发帖到应用程序,应用程序会说我是从西雅图发帖。但是,如果其他人从纽约发帖到应用程序,西雅图的位置数据将被覆盖,就好像每个用户都在纽约一样。这显然是一个重大问题。

我想我可以使用 Firebase 数据库(我已经在使用它来处理消息传递)来存储每个唯一用户的位置数据,然后在我发布时从数据库中检索它,但我一直试图找到一个解决我的问题没有成功。

再一次,我收集位置数据没有问题,我只想为每个唯一用户存储一个唯一位置。

下面是我的一些代码(注意:很抱歉,它太长了,但我不想省略任何可能帮助别人回答我的问题的代码):

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 中,分别存储每个用户的位置:这样他们就不会被其他用户覆盖。

向数据库结构中添加一个新分支,例如地点

接下来,添加一个名为 e.g. 的 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 的更多信息。

关于swift - 如何在 Swift 中从 Firebase 存储和检索数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38004111/

相关文章:

firebase - 共享 Firestore 文档或将协作者添加到 Firestore 文档

javascript - Firebase 处理异步函数

swift - 加入不同的节点以使用 firebase 立即观察它们

macos - 获取应用程序中目录的绝对路径

ios - 有没有办法在用户每次打开应用程序时不重新下载图像?

ios - 在 Xcode 8 (Swift 3) 中手动导入 Firebase Framework

javascript - 如何使用更新对象更新节点而不用 Google Cloud Function 覆盖所有子节点?

ios - 创建 Swift AVAudioPlayer 错误

ios - 在 swift 3.0 中画线

javascript - react-native 中的 clonewithrows 数组问题