본문 바로가기

IOS

Swift - Combine VS RxSwift

 

1. combine VS RxSwift

Reactive 프로그래밍 이라는 점의 공통점을 가지고 있다.

Rx는 iOS 이상부터, Combine는 iOS 13이상부터 사용가능하다.

Rx는 Third party framework인 반면 Combine은 애플에서 만든 framework 이다.

그리고 Rx는 Rxcocoa(UiKit)에서 Combine은 SwiftUI와 UIBinding을 하도록 만들어져있다.

 

Combine RxSwift
Publisher Observable
Subscriber Observer
Cancellable Disposable
CurrentValueSubject BehaviorSubject
PassthroughSubject PublishSubject
eraseToAnyPublisher asObservable
handleEvents() do()
receive(on:) subscriveOn()
store() disposed()
sink() subscribeBy()
assign(to:, on:) bind(to:)

 


2. combine - RemoveDuplicates()

더보기
import UIKit
import Combine

[1, 2, 3, 3, 3].publisher
    .print()
    // removeDuplicates 를 통해
    // 퍼블리셔에서 들어오는 중복값을 제거 할수가 있다.
    .removeDuplicates()
    .sink(receiveValue: {
        value in
        print("values : \(value)")
    })

 


3. combine - zip

더보기
import UIKit
import Combine

var subscriptions = Set<AnyCancellable>()
let name = PassthroughSubject<String, Never>()
let age = PassthroughSubject<Int, Never>()
// Zip 을 통해 2개의 퍼블리셔 이벤트를 하나로 묶어서 받을수가 있다.
name.zip(age)
    .sink {
        value in
        print(value) // A,B 의 튜플 형태
    }.store(in: &subscriptions)
// 쌍을 이루기 전까지 이벤트를 내 보내지 않는다.
name.send("철수")
age.send(13)
age.send(17)
name.send("영희")
age.send(30)
name.send("짱구")

 


4. combine - replaceNil

더보기
import UIKit
import Combine

struct Pet {
    var name : String?
}

//이름이 없으면 nil를 반환하는 애완동물 팩토리 메소드
func createPet(with name: String?) -> Pet? {
    guard let name = name else {
        return nil
    }
    return Pet(name: name)
}

var subscriptions = Set<AnyCancellable>()
let petNames = ["강아지", nil, "고양이"].publisher

petNames.map {
    createPet(with: $0)
}
// Map 에서 나온값이 nil 일 경우
// ReplaceNil 로 nil 의 값을 변경 할수가 있다.
.replaceNil(with: Pet(name: "이름없음"))
.sink(receiveValue: {
    result in
    print("들어온 이벤트 \(result?.name)")
}).store(in: &subscriptions)

 


5. combine - replaceNil

더보기
import UIKit
import Combine

struct Pet {
    var name : String
}

var subscriptions = Set<AnyCancellable>()
let pets = ["강아지", "초코", "고양이"].publisher

// 퍼블리셔 -> 서브스크라이버로 전달 되는 값들은
// 연사자들(오퍼레이터) 를 통해 바뀔수 있다.
pets.map({
    (petName: String) -> Pet in
    // map 을 통해 들어온 스트링 값을 Pet으로 변환함
    return Pet(name: petName)
}).sink(receiveValue: {
    result in
    print("들어온 이벤트 : \(result)")
}).store(in: &subscriptions)

 


6. combine - receive(on)

더보기
import UIKit
import Combine

Just(1)
    .map {
        value in
        print("메인 스레드 인가요0 : \(Thread.isMainThread)")
    }
    // receive 로 스레드 변경 가능
    // recevie 로 스레드를 변경 할경우 그 다음 로직은 변경한 스레드로 처리함
    .receive(on: DispatchQueue.global())
    .map {
        print("메인 스레드 인가요1 : \(Thread.isMainThread)")
    }
    .receive(on: DispatchQueue.main)
    .map {
        print("메인 스레드 인가요2 : \(Thread.isMainThread)")
    }

 


7. combine - subject

더보기
import UIKit
import Combine

// 초기값이 없는 패스 스루 서브젝트

let subject = PassthroughSubject<Int, Never>()

subject
    .print()
    .sink(receiveValue: {
        value in
        print("들어온 이벤트 : \(value)")
    })

//단 방향으로 이벤트 보낼때 사용
subject.send(1)
subject.send(2)

//completion 으로 데이터 스트림 종료
subject.send(completion: .finished)

 


8. combine - subject

더보기
import UIKit
import Combine

// 현재의 값을 가지고 있는 커런트 벨류 서브젝트
// 초기값을 설정함 (현재 : 0)
let subject = CurrentValueSubject<Int, Never>(0)

subject
    .print()
    .sink(receiveValue: {
        print("들어온 이벤트 : \($0)")
    })

// 이벤트를 보내기 전에는 초기값이 확인됨
print("subject.value : \(subject.value)")

// current value subject 를 통해 데이터를 보낸다
subject.send(1)
subject.send(2)

