RxSwift 调度者(三)
补充 publish
let ob = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
let ob2 = ob.publish()
ob2.subscribe(onNext: { print("第一次:\($0)") })
ob2.connect()
ob2.subscribe(onNext: { print("第二次:\($0)") })
- 一般来说
publish
和 connect
连用
- 继承链
publish -> multicast -> ConnectableObservableAdapter: ConnectableObservable -> ConnectableObservable: Observable
- 所以
publish
只有 subscribe
方法没有 on
方法
- 底层有一个
lazySubject
只初始化一次观察者,当有多次的subscribe
时,只执行第一次的 subscribe
-
connect
执行Connection: ObserverType
自己实现on
方法
UI 事件一定在主线程
DispatchQueue.global().async {
self.button.rx.tap
.subscribe(onNext: { _ in
print("\(Thread.current)")
})
}
-
self.button.rx.tap
是封装了ControlEvent
- 当
ControlEvent
进行subscribe
的时候 event
默认执行了subscribeOn
进入主线程
PublishSubject
-
PublishSubject
即是观察者也是订阅者
- 只接受订阅后发送的数据
- 创建 subject -> 收集观察者回调 -> 拿到
BehaviorSubject
-
BehaviorSubject
和 PublishSubject
类似,但是会保存订阅前的一个数据
BehaviorRelay
可以直接设置和拿到值
let br = BehaviorRelay<Int>(value: 100)
br.accept(1000)
br.value
总结:一般我们在页面传值的时候用 subject 比较多,序列的传递
Dispose
-
DisposeBag
底层有一个数组,保存了当前所有 bag 调用 dispose 或者重新初始化的话的时候回销毁
- 或者拿到创建的序列返回的
disposeable
进行 dispose
KVO
- Swift KVO 底层也是对 OC 的 KVO 进行了封装
- RAC 同理
- KVO 底层原理通过 runtime 创建当前监听类的子类实现监听属性的 get、set 方法,最终实现 change 的改变
RxSwift
内存管理
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
- 打印计数
RxSwift.Resources.total
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
print("计数viewWillAppear:\(RxSwift.Resources.total)")
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillAppear(animated)
print("计数viewWillDisappear:\(RxSwift.Resources.total)")
}
- 当
subscribe
注意循环引用
-
VC.bag
时注意循环
- unowned 无主引用,确保访问时不会被释放,因为设置后会一直引用对象,即使对象被释放了也会保持一个无效的引用,如果调用这个引用对象(无效引用)的方法就会崩溃
- weak 弱引用处理,作用域结束后清除弱引用对象
- 通过实现
中介者模式
class XCTimer: NSObject {
weak var target: NSObjectProtocol?
var sel: Selector?
var xcTimer: Timer? = nil
override init() {
super.init()
}
func xc_scheuledTimer(timeInterval ti: TimeInterval, target aTarget: Any, selector aSelector: Selector, userInfo: Any? = nil, repeats: Bool) {
self.xcTimer = Timer.init(timeInterval: ti, target: aTarget, selector: aSelector, userInfo: userInfo, repeats: repeats)
RunLoop.current.add(self.xcTimer!, forMode: .common)
self.target = aTarget as? NSObjectProtocol
self.sel = aSelector
guard self.target?.responds(to: self.sel) == true else {
return
}
let method = class_getInstanceMethod(self.classForCoder, #selector(timerAction))
class_replaceMethod(self.classForCoder, self.sel!, method_getImplementation(method!), method_getTypeEncoding(method!))
}
@objc
fileprivate func timerAction() {
if self.target != nil {
self.target!.perform(self.sel)
} else {
self.xcTimer?.invalidate()
self.xcTimer = nil
}
}
override func forwardingTarget(for aSelector: Selector!) -> Any? {
if self.target?.responds(to: self.sel) == true {
return self.target
}
else {
// 容错处理~ 可以通过 Runtime 来创建没实现的 Selector
// class_addMethod(self.classForCoder, aSelector, imp_, <#T##types: UnsafePointer<Int8>?##UnsafePointer<Int8>?#>)
return super.forwardingTarget(for: aSelector)
}
}
}
let time = XCTimer()
time.xc_scheuledTimer(timeInterval: 1, target: self, selector: #selector(time), repeats: true)
func time() {
}
- 所有的逻辑在中介层处理,使用
weak
关键字保证不被循环引用