ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • (Combine) Publisher, Subscriber + Subject
    iOS💖 2024. 10. 1. 21:11

    컴바인 부져버리겠어

     

    Publisher

    Publisher

    • Output type, 실패 type 정의 필요
    • Built-in Publisher
      • Just : 값을 다룸
      • Future : Function을 다룸
    • Publisher 을 자동으로 제공해주는 기능들 (iOS에서)
      • Timer
      • URLSession.dataTask
      • NotificationCenter
    let justPublisher = Just(1000)
    let subscription = justPublisher.sink { value in 
        print("received value: \(value)")
    }
    
    // received value: 1000
    let arrPublisher = [1, 2, 3, 4].publisher
    let subscription = arrPublisher.sink { value in
        print("received value: \(value)")
    }
    
    // received value: 1
    // received value: 2
    // received value: 3
    // received value: 4

     

     

        URLSession.dataTask 코드 예시 )

    // URLSessionTask : server에서 데이터를 받는 코드를 구현하는데 사용되는 객체
    struct SomeDecodable: Decodable {}
    
    URLSession.shard.dataTaskPublisher(for: URL(string: "https://www.google.com")!)
        .map { data, response in
            return data
        }
        .decode(type: SomeDecodable.self, decoder: JSONDecoder()) 
        // server에서 받은 데이터를 앱 내의 객체형으로 decoding 해줌

     

     

        Notifications 코드 예시 )

    let center = NotificationCenter.default
    let noti = Notification.Name("MyNoti")
    let notiPublisher = noti.publisher(for: noti, object: nil)
    let subscription = notiPublisher.sink { _ in
         print("Received Notification")
     }
     
    center.post(for: noti, object: nil)
    center.post(for: noti, object: nil)
    subscription.cancel()
    
    // Received Notification
    // Received Notification

     

     

        KeyPath binding to NSObject instances 코드 예시 )

    let ageLalbe = UILable() // UILable: NSObject
    print("lable text: \(ageLable.text)")
    
    Just(28)
        .map { "Age is \($0)" }
        .assign(to: \.text, on: ageLable)
    
    print("lable text: \(ageLable.text)")
    
    // lable text: nil
    // lable text: Optional("Age is 28")

     

     

        Timer 코드 예시 )

    // 1초마다, main thread에서, common(보통) 방법으로
    // 해당 publisher을 구독했을때, 알아서 타이머가 동작해라!
    let timer = Timer
        .publish(every: 1, on: .main, in: .common)
        .autoconnect()
        
    let timerSubscription = timer.sink { time in
        print("time: \(time)")
    }
    
    // 초반의 5초 후에 execute구문 실행
    DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
        timerSubscription.cancel()
    }
    
    // time: 2024-10-04 09:15:46 +0000
    // time: 2024-10-04 09:15:47 +0000
    // time: 2024-10-04 09:15:48 +0000
    // time: 2024-10-04 09:15:49 +0000
    // time: 2024-10-04 09:15:50 +0000

     

     

     

     

    Subscriber

    Subscriber

    • Publisher에게 데이터를 요청
    • Input type, 실패 type 정의 필요
    • Built-in subscriber
      • assign : publisher가 제공하는 데이터를 특정 객체의 key-path에 할당
      • sink : publisher가 제공하는 데이터를 받는 클로져를 제공

     

    코드 예시)

    데이터 제공해주는 arrPublisher에 assign subscriber로 붙었는데, 그 데이터를 object라는 객체의 property라는 프로퍼티에 할당

    let arrPublisher = [1, 2, 3, 4].publisher
    
    class combineClass {
        var property: Int = 0 {
            didSet {
                print("Did set property to \(property)")
            }
        }
    }
    
    let object = combineClass()
    let subscription = arrPublisher.assign(to: \.property, on: object) // (subscriber) to: key-path, on: object
    print("Final value: \(object.property)")
    
    // object > property > didSet의 구문 > print("Final value: \(object.property)")
    // Did set property to 1
    // Did set property to 2
    // Did set property to 3
    // Did set property to 4
    // Final value: 4

     

     

     

     

     

    Publisher & Subscriber Pattern

    Publisher-Subscriber Pattern

    • 컴바인 : 효율적인 비동기처리 방식
    • publisher 라는 a.k.a 생성자, 크리에이터
      = 서버에 연결되어 데이터 뿜는 역할
      • '서버에 연결되어 받게되는 데이터' 를 받기위해 연결되어야 하는데
        그래서 subscriber 이, publisher 에게 붙는다.

     

     

     

     

    Subscription

    • subscriber와 publisher가 연결됨을 나타내는 존재
    • Cancellable protocol 을 준수한다. 
      • 따라서, subscription을 통해 연결을 cancel 할 수 있다

     

    * print() 함수

    모든 publishing events의 로그 메세지를 프린팅 해주는 메소드

    let subject = PassthroughSubject<String, Never>()
    
    let subscription = subject
        .print("[Debug]")
        .sink { value in
            print("Subscriber received value: \(value)")
        }
        
    subject.send("Hi")
    subject.send("How are you?")
    subject.send("I'm good.")
    subject.cancel()
    
    //[Debug]: receive subscription: (PassthroughSubject)
    //[Debug]: request unlimited
    //[Debug]: receive value: (Hi)
    Subscriber received value: Hi
    //[Debug]: receive value: (How are you?)
    Subscriber received value: How are you?
    //[Debug]: receive value: (I'm good.)
    Subscriber received value: I'm good.
    //[Debut]: received finished

     

     

     

     

    Subject (Publisher)

    • send()를 통해 이벤트 주입시킬 수 있는 Publisher
    • 기존 비동기처리 방식에서 Combine 으로 전환시 유용!!
      This can be useful for adapting existing imperative code to the Combine model.
    • PassthroughSubject
      • Subscriber에게 값을 전달할 뿐
      • 전달한 값 들고있지 X
    • CurrentValueSubject
      • 초기값 필수
      • 최근(직전)에 받은 데이터를 들고있는다.
      • 새로운 데이터를 받으면, 직전에 들고있던 데이터를 output하고, 새로 받은 데이터도 배출한다.

    코드 예시) 

    // PassthroughSubject
    let publisher = PassthroughSubject<String, Never>()
    let subscription = publisher.sink { value in // sink : built-in subscriber
        print("subscription received value: \(value)")
    }
    
    publisher.send("Hello!")
    // subscription received value: Hello!
    // CurrentValueSubject
    // 초기값 필수!
    let publisher = CurrenrValueSubject<String, Never>("ABC")
    
    publisher.send("data1") 
    
    let subscription = publisher.sink { value in
        print("subsciption received value: \(value)")
    }
    
    publisher.send("data2")
    // subscription received value: data1 // 1. 이전값을 버려준다(= 버린다 = output)
    // subscription received value: data2 // 2. 현재주입된 값

     

     

     

     

     

    @ Published (Publisher)

    • @Published 로 선언된 property를 publisher로 만들어줌
    • Class 내에서만! 사용 가능
    • $ 를 사용하여 publisher에 접근 가능
    class Battery {
        @Published var battery: Int
        init(battery: Int) {
            self.battery = battery
        }
    }
    
    let phoneBattery = Battery(battery: 100)
    let subscription = phoneBattery.$battery.sink {
        print("Battery now: \($0)")
    }
    
    phoneBattery.battery = 20
    
    // Battery now: 100
    // Battery now: 20

     

     

     

     

     

     

     

     

     

     

    https://hortenssiaa.tistory.com/31

     

    (Combine) Scheduler, Operator

    컴바인 부져버리겠어 Scheduler언제, 어떻게 클로저가 실행되는지 결정해준다. (프로토콜이다)A protocol that defines when and how to execute a closure.Operator의 파라미터로 scheduler를 받을때가 있다. scheduler로

    hortenssiaa.tistory.com

     

    출처)

    https://developer.apple.com/videos/play/wwdc2019/722/

     

    Introducing Combine - WWDC19 - Videos - Apple Developer

    Combine is a unified declarative framework for processing values over time. Learn how it can simplify asynchronous code like networking,...

    developer.apple.com

    - 왕초보를 위한, 한 번에 끝내는 iOS 앱 개발 바이블

    https://developer.apple.com/documentation/combine/publisher/assign(to:on:)

     

    'iOS💖' 카테고리의 다른 글

    (Swift) mutating  (1) 2024.10.11
    (Combine) Scheduler, Operator  (3) 2024.10.07
    (Combine) 소개  (1) 2024.09.30
    (Swift) NSCollectionLayoutGroup. vertical / horizontal method 종류  (2) 2024.09.26
    (Swift) Collection Reusable View 사용  (0) 2024.09.26

    댓글

Designed by black7375.