RxSwift방식으로 델리게이트를 구현하는 방법
extension CLLocationManager: HasDelegate {
public typealias Delegate = CLLocationManagerDelegate
}
Rx + 확장 대상의 이름 + DelegateProxy확장할 클래스, 연관된 델리게이트 프로토콜DelegateProxyType, 연관된 델리게이트 프로토콜 채용class RxCLLocationManagerDelegateProxy: DelegateProxy<CLLocationManager, CLLocationManagerDelegate>
, DelegateProxyType, CLLocationManagerType {
//클래스 내부에서 확장 대상에 접근할 경우 약한참조 필수
//아예 접근 안하면 이 속성 자체 선언 필요 X
weak private(set) var locationManager: CLLocationManager?
init(locationManager: CLLocationManager) {
self.locationManager = locationManager
super.init(parentObject: locationManager, delegateProxy: RxCLLocationManagerDelegateProxy.self)
}
//클로저에서 DelegateProxy의 인스턴스를 리턴해야 함
static func registerKnownImplementations() {
self.register {
RxCLLocationManagerDelegateProxy(locationManager: $0)
}
}
}
extension Reactive where Base: CLLocationManager {
var delegate: DelegateProxy<CLLocationManager, CLLocationManagerDelegate> {
//DelegateProxy 인스턴스 리턴
//DelegateProxy class의 init을 사용하면 안됨(인스턴스가 두 개 이상 생성되면 문제 발생)
//따라서 proxy(for:) 메소드 사용
return RxCLLocationManagerDelegateProxy.proxy(for: base)
}
//여기부터는 필요에 따른 구현을 하면 된다.(델리게이트 내부에서 필요 메소드)
var didUpdateLocations: Observable<[CLLocation]> {
//직접 Observable을 만드는 것이 아닌 methodInvoked 사용
return delegate.methodInvoked(#selector(CLLocationManagerDelegate.locationManager( :didUpdateLocations:)))
.map { parameters in //didUpdateLocations는 두 개의 리턴값이 있기 때문
return parameters[1] as! [CLLocation]
}
}
}
//viewDidLoad에서 사용 예시
override func viewDidLoad() {
super.viewDidLaod()
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
//사용
locationManager.rx.didUpdateLocations
.subscribe(onNext: { locations in
print(locations)
})
.disposed(by: bag)
locationManager.rx.didUpdateLocations
.map { $0[0] }
.bind(to: mapView.rx.center)
.disposed(by: bag)
}