计算两个坐标之间的距离并将其显示在 UITableViewCell 的标签内

问题描述

我正在尝试计算两个坐标之间的距离并将它们显示在 UITableViewCell 的标签内。

到目前为止一切顺利 - 我现在的问题是,每次我滚动 tableview 时,标签的值都会改变并且距离完全混淆...... 到目前为止我读到的是,这个问题是由于出队和可重用数据造成的

但在我继续说之前,这是我的代码

class JobTableViewCell: UITableViewCell,CLLocationManagerDelegate {

@IBOutlet weak var distance: UILabel!

let location = CLLocationManager()
static var takenLocation: String?

override func layoutSubviews() {
    super.layoutSubviews()
    location.delegate = self
    self.location.startUpdatingLocation()
}

    
func locationManager(_ manager: CLLocationManager,didUpdateLocations locations: [CLLocation]) {
    if let lastLocation = locations.last {
        let geocoder = CLGeocoder()
        //get job coordinates
        geocoder.geocodeAddressstring(job.location) { placemarks,error in
            let placemarkW = placemarks?.first
            if let placemark = placemarkW
            {
                let lat = placemark.location?.coordinate.latitude
                let lon = placemark.location?.coordinate.longitude
                let jobLocation = CLLocation(latitude: lat!,longitude: lon!)
                //get user coordinates
                let myLocation = CLLocation(latitude: lastLocation.coordinate.latitude,longitude: lastLocation.coordinate.longitude)
                //get distance between coordinates
                let distance = myLocation.distance(from: jobLocation) / 1000
                self.distance.text = String(format: "%.01fkm",distance)
                self.job.distance = distance
                //JobTableViewCell.takenLocation = String(format: "%.01km",distance)
            } else {
                self.distance.text = "Not Valid"
                self.job.distance = 0.0

            }
            self.reloading?.reloadIt()
        }
    }
    self.location.stopUpdatingLocation()
    guard let _: CLLocationCoordinate2D = manager.location?.coordinate else { return }
}

}

我在计算或显示距离方面没有任何问题,我唯一的问题是我不知道如何重用 LabelData(如果这甚至是正确的方法:/)

据我所知,我需要转到 TableViewController 并编写类似 cell.distance.text = idonwkNowwhat内容,但这就是我卡住的地方

更新:

func tableView(_ tableView: UITableView,cellForRowAt indexPath: IndexPath) -> UITableViewCell{
    let cell = tableView.dequeueReusableCell(withIdentifier: "Jobcell",for: indexPath) as! JobTableViewCell
    let job = jobs[indexPath.row]
    cell.job = job
    cell.jobHeader.text = job.postHeader //just leave this line so the function is not empty 


    //cell.cellDelegate = self
    return cell
}

解决方法

这里有很多问题。

  1. 这并不是非常重要,但是获取地标、查找位置、获取纬度和经度以及构建新位置的过程是不必要的复杂。从 CLPlaceMark 返回的 geocodeAddressString 数组有一个 location,它是 CLLocation,所以直接使用它:

    geocoder.geocodeAddressString(job.location) { placemarks,error in
        guard
            let jobLocation = placemarks?.first(where: { $0.location != nil })?.location
        else {
            // handle error where no placemark with a valid location was found
            return
        }
    
        // get distance between coordinates
    
        let distance = myLocation.distance(from: jobLocation) / 1000
    
        // now update model or UI here
    }
    

    同样,didUpdateLocations 为您提供一组 CLLocation 对象,因此获取最后一个有效位置(即 horizontalAccuracy 为非负的位置)是一行代码:

    func locationManager(_ manager: CLLocationManager,didUpdateLocations locations: [CLLocation]) {
        guard
            let myLocation = locations.last(where: { $0.horizontalAccuracy >= 0 }) 
        else { return }
    
        // now just use `myLocation`
    }
    
  2. job.location 的地理编码不属于 didUpdateLocations

    如果您当前的位置更新,您真的需要再次对作业的位置进行地理编码吗? (我知道您似乎取消了位置更新,但这表明用户位置的逻辑与地理编码过程的一般性混淆。)

    此外,我建议 Job 对象不应具有 distance 属性,而应仅具有 coordinate 属性,即 CLLocationCoordinate2D。坐标是工作的属性,而不是与您当时碰巧所在位置的距离。应在显示和更新单元格时计算作业到用户当前位置的 CLLocationDistance

    将位置更新与地理编码分离的优点在于,您可以轻松地(例如,如果需要)保持位置更新。显然,如果您只显示到最近十分之一公里的距离,您可以添加 100 米的 distanceFilter,以减少正在执行的不必要的工作量。

  3. 您已将 CLLocationManager 设为单元格的属性(假设您的委托方法正在更新单元格属性)。经理不应该是单元的属性。对于整个视图(或可能是整个应用),您实际上只需要/想要一个 CLLocationManager

  4. 您正在更新异步完成处理程序闭包内的单元格属性。您需要非常小心,因为您不知道在关闭完成时单元格是否已被重用。如果您确实想要异步更新单元格,则应重新查询模型集合以获取更新的行。

所以,把这一切放在一起,我建议:

  • 更改Job模型以捕获坐标,而不是距离;

  • 当要显示单元格时,根据需要对地址进行地理编码(将坐标保存在模型中以节省执行冗余地理编码请求的需要);

  • 有一个 CLLocationManager 实例,只需在位置更改时重新加载表。

例如参见https://github.com/robertmryan/GeocoderTableView.git

,

几件事:

正如 Sandeep 在他们的评论中所说,在 layoutSubviews 中调用 self.location.startUpdatingLocation() 是一个坏主意。在 viewDidLoad()viewDidAppear() 执行此操作。

下一点:调用 geocodeAddressString(_:completionHandler:) 的完成处理程序获取用户的当前位置并计算新的距离值。然后将其存储到标签视图 distance 的文本中。大概这是一个不属于表格视图单元格的标签。

您应该做的是将距离值(作为双精度值)保存到视图控制器中的实例变量中,然后告诉您的表视图重新加载任何显示距离信息的单元格。如果这是单个单元格,您可以使用单个 indexPath 调用 reloadRows(at:with:)。如果它是多个(但不是全部)单元格,您可以传入一组 IndexPaths 以供单元格更新。如果您需要更新表格视图中的所有单元格,请调用 reloadData()

应该编写您的 tableView(_:cellForRowAt:) 表视图委托方法,以从您的实例变量中获取距离值并将其安装在需要它的单元格中。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...