티스토리 뷰
Combine이란?
반응형 프로그래밍의 개념을 기반으로 개발된 프레임워크
시간 경과에 따른 값을 처리하기 위한 통합된 선언적 API
반응형 프로그래밍
데이터 스트림과 변화의 전파에 관련된 선언형 프로그래밍 패러다임이다.
- 데이터 스트림 : 시간에 따라 만들어진 일련의 이벤트 ex) 탭 이벤트 스트림
- 선언형 프로그래밍
- 명령형 프로그래밍 선언형 프로그래밍
명령형 프로그래밍 선언형 프로그래밍 How(어떻게) What(무엇) 코드가 어떻게 작업을 수행해야 하는지 결과에 집중하고 구체적인 행위를 감춤
행위를 정의하고 행위에 데이터를 전달
핵심 개념들
- Publisher : 값을 방출하거나, 완료 이벤트나 실패 이벤트를 전할 수 있다.
- Just() : 단일 값을 즉시 생산하는 Publisher. 에러 타입은 항상 Never이다.
- Future() : 단일 값을 비동기적으로 생선하는 Publisher. promise()로 결과를 보내면 Subscriber의 sink()가 받는다.
- Subscriber : Publisher로부터 값을 받아 처리한다. sink() 로 Subscriber를 사용하고 Publisher에 연결한다.
- AnyCancellable : 구독을 취소할 수 있는 타입이다. 구독을 관리하고, 더 이상 필요하지 않을 때 자동으로 구독을 취소한다.
사용 예시
// AuthenticationService.swift
func signInWithGoogle() -> AnyPublisher<User, ServiceError> {
Future { [weak self] promise in
self?.signInWithGoogle { result in
switch result {
case .success(let user):
promise(.success(user))
case .failure(let error):
promise(.failure(.error(error)))
}
}
}.eraseToAnyPublisher()
}
// UserService.swift
func addUser(_ user: User) -> AnyPublisher<User, ServiceError> {
dbRepository.addUser(user.toObject())
.map { user }
.mapError { .error($0)}
.eraseToAnyPublisher()
}
// UserDBRepository.swift
func addUser(_ object: UserObject) -> AnyPublisher<Void, DBError> {
Just(object)
.compactMap { try? JSONEncoder().encode($0) }
.compactMap { try? JSONSerialization.jsonObject(with: $0, options: .fragmentsAllowed) }
.flatMap { value in
Future<Void, Error> { [weak self] promise in
self?.db.child(DBKey.Users).child(object.id).setValue(value) { error, _ in
if let error {
promise(.failure(error))
} else {
promise(.success(()))
}
}
}
}
.mapError { DBError.error($0) }
.eraseToAnyPublisher()
}
// AuthenticationViewModel.swift
private var subscriptions = Set<AnyCancellable>()
func send(action: Action) {
switch action {
case .checkAuthenticationState:
if let userId = container.services.authService.checkAuthenticationState() {
self.userId = userId
self.authenticationState = .authenticated
}
case .googleLogin:
isLoading = true
container.services.authService.signInWithGoogle()
.flatMap { user in
self.container.services.userService.addUser(user)
}
.sink { [weak self] completion in
// 에러 또는 완료 처리
if case .failure = completion {
self?.isLoading = false
}
} receiveValue: { [weak self] user in
// user 데이터를 받아 처리
self?.isLoading = false
self?.userId = user.id
self?.authenticationState = .authenticated
}.store(in: &subscriptions) // 필요하지 않으면 구독 자동 취소
return
case .logout:
container.services.authService.logout()
.sink { completion in
} receiveValue: { [weak self] _ in
self?.authenticationState = .unauthenticated
self?.userId = nil
}.store(in: &subscriptions)
}
}
'iOS > Swift' 카테고리의 다른 글
[Swift] 코딩테스트에 유용한 문자열 관련 함수들 (추가중) (0) | 2024.03.12 |
---|---|
[Swift] String의 요소 index로 접근하기 (0) | 2024.03.07 |