Combine

Combine (4) - Cancellable

Zedd0202 2020. 3. 24. 15:05

 

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

오늘은..

 

마지막..!! Cancellable을 공부해볼게요!

Combine을 공부하고 그걸 블로그에 포스팅 하는 입장으로서, 틀린 내용을 게시하지 않으려고 노력중입니다!

그럼에도 불구하고 틀린 내용이 있을 수 있으니

이 글만 보고 아 이게 이렇구나~라는 건 굉장히 위험합니다. 

그걸 꼭 염두하시고 글을 읽으시길 바랄게요 :D

틀린 내용을 발견하시면 댓글로 알려주시면 감사하겠습니다!

Combine이 유독......뭔가 조심스럽네요. 제가 1도 몰라서리 ㅎ

 

그럼 Cancellable을 공부해봅시다!

Cancellable 역시 프로토콜이구요! 

정의는 activity 또는 action이 취소(cancellation)를 지원함을 나타내는 프로토콜이라고 합니다..!

cancel()을 호출하면 할당 된 모든 리소스가 해제된대요.

타이머, 네트워크 액세스, 디스크 IO와 같은 부작용을 막는다고 해요.

 

이 Cancellable은 우리가..? 아니..제가..공부 한 적은 없지만 많이 봤어요!!

바로 sink의 result...

ㅇ ㅏ Cancellable인 줄 ㅎ AnyCancellable이네

그럼 AnyCancellable을 공부해봅시다!

AnyCancellable은 프로토콜은 아니고 class인데요.

딱 봐도 Cancellable 채택하게 생겼다 아님

응 맞아

AnyCancellable은 취소 되었을 때, 제공된 closure를 실행하는 type-erasing cancellable object입니다.

Subscriber 구현에서는 이 타입을 사용해서 caller가 publisher를 취소할 수 있지만, Subscription 객체를 사용하여 item을 요청할 수 없는 "cancellation token"을 제공할 수 있습니다. 

AnyCancellable 인스턴스는 deinitialized 될 때 자동으로 cancel()을 호출합니다.

 

자..! 그럼 cancel()을 명시적으로 호출해봅시다.

별로 어렵진 않은데요, 

이렇게 하면 되겠죠?!?!

send를 호출해도 아무 반응 없음 ㅎ 왜냐면 cancel 됐으니까..!!!

AnyCancellable의 생성자는 cancel()이 호출될 때 실행할 closure를 받는데요, sink에서...알아서 넣겠죠..!?

실제로, subscriber를 dump해보면..

이렇게 나옵니다.

cancel하고 나서는

이러케 nil...

 

그럼 제가 궁금한 점은..

sink로 subscriber를 만들었는데...cancel()을 호출했어.

근데 내가 원하는 클로져 실행시키고 싶어 < 이거 안되는건가요...!?!?!

저 클로져 안에 뭐가 들어있는거지..?

 

자..cancel되었을 때 내 closure를 실행시키는 방법은 이 글 후반부에서 다루도록 할게요.

먼저 Cancellable의 store(in: ) 메소드를 보도록 할게요!

자 store(in: ) 메소드는 뭐냐면..말그대로 store..저장하는 겁니다.

뭐를? Cancellable instance를...

그래서 어떻게 사용하면 되냐면..

store메소드안에 보면 파라미터의 타입이 Set<AnyCancellable>인걸 볼 수 있죠?  

응 그니까 Set<AnyCancellable>을 만들어주고, 그걸 그냥 store에 넘기면 됩니다. 짱쉽죠...

 

아무튼 store(in: )메소드의 사용법은 알겠죠? 

그럼 Subscription객체를 이용해서..취소되었을 때 내가 실행하고 싶은 closure를 실행하는 방법을 볼게요 ㅎㅎ

자..custom Subscriber를 만들어주었습니다. https://zeddios.tistory.com/966 

 

Combine (1-1) - Subcribers.Demand

안녕하세요 :) Zedd입니다. https://zeddios.tistory.com/925 Combine (1) - Publisher, Subscriber 안녕하세요 :) Zedd입니다. 이번 휴가동안 SwiftUI를 좀 해볼라하는데 Combine모르면 이거 걍 노답임.... -> 휴..

zeddios.tistory.com

에서 조금 수정한 예제에요. 위 글을 보신 분이라면..익숙하실거에요.

위 코드에서 눈여겨 봐야 할 점은, 

Subscription 타입 변수가 있다는 겁니다!

이 Subscription 역시 프로토콜이구요. Subscription은 Cancellable을 채택하고 있습니다. 

그럼 custom Subscription 타입을 만들어볼게요. 

https://github.com/sumitoberoi1/SwiftUI/blob/60e0536d0b06edd29dfc4eb126ba19b7d99f199f/SwiftUI-Flux/Models/AnySubscription.swift

를 참고했어요! (클래스 이름만 바꿈)

그럼 ZeddSubscription 인스턴스를 만들어서 ZeddSubscriber의 subscription안에 넣어주면 되겠죠?

이렇게 해줘볼게요!

subscribe앞에 print()를 호출했기 때문에 실행하면 콘솔에 로그들이 뜰거에요! 저번글에서는 단순히 print().~이런식으로 했는데 오늘은

print 안에 그냥 아무 String을 넣어봤어요~ 이렇게도 쓸 수 있다는 걸 알려드리고 싶었습니다..!

이렇게 뜨게 됩니다 ㅎㅎㅎ

자, 그럼 cancel되었을 때 "cancel!" 이 출력된 걸 볼 수 있죠!!!

내가 넣은 클로져가 실행이 되었습니다!!!

근데 지금 이거는..custom Subscriber만들고..

custom Subscription까지 만들어서......ㅎㅎㅎ 한거잖아요..!! 귀찮귀찮

Apple이 제공해주는 subscriber를 만들어주는 sink..를 가지고 cancel 되었는지 어쩐지를 판별을 어떻게 할 수 있을까요!?

 

찾아보니 handleEvent라는게 있어요!

정의는

"Performs the specified closures when publisher events occur." 

publisher 이벤트가 발생 할 때 지정한 closure를 수행한다...입니다!

사용방법을 볼게요!

이렇게 사용하시면 됩니다. 

당연히 sink를 써서;; 구독을 해야 send고 뭐고 작동을 하겠죠?

아 근데 진짜 아쉬운게 sink안에 있으면 안되는거야..>!?!?!?!?!?!

코드가 쓸데없이 길어지는 느낌인데..ㅠㅠ 

그래도 있는게 어디..라며...

감사해봅니다...

 

일단 제가 대충 정한..그러니까 Combine의 가장 대표적인 프로토콜들은 다 공부를 했네요..!

그래도 봐야 할게 엄청나게 많이 남았지만..ㅎㅎ 도움이 되었길 바랍니다.

 

참고 

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

 

Cancellable - Combine | Apple Developer Documentation

A type-erasing cancellable object that executes a provided closure when canceled.

developer.apple.com

https://www.avanderlee.com/debugging/combine-swift/

 

Combine debugging using operators in Swift - SwiftLee

Combine debugging can be hard because of the long stack traces and asynchronous callbacks. Learn how to benefit from Combine operators to solve this issue.

www.avanderlee.com