iOS 개발을 하면서 헷갈렸던 개념들을 다시 정리해보고 있습니다.
만약 틀린 내용이 있다면 피드백은 언제나 환영합니다.
더 자세하고 알고싶다면 아래쪽 참고사이트에서 확인하면 좋을 것 같습니다!
말투는 편한 말투로 작성하니 양해 부탁드립니다.
비동기 작업들을 이벤트 처리 연산자로 결합하여 처리하는 프레임워크
선언적 프로그래밍 형태
Stream 하나에 필요한 Operator들을 추가하여 쓰는 방식
// 선언형 프로그래밍인 Combine 예제 코드
$username
.debounce(for: 0.1, scheduler: RunLoop.main)
.removeDuplicates()
.map { $0.count >= 2 }
.assign(to: \.valid, on: self)
.store(in: &cancellableSet)
Publisher, Subscriber, Subscription, Subject, Scheduler, Operator
프로토콜이기 때문에 이를 채택하는 class 또는 struct를 직접 구현하여 사용 가능
// 직접 구현
class MyPublisher: Publisher {
typealias Output = Int // 성공 타입
typealias Failure = Never // 실패 타입
// subscription을 만들고 subscriber에게 전달
func receive<S>(subscriber: S) where S : Subscriber, Never == S.Failure, String == S.Input {
let subscription = CustomSubscription(subscriber: subscriber)
subscriber.receive(subscription: subscription)
}
}
이미 구현되어있는 AnyPublisher, Future, Just, Deferred, Empty, Fail, Record 사용 가능
// 예시1: Sequence에 정의되어있는 Publisher
let sequencePublisher = [1,2,3].publisher
// 예시2: Future
let futurePublisher = Future<Int, Never> { promise in
promise(.success(5))
}
프로토콜이기 때문에 이를 채택하는 class 또는 struct를 직접 구현하여 사용 가능
// 직접 구현
class MySubscriber: Subscriber {
typealias Input = Int // 성공 타입
typealias Failure = Never // 실패 타입
func receive(_ input: Int) -> Subscribers.Demand {
print("데이터 수신: \(input)")
return .none
}
func receive(subscription: Subscription) {
print("데이터 구독 시작")
subscription.request(.unlimited) // 구독할 데이터의 갯수를 제한하지 않는 것
}
func receive(completion: Subscribers.Completion<Never>) {
print("모든 데이터 발행 완료")
}
}
let subscriber = MySubscriber()
let subscription = sequencePublisher
.subscribe(subscriber)
이미 구현되어있는 AnySubscriber 사용 가능
// AnySubscriber 예시
let subscriber = AnySubscriber<Int, Never>(
receiveSubscription: { _ in
print("데이터 구독 시작")
},
receiveValue: { input in
print("데이터 수신: \(input)")
return .none
},
receiveCompletion: { _ in
print("모든 데이터 발행 완료")
}
)
let subscription = sequencePublisher
.subscribe(subscriber)
sink 함수를 써서 Publisher 내부에서 Subscriber가 생성되도록 함
let subscription = sequencePublisher
.sink(
receiveCompletion: { completion in
print(completion)
},
receiveValue: { s in
print("\(s) 받음")
}
)
subscription.cancel()
CurrentValueSubject는 최신값 저장 O, PassthrougSubject는 최신값 저장 X
// CurrentValueSubject 예시
let currentValueSubject = CurrentValueSubject<String, Never>("첫번째 값")
currentValueSubject
.sink(
receiveCompletion: { completion in
print(completion)
},
receiveValue: { s in
print("\(s) 받음")
}
)
currentValueSubject.send("두번째 값")
currentValueSubject.send("세번째 값")
currentValueSubject.send(completion: .finished)
// -- 콘솔 --
// 첫번째 값 받음
// 두번째 값 받음
// 세번째 값 받음
// finished
// PassthroughSubject 예시
let passthroughSubject = PassthroughSubject<String, Never>()
passthroughSubject
.sink(
receiveCompletion: { completion in
print(completion)
},
receiveValue: { s in
print("\(s) 받음")
}
)
passthroughSubject .send("두번째 값")
passthroughSubject .send("세번째 값")
passthroughSubject .send(completion: .finished)
// -- 콘솔 --
// 두번째 값 받음
// 세번째 값 받음
// finished
let subject = PassthroughSubject<Int, Never>()
subject .sink(
receiveValue: { value in
print(Thread.isMainThread) // true
}
)
subject.send(1)
let subject = PassthroughSubject<Int, Never>()
subject .sink(
receiveValue: { value in
print(Thread.isMainThread) // false
}
)
DispatchQueue.global().async {
subject.send(1)
}
receive는 호출한 시점부터 해당 쓰레드로 변경
publisher
.map { _ in print(Thread.isMainThread) } // true
.receive(on: DispatchQueue.global())
.map { print(Thread.isMainThread) } // false
subscribe는 어느 시점에서 호출하든 상관없이 시작하는 시점의 쓰레드를 변경
publisher
.map { _ in print(Thread.isMainThread) } // false
.subscribe(on: DispatchQueue.global())
.map { print(Thread.isMainThread) } // false
publisher
.map { _ in print(Thread.isMainThread) } // true
.subscribe(on: DispatchQueue.main())
.map { print(Thread.isMainThread) } // true
// map 예시
let subscription = [1, 2, 3].publisher
.map { $0 + 2 }
.sink(receiveValue: { print($0) })
// -- 콘솔 --
// 3
// 4
// 5
https://icksw.tistory.com/271
https://ios-development.tistory.com/1112
https://hereismyblog.tistory.com/14
https://zeddios.tistory.com/972