본문 바로가기

iOS/Combine

[Combine] append(_:) 의 3가지 사용방법

분류

Combine Framework    Publishers
Protocol    Publisher
Operator    Applying Sequence Operations to Elements

 

Append(_:)

[ 첫번째 ]:  가변인자로 여러개의 요소를 인자로 받아 append() 처리 후 발행 하는 경우

func append<T>(_ elements: Self.Output...) -> Publishers.Concatenate<Self,Publishers.Sequence<[Self.Ouput], Self.Failure>>

설명

[코드]

func append(numbers:Int...){
        cancellable = numbers.publisher
            .append(100, 200, 300)
            .sink { print("\($0)") }
}

//실행
append(numbers: 1,2,3,4,5)

// 결과: "1 2 3 4 5 100 200 300"

 

가변 인자로 여러개의 요소를 발행받아 append() 할 수 있다.

 

가변인자로 타입을 지정하는 방법은 type... 으로 ...을 붙여주면 된다.

예를 들어 Int형 가변인자를 받겠다고 한다면 Int... 으로 타입을 지정해주면 된다.

가변인자는 Swift에서 내부적으로 시퀀스 타입으로 처리된다.

 

Apple Combine 공식문서에서 해당 경우의 Append() 코드도 살펴보자

 

let dataElements = (0...10)
cancellable = dataElements.publisher
    .append(0, 1, 255)
    .sink { print("\($0)", terminator: " ") }


// Prints: "0 1 2 3 4 5 6 7 8 9 10 0 1 255"

 

여기서 dataElements ClosedRange 타입이다.

ClosedRange 특정 범위의 값을 표현하기 위한 타입이며 (시작 값...끝 값)의 범위를 포함한다.

Sequence Protocol을 준수하며, Sequence 의 기능을 제공할 수 있다.

 

[Apple Combine append(_:) Documentation]

 

append(_:) | Apple Developer Documentation

Appends a publisher’s output with the specified elements.

developer.apple.com

 


 

[ 두번째 ]: Sequence protocol 을 준수하는 값을 인자로 받아 append() 처리 후 발행 하는 경우

func append<S>(_ elements: S) -> Publishers.Concatenate<Self,Publishers.Sequence<S, Self.Failure>> where S : Sequence, Self.Output == S.Element 

설명

[코드]

Apple Combine 공식문서의 코드로 확인해보자.

 

let groundTransport = ["car", "bus", "truck", "subway", "bicycle"]
let airTransport = ["parasail", "jet", "helicopter", "rocket"]
cancellable = groundTransport.publisher
    .append(airTransport)
    .sink { print("\($0)", terminator: " ") }


// Prints: "car bus truck subway bicycle parasail jet helicopter rocket"

 

변수인 groundTransportairTransport 는 배열(array)로 Sequence Protocol을 준수한다.

코드를 보면 groundTransport를 발행하였고, Sequence Protocol를 준수하는 변수인 airTransport 를 append 하고 발행하고 있다.

 

해당 방식으로 사용하기 위한 규칙은 아래와 같다.

 

Publisher(Self)의 출력 타입(Output)과 동일한 요소 타입을 가진 시퀀스를 인자(_ element)로 받을 수 있다.

 

[참고]

[Apple Combine append(_:) Documentation]

 

append(_:) | Apple Developer Documentation

Appends a publisher’s output with the specified sequence.

developer.apple.com

 


 

[ 세번째 ]: publisher protocol 을 준수하는 값을 인자로 받아 append() 처리 후 발행 하는 경우

func append<P>(_ Publisher: P) -> Publishers.Concatenate<Self,P> where P : Publisher, Self.Failure == P.Failure, Self.Output == P.Output 

설명

[코드]

Apple Combine 공식문서의 코드로 확인해보자.

 

let numbers = (0...10)
let otherNumbers = (25...35)
cancellable = numbers.publisher //요소 발행 생성
    .append(otherNumbers.publisher)
    .sink { print("\($0)", terminator: " ") }
    
 // Prints: "0 1 2 3 4 5 6 7 8 9 10 25 26 27 28 29 30 31 32 33 34 35 "

 

 

sequence protocol 을 준수하는 closedRange 타입 의 numbers 와 otherNumbers 라는 변수가 있다.

변수로 할당된 요소들을 발행하는 Publisher 를 생성하였고, 발행된 타입을 따르는 Publisher(otherNumbers.publisher) 를 생성하여 append(otherNumbers.publisher) 해주고 있다.

 

해당 방식으로 사용하기 위한 규칙은 아래와 같다.

sequence protocol을 준수하는 값을 Publisher 로 생성 후 append() method를 사용할 수 있다.
Publisher로 생성하여 append() 를 작동하므로, 추가할 값 또한 sequence protocol을 준수하면서 Publisher로 발행된 것이어야 가능하다.

 

[참고]

[Apple Combine append(_:) Documentation]

 

append(_:) | Apple Developer Documentation

Appends the output of this publisher with the elements emitted by the given publisher.

developer.apple.com

 


[ 구현 예시 영상 및 코드 ]

 

[영상]

combine append() 를 활용하여 상품 추가

 

구현 영상

 

[구현 코드]

 

ApplyingSequenceOperationsToElements Class 구현

import Foundation
import Combine

final class ApplyingSequenceOperationsToElements{
    private var cancellable: AnyCancellable?
        
    func append<T>(arr: [T], ele: T, completion: @escaping (_ results: [T]) -> Void) {
        let arrPublisher = Publishers.Sequence<[T], Never>(sequence: arr)
     
        cancellable = arrPublisher
            .append([ele])
            .collect()
            .sink { results in
                completion(results)
            }
    }
}

 

ProductViewModel 구현

import Foundation

final class ProductViewModel:ObservableObject{
    static let shared = ProductViewModel()
    let applySequenceOperator = ApplyingSequenceOperationsToElements()
    @Published var products:[Product] = []
    
    
    func appendProduct(){
        var newProduct:Product
        
        if let lastProduct = products.last{
            newProduct = Product(id: lastProduct.id + 1)
        }else{
            newProduct = Product(id: 0)
        }
        
        applySequenceOperator.append(arr: products, ele: newProduct) { [weak self] results in
            self?.products = results
        }
    }
}

 

ProductView 구현

import SwiftUI

struct ProductView: View {
    @StateObject var vm = ProductViewModel.shared
    
    var body: some View {
        VStack{
            HStack{
                HStack{}.frame(width:24,height:24)
                Spacer()
                Text("Product")
                    .font(.system(size: 18))
                Spacer()
                HStack(spacing:8){
                    Button(action:{
                        vm.appendProduct()
                    }){
                        Image(systemName: "plus")
                            .frame(width:24, height:24)
                    }
                    Button(action:{}){
                        Image(systemName: "line.horizontal.3")
                            .frame(width:24, height:24)
                    }
                }
            }
            .padding(.horizontal, 16)
            .frame(height:50)
            VStack{
                ForEach(vm.products, id: \.id){ product in
                    HStack{
                        Text("ID: \(product.id)")
                    }
                    .frame(height: 48)
                }
            }
        }
        .frame(maxHeight: .infinity, alignment: .top)
    }
}

 

[GitHub Code]

 

GitHub - kgwoo/combine-study: swift combine study

swift combine study. Contribute to kgwoo/combine-study development by creating an account on GitHub.

github.com

 

 

'iOS > Combine' 카테고리의 다른 글

[Combine] Subscribe(구독) 의 의미 (Pub-Sub 패턴)  (0) 2023.06.16
[Combine] map(_:), tryMap(_:)  (0) 2023.06.13