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!!

enter image description here

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

Popular posts from this blog

Is there a better way to structure post methods in Class Based Views -

performance - Why is XCHG reg, reg a 3 micro-op instruction on modern Intel architectures? -

jquery - Responsive Navbar with Sub Navbar -