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() } }
你之前代码里的关键错误修正
- 错误解析坐标类型:你之前把
Coordinates当成字符串解析,实际它是字典类型,必须转成[String: Double]才能拿到经纬度 - 直接用DatabaseReference创建CLLocation:你之前尝试把Firebase的引用直接赋值给CLLocation的经纬度,这完全错误——必须先获取快照的
value,转成Double类型后才能使用 - 遍历逻辑错误:遍历用户时应该遍历
people下的每个用户节点,而不是遍历Coordinates的子节点
这样调整后,就能正确实现获取坐标、计算距离、按距离排序用户的需求啦~
内容的提问来源于stack exchange,提问作者noname87f
相关产品推荐
相关产品推荐

