我有一个Service类,它保存一个Subservices数组,其作用是使用2个闭包回调将一些事件发送回Service。
该服务使用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
}
}
但是xcode上的内存图实际上显示了一个保留周期,服务和子服务内存都泄露了!!
https://www.elastic.co/guide/en/elasticsearch/reference/2.3/docs-update.html
此外,从图中可以看出,它表明闭包捕获的服务和子服务的实例很强,这当然会引起参考周期。这是令人惊讶的,因为我实际上将服务的弱引用传递给闭包。对我来说,似乎不是xcode向我展示的。
我做错了吗?
PS:如果我改变传递给子服务初始化器的闭包,这样内存泄漏就会消失。谁能解释一下呢?
callbackOnSubserviceReady: { [weak self] in self?.onSubserviceReady($0) },
callbackOnBleEvent: { [weak self] in self?.onBleEvent(broadcastDict: $0)}
答案 0 :(得分:2)
在这个闭包调用表达式中:
{ [weak self] in self!.onSubserviceReady }()
编译后的代码生成一个闭包,该闭包没有对self
的强引用。
然后,闭包由()
调用,闭包评估self!.onSubserviceReady
。
如您所知,这是一个方法引用,它将该方法作为闭包返回。 (我们称之为 method-closure 。)
在Swift中,所有方法闭包都隐含了对self
的强引用,如果self
是弱引用则无关紧要。表达式self!.onSubserviceReady
(或self.onSubserviceReady
,当self
为非可选时)始终返回相同的方法闭包,它具有对self
的强引用。
调用后,[weak self]
不会影响评估结果。因此,如果您没有强烈引用闭包本身,[weak self]
无效,只需将self
设为可选。
另一方面,你的闭包表达式:
{ [weak self] in self?.onSubserviceReady($0) }
它本身就是一个闭包,你没有在那里调用闭包。因此,生成一个新的闭包,它具有对self
的弱引用,并且闭包(不是方法闭包!)被传递给初始化器并保存在实例属性中。
如果你想避免闭包造成的泄漏,你最好总是创建一个新的弱自闭,而不是使用方法闭包。