在 Swift 中引用回调时防止内存泄漏
Preventing memory leaks when referencing a callback in Swift
注意:此问题与 Swift、闭包、回调和内存泄漏有关...其余的仅供说明。
假设我们有一个 class,ValueAnimator,它具有以下初始化程序:
init(durationInSeconds: Int, sampleRate: Int, interpolation: Interpolator,
callback: @escaping (Double) -> Void) {
self.maxIterations = durationInSeconds * sampleRate
self.timeInterval = 1.0 / Double(sampleRate)
self.interpolation = interpolation
self.callback = callback
}
如您所见,我们有一个传入的回调。
现在,考虑从 ViewController 初始化 ValueAnimator 时定义回调的这两种不同方式:
选项一,在线定义回调:
class ViewController: ViewController {
var valueAnimator: ValueAnimator?
override func viewDidLoad() {
valueAnimator = ValueAnimator(durationInSeconds: 2, sampleRate: 2,
interpolation: .sineWaveFrom0To1To0)
{ [weak self] value in
guard let self = self else { return }
// Do something with value ...
}
valueAnimator?.start()
}
}
方案二,将回调定义为单独的函数并引用它:
(我更喜欢这种方式...因为我发现它不是 "cognitive load" 不在闭包中闭包...因此问题)
class ViewController: ViewController {
var valueAnimator: ValueAnimator?
override func viewDidLoad() {
valueAnimator = ValueAnimator(durationInSeconds: 2, sampleRate: 2,
interpolation: .sineWaveFrom0To1To0, callback: theCallback)
valueAnimator?.start()
}
func theCallback(value: Double) {
// Do something with the value ...
}
}
正如您在第一个版本中看到的那样,有一些针对引用循环的保护。
是否有某种方法可以在第二个版本中应用同样的保护...或者出于某种原因没有必要?
谢谢!
要对第二种方式应用相同的保护,请发送 self
而不是回调,并在您的 class ValueAnimator
中定义
weak var delegate:ViewController?
然后在响应里面做
delegate?.callback(value:<#value#>)
您可以选择使用父委托(self)调用任何函数。
init(durationInSeconds: Int, sampleRate: Int, interpolation: Interpolator, delegate:
AnyObject?, callback: @escaping (Double) -> Void) {
self.maxIterations = durationInSeconds * sampleRate
self.timeInterval = 1.0 / Double(sampleRate)
self.interpolation = interpolation
delegate?.callback(value: 0)
}
class ViewController: ViewController {
var valueAnimator: ValueAnimator?
override func viewDidLoad() {
valueAnimator = ValueAnimator(durationInSeconds: 2, sampleRate: 2,
interpolation: .sineWaveFrom0To1To0, delegate: self, callback: theCallback)
valueAnimator?.start()
}
func theCallback(value: Double) {
// Do something with the value ...
}
}
注意:此问题与 Swift、闭包、回调和内存泄漏有关...其余的仅供说明。
假设我们有一个 class,ValueAnimator,它具有以下初始化程序:
init(durationInSeconds: Int, sampleRate: Int, interpolation: Interpolator,
callback: @escaping (Double) -> Void) {
self.maxIterations = durationInSeconds * sampleRate
self.timeInterval = 1.0 / Double(sampleRate)
self.interpolation = interpolation
self.callback = callback
}
如您所见,我们有一个传入的回调。
现在,考虑从 ViewController 初始化 ValueAnimator 时定义回调的这两种不同方式:
选项一,在线定义回调:
class ViewController: ViewController {
var valueAnimator: ValueAnimator?
override func viewDidLoad() {
valueAnimator = ValueAnimator(durationInSeconds: 2, sampleRate: 2,
interpolation: .sineWaveFrom0To1To0)
{ [weak self] value in
guard let self = self else { return }
// Do something with value ...
}
valueAnimator?.start()
}
}
方案二,将回调定义为单独的函数并引用它:
(我更喜欢这种方式...因为我发现它不是 "cognitive load" 不在闭包中闭包...因此问题)
class ViewController: ViewController {
var valueAnimator: ValueAnimator?
override func viewDidLoad() {
valueAnimator = ValueAnimator(durationInSeconds: 2, sampleRate: 2,
interpolation: .sineWaveFrom0To1To0, callback: theCallback)
valueAnimator?.start()
}
func theCallback(value: Double) {
// Do something with the value ...
}
}
正如您在第一个版本中看到的那样,有一些针对引用循环的保护。
是否有某种方法可以在第二个版本中应用同样的保护...或者出于某种原因没有必要?
谢谢!
要对第二种方式应用相同的保护,请发送 self
而不是回调,并在您的 class ValueAnimator
中定义
weak var delegate:ViewController?
然后在响应里面做
delegate?.callback(value:<#value#>)
您可以选择使用父委托(self)调用任何函数。
init(durationInSeconds: Int, sampleRate: Int, interpolation: Interpolator, delegate:
AnyObject?, callback: @escaping (Double) -> Void) {
self.maxIterations = durationInSeconds * sampleRate
self.timeInterval = 1.0 / Double(sampleRate)
self.interpolation = interpolation
delegate?.callback(value: 0)
}
class ViewController: ViewController {
var valueAnimator: ValueAnimator?
override func viewDidLoad() {
valueAnimator = ValueAnimator(durationInSeconds: 2, sampleRate: 2,
interpolation: .sineWaveFrom0To1To0, delegate: self, callback: theCallback)
valueAnimator?.start()
}
func theCallback(value: Double) {
// Do something with the value ...
}
}