RxFSCalendarDelegateProxy.swift
import Foundation
import RxSwift
import RxCocoa
import FSCalendar
class RxFSCalendarDelegateProxy: DelegateProxy<FSCalendar, FSCalendarDelegate>, DelegateProxyType, FSCalendarDelegate {
static func registerKnownImplementations() {
self.register { (calendar) -> RxFSCalendarDelegateProxy in
RxFSCalendarDelegateProxy(parentObject: calendar, delegateProxy: self)
}
}
static func currentDelegate(for object: FSCalendar) -> FSCalendarDelegate? {
return object.delegate
}
static func setCurrentDelegate(_ delegate: FSCalendarDelegate?, to object: FSCalendar) {
object.delegate = delegate
}
}
extension Reactive where Base: FSCalendar {
var delegate : DelegateProxy<FSCalendar, FSCalendarDelegate> {
return RxFSCalendarDelegateProxy.proxy(for: self.base)
}
var didSelect : Observable<Date> {
return delegate.methodInvoked(#selector(FSCalendarDelegate.calendar(_:didSelect:at:)))
.map({ (params) in
return params[1] as? Date ?? Date()
})
}
}
MainViewController.swift
import UIKit
import ReactorKit
import FSCalendar
class MainViewController: BaseViewController, View {
typealias Reactor = MainViewReactor
let calendar = FSCalendar()
let label = UILabel()
init(reactor: Reactor) {
super.init()
defer { self.reactor = reactor }
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func setupLayout() {
self.view.addSubview(calendar)
}
override func makeConstraints() {
self.calendar.snp.makeConstraints {
$0.bottom.equalToSuperview()
$0.top.equalToSuperview()
$0.left.equalToSuperview()
$0.right.equalToSuperview()
}
}
func bind(reactor: MainViewReactor) {
// MARK: input
calendar.rx.didSelect.asObservable()
.map { Reactor.Action.setDay($0) }
.bind(to: reactor.action)
.disposed(by: disposeBag)
// MARK: output
}
}
I am trying to change FSCalendarDelegate func to Observable to use ReactorKit. But When I run this code, error occurred "RxCocoa/DelegateProxy.swift:230: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value" I don't know how to fix my DelegateProxy. why aSelector is nil?
You have discovered a bug. The code is crashing because FSCalendar is asking the delegate if it responds to a selector but the selector is nil
. Neither FSCalendar nor RxCocoa is checking the selector for nil.
I have submitted a pull request to the RxSwift repository to correct this problem.
While waiting for the pull request to go through the system, you can sub-class DelegateProxy and override the offending method:
class MyDelegateProxy<P: AnyObject, D>: DelegateProxy<P, D> {
override open func responds(to aSelector: Selector!) -> Bool {
guard aSelector != nil else { return false }
return super.responds(to: aSelector)
}
}
class RxFSCalendarDelegateProxy: MyDelegateProxy<FSCalendar, FSCalendarDelegate>, DelegateProxyType, FSCalendarDelegate {
static func registerKnownImplementations() {
self.register { (calendar) -> RxFSCalendarDelegateProxy in
RxFSCalendarDelegateProxy(parentObject: calendar, delegateProxy: self)
}
}
static func currentDelegate(for object: FSCalendar) -> FSCalendarDelegate? {
return object.delegate
}
static func setCurrentDelegate(_ delegate: FSCalendarDelegate?, to object: FSCalendar) {
object.delegate = delegate
}
}
As to why the aSelector
is nil... When FSCalendar wants to use a delegate method, it first checks to see if the method has been implemented. If not, then it checks to see if a deprecated version of the method is implemented. If there is no deprecated version, then it will ask the delegate if the nil
method is implemented. It feels kind of silly to me for FSCalender to do this, but apparently if this is done on a traditional delegate implementation, the OS responds with false. RxCocoa just assumes that no library would ever do this.