티스토리 뷰

Swift

Combine 뽀개기 3장: Subject

Esiwon 2023. 7. 26. 20:02

Subject

A publisher that exposes a method for outside callers to publish elements.
외부 호출자가 요소를 게시할 수 있도록 메서드를 노출하는 게시자입니다.

Subject또한 프로토콜이다. Subject도 쉽게 생각하면, publisher의 한 종류이다.

protocol Subject : AnyObject, Publisher

왜냐하면, Subject 또한 publisher를 채택받고 있기 때문이다.

자그럼 둘은 무슨 차이냐!

일반 publisher 같은 경우 선언과 동시에 방출될 값이 정해진다.

예를 들어, Just 같은 경우에도

let justPublisher = Just("Combine 첫 교시")

정해진 "Combine 첫 교시"라는 값 밖에 방출하지 못한다.

다른 여타 publisher도 형태만 다를 뿐이지 선언과 동시에 정해진 값 밖에 방출하지 못하는 것은 같다.

또한 값을 모두 방출하면, 자동적으로 completion이 호출된다.

하지만, Subject 같은 경우 추가적인 요소를 방출할 수 있다.

자세한 사용법은 코드로 확인하고, 그전에 구현되어 있는 Subject 소개하자면, 두개가 존재한다.

  • CurrentValueSubject
  • PassthroughSubject

둘의 차이는 "초기값이 있냐, 없냐"의 차이이다.

CurrentValueSubject

CurrentValueSubject 이녀석은 초기값이 있는 Subject

var subscriberBag = Set<AnyCancellable>()

let currentValueSubject = CurrentValueSubject<String, Never>("Safari")

currentValueSubject.sink { completion in
    print(completion)
} receiveValue: { value in
    print(value)
}.store(in: &subscriberBag)
Safari

위와 같이 CurrentValueSubject는 생성자에 초기값을 넣어줘야 한다.

실행해보면, Safari 호출되고 completion이 호출되지 않는 것을 볼 수 있다.

이는 아직 CurrentValueSubject의 작업이 끝나지 않았음을 알 수 있다.

currentValueSubject.value = "Combine"
currentValueSubject.send("swift")

위 코드를 아래에 추가하면,

Combine
swift

위와 같이 값을 추가로 방출하는 것을 볼 수 있다.

이번엔,

currentValueSubject.send(completion: .finished)
currentValueSubject.send("Rxswift")

위 같이 코드를 추가하면,

finished

finished가 호출되고 더이상 "Rxswift"라는 값은 방출하지 않는다.

이는 completion를 통해 작업이 끝났음을 선언했기 때문이다.

위와 같이 Subject 같은 경우 send 메서드를 통해 추가적인 값 방출이 가능하다

전체 코드,

var subscriberBag = Set<AnyCancellable>()
let currentValueSubject = CurrentValueSubject<String, Never>("Safari")// 필수적으로 초기값이 필요

currentValueSubject.sink { completion in
    print(completion)
} receiveValue: { value in
    print(value)
}.store(in: &subscriberBag)


currentValueSubject.value = "Combine"
currentValueSubject.send("swift")
currentValueSubject.send(completion: .finished)
currentValueSubject.send("Rxswift")
Safari
Combine
swift
finished

PassthroughSubject

PassthroughSubject같은 경우 currentValueSubject 보다 심플하다.

따로 초기값이 없기 때문이다.

enum InputError: Error {
    case unkown
}

let passthroughSubject = PassthroughSubject<String, InputError>()

passthroughSubject.sink { result in
    switch result {
    case .finished:
        print("input 끝")
    case .failure(let error):
        print(error.localizedDescription)
    }
} receiveValue: { value in
    print(value)
}.store(in: &subscriberBag)

위와 같이 생성자에 초기값이 들어가지 않는다.

passthroughSubject.send("m1Mac")
passthroughSubject.send("사고싶다.")

때문에 위와 같이 send 메서드를 통해 보낸 값만을 방출한다.

m1Mac
사고싶다.

또한, send(completion:) 메서드는 .finished만 보내는것이 아닌 Subject가 Error를 방출한다면,

passthroughSubject.send(completion: .failure(.unkown))

passthroughSubject.send("더이상 input를 받지 않음")

.failure를 통해 Error 방출이 가능하다.

unkown

역시 completion이 호출되었기 때문에 아래의 "더이상 input를 받지 않음"이라는 값을 방출하지 않는다.

전체 코드,

var subscriberBag = Set<AnyCancellable>()

enum InputError: Error {
    case unkown
}

let passthroughSubject = PassthroughSubject<String, InputError>()

passthroughSubject.sink { result in
    switch result {
    case .finished:
        print("input 끝")
    case .failure(let error):
        print(error)
    }
} receiveValue: { value in
    print(value)
}.store(in: &subscriberBag)

passthroughSubject.send("m1Mac")
passthroughSubject.send("사고싶다.")

passthroughSubject.send(completion: .failure(.unkown))
//passthroughSubject.send(completion: .finished)

passthroughSubject.send("더이상 input를 받지 않음")
m1Mac
사고싶다.
unkown
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/09   »
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
글 보관함