티스토리 뷰

Combine

[Combine] Scheduler

밀쿄 2019. 12. 15. 02:12

정말 연속 포스팅은 처음이네요..
오늘은 사담없이 바로 시작해보겠습니다

Scheduler

우리가 코딩을 하다보면은 쓰레드를 다뤄야할 일이 많습니다.
네트워크 작업이나, 연산이 많이 필요로 하는 작업은 백그라운드에서 돌려야하지만
화면과 관련된 UI 부분은 메인에서 사용해야합니다.
스케쥴러를 사용하면 일너 쓰레드를 제어할 수 있습니다.
쉽게 말하면 Scheduler는 쓰레드를 가르키는 말이겠네요

Before Combine

지난 시간에 만든 ImageDownloader 예제에서 쉽게 찾아볼 수 있습니다.


DispatchQueue.global().async {
    //Code
}

DispatchQueue.main.async {
    //Code
}

바로 DispatchQueue.main 이나 DispatchQueue.global같은 녀석들이죠.
이런 애들을 GCD(Grand Central Dispatch)라고 부르죠
이거 말고도 OperationQueue 같은 녀석들이 있습니다
GCD는 저수준의 C API이고 OperationQueue는 그런 GCD를 추상화시켜서 wrapping 시켜놓은 거라고 알고 있습니다.

At Combine

콤바인에서는 두가지가 있습니다.
바로 subscribe(on:) 과 receive(on:) 이 두가지가 있습니다.
오늘은 이 두 가지에 대해서 한 번 알아보겠습니다.

subscribe(on:) vs receive(on:)

먼저 이해하기 쉬운 receive(on:)부터 알아보겠습니다.

Just(1)
    .handleEvents(receiveOutput: { _ in print(Thread.isMainThread) }) //true
    .receive(on: DispatchQueue.global())
    .handleEvents(receiveOutput: { _ in print(Thread.isMainThread) }) //false
    .receive(on: DispatchQueue.main)
    .handleEvents(receiveOutput: { _ in print(Thread.isMainThread) }) //true
    .sink { value in
        print(value) //1
}.store(in: &cancelBag)

이런 식으로 receive(on:)안에 자기가 바꾸고 싶은 쓰레드를 집어 넣으면 됩니다.
그러면 receive(on:)을 호출한 시점부터 그 쓰레드로 동작하게 됩니다.

자 그렇다면 subscribe(on:)은 무엇일까요?
다음과 같은 코드를 작성해봅시다.

func printValue(_ value: Int) {
    Just(value)
        .handleEvents(receiveOutput: { _ in print(Thread.isMainThread) }) // 1번
        .receive(on: DispatchQueue.global())
        .handleEvents(receiveOutput: { _ in print(Thread.isMainThread) }) // 2번
        .receive(on: DispatchQueue.main)
        .handleEvents(receiveOutput: { _ in print(Thread.isMainThread) }) // 3번
        .receive(on: DispatchQueue.global())
        .handleEvents(receiveOutput: { _ in print(Thread.isMainThread) }) // 4번
        .subscribe(on: DispatchQueue.main)
        .handleEvents(receiveOutput: { _ in print(Thread.isMainThread) }) // 5번
        .sink { value in
            print(value) //1
    }.store(in: &cancelBag)
}
DispatchQueue.global().async {
    printValue(1)
}

1번부터 5번까지 어떤 결과물이 출력될까요?
정답은 true, false, true, false, false 입니다.

여기서 이런 의문이 들 수 있을껍니다.
함수 호출을 main이 아닌 곳에서 불렀는데 1번이 왜 true이며
5번은 왜 false인지

사실 이것은 subscribe(on:)때문에 발생한 현상입니다.
이 놈은 시작하는 시점에 메서드를 바꿉니다.
쉽게 말하면 시작하는 메서드를 결정하는 함수라고 생각하시면 됩니다.
즉 호출 시점이 상관없다는 뜻입니다.

그러므로 1번에서 메인큐에서 시작해서 글로벌큐 -> 메인큐 -> 글로벌큐에서 다시 메인큐으로 돌아 오지 않기 때문에
마지막 5번은 메인이 아닙니다.

Conclusion

receive(on:)은 특정 작업의 스케쥴러를 변경할 수 있어 여러번 사용하지만
subscribe(on:)은 동작하는 스트림의 스케쥴러를 바꾸기 때문에 한 번만 사용해서 쓰레드를 관리하는 것이 좋습니다.

'Combine' 카테고리의 다른 글

CombineLatest  (0) 2020.02.11
[Combine] Sequence  (0) 2019.12.20
[Combine]Just  (0) 2019.12.16
[Combine] Cancellable  (0) 2019.12.13
Start! Combine  (0) 2019.12.12
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함