[RxSwift] DelegateProxy

RudinP·4일 전
0

Study

목록 보기
379/380

RxSwift방식으로 델리게이트를 구현하는 방법

  • 특정 delegate가 실행되는 시점에 구독자에게 이벤트를 전달
  • delegate뿐만 아니라 dataSource또한 동일한 패턴으로 확장 가능

필수 구현 패턴

  • 보통 하나의 클래스와 두 개의 익스텐션을 구현

1. HasDelegate extension

extension CLLocationManager: HasDelegate {
	public typealias Delegate = CLLocationManagerDelegate
}
  • 관련된 Delegate를 typelias로 연결

2. DelegateProxy class

  • 이름은 Rx + 확장 대상의 이름 + DelegateProxy
  • 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)
        }
    }
}

3. Reactive extension

  • 확장대상을 Base로 함
  • delegate 속성 추가
    • 앞에서 구현했던 proxy의 superclass로
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)
}
profile
iOS 개발자가 되기 위한 스터디룸/스터디의 레퍼런스는 모두 kxcoding

0개의 댓글