LoginSignup
11

More than 5 years have passed since last update.

ViewControllerが表示されるイベントログを横断的に取得する - Activity Tracking

Last updated at Posted at 2016-08-25

ユーザーのアクティビティログを取る(すべてのviewDidAppearなど)

各ViewControllerが呼ばれたタイミング(viewDidAppearなど)でトラッカーを呼び出し、ユーザーの行動ログをとりたいときがあるかと思います。
しかし、すべてのViewControllerのviewDidAppearにその処理を書き込むことはあまり現実的ではありません。

検討する上ではだいたいこのような視点があると思います。

  • 実装コストを減らしたい、1度きりの実装で済ましたい
  • ログの漏れをなくしたい(特定のケースで取れてないことを防ぎたい
  • ログのせいでバグを起こしたくない
  • 将来的にも使い続けられる(言語のバージョンアップデートに左右されにくい

方法例

  1. NSNotificationを使う
  2. アスペクト指向ライブラリを使う
  3. Base Classを作る
  4. 独自の遷移メソッドをつくる
  5. File templateを使う

NSNotificationを使う

非公開のNSNotificationの中にUINavigationControllerDidShowViewControllerNotificationというものがあります。
これは、UINavigationControllerDelegateのnavigationController:didShowViewController:animatedが呼ばれた際に飛んでいます。
UINavigationControllerNextVisibleViewControllerというkeyで、表示されるViewControllerが取得できます。

// nameをnilにすると、すべてのnotificationを受け取れる
NSNotificationCenter.defaultCenter().addObserverForName(nil, object: nil, queue: nil) { (notification) in
    if notification.name == "UINavigationControllerDidShowViewControllerNotification",
        let userInfo = notification.userInfo as? [String: AnyObject],
        let viewController = userInfo["UINavigationControllerNextVisibleViewController"] as? UIViewController {
        debugPrint(viewController) // 表示されるViewControllerが取れる
    }
}

いいところ
ログの実装を完全に分離でき、また下手な影響を及ばす心配がありません。

気になるところ
UINavigationControllerを介さずに表示される場合のケースが取れないです。
また、非公開APIなのでいつ使えなくなるかは不明です。

アスペクト指向ライブラリを使う

横断的関心事を分離して実装していけるアスペクト指向のライブラリを使う手段です。
以下の様なライブラリがあるようです。

以下の記事も参考になりましたm(_ _)mありがとうございます
iOSのトラッキング実装ベストプラクティスを考える
妄想iOSアプリ新規開発の記事内の「トラッキング(横断的関心事)にあるの織り込み」

いいところ
網羅的に実装できます。実装コード量も少なく、コードが分離できているので管理も楽です。

気になるところ
ライブラリなので、もしサポートが足りない場合は修正を送るかforkしていく必要があります。(ただソース量が少ないので、自己管理下に置きやすそうではあります)
swizzleの黒魔術感があります。

Base Classを作る

すべてのUIViewControllerに継承させるBaseViewControllerを用意して、その中でトラッキングする処理を書くというものです。

class BaseViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)
        // ログ処理
    }
}

// 継承させることでログ処理を走らせる
class SampleViewController: BaseViewController {}

いいところ
この実装方法が打ち切られることはまずなさそうです。

気になるところ
新規にViewControllerを追加するときに必ず継承させることを意識する必要があります。
中で条件が書かれるようになるとしんどくなっていくと思います。

参考:iOSアプリの設計でBaseViewControllerのようなのは作りたくない

独自の遷移メソッドをつくる

ViewControllerが表示される方法としては、コードまたはStoryBoardで使われているメソッドたちがありますが、それを直接利用せずにそれぞれのメソッドをwrapしたメソッドを用意します。

extension UIViewController {
    func presentViewControllerWithLogging(viewControllerToPresent: UIViewController, animated: Bool, completion: (() -> Void)?) {
        // ログ処理
        self.presentViewController(viewControllerToPresent, animated: animated, completion: completion)
    }
}

いいところ
どのメソッドを通して開かれたのを知りたいときはいいかも、、?

気になるところ
抜け漏れがないように絶対このメソッドを使うようにさせるのが辛そうです。

File templateを使う

Xcodeで、新しいファイルを追加する際に、customで用意したFileTemplateを選択することができます。
そこに、トラッキングする処理が書かれた状態のUIViewControllerのテンプレートを用意してしまうという方法です。

いいところ
コード編集を毎回意識することになるので、影響コントロールはしやすいかもしれません。

気になるところ
必ずカスタムテンプレートを使うことを意識する必要があります。
コードがあまりきれいに見えなさそうです。

まとめ

選ぶ判断は自分たちの設計方針、なにをメリデメにするかで変わってくると思いますので、そこに照らしあわせて選ぶことがよいと思います。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11