反向地理编码CLGeocoder内存泄漏。

问题描述 投票:0回答:1

我正在编写一个使用反转地理编码和CLGeocoder命令的应用程序,我正在使用Xcode 11.3和Swift 5。我使用的是Xcode 11.3和Swift 5。

我使用的代码是标准的,并且可以工作,即我可以很好地执行反向地理编码。 问题是,我的应用程序每隔5分钟就会调用反向地理编码来报告当前的地址--这个工作绝对正常......然而,大约4天后,我的应用程序在我的测试iPhone上不再工作了。 当我说不再工作,我的意思是,我点击图标打开应用程序,它返回到IOS。 当我在模拟器上运行应用程序时,我可以看到大约每5分钟内存消耗就会增加0.01MB,这表明也许在4天后容器内存已满,应用程序停止正常工作。

因此综上所述,我的问题是有没有人注意到,当使用反向地理编码一段时间后,他们的应用无法正常运行。

我知道它的反向地理编码,因为如果我不调用函数,那么内存消耗就会保持静态。

我知道有限制的频率,你可以调用reversegeolocation - 也许苹果知道它的泄漏,这就是为什么限制在那里(以分散人们从做我正在做的事情)?

我已经附上了整个股票标准代码。 我稍微修改了一下,去掉了频率元素,现在让你点击屏幕上的按钮来触发反向定位......。大约10次点击后,你会看到你的内存增加,如果你继续这样做,你会继续看到内存增加......。(最好每隔15 - 20秒试一次)....

我的代码。

import Foundation
import UIKit
import CoreLocation


class ViewController: UIViewController, CLLocationManagerDelegate {

    let locationManager:CLLocationManager = CLLocationManager()

    var currentLatitude: Double = 37.33030778
    var currentLongitude: Double = -122.02896839


    @IBOutlet var myButton: UIButton!



    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.

        locationManager.delegate = self

        print("Running")

    }


    @IBAction func myButtonPressed(_ sender: Any) {
        // Print inside IBACTION
        print("Inside IBACTION")

        // incease latitude and longitue
        currentLatitude = currentLatitude + 0.10
        currentLongitude = currentLongitude + 0.10
        myReverseGeo()
    }



    func myReverseGeo() {

        let location = CLLocation(latitude: currentLatitude, longitude: currentLongitude)

        let geocoder: CLGeocoder = CLGeocoder()

        geocoder.reverseGeocodeLocation(location, completionHandler: {(placemarks, error) -> Void in

            if error != nil {
                let errorString = String(describing: error?.localizedDescription)

                print("Reverse Geocoding failed")
                print(errorString)

                return
            }

            let placemark = placemarks! as [CLPlacemark]

                if placemark.count > 0 {

                    let placemark = placemarks![0]

                    let eventCity = placemark.locality
                    let eventState = placemark.subAdministrativeArea
                    let eventCountry = placemark.country

                    print(eventCity!)
                    print(eventState!)
                    print(eventCountry!)

                }
        })

    }

}

First image prior to doing a Reverse Geolocation

Several minutes in after a number of calls to Reverse Geolocation

After 14 mins the utilisation is up to 12MB, after starting at 10.7MB大家有什么办法可以阻止内存泄漏(除了不使用反向地理编码)?

swift memory-leaks reverse-geocoding clgeocoder
1个回答
0
投票

我不认为你的内存问题是来自于这个例程。我运行了144次迭代(12分钟,每5秒发射一次;相当于每5分钟运行12小时),没有看到明显的内存增长。

enter image description here

(每一个 "兴趣点 "标志都是一个反向地理编码请求)

不过,有几点观察。

  1. 但有几点观察: CLGeocoder 每一个请求,我都会实例化一个,并反复执行 reverseGeocodeLocation 用这一个实例进行调用。

  2. 关于对 CLGeocoder主要的限制是你不能同时执行geocode请求(如果你试图这样做,它只是失败与错误)。

  3. 关于你为什么会出现内存增长,我无法评论,因为我无法重现你描述的行为。也许你打开了一些调试选项(malloc堆栈痕迹,僵尸等)。这将产生你所描述的行为。关闭所有可选的内存诊断程序,并执行一次发布构建。

  4. 如果内存在增长,有两个工具是有用的。

    • "Debug Memory Graph "将向你展示已经创建的对象,你可以查看在哪里建立了哪些强引用。

    • 如果你使用Instruments中的 "Leaks "工具(它还提供了 "Allocations "工具)对应用程序进行剖析,你就可以确切地检查哪些分配在哪里被创建了。 

    如需了解更多信息,请参阅 Leaks仪器不显示内存泄漏,如何调试?

  5. 一般情况下,如果我们要寻找用户位置的更新,在 访问服务重变服务 是更高效的方式。为什么要通过每五分钟做一次来消耗用户的电池呢,因为用户会有很长的时间跨度没有移动。让设备在用户移动时告诉你的应用,而不是不断地进行投票。


这不是非常相关的,但这是我生成上面图片的代码。

var counter = 0
var simulatedTimeInterval: TimeInterval = 0
let maxCounter = 12 * 60 / 5 // how many geocode request in 12 hours, every five minutes

let formatter: DateComponentsFormatter = {
    let formatter = DateComponentsFormatter()
    formatter.unitsStyle = .full
    return formatter
}()

func startTimer() {
    Timer.scheduledTimer(withTimeInterval: 5, repeats: true) { [weak self] timer in
        guard
            let self = self,
            self.counter < self.maxCounter
        else {
            timer.invalidate()
            return
        }

        self.counter += 1
        self.simulatedTimeInterval += 60 * 5 // add 5 minutes
        let simulatedTimeString = self.formatter.string(from: self.simulatedTimeInterval)!

        os_signpost(.event, log: pointsOfInterest, name: "Geocode", "Request #%d @ %{public}@", self.counter, simulatedTimeString)

        self.updateLocation()
        self.myReverseGeo()
    }
    print("Running")
}

func updateLocation() {
    currentLatitude += 0.010
    currentLongitude += 0.010
}

func myReverseGeo() {
    let location = CLLocation(latitude: currentLatitude, longitude: currentLongitude)

    let geocoder = CLGeocoder()

    geocoder.reverseGeocodeLocation(location) { placemarks, error in
        guard
            error == nil,
            let placemark = placemarks?.first,
            let city = placemark.locality,
            let state = placemark.administrativeArea,
            let country = placemark.country
        else {
            print("Reverse Geocoding failed")
            print(error ?? "No placemarks found")
            return
        }

        print(city, state, country)
    }
}

有了

import os.signpost

let pointsOfInterest = OSLog(subsystem: "Geocode", category: .pointsOfInterest)
© www.soinside.com 2019 - 2024. All rights reserved.