// 마지막으로 보낸 값을 알수가 있다.
print("subject.value : \(subject.value)")
subject.send(3)
print("subject.value : \(subject.value)")
// completion 으로 스트림 종료
subject.send(completion: .finished)

 


9. combine - just

더보기
import UIKit
import Combine

let subscription = Just(11111)
.sink(receiveCompletion: {
    result in
        switch result {
        case .finished:
            print("데이터 스트림 종료")
        case .failure:
            print("실패")
        }
}, receiveValue: {
    (value : Int) in
    print("받은값 : \(value)")
})

 


10. combine - AnyCancellable

더보기
import UIKit
import Combine

// 콤바인 데이터 스트림은 cancel 이나 complete 가
// 되지 않는 이상 메모리에 살아 있습니다.
// AnyCancellable 를 통해 메모리 관리가 가능합니다.
var mySubscriptions = Set<AnyCancellable>()

let myNotification = Notification.Name("알림총")
let publisher = NotificationCenter.default.publisher(for: myNotification, object: nil)

let subscription = publisher.sink(receiveValue: {
    value in
    print("받은 데이터 : \(value)")
}).store(in: &mySubscriptions)
// AnyCancellable 셋 안에 store 메소드로
// 서브 스크라이버를 넣어두면 해당 객체가 메모리에서 사라질때 같이 사라지게 해줍니다.
NotificationCenter.default.post(name: myNotification, object: nil)

 


11. combine - Publisher

더보기
import UIKit
import Combine

// word 멤버 변수를 가지고 있는 펫 클래스
class MyPet {
    var word : String = "" {
        didSet {
            print("MyPet didSet() : \(word)")
        }
    }
}

let myPet = MyPet()
let myPublisher = ["왈왈", "왈왈왈왈"].publisher
// 하나의 퍼블리셔를 여러 곳에 구독 할 수 있습니다.
// ex: 사용자 정보 뷰모델 1 vs 관련된 화면들 N
let firstSub = myPublisher.sink(receiveValue: {
    (result : String) in
    print("첫번째 구독 : \(result)")
    
})
let secondSub = myPublisher.sink(receiveValue: {
    (result : String) in
    print("두번째 구독 : \(result)")
    
})

let thirdSub = myPublisher.assign(to: \.word, on: myPet)

 


12. combine - Publisher

더보기
import UIKit
import Combine

// 노티피케이션을 사용

// 알림총 이라는 이름의 노티피케이션
let myNotification = Notification.Name("알림총")
// 노티피케이션으로 퍼블리셔 를 만들수 있습니다.
let publisher = NotificationCenter.default.publisher(for: myNotification, object: nil)

// 퍼블리셔 구독 진행
let subscription = publisher.sink(receiveValue: {
    value in
    print("받은 데이터 : \(value)")
})

// 노티피케이션 센터 디폴트 post 로 데이터 스크림 발사 X3
NotificationCenter.default.post(name: myNotification, object: nil)
NotificationCenter.default.post(name: myNotification, object: nil)
NotificationCenter.default.post(name: myNotification, object: nil)

 


13. combine - assign

더보기
import UIKit
import Combine

// word 멤버 변수를 가지는 펫 클래스
class MyPet {
    var word : String = "" {
        didSet {
            print("MyPet didSet() : \(word)")
        }
    }
}

let myPet = MyPet()
// 왈왈 을 내보내는 퍼블리셔
let publisher = ["왈왈","왈왈왈왈"].publisher
// 클래스 인스턴스 의 멤버변수와 퍼블리셔 이벤트 값을 연결
// assign(to : 연결할 멤버변수, on : 객체 인스턴스)
// MyPet 의 word 와 연결
let mySubscriber = publisher
    .assign(to: \.word, on: myPet)

 


14. combine - publisher

더보기
import UIKit
import Combine

// 퍼블리셔 -> 보내는 애 ex) 유튜버
// 서브스크라이버 -> 받는 애 ex) 구독자
// 보내는 애 (1) vs 받는 애 (다수) - 보통 1 : N 의 관계

// 배열 뒤에 publisher 로 퍼블리셔를 만들수 있습니다.
let myPublisher = [1,3,5].publisher
print("myPublisher : \(myPublisher)")

// 퍼블리셔에 sink 라는 구독 행위를 통해 서브스크라이버를 만듭니다.
let subscriber = myPublisher.sink(receiveValue: {
    (result : Int) in
    // 구독을 통해 1,3,5 라는 이벤트 흐름이 들어왔습니다.
    print("result : \(result)")
})

 

 

'IOS' 카테고리의 다른 글

SwiftUI - YoutubeKitPlayer  (0) 2021.11.17
Swift - TextView PlaceHolder  (0) 2021.08.26
Swift - UITableView + ListClick  (0) 2021.08.13
Swift - Property Wrapper  (0) 2021.08.06
Swift - Reactive Programming (Rx)  (0) 2021.08.02