You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Firebase坐标转CLLocationDegrees实现用户距离计算与排序

解决Firebase坐标转CLLocationDegrees并计算用户距离、排序的问题

先给你纠正一个小误解——从你贴的数据库结构来看,Coordinates下面的经纬度是数字类型(不是字符串),所以不用做字符串转数字的额外操作,省了一步!接下来我帮你梳理完整的实现流程,修正你代码里的问题:

第一步:定义正确的用户模型&获取所有用户数据

首先你需要一个能存储用户ID、经纬度的模型(可以根据需求添加其他属性),然后正确解析Firebase返回的用户数据:

// 定义用户模型
struct Userx {
    let userId: String
    let latitude: CLLocationDegrees
    let longitude: CLLocationDegrees
    // 可以添加其他属性:education、photoPosts等
}

// 全局/类内变量
var refArtists: DatabaseReference!
var allUsers = [Userx]()
let currentUserId = Auth.auth().currentUser?.uid

// 在viewDidLoad里初始化监听
override func viewDidLoad() {
    super.viewDidLoad()
    refArtists = Database.database().reference().child("people")
    startObservingUsers()
}

// 监听所有用户数据
func startObservingUsers() {
    refArtists.observe(.value) { snapshot in
        guard snapshot.exists() else { 
            print("没有用户数据")
            return 
        }
        self.allUsers.removeAll()
        
        // 遍历每个用户的快照
        for userSnapshot in snapshot.children.allObjects as! [DataSnapshot] {
            let userId = userSnapshot.key
            // 跳过当前登录用户
            guard userId != self.currentUserId else { continue }
            
            // 解析用户字典&坐标字典
            guard let userDict = userSnapshot.value as? [String: Any],
                  let coordsDict = userDict["Coordinates"] as? [String: Double],
                  let lat = coordsDict["latitude"],
                  let lon = coordsDict["longitude"] else {
                print("解析用户\(userId)坐标失败")
                continue
            }
            
            // 创建Userx对象加入数组
            let user = Userx(userId: userId, latitude: lat, longitude: lon)
            self.allUsers.append(user)
        }
        
        // 数据获取完成后,计算距离并排序
        self.calculateDistancesAndSortUsers()
        self.table.reloadData()
    }
}

第二步:计算当前用户与其他用户的距离并排序

接下来我们先获取当前用户的坐标,然后遍历所有其他用户,计算距离后按距离从小到大排序:

func calculateDistancesAndSortUsers() {
    guard let currentUserId = currentUserId else {
        print("未登录")
        return
    }
    
    // 只获取一次当前用户的坐标(用observeSingleEvent)
    refArtists.child(currentUserId).child("Coordinates").observeSingleEvent(of: .value) { snapshot in
        guard let currentCoords = snapshot.value as? [String: Double],
              let currentLat = currentCoords["latitude"],
              let currentLon = currentCoords["longitude"] else {
            print("获取当前用户坐标失败")
            return
        }
        
        // 把当前用户的坐标转成CLLocation对象
        let currentLocation = CLLocation(latitude: currentLat, longitude: currentLon)
        
        // 创建一个包含用户和对应距离的数组
        var usersWithDistance = [(user: Userx, distanceInMeters: CLLocationDistance)]()
        
        for user in self.allUsers {
            let userLocation = CLLocation(latitude: user.latitude, longitude: user.longitude)
            // 计算距离(单位:米)
            let distance = currentLocation.distance(from: userLocation)
            usersWithDistance.append((user: user, distanceInMeters: distance))
        }
        
        // 按距离从小到大排序
        let sortedUsers = usersWithDistance.sorted { $0.distanceInMeters < $1.distanceInMeters }
        
        // 打印验证结果
        for sortedItem in sortedUsers {
            print("用户ID: \(sortedItem.user.userId),距离当前用户: \(String(format: "%.2f", sortedItem.distanceInMeters))米")
        }
        
        // 这里可以把排序后的用户数组赋值给tableView的数据源
        // self.sortedUserDataSource = sortedUsers.map { $0.user }
        // self.table.reloadData()
    }
}

你之前代码里的关键错误修正

  1. 错误解析坐标类型:你之前把Coordinates当成字符串解析,实际它是字典类型,必须转成[String: Double]才能拿到经纬度
  2. 直接用DatabaseReference创建CLLocation:你之前尝试把Firebase的引用直接赋值给CLLocation的经纬度,这完全错误——必须先获取快照的value,转成Double类型后才能使用
  3. 遍历逻辑错误:遍历用户时应该遍历people下的每个用户节点,而不是遍历Coordinates的子节点

这样调整后,就能正确实现获取坐标、计算距离、按距离排序用户的需求啦~

内容的提问来源于stack exchange,提问作者noname87f

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:48:52