swift - ios memory leak using closure callbacks -
i have service class keeps array of subservices role send service events using 2 closure callbacks.
the service initializes subservice objects 2 closures take weak reference service in order avoid retain cycle.
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 } }
but memory graph on xcode showing retain cycle both service , subservice memory leaked!!
moreover looking @ graph can seen indicates instances of service , subservices captured closures strong of course cause reference cycle. surprising because pass weak reference of service closures. seems not true me xcode showing me.
is there i'm doing wrong?
ps: if change closure passed subservice initializer way memory leaks disappear. can explain it?
callbackonsubserviceready: { [weak self] in self?.onsubserviceready($0) }, callbackonbleevent: { [weak self] in self?.onbleevent(broadcastdict: $0)}
in closure call expression:
{ [weak self] in self!.onsubserviceready }()
the compiled code generates closure not have strong reference self
.
then, closure invoked ()
, closure evaluates self!.onsubserviceready
.
as know method reference , returns method closure. (let's call method-closure.)
and in swift, method-closures have implicit strong references self
, irrelevant if self
weak reference or not. expression self!.onsubserviceready
(or self.onsubserviceready
, when self
non-optional) returns same method-closure, has strong reference self
.
once invoked, [weak self]
not affect evaluated result. so, when not make strong reference closure itself, [weak self]
has no effect make self
optional.
on other hand, closure expression:
{ [weak self] in self?.onsubserviceready($0) }
it closure , not invoking closure there. so, new closure generated, has weak reference self
, , closure (which not method-closure!) passed initializer , held in instance property.
you should better create new weak-self closure, rather using method-closure, if want avoid leaks caused closures.
Comments
Post a Comment