본문 바로가기

Swift/All

Combine 기본 사용법 정리

- Publisher

import Combine

class SomeObject {
    var vsalue: String = "" {
        didSet {
            print(vsalue)
        }
    }
    
    var asdfasdf: String = "" {
        didSet {
            print(asdfasdf)
        }
    }
}

let someObject = SomeObject()

let publisher = ["울릉도", "동남쪽", "뱃길 따라 이백리"].publisher

_ = publisher.assign(to: \SomeObject.asdfasdf, on: someObject)
//위 아래 두 개 다 같은거
_ = publisher.assign(to: \.asdfasdf, on: someObject)

 

근데 publisher는 애초에 정해진 값만 가지고 하는거고 값 나중에 외부에서 값 추가가 안됨

 

ex) 변화가 없는 페이지의 경우 불러온 뒤 publisher를 만들어 그걸 표시하면 되지만 페이지 네이션에 따라 배열이 추가되는 경우라면 사용 못합

 

- Subject(PassthroughSubject)

import Combine

enum TestError: Error {
    case 실패입니다
}

let subject = PassthroughSubject<String, TestError>()

subject.send("zero")

let a = subject.sink(receiveCompletion: { completion in
    switch completion {
    case .finished:
        print("끝~")
    case .failure(let error):
        print("\(error)")
    }
}, receiveValue: { value in
    print(value)
})

subject.send("one")
subject.send("two")
subject.send("three")
subject.send(completion: .failure(TestError.실패입니다))

PassthroughSubject 를 이용하면 구독 이후 send를 통해 새로운 값을 추가했을 때 그 값도 반영이 됨

하지만 구독 전에 추가된 값은 반영이 안됨

(추가로 .failure를 send로 전달 할 수도 있으며 아래 보면 .finished로 끝낼 수도 있음)

 

 

빨간 부분처럼 조건을 걸어 cancel도 가능하며 cancel되면 그 이후 send는 반영 x

 

 

또 finished 혹은 failure가 전달되면 그 이후에 어떤 값이 전달돼도 반영 x

 

- Subject(CurrentValueSubject)

import Combine

enum TestError: Error {
    case 실패입니다
}

let subject = CurrentValueSubject<String, TestError>("울릉도")

let a = subject.sink(receiveCompletion: { completion in
    switch completion {
    case .finished:
        print("끝~")
    case .failure(let error):
        print("\(error)")
    }
}, receiveValue: { value in
    print(value)
})

subject.send("동남쪽")
subject.send("뱃길따라 이백리")
subject.send("외로운")
subject.send("섬하나")

"울릉도" 라는 초기값이 할당되어 있고 그 이후로 send되는 값들도 다 반영된다

(나머지 .failure, .finishied, .cancel등 동일)

- Subject와 RxSwift 비교

아는게 RxSwift밖에 없어서 내가 이해하기 편하고자 굳이굳이 비교를 해보자면

'PassthroughSubject'는 rx의 publishSubject, (초기값이 없다)
'CurrentValueSubject'는 rx의 behaviorSubject와 비슷하다고 보여진다 (초기값이 있다

 

 

 

- store 와AnyCancellable

Combine에도 RxSwift의 Disposed(by:) 그리고 DisposeBag과 비슷한 역할을 하는게 있는데

그것이 말고 .store(& )와 Set<AnyCancellable>()이다

사용방법도 거의 동일 ㄷㄷ;;

import Combine

enum TestError: Error {
    case 실패입니다
}

//요기다 만들고
var cancellables = Set<AnyCancellable>()

let subject = CurrentValueSubject<String, TestError>("울릉도")

let a = subject.sink(receiveCompletion: { completion in
    switch completion {
    case .finished:
        print("끝~")
    case .failure(let error):
        print("\(error)")
    }
}, receiveValue: { value in
    print(value)
}).store(in: &cancellables) //요기서 추가

이런 식으로 말이다

 

 

거진 1년을 미뤄왔던 Combine공부...

뭔가 Rx를 처음 공불 할 때 혼란스러워 했던 경험을 몸이 기억해서인지 자꾸 꺼려졌는데 Rx를 이미 알고 있는 입장에서 이렇게 기본 사용법 까지는 금방 했던 것 같다

(속내를 완전히 이해 한다기 보다는 Rx와 비교하면서 공부를 하다 보니 말이다)

 

이 정도면 그냥 스트림 만들기에는 적당한 것 같고 다음에는 operator에 대해 공부해보려고 한다