후발주자라 그런지 Rx와 비슷한 방식이 적용됐다. @published, PassthroughSubject, CurrentValueSubject의 차이를 알아보기 위해 예제를 만들어 보자.
class TestEnvironment: ObservableObject { @Published var value1 = "aaa" @Published var value2 = PassthroughSubject<String, Never>() @Published var value3 = CurrentValueSubject<String, Never>("aaa") }
// SceneDelegate.swift let testEnvironment = TestEnvironment() let contentView = ContentView().environmentObject(testEnvironment)
struct ContentView: View { @EnvironmentObject var testEnvironment: TestEnvironment @State var cancellable = Set<AnyCancellable>() var body: some View { VStack { Button(action: { print("--------- click-aaa ---------") self.testEnvironment.value1 = "aaa" self.testEnvironment.value2.send("aaa") self.testEnvironment.value3.send("aaa") }) { Text("Button aaa") } Button(action: { print("--------- click-bbb ---------") self.testEnvironment.value1 = "bbb" self.testEnvironment.value2.send("bbb") self.testEnvironment.value3.send("bbb") }) { Text("Button bbb") } }.onAppear { print("onAppear =============== ") self.testEnvironment.$value1 .filter { String($0) == "aaa" } .sink { print("value1-aaa: \($0)") } .store(in: &self.cancellable) self.testEnvironment.value2 .filter { String($0) == "aaa" } .sink { print("value2-aaa: \($0)") } .store(in: &self.cancellable) self.testEnvironment.value3 .filter { String($0) == "aaa" } .sink { print("value3-aaa: \($0)") } .store(in: &self.cancellable) self.testEnvironment.$value1 .filter { String($0) == "bbb" } .sink { print("value1-bbb: \($0)") } .store(in: &self.cancellable) self.testEnvironment.value2 .filter { String($0) == "bbb" } .sink { print("value2-bbb: \($0)") } .store(in: &self.cancellable) self.testEnvironment.value3 .filter { String($0) == "bbb" } .sink { print("value3-bbb: \($0)") } .store(in: &self.cancellable) } } }
onAppear =============== value1-aaa: aaa value3-aaa: aaa --------- click-aaa --------- value1-aaa: aaa value2-aaa: aaa value3-aaa: aaa --------- click-aaa --------- value1-aaa: aaa value2-aaa: aaa value3-aaa: aaa --------- click-bbb --------- value1-bbb: bbb value2-bbb: bbb value3-bbb: bbb --------- click-bbb --------- value1-bbb: bbb value2-bbb: bbb value3-bbb: bbb
결론
@Published + 일반 변수 타입
- 일반 변수를 구독형으로 만들어 줌
- 단 사용할 때 변수 앞에
$
를 붙여줘야 함 - 구독 시작하자마자 발행이 되기 때문에 Rx의 BehaviorSubject와 비슷해짐
- 초기값이 없으면 실제 사용하는 곳에서 무지 귀찮아지니까 차라리 PassthroughSubject로 바꾸는게 좋아보임
PassthroughSubject
- Rx의 PublishedSubject와 비슷
- 구독 후 값이 들어왔을 때만 발행됨
- 같은 값이 또 들어와도 발행됨
CurrentValueSubject
- Rx의 BehaviorSubject와 비슷
- 구독하자마자 현재 값이 발행됨
- 무조건 초기값을 지정해야 함