ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • (Combine) Scheduler, Operator
    iOS💖 2024. 10. 7. 16:52

    컴바인 부져버리겠어

     

    Scheduler

    • 언제, 어떻게 클로저가 실행되는지 결정해준다. (프로토콜이다)
      A protocol that defines when and how to execute a closure.
    • Operator의 파라미터로 scheduler를 받을때가 있다. 
    • scheduler로 작업을 Background / Main 스레드에서 작업할 수 있도록 결정해준다.

     

    2가지 메소드 (subscribe(on:) , receive(on:))

    • subscirbe(on:)
      • Publisher가 어느 thread에서 수행할지 결정
    • receive(on:)
      • Operator, Subscriber가 어느 thread에서 수행할지 결정
      • UI 업데이트에 필요한 데이터를 Main thread에서 받을 수 있게 도와줌

    on 의 type: scheduler

     

    코드 예시) 

    let jsonPublisher = MyJSONLoaderPublisher()
    
    jsonPublisher
        .subscribe(on: backgroundQueue)
        .receive(on: RunLoop.main)
        .sink { value in
            lable.text = value
        }
    }
    let arrPublisher = [1, 3, 5].publisher
    
    let queue = DispatchQueue(label: "custom")
    
    let subscription = arrPublisher
        .subscribe(on: queue)
        .map { value -> Int in
            print("transform: \(value), thread: \(Thread.currenrt)")
            return value + 1
        }
        .receive(on: DispatchQueue.main)
        .sink { value om
            print("Receive Value: \(value), thread: \(Thread.current)")
        }

     

     

     

    Operator

    • Publisher에게 받은 값을 가공하여 Subscriber에게 제공
    • Input, Output, 실패 type 을 받는다
    • Built-in Operator
      • map, filter, reduce, collect, combineLatest 등..

    Operator



        map 코드 예시 )

    map:  특정 형식으로 가공

    let intPublisher = PassthroughSubject<Int, Never>()
    let subscription1 = intPublisher
        .map { $0 * 2 }
        .sink { value in
            print("value: \(value)")
        }
    
    intPublisher.send(10)
    intPublisher.send(20)
    intPublisher.send(30)
    subscription1.cancel()
    
    // value: 20
    // value: 40
    // value: 60
    Publishers.CombineLatest(strPublisher, intPublisher).sink{ str, int in return... }
    // 위의 형식도 가능!

     

     

     

        filter 코드 예시 )

    filter:  넘겨받은 데이터 중, 조건을 만족하는 일부를 넘기는 역할

    let strPublisher = PassthroughSubject<String, Never>()
    let subscription2 = strPublisher
        .filter { $0.contains("a") }
        .sink { value in
            print("Filtered value: \(value)")
        }
    
    strPublisher.send("abc")
    strPublisher.send("hakyung")
    strPublisher.send("jenny")
    strPublisher.send("jack")
    strPublisher.send("joon")
    subscription2.cancel()
    
    // Filtered value: abc
    // Filtered value: hakyung
    // Filtered value: jack

     

     

     

       Basic ComebineLatest 코드 예시 )

    2개의 publisher 를 같이 받는것

    // Basic CombineLatest
    // 2개의 publisher 를 같이 받는것
    /* ex
     "a",           "b",   "c"
          1,     2   3           5
        (a,1)  (a,2) (b,3) (c,3) (c,5)
     */
    let strPublisher = PassthroughSubject<String, Never>()
    let intPublisher = PassthroughSubject<Int, Never>()
    
    strPublisher.combineLatest(intPublisher).sink { str, int in
        print("Receive: \(str), \(int)")
    }
    
    strPublisher.send("x")
    intPublisher.send(1)
    strPublisher.send("y")
    intPublisher.send(2)
    intPublisher.send(3)
    strPublisher.send("z")
    
    // Receive: x, 1
    // Receive: y, 1
    // Receive: y, 2
    // Receive: y, 3
    // Receive: z, 3

     

     


       Advanced ComebineLatest
     코드 예시 )

    // sign in check
    let usernamePublisher = PassthroughSubject<String, Never>()
    let passwordPublisher = PassthroughSubject<String, Never>()
    
    let validateCredentialSubscription = usernamePublisher.combineLatest(passwordPublisher)
        .map { (username, password) -> Bool in
            return !username.isEmpty && !password.isEmpty && password.count > 12
        }
        .sink { valid in
            print("Credential valid? \(valid)")
        }
    
    usernamePublisher.send("hakyungsohn")
    passwordPublisher.send("weekpw")
    // Credential valid? false
    
    passwordPublisher.send("verystrongpassword")
    // Credential valid? true

     

     


       Merge
     코드 예시 )

    같은 Output Type인 여러개의 publisher을 합치고 싶을때

    public func merge<P>(with other: P) 
        -> Publishers.Merge<Self, P> where P : Publisher, 
             Self.Failure == P.Failure, 
             Self.Output == P.Output
    let publisher1 = [1, 2, 3, 4, 5].publisher
    let publisher2 = [300, 400, 500].publisher
    
    let mergedPublisherSubscription = publisher1.merge(with: publisher2)
        .sink { value in
            print("Merge: subscription received value: \(value)")
        }
        
    // Merge: subscription received value: 1
    // Merge: subscription received value: 2
    // Merge: subscription received value: 3
    // Merge: subscription received value: 4
    // Merge: subscription received value: 5
    // Merge: subscription received value: 300
    // Merge: subscription received value: 400
    // Merge: subscription received value: 500
    Publishers.Merge(publisher1, publisher2).sink { value in 
        print("Merge: subscription received value: \(value)")
    }
    // 위의 형식도 사용 가능!

     

     

     

       removeDuplicates 코드 예시 )

    받은 데이터 중, 중복되는 데이터 삭제

    var subscriptions = Set<AnyCancellable>() // subscription 여러개 담는 통
    
    let word = "you you ! hey girl baby girl"
        .components(seperatedBy: " ")
        .publisher
    
    word
        .removeDuplicates()
        .sink { value in
            print(value)
        }.store(in: &subscriptions)
        
    // you
    // !
    // hey
    // girl
    // baby

     

     

     

       compactMap 코드 예시 )

    - 받은 데이터를 map등으로 transform한 결과 중, nil은 제거하고 데이터 전달

    - optional 하지 않게 전달

    var subscriptions = Set<AnyCancellable>()
    
    // Float()형으로 변형했을때, nil 값은 제외하고 데이터 전달
    let word = ["apple", "1.25", "333", "t", "0.4", "12"].publisher
    
    word
        .compactMap{ Float($) }
        .sink{ value in
            print(value)
        }.store(in: &subscriptions)
        
    // 1.25
    // 333
    // 0.4
    // 12

     

     

     

       ignoreOutput 코드 예시 )

    publisher 를 구독은 했지만,  데이터 받는 것을 무시할 때

    var subscriptions = Set<AnyCancellable>()
    
    // 1만개의 데이터가 들어올 예정이지만, 무시할 예정
    let numbers = (1...10_000).publisher
    
    numbers
        .ignoreOutput()
        .sink(receiveCompletion: { print("Completed with: \($0)") },
              receiveValue: { print($0) })
        .store(in: &subscriptions)
    
    // Completed with: finished

     

     

     

       prefix 코드 예시 )

    여러 개의 데이터를 받을 때, 앞에서 n개만 받겠다

    var subscriptions = Set<AnyCancellable>()
    
    let tens = (1...10).publisher
    
    tens
        .prefix(2)
        .sink(receiveCompletion: { print("Completed with: \($0)") },
              receiveValue: { print($0) }
        .store(in: &subscriptions)
        
    // 1
    // 2
    // completed with: finished

     

     

     

     

     

     

     

     

     

    https://hortenssiaa.tistory.com/30?category=1120065

     

    (Combine) Publisher, Subscriber + Subject

    컴바인 부져버리겠어 PublisherOutput type, 실패 type 정의 필요Built-in PublisherJust : 값을 다룸Future : Function을 다룸Publisher 을 자동으로 제공해주는 기능들 (iOS에서)TimerURLSession.dataTaskNotiicationCenterlet justP

    hortenssiaa.tistory.com

     

    https://developer.apple.com/documentation/combine/scheduler

     

    Scheduler | Apple Developer Documentation

    A protocol that defines when and how to execute a closure.

    developer.apple.com

    https://developer.apple.com/documentation/combine/just-publisher-operators

     

    Publisher Operators | Apple Developer Documentation

    Methods that create downstream publishers or subscribers to act on the elements they receive.

    developer.apple.com

     

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

    (Swift) Generic 제네릭  (2) 2024.10.11
    (Swift) mutating  (1) 2024.10.11
    (Combine) Publisher, Subscriber + Subject  (4) 2024.10.01
    (Combine) 소개  (1) 2024.09.30
    (Swift) NSCollectionLayoutGroup. vertical / horizontal method 종류  (2) 2024.09.26

    댓글

Designed by black7375.