简体   繁体   中英

Retain Cycle in closure

I try to implement some variant of Coordinator pattern, but I face problem with retain cycle in closure. It looks like that:

func goTo() {
    let coord = SecondViewCoordinator(nav: navigationController)
    add(coord)
    coord.start()
    coord.deinitIfNeeded = { [weak self] in
        guard let self = self else { return }
        self.free(coord)
    }
}

As you can see I set deinitIfNeeded and then, if in SecondViewCoordinator call deinitIfNeeded?() controller pops correctly, but reference to SecondViewCoordinator is still exist even though childCoordinators array is empty.

My Coordinator class looks like that:

class Coordinator {

    weak var navigationController: UINavigationController?
    var childCoordinators: [Coordinator] = []
    var deinitIfNeeded: (() -> ())?

    init(nav: UINavigationController?) {
        self.navigationController = nav
    }

    func add(_ coordinator: Coordinator) {
        childCoordinators.append(coordinator)
    }

    func free(_ coordinator: Coordinator) {
        childCoordinators = childCoordinators.filter({ $0 !== coordinator })
    } 
}

memory graph presents this:

在此处输入图片说明

any ideas?

In

coord.deinitIfNeeded = { [weak self] in
    guard let self = self else { return }
    self.free(coord)
}

You are holding a strong reference to coord inside the closure. Try something like this;

coord.deinitIfNeeded = { [weak self, weak coord] in
    guard let self = self, let coord = coord else { return }
    self.free(coord)
}

The memory graph is giving a hint that this is the case (the right side says the strong reference is in a closure).

You could also set coord.deinitIfNeeded to nil inside the closure.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM