Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
0
Help us understand the problem. What is going on with this article?
@m-inada0408

【RxSwift】Reactive の Extension を作成する際にメモリリークが発生した

環境

  • Xcode 12.3
  • RxSwift 5.1.1

目的

  • TabTestViewControllerself.viewDidLayoutSubviews() 呼び出しを検知しその際の self.index を流す Observable<Int> を作成したい
TabTestViewController.swift

// こんな感じで利用する currentIndexDidChange を Extension で実装
self.rx.currentIndexDidChange
    .subscribe(self.indexSubject)
    .disposed(by: self.disposeBag)

当初実装

  • 以下のように実装するとメモリリークが発生する
TabTestViewController+rx.swift

extension Reactive where Base: TabTestViewController {

    var currentIndexDidChange: Observable<Int> {

        // メモリリークが発生
        return sentMessage(#selector(base.viewDidLayoutSubviews))
            .map { _ in base.currentIndex }
            .distinctUntilChanged()
            .share(replay: 1)
    }
}

原因

  • base がクロージャ内部で強参照されていることによる

間違い: self を弱参照しようとした

  • 「クロージャの中では selfを弱参照」と手癖で実装しようとしたところコンパイルエラー
    • Reactive<Base> は構造体のため weak が使えない
TabTestViewController+rx.swift

extension Reactive where Base: TabTestViewController {

    var currentIndexDidChange: Observable<Int> {

        // 'weak' may only be applied to class and class-bound protocol types, not 'Reactive<Base>'
        return sentMessage(#selector(base.viewDidLayoutSubviews))
            .map { [weak self] _ in

                guard let self = self else { fatalError() }

                return self.base.currentIndex
            }
            .distinctUntilChanged()
            .share(replay: 1)
    }
}

解決: base を弱参照とする

  • TabTestViewController はクラスのため weak で弱参照することができる
TabTestViewController+rx.swift
extension Reactive where Base: TabTestViewController {

    var currentIndexDidChange: Observable<Int> {

        // viewDidLayoutSubviewsのタイミングでcurrentIndexの変化を検知する
        return sentMessage(#selector(base.viewDidLayoutSubviews))
            .map { [weak base] _ in

                guard let base = base else { fatalError() }

                return base.currentIndex
            }
            .distinctUntilChanged()
            .share(replay: 1)
    }
}
0
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
secual
スマートセキュリティおよびスマートタウンに関わる製品の企画・開発・製造・販売及びその運営サービスの提供しています。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
0
Help us understand the problem. What is going on with this article?