ios - 如何在 Swift 中同步对我的 web 服务的调用并在 map 上显示数据(使用标记聚类)?

标签 ios swift mkmapview nsoperation markerclusterer

我正在编写一个在 map 上显示大量点的应用程序。我可以将它们全部作为 json 获取并将其放在 map 上,但是这样点太多了,所以我考虑实现标记集群。因为我在 Swift 工作,所以我决定使用这个库:https://github.com/ribl/FBAnnotationClusteringSwift

为了避免在我的 map 上使用大量数据,我创建了一个后端网络服务,该服务获取当前用户位置和可见半径作为参数。作为答案,它返回一个带有兴趣点 gps 坐标的 JSON。

因为我使用的是 AlamoFireSwiftyJSON,所以我创建了一个方法来从我的网络服务中获取记录,如下所示,它使用 map (纬度和经度)以及可见半径:

func fetchRecords(radius: Double, lat: Double, lon: Double){
        Alamofire.request(.GET, "http://mywebservice/records", parameters: ["long": lon, "lat": lat, "radius": radius ])
            .responseJSON { response in

                switch response.result {
                case .Success:
                    self.array.removeAll()
                    if let jsonData = response.result.value as? [[String: AnyObject]] {
                        for requestJSON in jsonData {
                            if let request = SingleRecord.fromJSON(JSON(requestJSON)){

                                let pinOne = FBAnnotation()
                                pinOne.coordinate = CLLocationCoordinate2D(latitude: request.latitude, longitude: request.longitude)
                                self.array.append(pinOne)

                            }
                        }
                    }

                    self.clusteringManager.addAnnotations(self.array)

                case .Failure(let error):
                    print("SWITCH ERROR")
                    print(error)
                }

        }
    }

我正在获取当前位置的记录,并为每条记录创建一个 FBAnnotation()。此外,我将所有点附加到数组“self.array”。到目前为止一切顺利。

我想始终从服务器获取实际数据,所以我决定实现方法 regionDidChangeAnimated:

func mapView(mapView: MKMapView, regionDidChangeAnimated animated: Bool) {

    self.center = mapView.centerCoordinate.latitude.description
    self.radius = self.getRadius(mapView)


    NSOperationQueue().addOperationWithBlock({

        self.fetchRecords(self.radius, lat: self.mapView.centerCoordinate.latitude, lon: self.mapView.centerCoordinate.longitude)

        let mapBoundsWidth = Double(self.mapView.bounds.size.width)

        let mapRectWidth:Double = self.mapView.visibleMapRect.size.width

        let scale:Double = mapBoundsWidth / mapRectWidth
        let annotationArray = self.clusteringManager.clusteredAnnotationsWithinMapRect(self.mapView.visibleMapRect, withZoomScale:scale)

        self.clusteringManager.displayAnnotations(annotationArray, onMapView:self.mapView)

    })

我在上面所做的是 - 首先 - 获取给定位置的所有当前记录,然后使用 FBAnnotationClusteringSwift 中准备好的代码。

但是不行,我怀疑是线程的问题,可能是array还没有填满,或者什么的(?),但是结果如下:

当我打开 map 时,我看到:

enter image description here

但是当我稍微移动 map 时,标记突然增加:

enter image description here

每一步都一样:

enter image description here

等等。当我放大 map 时也会发生同样的情况,即使屏幕中间只剩下一个标记簇 - 每缩放一步它都会增加其数量而不是更改为单个图钉。每次调用 fetchRecords 后,我都试图从数组中删除所有元素,但它也没有帮助。

有谁知道这里可能是什么问题?我知道这是一个罕见的话题,但也许有人可以给我任何提示,我将非常感激。谢谢!

最佳答案

在你的 fetch 函数中添加一个完成处理程序

func fetchRecords(radius: Double, lat: Double, lon: Double, completionHandler: (() -> Void)?){
    Alamofire.request(.GET, "http://mywebservice/records", parameters: ["long": lon, "lat": lat, "radius": radius ])
        .responseJSON { response in

            switch response.result {
            case .Success:
                self.array.removeAll()
                if let jsonData = response.result.value as? [[String: AnyObject]] {
                    for requestJSON in jsonData {
                        if let request = SingleRecord.fromJSON(JSON(requestJSON)){

                            let pinOne = FBAnnotation()
                            pinOne.coordinate = CLLocationCoordinate2D(latitude: request.latitude, longitude: request.longitude)
                            self.array.append(pinOne)

                        }
                    }
                }
                //TODO: -Clean your data before adding new things

                self.clusteringManager.addAnnotations(self.array)
                //call the closure after everything is done
                completionHandler()

            case .Failure(let error):
                print("SWITCH ERROR")
                print(error)
            }

    }
}

并在主函数中使用

self.fetchRecords(self.radius, lat: self.mapView.centerCoordinate.latitude, lon: self.mapView.centerCoordinate.longitude) { [weak self] in

    let mapBoundsWidth = Double(self?.mapView.bounds.size.width)

    let mapRectWidth:Double = self?.mapView.visibleMapRect.size.width

    let scale:Double = mapBoundsWidth / mapRectWidth
    let annotationArray = self?.clusteringManager.clusteredAnnotationsWithinMapRect(self.mapView.visibleMapRect, withZoomScale:scale)

    self?.clusteringManager.displayAnnotations(annotationArray, onMapView:self?.mapView)
}

这样你将确保 self?.clusteringManager.displayAnnotations 在你的 fetch 之后完成

关于ios - 如何在 Swift 中同步对我的 web 服务的调用并在 map 上显示数据(使用标记聚类)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35649480/

相关文章:

objective-c - 检查 mkmapview 上点击了哪个 map View 注释

objective-c - 当绘制较小的图像时,drawInRect 会失去分辨率吗?

ios - Apple 是否将电子邮件限制为 Facebook 登录中的必填字段?

ios - Swift 中 Struct 中 String 和 NSString 的区别

ios - 删除不存在的 key 时,Firebase 数据库不会返回错误

c - 在 UIViewController 中添加 View 时出现空白

iphone - 使用CALayer时等效的UIViewAnimationOptionBeginFromCurrentState

ios - Swift/Math - 缩放时保持原点

ios - 文档选择器 Controller 的多项选择

ios - 如何在放大时在 mkmapview 上显示更多注释并在缩小时显示更少?