티스토리 뷰

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)
    }
}
공지사항
최근에 올라온 글
최근에 달린 댓글
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
글 보관함