一、基本介紹
1,sendMessage 與 methodInvoked 的區別
(1)在之前的幾篇文章中,我用到了 methodInvoked
這個 Rx
擴展方法,其作用是獲取代理方法執行后產生的數據流。
- Swift - RxSwift的使用詳解19(特征序列3:ControlProperty、 ControlEvent)
- Swift - RxSwift的使用詳解58(DelegateProxy樣例1:獲取地理定位信息 )
- Swift - RxSwift的使用詳解59(DelegateProxy樣例2:圖片選擇功能 )
- Swift - RxSwift的使用詳解60(DelegateProxy樣例3:應用生命周期的狀態變化)
(2)除了 methodInvoked
外,還有個 sentMessage
方法也有同樣的作用,它們間只有一個區別:
-
sentMessage
會在調用方法前發送值。 -
methodInvoked
會在調用方法后發送值。
2,實現原理
(1)其原理簡單說就是利用 Runtime
消息轉發機制來轉發代理方法。同時在調用返回值為空的代理方法的前后分別產生兩種數據流。
(2)比如最開始的代理為 A,然后我們把代理改為 AProxy
,并把 A 設置為 AProxy
的_forwardToDelegate
。這樣所有的代理方法將會變成到達 AProxy
,接著 AProxy
對這些方法進行如下操作:
- 首先調用
sentMessage
方法 - 接著調用原代理方法
- 最后調用
methodInvoked
方法
二、使用樣例
我們分別通過 sendMessage
以及 methodInvoked
方法來獲取 selector
對應的 Observable
,并將它們與原方法做比較,看看執行的先后順序。
(注意:兩個樣例中 selector
都不是代理方法,但不影響效果的演示。)
樣例1:攔截 VC 的 viewWillAppear 方法
import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {
let disposeBag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
//使用sentMessage方法獲取Observable
self.rx.sentMessage(#selector(ViewController.viewWillAppear(_:)))
.subscribe(onNext: { value in
print("1")
})
.disposed(by: disposeBag)
//使用methodInvoked方法獲取Observable
self.rx.methodInvoked(#selector(ViewController.viewWillAppear(_:)))
.subscribe(onNext: { value in
print("3")
})
.disposed(by: disposeBag)
}
//默認的viewWillAppear方法
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
print("2")
}
}
運行結果如下:
樣例2:攔截自定義方法
import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {
let disposeBag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
//使用sentMessage獲取方法執行前的序列
self.rx.sentMessage(#selector(ViewController.test))
.subscribe(onNext: { value in
print("1:\(value[0])")
})
.disposed(by: disposeBag)
//使用methodInvoked獲取方法執行后的序列
self.rx.methodInvoked(#selector(ViewController.test))
.map({ (a) in
return try castOrThrow(String.self, a[0])
})
.subscribe(onNext: { value in
print("3:\(value)")
})
.disposed(by: disposeBag)
//調用自定義方法
test("hangge.com")
}
//自定義方法
@objc dynamic func test(_ value:String) {
print("2:\(value)")
}
}
//轉類型的函數(轉換失敗后,會發出Error)
fileprivate func castOrThrow<T>(_ resultType: T.Type, _ object: Any) throws -> T {
guard let returnValue = object as? T else {
throw RxCocoaError.castingError(object: object, targetType: resultType)
}
return returnValue
}
運行結果如下: