ont*_*oon 2 xcode memory-leaks ios swift
我有一个 Service 类,它保存一组子服务,其作用是使用 2 个闭包回调将一些事件发送回服务。
该服务使用 2 个闭包来初始化子服务对象,这两个闭包采用对服务的弱引用以避免保留周期。
public class T4fService {
lazy var t4fSubServices: [T4fSubService?] = self.populateSubServices()
let callbackOnServiceReady: (_ isReady: Bool) -> ()
let callbackOnBleEvent: (_ broadcastDict: NotificationDict) -> ()
init?(id: T4fServiceId,
callbackOnServiceReady: @escaping (_ isReady: Bool) -> (),
callbackOnBleEvent: @escaping CharacteristicCallback){
self.callbackOnServiceReady = callbackOnServiceReady
self.callbackOnBleEvent = callbackOnBleEvent
}
func populateSubServices() -> [T4fSubService?] {
switch self.t4fServiceId {
case .compassServiceId:
return [T4fSubService( t4fBlePeripheralType: .Two4All, t4fCharacteristicUuidsArray: [T4fBleUuid.imuMagnetometerCharacteristicUuid],
callbackOnSubserviceReady: { [weak self] in self!.onSubserviceReady }(),
callbackOnBleEvent: { [weak self] in self!.onBleEvent}())]
func onSubserviceReady(_ isReady: Bool) {
...
}
public func onBleEvent(broadcastDict: NotificationDict) {
...
}
}
class T4fSubService{
let callbackOnSubserviceReady: (_ isReady: Bool) -> ()
let callbackOnBleEvent: (_ broadcastDict: NotificationDict) -> ()
init?(t4fBlePeripheralType: T4fBlePeripheralType,
callbackOnSubserviceReady: @escaping (_ isReady: Bool) -> (),
callbackOnBleEvent: @escaping (_ broadcastDict: NotificationDict) -> ()){
self.callbackOnSubserviceReady = callbackOnSubserviceReady
self.callbackOnBleEvent = callbackOnBleEvent
}
}
Run Code Online (Sandbox Code Playgroud)
但是 xcode 上的内存图实际上显示了服务和子服务内存泄漏的保留周期!
而且从图中可以看出,闭包捕获的Service和Subservice的实例很强大,这当然会导致引用循环。这是令人惊讶的,因为我实际上将服务的弱引用传递给了闭包。对我来说,xcode 向我展示的内容似乎并不真实。
我做错了什么吗?
PS:如果我以这种方式更改传递给子服务初始化程序的闭包,内存泄漏就会消失。谁能解释一下吗?
callbackOnSubserviceReady: { [weak self] in self?.onSubserviceReady($0) },
callbackOnBleEvent: { [weak self] in self?.onBleEvent(broadcastDict: $0)}
Run Code Online (Sandbox Code Playgroud)
在此闭包调用表达式中:
{ [weak self] in self!.onSubserviceReady }()
Run Code Online (Sandbox Code Playgroud)
编译后的代码生成一个没有强引用的闭包self。
然后,闭包由 调用(),闭包计算self!.onSubserviceReady。
如您所知,这是一个方法引用,它以闭包的形式返回该方法。(我们称之为方法闭包。)
在 Swift 中,所有方法闭包都有对 的隐式强引用self,是否self为弱引用无关紧要。表达式self!.onSubserviceReady(或self.onSubserviceReady,当self为非可选时)始终返回相同的方法闭包,该方法闭包对 具有强引用self。
一旦调用,[weak self]不影响评估结果。因此,当您不对闭包本身进行强引用时,[weak self]没有任何效果,而只是设为self可选。
另一方面,你的闭包表达式:
{ [weak self] in self?.onSubserviceReady($0) }
Run Code Online (Sandbox Code Playgroud)
它本身就是一个闭包,并且您没有在那里调用闭包。因此,生成了一个新的闭包,它具有对 的弱引用self,并且该闭包(不是方法闭包!)被传递给初始值设定项并保存在实例属性中。
如果你想避免闭包引起的泄漏,你最好总是创建一个新的弱自闭包,而不是使用方法闭包。