레거시 코드를 Rx로 변환하기

이런 레거시 코드가 있다.

1
2
3
4
5
6
7
8
9
10
11
func downloadImage(from url: URL,
completion: @escaping (UIImage?) -> Void)
{
DispatchQueue.main.async {
if let image = try? UIImage(data: Data(contentsOf: url)) {
completion(image)
} else {
completion(nil)
}
}
}

이 코드에 RxSwift를 적용하기 위해서 코드 다음처럼 일일이 수정하게 된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
func downloadImage(from url: URL) -> Observable<UIImage?> {
return Observable.create { emitter in
DispatchQueue.main.async {
if let image = try? UIImage(data: Data(contentsOf: url)) {
emitter.onNext(image)
} else {
emitter.onNext(nil)
}
emitter.onCompleted()
}
return Disposables.create()
}
}

그리고 그게 많아지면 아주 귀..찮다

자동으로 처리해 보자

바꾸다 보면, 공통적인 부분 보인다. 매번 새로 만들지 말고 Rx를 적용해 보자.

1
2
3
4
5
6
7
8
9
10
11
func reactivex<I, O>(_ f: @escaping (I, @escaping (O) -> Void) -> Void) -> (I) -> Observable<O> {
return { i in
return Observable.create { emitter in
f(i, { o in
emitter.onNext(o)
emitter.onCompleted()
})
return Disposables.create()
}
}
}

보통 레거시 코드는 인풋을 받고 아웃풋을 고차함수로 받게 되니까, 이런형태의 함수들을 Rx로 커링하는 함수를 만들었다.

이 함수를 사용해서 레거시에 Rx가 적용된 함수를 얻을 수 있다.

1
let rxdownloader = reactivex(downloadImage)

이제 rxdownloader를 새로운 함수처럼 사용하면 된다.

코드는 여기에,
https://gist.github.com/iamchiwon/46b3732ec20fac568eb509adc2ec927a