iOS에서 Combine 프레임워크를 사용한 반응형 프로그래밍: 데이터 바인딩과 스트림 관리 기술.

작성일 :

iOS에서 Combine 프레임워크를 사용한 반응형 프로그래밍: 데이터 바인딩과 스트림 관리 기술

Combine 프레임워크는 iOS 13에서 처음 도입된 반응형 프로그래밍 도구로서, 데이터 바인딩과 스트림 관리를 쉽게 처리할 수 있게 해줍니다. 이 글에서는 Combine의 기본 개념부터 실전에서 효과적으로 사용하는 방법까지 다룹니다.

Combine 프레임워크의 기본 개념

Combine 프레임워크는 PublisherSubscriber라는 두 가지 주요 개념을 중심으로 돌아갑니다. Publisher는 데이터를 스트림으로 전달하는 역할을 하며, Subscriber는 이러한 데이터를 소비하는 역할을 합니다.

Publisher와 Subscriber

Publisher는 데이터의 발생을 의미하며, 여러 요소를 통해 생성할 수 있습니다. 가장 기본적인 예로 JustFuture가 있으며, 각각 단일 값과 비동기 작업을 나타냅니다.

  • Just 예제:
swift
import Combine

let justPublisher = Just(5)
  • Future 예제:
swift
import Combine

let futurePublisher = Future<Int, Never> { promise in
    DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
        promise(.success(42))
    }
}

SubscriberPublisher가 발행하는 데이터를 받기 위해 subscribe 메서드를 호출합니다. 구독자는 데이터를 수신하고, 이를 처리하거나 표시할 수 있습니다.

swift
let subscriber = Subscribers.Sink<Int, Never>(
    receiveCompletion: { completion in
        print(completion)
    },
    receiveValue: { value in
        print("Received value: \(value)")
    }
)

justPublisher.subscribe(subscriber)

데이터 바인딩과 데이터 변환

Combine의 강력한 기능 중 하나는 데이터 변환과 바인딩입니다. map, filter, scan 같은 연산자를 사용하여 데이터 스트림을 변환할 수 있습니다.

map 연산자

map 연산자는 입력 값을 변환하여 새로운 값을 반환합니다. 예를 들어, 숫자 스트림을 문자열로 변환할 수 있습니다.

swift
let numberPublisher = Just(4)
let stringPublisher = numberPublisher.map { number in
    return "Number is: \(number)"
}
stringPublisher.sink { value in
    print(value)
}

filter 연산자

filter 연산자는 조건에 맞는 값만 통과시키는 역할을 합니다. 예를 들어, 짝수만 통과시키는 필터를 만들 수 있습니다.

swift
let numbers = [1, 2, 3, 4, 5].publisher
let evenNumbers = numbers.filter { $0 % 2 == 0 }
evenNumbers.sink { value in
    print(value)
}

Subject와 연결 상태 관리

Combine에서 SubjectPublisherSubscriber의 역할을 동시에 수행합니다. 가장 자주 사용되는 SubjectPassthroughSubjectCurrentValueSubject입니다.

PassthroughSubject

Subject는 구독 후 발생한 이벤트만 전달합니다.

swift
let passthrough = PassthroughSubject<String, Never>()
passthrough.sink { value in
    print("Received: \(value)")
}

passthrough.send("Hello")

CurrentValueSubject

Subject는 현재 값을 저장하며, 구독 시 즉시 전송합니다.

swift
let currentValue = CurrentValueSubject<Int, Never>(0)

currentValue.sink { value in
    print("Current value: \(value)")
}

currentValue.send(10)

연결 상태 관리

스트림 구독자는 정상적인 완료나 에러로 끝날 수 있으며, 이를 sink의 인자로 전달받은 클로저를 통해 처리할 수 있습니다.

swift
let simplePublisher = [1, 2, 3].publisher

let subscriber = simplePublisher.sink(
    receiveCompletion: { completion in
        switch completion {
        case .finished:
            print("Finished")
        case .failure(let error):
            print("Error: \(error)")
        }
    },
    receiveValue: { value in
        print(value)
    }
)

Combine 프레임워크의 실제 사용 예제

실제로 Combine 프레임워크는 네트워크 요청, 사용자 인터페이스 업데이트 등 다양한 상황에서 활용될 수 있습니다. 간단한 네트워크 요청 예제를 살펴보겠습니다.

swift
import Foundation
import Combine

struct Post: Decodable {
    let id: Int
    let title: String
}

let url = URL(string: "https://jsonplaceholder.typicode.com/posts/1")!

let networkPublisher = URLSession.shared.dataTaskPublisher(for: url)
    .map { $0.data }
    .decode(type: Post.self, decoder: JSONDecoder())
    .eraseToAnyPublisher()

networkPublisher.sink(
    receiveCompletion: { completion in
        print(completion)
    },
    receiveValue: { post in
        print(post)
    }
)

이 예제에서는 URLSession의 dataTaskPublisher를 사용하여 네트워크 요청을 수행하고, 결과를 decode 연산자로 변환한 후, sink를 통해 데이터를 구독합니다.

이처럼 Combine 프레임워크는 iOS 개발에서 데이터 스트림을 관리하고, 반응형 프로그래밍을 쉽게 구현하는 데에 강력한 도구가 될 수 있습니다. 이를 통해 더 깨끗하고 유지 보수하기 쉬운 코드를 작성할 수 있습니다.