RxSwift

RxSwiftでオブジェクト数を確認する

RxSwiftを使って実装する際にObservableが残り続けてしまってメモリーリークにつながってるのではないか心配になることがあるかと思います。
そのために簡単にRxSwiftで現状使われてるオブジェクト数を確認するためのプロパティが用意されているのでそれを紹介します。

RxSwiftそのものについてはこちらの記事でまとめていますので、もしわからない人は読んでみてください。

【Swift】RxSwiftを理解するはじめに 今回RxSwiftを使ってみました。というのも業務で作ってるiOSアプリのコードがMVVMもどきのくちゃくちゃなコードかつフ...

準備

結論から言ってしまうと、


RxSwift.Resources.total

と書くことで現状のオブジェクト数を確認することができますが、下準備が必要です。

というのもこのtotalの定義を辿ってみると、


//
// Rx.swift
// RxSwift
//
// Created by Krunoslav Zaher on 2/14/15.
// Copyright © 2015 Krunoslav Zaher. All rights reserved.
//

#if TRACE_RESOURCES
    fileprivate var resourceCount: AtomicInt = 0

    /// Resource utilization information
    public struct Resources {
        /// Counts internal Rx resource allocations (Observables, Observers, Disposables, etc.). This provides a simple way to detect leaks during development.
        public static var total: Int32 {
            return resourceCount.valueSnapshot()
        }

        /// Increments `Resources.total` resource count.
        ///
        /// - returns: New resource count
        public static func incrementTotal() -> Int32 {
            return AtomicIncrement(&resourceCount)
        }

        /// Decrements `Resources.total` resource count
        ///
        /// - returns: New resource count
        public static func decrementTotal() -> Int32 {
            return AtomicDecrement(&resourceCount)
        }
    }
#endif

というようになっていて、RxSwiftTRACE_RESOURCESのフラグを付けたビルドバージョンでなければ使えないので注意です。
特にswift3からこのような仕様になっているので注意が必要です。以前までのバージョンだとRxSwift.resourceCountとなっています。

CocoaPodsでインストールする際に、


target 'SampleApp' do
  # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
  use_frameworks!

  # Pods for SampleApp
  pod 'RxSwift', :git => 'https://github.com/ReactiveX/RxSwift', :branch => 'rxswift-3.0'
  pod 'RxCocoa', :git => 'https://github.com/ReactiveX/RxSwift', :branch => 'rxswift-3.0'

  # ここから
  post_install do |installer|
    installer.pods_project.targets.each do |target|
      if target.name == 'RxSwift'
        target.build_configurations.each do |config|
          if config.name == 'Debug'
            config.build_settings['OTHER_SWIFT_FLAGS'] ||= ['-D', 'TRACE_RESOURCES']
          end
        end
      end
    end
  end
  # ここまで

  target 'SampleAppTests' do
    inherit! :search_paths
    # Pods for testing
  end

  target 'SampleAppUITests' do
    inherit! :search_paths
    # Pods for testing
  end

end

このようにつけることによって、TRACE_RESOURCESのフラグをDebugビルドのときのみにつけることができます。
Carthageでのやりかたは今回は特に調べてないですが、要はTRACE_RESOURCESのフラグをつけれれば大丈夫です。

補足ですが、swift3で導入する際にはReadmerxswift-3.0ブランチでって書いてありますが、CocoaPodsでブランチ指定でインストールする場合は上記のように書きます。

先程のようにPodfileを書き換えて


pod install

すれば、


RxSwift.Resources.total

が使えるようになったかと思います。
totalの数なので大まかにしか確認することができませんが、極端に増えていないかどうかを確認することができます。
totalに含まれる対象ですが、ソースコードのコメントに


Counts internal Rx resource allocations (Observables, Observers, Disposables, etc.).

というように記述があります。
印象としてはRxCocoaを使っている場合にUI関連のものはObservableをプロパティとして持つのでそれもカウントされている印象でした。

リリースビルドで使えないので注意

RxSwift.Resources.totalを単発で使う場合は大丈夫ですが、もし残しておく場合に、先程から言っているようにDebugビルドのときのみフラグを有効にしているのでリリースビルドの際にエラーが出るかと思います。
対処法としては、TRACE_RESOURCESをリリースビルドでも有効にすることでも解決できますが、


#if DEBUG
    RxSwift.Resources.total
#endif

というように囲むようにしましょう。
この書き方を使えるようにするには、「BuildSettings」「OtherSwiftFlags」にこのように「-D DEBUG」をつけるようにしましょう。

これで完了です。
細かいデバッグはできませんが大まかな確認にはなると思うので参考にしていただければ嬉しいです。