티스토리 뷰

Combine

Combine (3) - Scheduler

Zedd0202 2020. 3. 23. 12:43
반응형

 

안녕하세요 :) Zedd입니다.

Publisher와 Subscriber, Subject를 공부했는데요, 오늘은 Scheduler를 공부해볼게요.

역시나 프로토콜입니다.

 

Scheduler


 

Scheduler는 closure의 실행시기와 방법을 정의하는 프로토콜이에요.

이 Scheduler를 이용해서 가능한 빨리 코드를 실행시킬 수도 있고,

특정 시간 이후에 코드를 실행시킬 수도 있어요. 

개별 Scheduler 구현은 시간 관리 시스템(time-keeping system)에 적합한 것을 사용해야한대요.

Scheduler는 이를 SchedulerTimeType으로 표시합니다.

이 타입은 SchedulerTimeIntervalConvertible을 준수하므로 .milliseconds (500)와 같은 편리한 함수를 사용해서 시간을 표현할 수 있습니다!

Scheduler에 옵션을 줄 수도 있는데요, 이러한 옵션은 작업을 실행하는 스레드 또는 디스패치 큐와 같은 요소를 제어할 수 있다고 합니다!

 

됐고, 코드로 보는게 가장 이해가 빠를 것 같아요.

아니 근데 공식 문서 무슨 일......설명 좀만 더 해주지 ㅠ

https://www.vadimbulavin.com/understanding-schedulers-in-swift-combine-framework/

 

Understanding Schedulers in Swift Combine Framework

Let's learn what are schedulers in Swift Combine Framework along with several related topics: which schedulers are built into Combine? What's the difference between receive(on:) and subscribe(on:)? How to switch schedulers? How to perform asynchronous work

www.vadimbulavin.com

여기가 설명이 너무너무 잘되어있네요.

이 글을 공부하면서 제가 추가 할 것들 있으면 추가할게요!

 

우리가 Publisher와 Subcriber, Subject를 공부할 때 Scheduler에 대한 코드는 전혀 없었습니다.

네! Scheduler를 지정하지 않더라도 Combine은 기본 Scheduler를 제공해요.

Scheduler는 element가 생성된 스레드와 동일한 스레드를 사용합니다. 

기본적으로 main thread에서 일어날거니까? sink에서 true가 찍히는 것을 볼 수 있죠.

background 스레드에서 element를 발행하면 background 스레드에서 element를 받는다..도 확인해볼까요? 

자.

그냥 send를 보내고, dispatchQueue.global에 감싸서 send를 보내봤어요.

send(1)은 메인 쓰레드로 부터 왔고

send(2)는 백그라운드 스레드로 부터 온 것을 볼 수 있습니다. 

그러니까

 

"Scheduler는 element가 생성된 스레드와 동일한 스레드를 사용합니다. "

는 이해가셨나요!?

 

이렇게 Combine의 기본 Scheduler를 봤으니..Scheduler를 명시적으로 지정해주는? 그러니까 Scheduler를 switching해주는 걸 공부해볼게요. 

Combine의 receive(on: )subscribe(on:)으로 할 수 있습니다.

 

먼저 receive(on: )을 볼게요!

 receive(on: )은 publisher로 부터 element를 수신할 scheduler를 지정하는 역할을 합니다.

정확히 말하면 downstream의 실행 컨텍스트를 변경하는 역할을 해요.

(subscribe(on:)은 upstream에 영향.)

정의 아주 정-직

예제로 볼게요.

자,  receive(on: )이 "publisher로 부터 element를 수신할 scheduler를 지정하는 역할을 합니다."라고 그랬죠?

원래 기본적으로 element가 생성된 스레드가 MainThread여서 처음에는 true가 나왔지만, receive(on: )을 사용하여 scheduler를 DispatchQueue.global()로 바꿔주니 이제 isMainThread가 false로 나오는 것을 볼 수 있죠? 


혹시나 궁금하신 분들이 생길까봐..!

위에서 Scheduler는 프로토콜이라고 그랬죠? receive(on: )이나 아래에서 언급할 subscribe(on:)은 파라미터 타입으로 이 Scheduler타입을 받습니다. 그리고 DispatchQueue, OperationQueue, RunLoop, ImmediateScheduler 얘네는 전부 Scheduler를 채택하고 있어요. 물론 iOS 13이상 부터 ㅎ 그러니까 암거나 막 넣어두 됨


그냥 궁금해서 main으로 바꿔봤는데

다 true가 찍히겠죠? 

 

subscribe(on:)은 subscribe, cancel, request operation을 수행 할 scheduler를 지정하는 역할을 합니다.

위에서도 언급했지만, upstream의 실행 컨텍스트를 변경해요. 

 

위에서 언급했듯이 파라미터 타입은 Scheduler입니다!

자..제가 여기서 막혔습니다...

제가 저기 위에 올린 링크의 글을 참고하면서 공부하고 있는데...

왜 subscribe(on:)의 위치는 상관이 없다고 하지..?

https://www.vadimbulavin.com/understanding-schedulers-in-swift-combine-framework/

이게 잘 이해가 안갔어요.

근데 저는 애플 문서에는 그런 내용이 없는데

1. 왜 subscribe(on:)의 위치가 상관없다고 하는지. upstream에만 영향을 준대매

2. subscribe(on:)이 upstream의 실행 컨텍스트를 변경하는데 왜 subscribe(on: ) 다음에 isMainTread가 false가 나오는지..(이건 아래 예제에 나와요)

암튼 이 2가지가 이해가 안가서 계속 글을 못쓰고 있었어요~

http://trycombine.com/posts/subscribe-on-receive-on/

 

subscribe(on:) vs receive(on:)

