쉽게 배우는 RxSwift (#2) - 비동기 작업

Rx의 용도

Rx는 어디에 적용해야 합니까? 비동기처리 라이브러리니까 비동기 처리할 때 사용하면 됩니다.

물론 동기 데이터도 RxSwift를 사용해서 비동기적으로 처리할 수 있지만, 그저 Rx를 쓰고싶다는 마음에 과용하는 것은 득될게 없습니다.

비동기 작업

비동기 작업은 동기적이지 않은 작업 입니다. 동기적인 작업은 선행작업이 끝날때까지 기다렸다가 다음작업이 진행되는 것입니다. 그래서 비동기 작업은 선행작업이 끝나지 않아도 다음작업이 진행되는 것입니다.

그래서 보통 시간이 오래걸리는 작업의 경우 - 예를들어 네트워크로부터 데이터를 다운로드 하는 경우 - 비동기로 처리하게 됩니다.

비동기로 수행되는 작업은 수행후 결과를 콜백을 통해서 전달합니다. 그래서 호출하는 코드와 그 결과를 받아서 사용하는 부분이 코드가 분리되고 파편화 됩니다.

비동기로 작업되는 경우 여러 작업이 동시에 처리되는 경우가 많기 때문에, 쓰레드로 나눠서 처리하게 됩니다. 그러다 보니 쓰레드 관리도 해줘야 합니다.

여러 작업이 얽히거나 시나리오가 복잡해지면 매우 골치아파집니다.

비동기 라이브러리

이런 비동기 처리를 선형적으로 만들어 Callback-Hell 애서 벗어나게 도와주는 라이브러리들이 있습니다.

비교해 보시면 모두 사용 형태가 같다는 것을 알 수 있습니다.

1. PromiseKit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
UIApplication.shared.isNetworkActivityIndicatorVisible = true

let fetchImage = URLSession.shared.dataTask(.promise, with: url).compactMap{ UIImage(data: $0.data) }
let fetchLocation = CLLocationManager.requestLocation().lastValue

firstly {
when(fulfilled: fetchImage, fetchLocation)
}.done { image, location in
self.imageView.image = image
self.label.text = "\(location)"
}.ensure {
UIApplication.shared.isNetworkActivityIndicatorVisible = false
}.catch { error in
self.show(UIAlertController(for: error), sender: self)
}

2. BoltsFramework

1
2
3
4
5
6
7
8
9
10
save(object).continueWith { task in 
if task.cancelled {
// Save was cancelled
} else if task.faulted {
// Save failed
} else {
// Object was successfully saved
let result = task.result
}
}

4. RxSwift

1
2
3
4
5
6
7
8
9
10
11
save(data)
.subscribe { event in
switch event {
case .next(_):
//save sucess
case .completed:
//job completed
case .error(_):
//job cancled with error
}
}

RxSwfit

이제 본격적으로 RxSwift 내용이 시작됩니다.

  1. 비동기 데이터는 Observable 에 담겨 전달됩니다.
  2. 이 데이터를 받아서 처리하는 것은 subscribe 에서 처리합니다.
  3. 처리방식은 3가지가 있습니다.
    1
    2
    3
    .next : 데이터 전달
    .complted : 데이터 전달 끝
    .error : 오류 발생

가장 간단하게 Observable 을 만들 수 있는 것은 just 입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
_ = Observable.just("Hello World")
.subscribe { event in
switch event {
case .next(let greeting):
print(greeting)
case .completed:
print("[completed]")
case .error(let err):
print("[error: \(err)]")
}
}

// Hello World
// [completed]

_ = 로 리턴값을 처리하는 것은 다음에 알아봅시다.

이번에는 just 가 아니라 from 을 사용해 보갰습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
_ = Observable.from(["Hello", "World"])
.subscribe { event in
switch event {
case .next(let greeting):
print(greeting)
case .completed:
print("[completed]")
case .error(let err):
print("[error: \(err)]")
}
}

// Hello
// World
// [completed]

결과를 보니 from 에서 array 로 입력값을 주니까 하나씩 전달되고 맨 끝에 completed 가 되는 것을 볼 수 있습니다.

이렇게 Observable 이 전달하는 데이터를 순차적으로 받아서 subscribe 에서 처리하하고 데이터가 다 끝나면 completed 가 되는 기본 동작을 알아봤습니다.