为何该RxFeedback代码未产生内存泄漏?ARC原理解析
RxFeedback中强引用self未引发内存泄漏的原因解析
首先看相关Swift代码:
ViewModel 代码
class ViewModel { ... func state(with bindings: @escaping (Driver<State>) -> Signal<Event>) -> Driver<State> { Driver.system( initialState: .initial, reduce: State.reduce(state:event:), feedback: bindings, react(request: { $0.startLoading }, effects: { _ in self.fetchFavoriteRepositoriesUseCase.execute() .asObservable() .observe(on: self.scheduler) .map(self.repositoriesToRepositoryViewModelsMapper.map(input:)) .map { repositories in .loaded(repositories) } .asSignal { error in .just(.failed(error.localizedDescription)) } })) } ... }
ViewController 代码
class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() let initialTrigger = BehaviorRelay<Void>(value: ()) let trigger = Observable.merge(initialTrigger.asObservable(), refreshRelay.asObservable()) let uiBindings: (Driver<FavoriteRepositoriesViewModel.State>) -> Signal<FavoriteRepositoriesViewModel.Event> = bind(self) { me, state in let subscriptions = [ state.drive(onNext: { state in switch state { case .initial: print("Initial") case .loading: print("Loading") case .failed: print("Failed") case .loaded: print("Loaded") } }) ] let events: [Signal<FavoriteRepositoriesViewModel.Event>] = [ trigger.map { .load } .asSignal(onErrorSignalWith: .empty()) ] return Bindings(subscriptions: subscriptions, events: events) } viewModel.state(with: uiBindings) .drive() .disposed(by: disposeBag) } }
问题描述
我现在在理解为什么上述RxFeedback的react方法没有产生内存泄漏:该方法的effects参数是@escaping闭包,我没有对self做弱引用处理,而是在闭包中强引用self来调用用例。我推测这和RxFeedback无关,而是我对ARC和内存管理的理解有盲区。我通过将ViewController从导航控制器弹出的方式测试了它的释放情况,希望得到这段代码未形成引用循环的详细解释。
原因解析
要搞清楚为什么没有形成循环引用,我们先梳理整个引用关系链:
- ViewController 强引用
viewModel和disposeBag viewModel的state方法中,react的effects闭包强引用viewModel(也就是闭包里的self)- 这个闭包被RxFeedback的
Driver.system内部的反馈逻辑持有,而Driver.system返回的Driver订阅被添加到了disposeBag中
乍一看似乎形成了ViewController -> disposeBag -> 订阅 -> Driver内部 -> effects闭包 -> viewModel -> ViewController的循环,但实际上这个环会在ViewController被弹出时被主动打破:
- 当ViewController从导航栈弹出后,导航控制器对它的强引用会被解除。此时如果没有其他外部强引用,ARC会尝试释放ViewController。
- ViewController的
deinit方法执行时,其持有的disposeBag会被销毁,disposeBag内部的所有订阅都会被清理。 - 订阅被销毁时,Rx框架会回收所有和该订阅关联的资源,包括
Driver.system内部对effects闭包的持有引用。 - 一旦
effects闭包对viewModel的强引用被解除,viewModel的唯一强引用就来自即将被释放的ViewController,因此viewModel也会被ARC回收。
整个过程中并没有形成永久的循环引用,因为disposeBag的销毁会主动切断闭包对viewModel的引用,打破了潜在的循环。如果没有正确使用disposeBag管理订阅,那确实会引发循环引用导致内存泄漏,但这段代码里的订阅被正确绑定到了ViewController的disposeBag,所以能在ViewController释放时及时清理所有相关资源。
内容的提问来源于stack exchange,提问作者hydro1337x
相关产品推荐
相关产品推荐