The difference between subscribe(on:) and receive(on:) in Combine and when to use which operator

trycombine.com

여기서 저의 궁금증을 풀 수 있었어요!

위 링크 내용도 좋지만...저는 진짜 몇번을 읽었는지 모르겠어요. 잘 이해가 안감.....그냥 제가 이해한 내용을 풀어볼게요! 틀린 내용이 있을 수도 있으니...아주 매의 눈으로 보시길 바랍니다.

처음부터 제가 틀린 내용을 안적으면 되는건데 ㅠㅠ 저도 정말 많이 찾아본답니다.....

그럼에도 불구하고 실수 할 수 있으니 글 전부를 100% 신뢰하지 말아주세요. 이건 이 글 뿐만 아니라 모든 글에 해당합니다. 

틀린 부분 지적은 언제든지 환영이고 또 환영.......

 

자 일단..

이렇게 하면 저~~기 위에서 본것과 같이 isMainThread가 true로 나오겠죠? 다시 한 번 말하지만,

"Scheduler는 element가 생성된 스레드와 동일한 스레드를 사용합니다. "

 

자 그럼 subscribe(on:)을 넣어보겠습니다. 

그러면 sink안에서 false가 나온 것을 볼 수 있죠!

저는 이 부분이 잘 이해가 안갔어요. subscribe(on:)은 upstream에만 영향 준대매..

출처 https://stackoverflow.com/questions/53441858/explain-about-downstream-and-upstream-in-rxjava

내가 upstream의 개념을 잘못 알고있는건가..? 하는 생각이 들었어요.

하지만 이유는...

위 코드에서 subscribe(on:)은 지정된 global queue에서 upstream을 subscribe하므로..

그러니까

1. 구독 자체가 global queue에서 일어났고, 

2. output downstream이 동일한 queue에서 전달되므로!

sink에서도 false를 리턴하게 됩니다.

왜냐? "Scheduler는 element가 생성된 스레드와 동일한 스레드를 사용합니다."때문. 

구독 자체가 global queue에서 일어났으니,

element생성도 global queue에서 일어난거죠..!!

그래서 sink에서 false가 나게 됩니다. 

 

그래서 위에..블로그에서 subscribe(on: )의 위치가 상관이 없다고 한 걸까요? receive(on: )으로 명시적으로 downstream의 스케쥴러를 변경하지 않는 이상, subscribe 자체가 일어나는 스케쥴러를 지정하는거니..

whole stream이 subscribe(on: )에서 명시한 스케쥴러에서 작동(?)하게 되는 것이죠..

아무튼 저는 이렇게 이해를 했습니다 ㅎ

 

Combine의 Scheduler를 공부하신 분이 만약 이 글을 보시게 된다면..!!!

혹시라도 틀린 내용이 있다거나 그러면 꼭 알려주시면 감사하겠습니다 :D

3월 3일부터 이 글을 쓰기 시작했네요..!!!! 이제서야..마무리...

너무 개운ㅎㅏㄷ ㅏ...

 

참고: 

https://developer.apple.com/documentation/combine/scheduler

 

Scheduler - Combine | Apple Developer Documentation

Performs the action at some time after the specified date, at the specified frequency, optionally taking into account tolerance if possible. Required.

developer.apple.com

https://www.vadimbulavin.com/understanding-schedulers-in-swift-combine-framework/

 

Understanding Schedulers in Swift Combine Framework

Let's learn what are schedulers in Swift Combine Framework along with several related topics: which schedulers are built into Combine? What's the difference between receive(on:) and subscribe(on:)? How to switch schedulers? How to perform asynchronous work

www.vadimbulavin.com

http://trycombine.com/posts/subscribe-on-receive-on/

 

subscribe(on:) vs receive(on:)

The difference between subscribe(on:) and receive(on:) in Combine and when to use which operator

trycombine.com

 

반응형

'Combine' 카테고리의 다른 글

Combine + UIKit  (2) 2020.04.19
Combine (4) - Cancellable  (0) 2020.03.24
Combine (3) - Scheduler  (4) 2020.03.23
Combine (2) - Subject  (1) 2020.02.29
Combine (1-1) - Subcribers.Demand  (0) 2020.02.26
Combine (1) - Publisher, Subscriber  (1) 2020.02.25
댓글
  • 프로필사진 제디오스 아디오...제디오스! 2020.03.23 13:58
  • 프로필사진 됴르륵... 안된다고 하셨던 이 부분!

    ```
    publisher .map { _ in print(Thread.isMainThread) } // true
    .receive(on: DispatchQueue.main) // main
    .map { print(Thread.isMainThread) }
    .sink { print(Thread.isMainThread) }
    ```

    됩니다!

    오류가 고쳐진 걸까요
    왜 제드님이 할 땐 안되고 6개월 지난 지금 하니까 되는걸까 @_@?
    2020.09.11 11:32
  • 프로필사진 Favicon of https://zeddios.tistory.com BlogIcon Zedd0202 오 그러네요!! 감사합니다! 2020.09.11 11:48 신고
  • 프로필사진 Favicon of https://iosdev.tistory.com BlogIcon 개발하는 에버 Subject로 테스트 할 때 기준으로 보면 element가 생성되는 스레드는 구독하는곳의 스레드가 아니라 send(Output)이 발생하는 스레드인것 같구요
    이 때 subscribe(on:)과 상관없이 별도로 receive(on:)으로 스케쥴러를 명시해주지 않았다면 send와 동일한 스레드의 결과를 sink에서 받는것 같습니당...
    2022.03.07 21:20 신고
댓글쓰기 폼
반응형
Total
4,015,933
Today
425
Yesterday
2,463