ios - 适用于 iOS 的 GoogleMaps SDK - SWIFT 3 : When hiding a marker and then adding the map view back, CPU 卡在 100%

标签 ios google-maps swift3

场景

  • UIViewController 将 self.view 设置为 viewDidLload 中的 GMSMapView
  • 一个方法将创建标记并将它们存储在 self.markers 中,并将 marker.map 设置为 self.view as! GMSMapView

到目前为止,该应用程序运行良好

  • 稍后,另一种方法在执行某些操作后(希望切换这些标记)将所有 self.markers.map 设置为 nil

到这里一切顺利,标记从 map 上消失了

  • 同样,另一种方法想要返回这些标记,将所有 self.markers.map = self.view 设置为! GMSMapView

这里 cpu 卡在 100%(在 8 核机器的模拟器上)

如果 self.markers.map 再次重置为 nil,则 cpu 回到 ~0% 并且一切正常。

问题

这是对 cpu 或 GoogleMaps SDK 的限制吗?有没有办法避免这个问题?

重现步骤

在提取相关代码位之后,我还添加了类似的条件,其中标签被创建为另一个标记的图标。

经过一些测试,它似乎只与要处理的标记数量有关。查看 LabelCount 并设置为不同的值,在我的 cpu 中,问题出现在 200 个标记而不是 100 个标记(即:400 个标记,因为标签有一个额外的标记)

示例代码

import UIKit
import GoogleMaps

class ViewController: UIViewController {
    // The problem is noticed when markers have a UIImage
    // Set below to false to see normal cpu behaviour
    static let LabelsMakeProblem = true
    static let LabelCountFine = 100
    static let LabelCountProblems = 200
    static let LabelCount = ViewController.LabelCountProblems
    static let labelWidth = 200
    static let labelHeight = 20

    var coords = [CLLocationCoordinate2D]()
    static let initLat = Double(-33)
    static let initLong = Double(-70)
    static let zoomThreshold = Float(13)
    var oldZoom : Float!
    var markers = [Int: [GMSMarker]]()
    var labels = [Int: [GMSMarker]]()

    override func viewDidLoad() {
        super.viewDidLoad()
        // Generate some random points
        let initCoord = CLLocationCoordinate2D(latitude: ViewController.initLat, longitude: ViewController.initLong)
        let deltaCoord = 0.001
        for i in 0...200 {
            let multiplier = Double(i)
            self.coords.append(CLLocationCoordinate2D(
                latitude: initCoord.latitude + multiplier * deltaCoord,
                longitude: initCoord.longitude + multiplier * deltaCoord))
        }

        // Create a map
        let camera = GMSCameraPosition.camera(withLatitude: ViewController.initLat, longitude: ViewController.initLong, zoom: ViewController.zoomThreshold * 1.3)
        let mapView = GMSMapView.map(withFrame: .zero, camera: camera)
        mapView.delegate = self
        self.view = mapView
        self.oldZoom = mapView.camera.zoom

        // Add markers
        let label = self.createLabel()
        for (idx, coord) in self.coords.enumerated() {
            // Init marker arrays
            if self.markers[idx] == nil {
                self.markers[idx] = [GMSMarker]()
            }
            if self.labels[idx] == nil {
                self.labels[idx] = [GMSMarker]()
            }
            let marker = GMSMarker(position: coord)
            marker.map = mapView
            self.markers[idx]?.append(marker)
            if ViewController.LabelsMakeProblem {
                label.text = coord.latitude.description
                let contextSize = CGSize(width: ViewController.labelWidth, height: ViewController.labelHeight)
                let opaque = false
                UIGraphicsBeginImageContextWithOptions(contextSize, opaque, UIScreen.main.scale)
                if let currentContext = UIGraphicsGetCurrentContext(){
                    let labelBox = CGRect(x: 2, y: 2,
                                          width: ViewController.labelWidth, height: ViewController.labelHeight)
                    label.frame = labelBox
                    label.layer.render(in: currentContext)
                    let labelImage = UIGraphicsGetImageFromCurrentImageContext()
                    let labelMarker = GMSMarker(position: coord)
                    labelMarker.icon = labelImage
                    labelMarker.map = mapView
                    self.labels[idx]?.append(labelMarker)
                }
                UIGraphicsEndImageContext()
            }
        }

    }

    private func createLabel() -> UILabel{
        let label = UILabel()
        label.backgroundColor = UIColor.clear
        label.shadowColor = UIColor.white
        label.shadowOffset = CGSize(width: 5, height: 2)
        label.textColor = UIColor.black
        label.adjustsFontSizeToFitWidth = true
        label.textAlignment = .center
        return label
    }

