Swift递归闭包堆栈溢出bug

Sol*_*Dev 0 stack-overflow recursion closures swift

更新:应该注意的是,下面的问题是学术性质和核心位置的使用,或者位置数据的轮询与问题无关 - 执行此操作的正确方法始终是通过核心位置委托方法.我最初的问题最终归结为:"swift中是否有无限递归?(或尾递归)".答案是否定的.这是由于堆栈空间耗尽导致我的错误的原因.

原始问题:我遇到了一个通过闭包传递值的递归函数的问题.我是一个长期的Objective-C开发人员,但是没有在Swift编程很长时间,所以也许我错过了一些明显的东西.这是函数以及我如何调用它:

public func getLocation(completion: @escaping (CLLocationCoordinate2D?) -> ())
{
    completion(self.currentLocation)
    weak var weakSelf = self
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
        weakSelf?.getLocation(completion: {location in
            completion(weakSelf?.currentLocation)
        })
    }
}

LocationManager.shared.getLocation(completion: {location in
        if(location != nil)
        {
            weakSelf?.lonLabel.text = "Lat: " + location!.latitude.description
            weakSelf?.latLabel.text = "Lon: " + location!.longitude.description
        }
    })
Run Code Online (Sandbox Code Playgroud)

Thread 1: EXC_BAD_ACCESS (code=2, address=0x16f1b7fd0)运行一段时间后我得到的错误(描述)是这样的:

在此输入图像描述

我想要完成的是将自动更新位置值传递给位置管理器对象.我正在考虑另一种方法,performSelector withObject afterDelay但在这一点上,我只是想知道为什么会崩溃?

Ale*_*ica 5

你正在通过getLocation(completion:)调用getLocation(completion:)来调用堆栈溢出,getLocation(completion:)直到你的堆栈空间不足为止.

你可以用一个DispatchSourceTimer代替:

import Dispatch

let timer = DispatchSource.makeTimerSource(queue: DispatchQueue.main)
timer.schedule(deadline: .now(), repeating: .seconds(5), leeway: .milliseconds(100))

timer.setEventHandler { [weak self] in
    guard let strongSelf = self,
          let location = LocationManager.shared.currentLocation else { return }
    strongSelf.lonLabel.text = "Lat: \(location.latitude)"
    strongSelf.latLabel.text = "Lon: \(location.longitude)"
}

timer.resume()
Run Code Online (Sandbox Code Playgroud)

但这种整个民意调查方法没有任何意义.您的位置代表已被告知位置更改.您可以随后更改标签.

  • 正如评论中指出的那样,这一切都不应该做.只需使用正确的委托方法在用户位置更改时更新标签.更新标签的频率远远高于更新位置的意义. (3认同)