显示用户位置

Displaying user location

我有一个使用 JSQMessagesViewController 框架构建的简单消息传递应用程序。我一直在尝试使用 CoreLocation 来收集用户的位置,并且我想在实际消息内容下显示该位置 (attributedTextForCellBottomLabelAtIndexPath)。我已经解决了所有这些问题,但问题是每个位置对于每条消息都必须是唯一的,这是行不通的。

例如,如果用户从西雅图发送消息,则消息下方应显示 "Seattle"。如果另一个用户向 San Fransisco 发送另一条消息,它应该在他们的消息下方显示 "San Fransisco"。

现在发生的事情是,所有消息都说它们来自用户当前所在的位置(假设他们在西雅图)。所以不管对方是不是在旧金山,消息都会显示是西雅图。

这是一个非常令人困惑的问题,但我认为应该有一个简单的解决办法...

这是 attributedTextForCellBottomLabelAtIndexPath 的代码:

override func collectionView(collectionView: JSQMessagesCollectionView!, attributedTextForCellBottomLabelAtIndexPath indexPath: NSIndexPath!) -> NSAttributedString! {

        let message = messages[indexPath.item]

        // Call data I have retrieved below with message
        let text = getLocation()

        if message.senderId == senderId {
            return nil
        } else {
            return NSAttributedString(string: text)
        }

    }

注意:我有一个名为 getLocation() 的函数,它只是 returns 用户的 city/state/country

下面是 class ChatViewController 上下文的其余代码:

/*
 * Copyright (c) 2016 Ahad Sheriff
 */

import UIKit
import Firebase
import JSQMessagesViewController
import CoreLocation

class ChatViewController: JSQMessagesViewController, CLLocationManagerDelegate {

    // MARK: Properties

    //Firebase
    var rootRef = FIRDatabase.database().reference()
    var messageRef: FIRDatabaseReference!
    var locationRef: FIRDatabaseReference!

    //JSQMessages
    var messages = [JSQMessage]()
    var outgoingBubbleImageView: JSQMessagesBubbleImage!
    var incomingBubbleImageView: JSQMessagesBubbleImage!

    //Location
    var city: String = ""
    var state: String = ""
    var country: String = ""
    var locationManager = CLLocationManager()
    var locationId: String = ""

    func getLocation() -> String {
        if city == ("") && state == ("") && country == (""){
            return "Planet Earth"
        }
        else {
            if country == ("United States") {
                return self.city + ", " + self.state
            }
            else {
                return self.city + ", " + self.state + ", " + self.country
            }
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        // Initialize location
        locationManager.delegate = self
        locationManager.requestWhenInUseAuthorization()

        if CLLocationManager.locationServicesEnabled() {
            //collect user's location
            locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers
            locationManager.requestLocation()
            locationManager.startUpdatingLocation()
        }

        title = "Chat"
        setupBubbles()
        // No avatars

        // Remove file upload icon
        self.inputToolbar.contentView.leftBarButtonItem = nil;
        // Send button
        self.inputToolbar.contentView.rightBarButtonItem.setTitle("Send", forState: UIControlState.Normal)

        collectionView!.collectionViewLayout.incomingAvatarViewSize = CGSizeZero
        collectionView!.collectionViewLayout.outgoingAvatarViewSize = CGSizeZero

        //Firebase reference
        messageRef = rootRef.child("messages")
        locationRef = 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
        {
            //stop updating location
            locationManager.stopUpdatingLocation()

            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(
            purp)
        incomingBubbleImageView = factory.incomingMessagesBubbleImageWithColor(
            redish)
    }

    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.whiteColor()
        }

        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

        let locRef = locationRef.childByAutoId()
        let locItem = [
            senderId : [
                "location": getLocation()
            ]
        ]

        locRef.setValue(locItem)

        // 4
        JSQSystemSoundPlayer.jsq_playMessageSentSound()

        // 5
        finishSendingMessage()

        Answers.logCustomEventWithName("Message sent", customAttributes: nil)

    }

    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()

            Answers.logCustomEventWithName("Visited RoastChat", customAttributes: nil)

        }
    }


    override func collectionView(collectionView: JSQMessagesCollectionView!, attributedTextForCellBottomLabelAtIndexPath indexPath: NSIndexPath!) -> NSAttributedString! {

        let message = messages[indexPath.item]

        // Call data I have retrieved below with message
        let text = getLocation()

        if message.senderId == senderId {
            return nil
        } else {
            return NSAttributedString(string: text)
        }

    }

    override func collectionView(collectionView: JSQMessagesCollectionView, layout collectionViewLayout: JSQMessagesCollectionViewFlowLayout, heightForCellBottomLabelAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        return kJSQMessagesCollectionViewCellLabelHeightDefault
    }

}

注意:您也可以忽略我将用户位置保存到 Firebase 的代码。

提前感谢您的帮助!如果您还有其他问题,请告诉我。

您的问题是您设置的是客户端底部消息标签,而不是消息中的数据。所以每个底部标签都是由用户而不是消息的发起者设置的。

我不知道那之后是否成功,但本质上你是在本地获取位置数据,所以如果你在西雅图的 Mark 和不在西雅图的 Deric 之间进行对话西雅图。

EX.Conversation

马克嗨

Deric Wazzup

它总是会说西雅图,因为您正在本地从客户端获取位置数据并在此函数中进行设置。

func getLocation()

因此,当您查看来自 Mark 的 phone 的对话时,您正在根据 Mark 的位置设置位置数据,即使对于来自 'Deric' 的消息也是如此].

所以解决这个问题的方法是将位置数据保存到消息中并存储在firebase中。然后更改此功能以提取底部标签的数据。类似的东西。

override func collectionView(collectionView: JSQMessagesCollectionView!, attributedTextForCellBottomLabelAtIndexPath indexPath: NSIndexPath!) -> NSAttributedString! {

let message = messages[indexPath.item]

// Call data I have retrieved below with message
let text = message.location   <- Here is a suggested solution ****

if message.senderId == senderId {
    return nil
} else {
    return NSAttributedString(string: text)
}

}

我希望这很清楚。我知道这是一个令人困惑的问题和几乎同样令人困惑的答案。但本质上你需要将位置保存到 messageData post 它到你的后端 firebase 然后显示给定消息。

我认为你绝对是在正确的道路上,只是错过了那一件。

编辑: 我会看看这个 https://firebase.googleblog.com/2015/09/introducing-multi-location-updates-and_86.html

但是为了简单起见,我只解析位置数据并将其保存到 firebase 上的消息对象中,这样当您尝试显示留言。