适用于iOS的GoogleMaps SDK - SWIFT 3:当隐藏标记并添加地图视图时,cpu会陷入100% [英] GoogleMaps SDK for iOS - SWIFT 3: When hiding a marker and then adding the map view back, the cpu gets stuck at 100%

查看:111
本文介绍了适用于iOS的GoogleMaps SDK - SWIFT 3:当隐藏标记并添加地图视图时,cpu会陷入100%的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

场景




  • UIViewController将 self.view 设置为 GMSMapView in viewDidLload

  • 方法将创建标记并将它们存储在 self.markers 并将 marker.map 设置为 self.view as! GMSMapView



到目前为止,该应用表现良好


  • 稍后,在某个操作之后的另一个方法(查看切换这些标记)将所有 self.markers.map 设置为 nil



到这里一切顺利,标记从地图上消失了。 b
$ b


  • 再一次,希望返回这些标记的另一种方法将所有 self.markers.map = self.view设置为! GMSMapView



在这里,cpu被锁定在100%(在8核心机器的模拟器上) / p>

如果 self.markers.map 被重置为 nil 再次,CPU回到〜0%,一切都很好。



问题



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



重现步骤



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



经过一些测试后,它似乎与只处理标记的数量有关。请参阅 LabelCount 并设置为不同值,在我的cpu中,问题出现在200,但没有100个标记(即400标记,因为标记有额外的标记) / p>

示例代码



 导入UIKit 
导入GoogleMaps

class ViewController:UIViewController {
//当标记具有UIImage
时,会发现问题//设置下面为false以查看正常的cpu行为
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 marker = [Int:[GMSMarker]]()
var labels = [Int:[GMSMarker]]()

覆盖func viewDidLoad(){
super.viewDidLoad()
//产生一些随机点
让initCoord = CLLocationCoordinate2D(latitude:ViewController.initLat,longitude:ViewController.initLong)
让deltaCoord = 0.001
for i在0 ... 200 {
let multiplier = Double(i)
self.coords.append(CLLocationCoordinate2D(
latitude:initCoord.latitude + multiplier * deltaCoord,
longitude: initCoord.longitude + multiplier * deltaCoord))
}

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

//添加标记
let label = self.createLabel()
for(idx, co)在self.coords.enumerated(){
//初始标记数组
如果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)
如果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)
如果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
返回标签
}

)func hideMarkers(){
用于self.markers.values.makeIterator()中的标记{
用于标记中的标记{
marker.map = nil
}
}
print(标记隐藏)
}

func showMarkers(){
让mapView = self.view as! GMSMapView
var bounds = GMSCoordinateBounds()
用于self.markers.values.makeIterator()中的标记{
用于标记中的标记{
marker.map = mapView
bounds = bounds.includingCoordinate(marker.position)
}
}
print(在缩放时显示标记:\(mapView.camera.zoom))
//确保我们看到标记
let cameraUpdate = GMSCameraUpdate.fit(bounds)
mapView.animate(with:cameraUpdate)
}

func hideLabels(){
标记为self.labels.values.makeIterator(){
标记中的标记{
marker.map = nil
}
}
print(Labels隐藏)
}

func showLabels(){
让mapView = self.view as! GMSMapView
用于self.labels.values.makeIterator()中的标记{)
用于标记中的标记{
marker.map = mapView
}
}
print(在缩放显示标签:\(mapView.camera.zoom))
}

}

扩展ViewController:GMSMapViewDelegate {
///放大时隐藏标签,放大时显示它们
func mapView(_ mapView:GMSMapView,idleAt position:GMSCameraPosition){
print(Zoom update:\(position.zoom) )
如果position.zoom< self.oldZoom&& position.zoom< ViewController.zoomThreshold {
self.hideLabels()
} else if position.zoom> self.oldZoom&& position.zoom> ViewController.zoomThreshold {
self.showLabels()
}
//跟踪更改
self.oldZoom = position.zoom
}
}


解决方案

这是我使用的群集方法。 b

  //用于检测用户滚动地图的方法
@objc(mapView:didChangeCameraPosition :) func mapView(_:GMSMapView,didChange _:GMSCameraPosition) {
self.counter = self.counter + 1
self.requestForMap(counter:self.counter)
}

//如果用户在0.2秒内没有做任何事请求服务器数据
fileprivate func requestForMap(counter:Int){
DispatchQueue.main.asyncAfter(截止日期:.now()+ 0.2){[weak self] in

警卫let`self` = self else {
return
}

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



code>

这在客户端上

  //获取可见区域的坐标
扩展GMSMapView {

func boundings() - > [String:Any] {
让screenBounds = UIScreen.main.bounds
让topPoint = CGPoint(x:15,y:60)
让bottomPoint = CGPoint(x:screenBounds.width - 15,y:screenBounds.height)
let shoudBeFull = self.camera.zoom> 15 //如果用户放大请求区域
中的所有数据让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 ] ,在我从服务器获取一个对象数组后,通过这个数组,删除那些不在新数据中并添加新数据的元素,这些元素都是新的


Scenario

  • UIViewController sets self.view as GMSMapView in viewDidLload
  • A method will create markers and store them in self.markers and set marker.map to the self.view as! GMSMapView

So far the app behaves well

  • Later, another method after some action (looking to toggle those markers) sets all self.markers.map to nil

Up to here all goes well and the markers are gone from the map

  • Again, another method that wants those markers back, sets all self.markers.map = self.view as! GMSMapView

Here the cpu gets stuck at 100% (on a simulator in an 8 core machine)

If the self.markers.map gets reset to nil again, the cpu goes back to ~0% and all is good.

Question

Is this a limitation on cpu or GoogleMaps SDK? Is there a way to avoid the problem?

Steps to reproduce

After extracting the bits of code related, I added also similar conditions where a Label is being created as an icon for another marker.

After some tests it seems it is related on the amount of markers to process only. See LabelCount and set to different values, in my cpu the problem appeared with 200 but not with 100 markers (ie: 400 markers as there is an extra marker for the label)

Example code

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
    }
}

解决方案

This is clustering approach I am using

//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()
        }
    }
}

to get pins in area I do this on client

// 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
    }
}

then this data as JSON is passed to the server and the server gets pins' data for objects, coordinates of which are inside this bounding. We are using node.js, not sure how it works there.

Then I have an array of currently displayed pins like var pins = [GMSMarker], after I get an array of objects from server I go through this array, remove those, which are not in new data and add those, which are new

这篇关于适用于iOS的GoogleMaps SDK - SWIFT 3:当隐藏标记并添加地图视图时,cpu会陷入100%的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