22
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

メソッドのhookは正しいタイミングで行おう【RxSwift/RxCocoa】

Last updated at Posted at 2017-07-23

メソッドのhook?

RxCocoaではsentMessagemethodInvokedというメソッドをフックするオペレータがあり、「ある関数が呼ばれたらこの処理をしたい」ということが実現できます。 

sentMessage

ある関数が呼ばれる直前をhookすることができます。

(数値の順番通りに処理されます)

import UIKit
import RxSwift
import RxCocoa

extension UIViewController {
    func doSomething() {
        defer { print("3") }
        print("2")
    }
}

final class ViewController: UIViewController {

    let disposeBag = DisposeBag()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        rx.sentMessage(#selector(UIViewController.doSomething))
            .subscribe(onNext: { _ in
                print("1")
            })
            .disposed(by: disposeBag)

        doSomething()
        print("4")        
    }    
}

methodInvoked

ある関数の処理が終わった直後をhookすることができます。

(数値の順番通りに処理されます)

import UIKit
import RxSwift
import RxCocoa

extension UIViewController {
    func doSomething() {
        defer { print("2") }
        print("1")
    }
}

final class ViewController: UIViewController {

    let disposeBag = DisposeBag()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        rx.methodInvoked(#selector(UIViewController.doSomething))
            .subscribe(onNext: { _ in
                print("3")
            })
            .disposed(by: disposeBag)

        doSomething()
        print("4")
    }
}

面白いこと :coffee:

sentMessagemethodInvokedはそれぞれ関数に渡ってくる引数を取得することができます。戻り値がObservable<[Any]>となっているため引数ラベルなどは使えませんが、引数が先頭から何番目かを指定することで引数を取得できます。

つまりどういうことなのか? :thinking:

使い道としては指定した関数内の同期処理が完全に終わってるタイミングを保証できるのがmethodInvokedです。なので、指定した関数内の処理後でないと特定のプロパティが更新されていない可能性があるなどのものは全てmethodInvokedを使います。反対に指定した関数が呼ばれたタイミングで関数内の処理とは無関係に処理したい場合はsentMessageを使います。

:warning:
注意として指定した関数内に非同期処理があった場合にはそれは関数オブジェクトの生存期間と別管理となるため無視されます。sentMessagemethodInvokedの内部実装ではSelectorが呼ばれるタイミングと関数がdeallocatedされたタイミングで通知を行なっているので関数がdeallocatedになっても処理が継続するものについては通常通りcompletion等で対応するしかありません。

参考:
https://github.com/ReactiveX/RxSwift/blob/102424379fb8d6c69b33b95c67504679042f44cc/RxCocoa/Foundation/NSObject%2BRx.swift

22
15
1

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
22
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?