    func hideMarkers() {
        for markers in self.markers.values.makeIterator() {
            for marker in markers {
                marker.map = nil
            }
        }
        print("Markers hidden")
    }

    func showMarkers() {
        let mapView = self.view as! GMSMapView
        var bounds = GMSCoordinateBounds()
        for markers in self.markers.values.makeIterator() {
            for marker in markers {
                marker.map = mapView
                bounds = bounds.includingCoordinate(marker.position)
            }
        }
        print("Show markers at zoom:\(mapView.camera.zoom)")
        // Ensure we see the markers
        let cameraUpdate = GMSCameraUpdate.fit(bounds)
        mapView.animate(with: cameraUpdate)
    }

    func hideLabels() {
        for markers in self.labels.values.makeIterator() {
            for marker in markers {
                marker.map = nil
            }
        }
        print("Labels hidden")
    }

    func showLabels() {
        let mapView = self.view as! GMSMapView
        for markers in self.labels.values.makeIterator() {
            for marker in markers {
                marker.map = mapView
            }
        }
        print("Show labels at zoom:\(mapView.camera.zoom)")
    }

}

extension ViewController : GMSMapViewDelegate {
    /// Hide labels when zooming out and show them when zooming in
    func mapView(_ mapView: GMSMapView, idleAt position: GMSCameraPosition) {
        print("Zoom update: \(position.zoom)")
        if position.zoom < self.oldZoom && position.zoom < ViewController.zoomThreshold {
            self.hideLabels()
        } else if position.zoom > self.oldZoom && position.zoom > ViewController.zoomThreshold {
            self.showLabels()
        }
        // Track changes
        self.oldZoom = position.zoom
    }
}

最佳答案

这是我正在使用的聚类方法

//method to detect when user scrolls map
@objc(mapView:didChangeCameraPosition:) func mapView(_: GMSMapView, didChange _: GMSCameraPosition) {
    self.counter = self.counter + 1
    self.requestForMap(counter: self.counter)
}

//if user did nothing for 0.2 seconds request data from server
fileprivate func requestForMap(counter: Int) {
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { [weak self] in

        guard let `self` = self else {
            return
        }

        if counter == self.counter {
            self.sessionManager.session.invalidateAndCancel()
            self.requestData()
        }
    }
}

为了获取区域中的图钉,我在客户端上执行此操作

// get coordinates of visible area
extension GMSMapView {

    func boundings() -> [String: Any] {
        let screenBounds = UIScreen.main.bounds
        let topPoint = CGPoint(x: 15, y: 60)
        let bottomPoint = CGPoint(x: screenBounds.width - 15, y: screenBounds.height)
        let shoudBeFull = self.camera.zoom > 15 //if user is zoomed in a lot request all data in area
        let bouding = [
            "top": [
                "lat": self.projection.coordinate(for: topPoint).latitude,
                "lon": self.projection.coordinate(for: topPoint).longitude,
            ],
            "bottom": [
                "lat": self.projection.coordinate(for: bottomPoint).latitude,
                "lon": self.projection.coordinate(for: bottomPoint).longitude,
            ],
            "full": shoudBeFull,
        ] as [String: Any]
        return bouding
    }
}

然后将此数据作为 JSON 传递给服务器,服务器获取对象的引脚数据,其坐标在此边界内。我们正在使用 node.js,不确定它在那里是如何工作的。

然后我有一组当前显示的引脚,如 var pins = [GMSMarker],在我从服务器获取一组对象后,我遍历该数组,删除那些不在新的中数据并添加那些,这是新的

关于ios - 适用于 iOS 的 GoogleMaps SDK - SWIFT 3 : When hiding a marker and then adding the map view back, CPU 卡在 100%,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43910085/

相关文章:

ios - 缺少包产品 <包依赖项名称>

ios - 当 UITableViewController 的子类包含在 subview 中时,它不会触发 didSelectRowAtIndexPath,我该如何解决这个问题?

objective-c - 如何使 MPMoviePlayerViewController 以横向模式启动但仍允许更改方向

java - 最后一个已知位置是在多长时间前记录的?

ios - UIPickerView 的 "reusing view"始终为 nil

ios - UITextField 未显示在 View 中

ios - 如何创建一个包含 key ==> Value 的 .Plist?

java - Android透明Fragment/GoogleMap

angular - ionic 3 : Uncaught (in promise): ReferenceError: google is not defined ReferenceError

swift - 在 Swift 3 中将数组多个对象添加到 [Any]