brunch

You can make anything
by writing

C.S.Lewis

by Tilltue May 02. 2021

Swift Combine 변형 Operators

collect, map, replace, scan

* 이글은 Swift 5 기준으로 작성했다.


Combine 의다양한 Transform Operators 들을 알아보자



1. Collect

finish 될때까지 이벤트를 모두 모아준다.

* 주의: 갯수에 한계치가 없으므로 메모리 관리에 주의해야 한다.


subject.collect().sink {

            print($0)

        } receiveValue: {

            print($0)

        }.store(in: &cancellable)


일정한 시간간격(500ms)을 두고 sujbect를 통해 이벤트를 전달하고 collect 한 로그이다.


2021-05-01 14:39:42 +0000 emit 1

2021-05-01 14:39:43 +0000 emit 2

2021-05-01 14:39:43 +0000 emit 3

[1, 2, 3]

finished



1-2. Collect(count)

 

주어진 count 만큼 모아서 이벤트가 전달된다. finish 가 되면 담겨져있는 만큼의 이벤트가 전달된뒤 종료된다.


2021-05-01 14:49:00 +0000 emit 1

2021-05-01 14:49:01 +0000 emit 2

[1, 2]

2021-05-01 14:49:02 +0000 emit 3

2021-05-01 14:49:02 +0000 emit 4

[3, 4]

2021-05-01 14:49:03 +0000 emit 5

[5]

finished


1-3. Collect(Publishers.TimeGroupingStrategy)

Publishers.TimeGroupingStategy 의 종류

문서: https://developer.apple.com/documentation/combine/publishers/timegroupingstrategy


- byTime(Context, Context.SchedulerTimeType.Stride)

주어진 스케쥴러와 시간동안 발생한 이벤트를 모아 전달한다.

subject.collect(.byTime(DispatchQueue.main, .seconds(1))).sink {

            print($0)

        } receiveValue: {

            print($0)

        }.store(in: &cancellable)


2021-05-01 14:58:06 +0000 emit 0

2021-05-01 14:58:07 +0000 emit 1

[0, 1]

2021-05-01 14:58:07 +0000 emit 2

2021-05-01 14:58:08 +0000 emit 3

2021-05-01 14:58:08 +0000 emit 4

[2, 3, 4]

2021-05-01 14:58:09 +0000 emit 5

[5]

2021-05-01 14:58:09 +0000 emit 6

[6]

finished


- byTimeOrCount(Context, Context.SchedulerTimeType.Stride, Int)

주어진 스케쥴러와, 카운트 의 조건이 맞으면 이벤트가 발생한다.

subject.collect(.byTimeOrCount(DispatchQueue.main, .milliseconds(700), 2)).sink {

            print($0)

        } receiveValue: {

            print($0)

        }.store(in: &cancellable)


그림과 온전히 일치하는 예제를 만들진 못했지만 로그는 아래와 같다.

2021-05-01 15:03:30 +0000 emit 0

2021-05-01 15:03:31 +0000 emit 1

[0, 1]

2021-05-01 15:03:31 +0000 emit 2

[2]

2021-05-01 15:03:32 +0000 emit 3

[3]

2021-05-01 15:03:32 +0000 emit 4

2021-05-01 15:03:33 +0000 emit 5

[4, 5]

2021-05-01 15:03:33 +0000 emit 6

[6]

finished


2. Map

Swift 의 표준 map 과 동일하게 이해하면 된다. 값을 변형한다.

예제는 생략... :D


2-2. Map ( key paths )

- map<T>(_:)

- map<T0, T1>(_:_:)

- map<T0, T1, T2>(_:_:_:)

Key path 를 통해 map이 가능하다.


예를 들어 CGPoint 로 이벤트가 나온다고 하면 아래와 같이 작성할수 있다.


subject.map(\.x, \.y)

            .sink {

                print($0)

            } receiveValue: {

                print($0, $1)

            }.store(in: &cancellable)


2021-05-01 15:16:34 +0000 emit 0

0.0 0.0

2021-05-01 15:16:35 +0000 emit 1

1.0 1.0

finished


.map(\.x, \.y) 를 .map(\.x) 등으로 필요한 key paths 로 유용하게 사용가능하다.


2-3. tryMap

try 구문을 사용 할수 있다. 에러가 발생하면 failure 로 전달된다.


publisher.tryMap{ try FileManager.default.contentsOfDirectory(atPath: $0) }

            .sink {

                print($0)

            } receiveValue: {

                print($0, $1)

            }.store(in: &cancellable)


failure("blabla")


3. flatMap

flatMap 은 element 로부터 새로운 publisher 를 리턴한다.

같은 타입의 downstream publisher 들을 하나의 publisher 로 변경한다.

검색 키워드로 google 검색을 하도록 작성해본 예제이다.


3-2. flatMap(maxPublisher)

최대 publisher 의 갯수를 지정할수 있다.

위의 그림처럼 2개의 publisher 의 이벤트만 전달된다.


4. replaceNil(with:)

nil 이 전달될때 지정한 값으로 치환한다.



4-2. replaceEmpty(with:)

empty 일때 주어진 값의 이벤트를 방출


5. scan

initial Value 를 가지고 계산값을 축적한다.



Swift 의 기본 함수와 비슷한 동작을 가지는 것들이 있어서 어렵지는 않은것 같다 :D

마침.

브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari