【问题标题】:create a function that finds the closest object base on Lat long in an array创建一个函数,在数组中查找基于 Lat long 的最近对象
【发布时间】:2020-09-13 23:08:53
【问题描述】:

我创建了以下代码,用于获取数组中离用户位置最近的点。这是行不通的。我可以得到位置,但不是最近的。我的目标是能够找到最近的点并打印出项目的 pm2 值。

import UIKit
import CoreLocation

extension Point {
    var location: CLLocation { .init(latitude: latitude ?? 5, longitude: longitude ?? 5) }
}

class popAirViewController: UITableViewController, CLLocationManagerDelegate {
    private let popAirURL = "https://www.purpleair.com/json"
    private var results = [Point]()
    var locationManager: CLLocationManager!
    var PM5Value: Int = 5
    var points: [Point] = []
    var destination: CLLocation?
    //Temporary background image
    var backgroundImage: String = "Green"
    // sets PM5 text Label
    @IBOutlet weak var latLabel: UILabel!
    //@IBOutlet weak var latLabel: UILabel!
     func PM5Text(){
        latLabel.text = "56.5"
        latLabel.textAlignment = .center
        latLabel.numberOfLines = 10
        latLabel.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height+300)
     }
    override func viewDidLoad() {
        self.tableView.backgroundView = UIImageView(image: UIImage(named: backgroundImage))
        self.tableView.backgroundColor = .clear
        super.viewDidLoad()
        //sets background images
        if 0 ... 50 ~= Int(PM5Value) {
        self.tableView.backgroundView = UIImageView(image: UIImage(named: "Green"))}
        else if 51 ... 100 ~= Int(PM5Value) {
        self.tableView.backgroundView = UIImageView(image: UIImage(named: "Yellow"))}
        else if 101 ... 150 ~= Int(PM5Value) {
        self.tableView.backgroundView = UIImageView(image: UIImage(named: "Orange"))}
        else if 151 ... 1000 ~= Int(PM5Value) {
        self.tableView.backgroundView = UIImageView(image: UIImage(named: "Purple"))}
        print(PM5Value)
        self.navigationController?.navigationBar.isHidden = true;
        //let fullImageView = UIImageView(frame: self.view.frame)
        //view.addSubview(fullImageView)
        if (CLLocationManager.locationServicesEnabled())
        {
            locationManager = CLLocationManager()
            locationManager.delegate = self
            locationManager.desiredAccuracy = kCLLocationAccuracyBest
            locationManager.requestAlwaysAuthorization()
            locationManager.startUpdatingLocation()
        }
        tableView.estimatedRowHeight = 92.0
        tableView.rowHeight = UITableView.automaticDimension
        getLatestLocations()
    }
    // MARK: - Table view data source
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        PM5Text()
    }
    override func numberOfSections(in tableView: UITableView) -> Int {
        // Return the number of sections
        return 1
    }
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // Return the number of rows
        return results.count
    }
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! KivaLoanTableViewCell
        // Configure the cell...
        cell.amountLabel.text = results[indexPath.row].pm2
        return cell
    }
    // MARK: - Helper methods
    func getLatestLocations() {
        guard let pointUrl = URL(string: popAirURL) else {
            return
        }
        let request = URLRequest(url: pointUrl)
        let task = URLSession.shared.dataTask(with: request, completionHandler: { (data, response, error) -> Void in
            if let error = error {
                print(error)
                return
            }
            // Parse JSON data
            if let data = data {
                self.results = self.parseJsonData(data: data)
                // Reload table view
                OperationQueue.main.addOperation({
                    self.tableView.reloadData()
                })
            }
        })
        task.resume()
    }
    func parseJsonData(data: Data) -> [Point] {
        var points = [Point]()
        do {
            let jsonResult = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.mutableContainers) as? NSDictionary
            // Parse JSON data
            let jsonPoints = jsonResult?["results"] as! [AnyObject] as [AnyObject]
            for jsonPoint in jsonPoints {
                var point = Point()
                point.latitude = jsonPoint["Lat"] as? Double
                point.longitude = jsonPoint["Lon"] as? Double
                point.pm2 = jsonPoint["PM2_5Value"] as? String
                let latq = point.latitude
                let lonq = point.longitude
                //let destination = CLLocationCoordinate2DMake(latq ?? 5, lonq ?? 5)
                self.destination = CLLocation(latitude: latq ?? 5, longitude: lonq ?? 5)
                points.append(point)
                //print(destination)
              print("Destination=: \(destination!)")
            }
        } catch {
            print(error)
        }
        return points 
    }
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        var userLocation:CLLocation = locations[0]
        let long = userLocation.coordinate.longitude;
        let lat = userLocation.coordinate.latitude;
        if let closestPoint = points.min(by:{
            $0.location.distance(from: userLocation) < $1.location.distance(from: userLocation)
        }) {
            print("closest point:", closestPoint)
        }
        if destination == nil{
            return
        }
        userLocation = CLLocation(latitude: lat , longitude: long )
    }
}

【问题讨论】:

  • 如果你发布你的json字符串会容易得多
  • 谢谢利奥。我按照建议使用完整代码编辑了帖子,但被拒绝了。
  • 您可能试图编辑我的答案。它需要得到批准。正如我已经提到的,只需使用我在帖子中建议的内容更新您的代码。
  • 我仍然无法让它工作。我现在用完整的代码编辑了我的原始帖子。
  • 你遇到了什么错误?如果您没有收到错误,print("closest point:", closestPoint) 会打印什么?

标签: arrays json swift


【解决方案1】:

您可以使用 CLLocation distance(from: CLLocation) 方法获取与当前位置的距离,并使用min(by: ) 方法获取与您的点的最小距离:

var points: [Point] = []

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    let location = locations[0]
    if let closestPoint = points.min(by: {
        $0.location.distance(from: location) < $1.location.distance(from: location)
    }) {
        print("closest point:", closestPoint)
    }
    
}

添加此助手以从您的位置构建位置:

extension Point {
    var location: CLLocation { .init(latitude: latitude, longitude: longitude) }
}

顺便说一句,Swift 命名约定以小写字母开头:

struct Point: Equatable {
    let pm2: String
    let latitude: Double
    let longitude: Double
}

编辑/更新:与您的问题无关,但您应该使用 Codable 协议来解析来自 API 的 json 响应:

游乐场测试:

import UIKit
import CoreLocation
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true

struct Root: Codable {
    let results: [Point]
}

struct Point: Codable {
    let pm2: String?
    let latitude, longitude: Double?
    enum CodingKeys: String, CodingKey {
        case pm2 = "PM2_5Value", latitude = "Lat", longitude = "Lon"
    }
}

extension Point {
    var location: CLLocation { .init(latitude: latitude ?? .zero, longitude: longitude ?? .zero) }
}
let popAirURL = "https://www.purpleair.com/json"
URLSession.shared.dataTask(with: URL(string: popAirURL)!) { data, response, error in
    guard let data = data else {
        print("error", error!)
        return
    }
    do {
        let points = try JSONDecoder().decode(Root.self, from: data).results
        let location = CLLocation(latitude: 38, longitude: -121)
        if let closestPoint = points.min(by: {
            $0.location.distance(from: location) < $1.location.distance(from: location)
        }) {
            print("closest point:", closestPoint)  // closest point: Point(pm2: Optional("107.47"), latitude: Optional(38.100134), longitude: Optional(-120.860454))
        }
    } catch {
        print(error)
    }
}.resume()

【讨论】:

  • 感谢 Leo,将解决命名约定。您的代码在这一行 if let closestPoint = points.min(by: { 上给了我这个错误“无法在当前上下文中推断闭包类型”
  • 编辑您的问题并发布您的实际代码。如果你用上面的代码更新你的项目,你不会得到任何错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-10
  • 1970-01-01
  • 2018-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多