适用于 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%
问题描述
- UIViewController 在
viewDidLload
中将 - 一个方法将创建标记并将它们存储在
self.markers
中并将marker.map
设置为self.view as!GMSMapView
self.view
设置为 GMSMapView
- UIViewController sets
self.view
asGMSMapView
inviewDidLload
- A method will create markers and store them in
self.markers
and setmarker.map
to theself.view as! GMSMapView
到目前为止,该应用运行良好
So far the app behaves well
- 稍后,在某些操作(寻找切换这些标记)之后的另一个方法将所有
self.markers.map
设置为nil
到这里一切顺利,标记从地图上消失
Up to here all goes well and the markers are gone from the map
- 同样,另一种想要返回这些标记的方法,将所有
self.markers.map = self.view 设置为!GMSMapView
这里 cpu 卡在 100%(在 8 核机器的模拟器上)
Here the cpu gets stuck at 100% (on a simulator in an 8 core machine)
如果 self.markers.map
再次被重置为 nil
,cpu 会回到 ~0% 并且一切正常.
If the self.markers.map
gets reset to nil
again, the cpu goes back to ~0% and all is good.
这是对 CPU 或 GoogleMaps SDK 的限制吗?有没有办法避免这个问题?
Is this a limitation on cpu or GoogleMaps SDK? Is there a way to avoid the problem?
在提取相关的代码位后,我还添加了类似的条件,其中一个标签被创建为另一个标记的图标.
After extracting the bits of code related, I added also similar conditions where a Label is being created as an icon for another marker.
经过一些测试,它似乎只与要处理的标记数量有关.请参阅 LabelCount
并设置为不同的值,在我的 cpu 中,问题出现在 200 而不是 100 个标记(即:400 个标记,因为标签有一个额外的标记)
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)
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()
}
}
}
为了获得区域内的别针,我在客户端上执行此操作
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
}
}
然后将此数据作为 JSON
传递给服务器,服务器获取对象的 pin 数据,其坐标在此边界内.我们正在使用 node.js,不确定它在那里是如何工作的.
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.
然后我有一个当前显示的引脚数组,如 var pins = [GMSMarker]
,在我从服务器获取一组对象后,我通过这个数组,删除那些不在新的数据并添加那些新的
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屋!