SOLID 원칙

#객체지향프로그래밍

객체지향 5대 원칙(SOLID)

  1. SRP(단일 책임 원칙)
  2. OCP(개방-폐쇄 원칙)
  3. LSP(리스코프 치환 원칙)
  4. DIP(의존 역전 원칙)
  5. ISP(인터페이스 분리 원칙)

앞 자를 따서 SOLID 원칙 이라고 부른다.

 

Single Responsiblity Principle (단일 책임 원칙)

한 클래스는 하나의 책임만 가져야 한다.

  • 새로운 요구사항과 변경에 잘 대응하기 위해서는 응집도는 높고 결합도는 낮게 구현하여야 한다.
  • 하나의 클래스에서 많은 기능이 있다면 클래스 내부의 함수끼리 강한 결합을 발생할 가능성이 높아진다.

 

Open-Closed Principle (개방-패쇄 원칙)

소프트웨어 요소는 확장에는 열려 있으나 변경에는 닫혀 있어야 한다.

  • 변경되는 것이 무엇인지*에 초점을 맞춘다.
  • 문장만 보기엔 잘 이해가 되지 않으니 아래 코드를 보자.
    class Cafe {
        func order() {
            print(“스타벅스 아메리카노”)
        }
    }

    let cafe = Cafe()
    cafe.order()

기본적으로 스타벅스의 아메리카노를 주문한다. 만약 스타벅스의 아메리카노가 아닌 투썸플레이스의 아메리카노를 주문하도록 요구사항이 변경 되었다면 Cafe의 order 메소드를 수정해야 한다. 이러한 소스코드 변경은 OCP 원칙에 위배된다.

    protocol Cafe {
        func play()
    }

    class Starbucks: Cafe {
        func order() {
            print(“스타벅스 아메리카노”)
        }
    }

    class TwoSomePlace: Cafe {
        func order() {
            print(“투썸플레이스의 아메리카노”)
        }
    }

위 코드 처럼 해당 클래스가 주문을 한다는 역할이 분명하게 정해져 있다. 이럴 때 추상화를 사용하여 OCP원칙을 지킬 수 있다. 각 클래스들은 고정된 Protocol에 의존하기 때문에 수정에 대하여 닫혀있고 해당 Protocol을 구현하기만 하면 확장에 대해여 열려 있게 된다.

 

LSP(Liskov substitution principle)

  • 프로그램의 겍체는 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다.
  • 상위 클래스 자리에 하위 클래스가 치환되어도 아무 문제 없어야 한다.

가장 대표적인 예로 정사각형과 직사각형이 있다. 정사각형은 직사각형이 될 수 있지만 직사각형은 정사각형이라고 할 수 없다. 만약 직사각형이 상위 클래스라면 LSP를 위반하게 된다.

 

ISP(Interface Segregation Principle)

  • 하나의 큰 인터페이스보다 특정 케이스를 위한 여러개의 인터페이스를 사용해야 한다.
  • 큰 덩어리의 인터페이스들을 구체적이고 작은 단위들로 분리시킴으로써 해당 인터페이스를 채택할 때 꼭 필요한 메서드만 이용할 수 있게 해야한다.
  • 해당 원칙을 준수하게 되면 내부 의존성이 약해져 리팩토링을 쉽게 할 수 있다.

 

DIP(Dependency Inversion Principle)

  • 소프트웨어 모듈들을 분리하는 특정 형식
  • 구체화보다 추상화에 의존해야 한다.
  • 의존성 주입은 이 원칙을 따르는 방법 중 하나이다.
  • DIP는 다음과 같은 내용을 담고 있다.
    1. 상위 모듈은 하위 모듈에 의존해서는 안된다. 상위 모듈과 하위 모듈 모두 추상화에 의존해야 한다.
    2. 추상화는 세부 사항에 의존해서는 안된다. 세부사항이 추상화에 의존해야 한다.
Class CafeStore {
	private let cafe: Cafe
    
    init(cafe: Cafe) {
    	self.cafe = cafe
    }
    
    func order() {
    	cafe.order()
    }
}

let starbucksStore = CafeStore(cafe: Starbucks())
let twosomeplaceStore = CafeStore(cafe: TwosomePlace())

starbucsStore.oredr()
twosomeplaceStore.order()

기존에 만들었던 스타벅스와 투썸을 의존성 주입을 통하여 타입만 변경해줌으로써 다른 코드들은 유지한 채 가게를 수정 할 수 있게 된다.

반응형

Publisher

#Combine #Publisher

Just

  • 가장 단순한 형태의 Publisher 입니다. 에러 타입은 항상 Never 입니다.
    Just((0...5))
      .sink { value in
          print(value) // 0...5
      }

 

Future

  • 일반적으로 Publisher의 처리를 sink 라는 구독을 형태로 많이 처리하게 되는데 이 때 클로저를 전달하는 과정에서 콜백 기반의 completion 핸들러를 사용하게 되는데 Futrue를 통하여 더욱 깔끔한 코드 작성이 가능해 집니다.
  let myFuture = Future<Int, Never> { promise in
      promise(.success(10))
  }
  myFuture.sink { value in
      print(value) // 10
  }
  • URLSeesion 이나 Alamofire 등 RestFul 관련 API 비동기 요청시에 해당 요청이 성공했는지, 실패 했는지에 대한 여부를 리턴해주는 예제 입니다.
func isSuccessAPIRequest() -> AnyPublisher<Bool, Never> { 
    Future<Bool, Never> { promise in 
        urlRequestPublisher
            .sink(
                receiveCompletion: { completion in 
                    switch completion {
                    case .finished: 
                        print("finished")
                        promise(.success(true))
                    case .failure(let error): print(error.localizedDescription)
                        promise(.success(false))
                    }
                }, receiveValue: { value in
                    print(value)
                }
            )
    }
    .eraseToAnyPublisher()
}

isSuccessAPIRequest()
	.sink { 
		if $0 {
			// true
		} else {
			// false
		}
	}

 

Fail

  • 지정한 종류의 에러로 즉시 종료하는 Publisher 입니다.

 

Empty

  • 값을 게시하지 않고 선택적으로 즉시 완료되는 Publisher 입니다.
  Empty<String, Never>()
      .sink(
          receiveCompletion: { 
              print($0) // finished
          },
          receiveValue: {
              print("receiveValue : \($0)") // 출력 안함
          }
      )

 

Deferred

  • 구독이 일어나기 전까지 대기상태로 있다가 구독이 일어 났을 때 Publisher가 결정이 됩니다. 클로저 안에는 지연 실행 할 Publisher 를 반환합니다.
    Deferred { Just(Void()) }
      .sink(receiveValue: { print("Diferred") })

 

Sequence

  • 요소의 주어진 Sequence를 반환하는 Publisher 입니다.
  • Publisher가 Sequence에 있는 요소들을 하나 하나 제공해주며 모든 요소들이 다 제공되었을 때 종료됩니다.
    Publishers.Sequence<[Int], Never>(sequence: [1, 2, 3])
        .sink(receiveValue: { 
            print("Sequence : \($0)")
        })
    /*
     Sequence : 1
     Sequence : 2
     Sequence : 3
     */
반응형

Combine이 가지고 있는 기능들을 정리해보았습니다. 앞으로 해당하는 글을 계속 쓰면서 업데이트 할 예정입니다.

업데이트를 하게되면 해당 설명 아래에 링크를 추가하겠습니다!

 

Publisher 종류 

  1. Just: 위에서 본것과같이 가장 단순한 형태의 Publsiher로 에러타입으로 Never를 갖습니다.
  2. Promise: Just와 비슷하지만 Filter Type을 정의할 수 있습니다.
  3. Fail: 정의된 실패타입을 내보냅니다.
  4. Empty: 어떤 데이터도 발행하지 않는 퍼블리셔로 주로 에러처리나 옵셔널값을 처리할때 사용됩니다.
  5. Sequence: 데이터를 순차적으로 발행하는 Publisher로 (1…10).Publisher로 이에 해당합니다.
  6. ObservableObjectPublisher: SwiftUI에서 사용되는 ObservableObject를 준수하는 퍼블리셔입니다.

 

Swift - Combine의 Publisher 알아보기 Just, Future, Fail, Empty, Deferred, Sequence

Publisher #Combine #Publisher Just 가장 단순한 형태의 Publisher 입니다. 에러 타입은 항상 Never 입니다. Just((0...5)) .sink { value in print(value) // 0...5 } Future 일반적으로 Publisher의 처리를 sin..

todayssky.tistory.com

https://todayssky.tistory.com/17


Operator 종류

  • Mapping Element
    • 데이터를 다른 데이터 타입으로 변형
    • Scan
    • setFailureType
    • map
    • flatMap : 최대수 지정 후 새로운 publisher를 반환, 모든 publisher를 성공적으로 완료해도 전체 스트림은 완료되지 않고 계속 살아있음
  • Filtering
    • 조건에 맞는 데이터만 허용
      • compactMap() : filter에서 Optional제거 → 성공적인 리턴만 반환
      • replaceEmpty : empty일 경우 임의값 출력
      • filter : 기본
      • replaceError
      • removeDuplicates : 중복 제거
  • Reduce
    • 데이터 스트림을 모아서 출력
    • Collect
    • reduce
    • tryReduce
    • ignoreOutput : 입력값을 모두 무시하고 완료 이벤트만 보냄
  • Mathematic operations on
    • 숫자시퀀스값과 관련된 스트림을 제어
    • Max, count, min
  • Sequence
    • 데이터 시퀀스를 변형할때 사용
    • Prepend
    • firstWhere
    • tryFirstWhere
    • first : 클로저의 bool에 일치하는 항목중 첫번째를 가져옴
    • lastWhere
    • tryLastWhere
    • last : 마지막을 가져옴 ( 마지막엔 copletion에 finished를 보내줘야함 )
    • dropWhile : true가 될때까지 drop, true 이후로 출력(포함)
      • filter와의 차이점 : filter는 모든 데이터가 해당 조건문을 비교해야함
    • prefix : prefix(2) 두 값을 내보내면 publisher가 완료됨
    • prefix(while: {} ) : 클로저의 결과가 true일 경우 완료
    • prefix(untilOutputFrom: ) : 해당 신호가 오면 완료
    • → prefix는 drop과 반대 개념인것 같음

연산자 결합

  • prepend : 먼저 추가 후 publisher 완료
  • append : 완료 한 후 항목 추가
  • swiftchToLatest() : publisher가 바뀌면 이전 subscribe 취소
  • merge(with:) : 병합
  • combineLatest : 결합 → 타입이 달라도 됨 (한 쌍이 도착할 때 마다 한쪽이 기다림)

Time 연산자

  • delay : 지정 시간(초) 만큼 딜레이를 준 후 값을 보냄
  • collect(.byTime) : 지정 시간만큼 기다린 후 배열로 모아서 보냄
  • debounce : 지정 시간을 기다린 후 출력 (일시정지)
  • throttle : 지정 시간을 기다린 후 가장 최신 값을 출력 ( 일시정지 x)
    • share() 연산자를 추가하면 모든 구독자가 동일한 출력을 동시에 볼 수 있음
    • debounce와 비슷하지만 다름 (차이점?)
  • subject.timeout : 마지막 응답 후 지정 시간이 지나면 게시가자 완료됨
  • subject.measureInterval : 시간 간격 출력

Sequence 연산자

  • min : 완료 이벤트를 수신한 후 최소값을 구함
    • Comparable 프로토콜을 준수하지 않으면 min(by:) 클로저를 구현해야함
  • max : min과 같이 완료 이벤트를 수신한 후 최대값을 구함
  • first() : 첫번째값만 받고 구독취소
    • .(where:) : 해당하는 첫번째 값을 받음
  • last() : finished를 기다린 후 마지막 인자를 받음
  • output(at :) : 해당 인덱스에 해당하는 순서까지 받음 (구독 취소됨) , (in:) : 해당 범위

publisher query

  • count()
  • contains() : bool을 반환 , where 사용
  • allStatisy : contains의 전체버전 ( 하나라도 false시 즉시 구독 해제 및 false 리턴 )
  • reudce( { } ) : 단일값을 반환

Subject

  • publisher의 일종
  • 외부의 데이터를 안으로 주입시킬 수 있음 → SwiftUI같은 다른 Framework와도 쉽게 연동 가능
  • PassthroughSubject
    • 상태값을 가지지 않음
  • CurrentValueSubject
    • 상태값을 가짐
    • UI 상태값에 따라 데이터를 발행할 때 유용

Cancellable

  • Subscriber의 리턴값
  • cancle() 메서드로 스트림 중단 가능

eraseToAnyPublisher

  • 데이터 스트림과 상관없이 최종적인 형태의 Publisher를 리턴

리소스 관리

  • share()
  • multicast
  • future class

사용할만한 소스

  • 시간 간격 출력
class TimeLogger: TextOutputStream {
  private var previous = Date()
  private let formatter = NumberFormatter()

  init() {
    formatter.maximumFractionDigits = 5
    formatter.minimumFractionDigits = 5
  }

  func write(_ string: String) {
    let trimmed = string.trimmingCharacters(in: .whitespacesAndNewlines)
    guard !trimmed.isEmpty else { return }
    let now = Date()
    print("+\(formatter.string(for: now.timeIntervalSince(previous))!)s: \(string)")
    previous = now
  }
}

/* ex)
let subscription = (1...3).publisher
  .print("publisher", to: TimeLogger())
  .sink { _ in }
*/
  • http decode
func story(id: Int) -> AnyPublisher<Story, Error> {
  URLSession.shared
    .dataTaskPublisher(for: EndPoint.story(id).url)
    .receive(on: apiQueue)  // 수신할 스케줄러를 정의
    .map(\.data)
    .decode(type: Story.self, decoder: decoder)
    .catch { _ in Empty<Story, Error>() } // 게시자의 오류를 다른 게시자로 대체
    .eraseToAnyPublisher()
}

// 커스텀 디버그 스트링
extension Story: CustomDebugStringConvertible {
  public var debugDescription: String {
    return "\n\(title)\nby \(by)\n\(url)\n\(id)\n\(time)\n-----"
  }
}
반응형

SwiftUI에서 UIkit 사용하기


SwiftUI에서 UIkit를 사용하기 위해서는 UIViewRepresentable을 채택하는 struct를 구현하면 됩니다.

UIViewRepresentable을 채택하게 되면 필수로 구현해야 하는 makeUIView와 updateUIView가 있고 UIViewType을 원하는 UIkit의 View로 변경하면 됩니다.

UIViewRepresentable

// 구현
struct SwiftUIView: UIViewRepresentable {
	func makeUIView(context: Context) -> UIViewType {
    	let view = UIViewType()
        return view
    }
    
    func updateUIView(_ view: UIViewType, context: Context) {
    
    }
}


// 사용
struct MyView: View {
	var body: some View {
    	VStack { 
        	SwiftUIView()
        }
    }
}

UIViewControllerRepresentable

만약 Custom View가 아닌 하나의 Controller일때는 UIViewControllerRepresentable이라는 것을 따로 제공합니다. 

makeUIViewController에 해당하는 ViewController를 리턴하도록 해주면 됩니다.

struct MyViewControllerRepresentation: UIViewControllerRepresentable { 
	func makeUIViewController(context: Context) -> ViewController {
		
    }

	func updateUIViewController(_ uiViewController: ViewController, context: Context) { 
    
    } 
}

 

 

SwiftUI에서 Storyboard 사용하기


코드로 구현된 UIViewController가 아닌 Storyboard(.xib)로 구현되어있다면 어떻게 해야할까요?

UIStoryboard

struct MyViewControllerRepresentation: UIViewControllerRepresentable { 
	func makeUIViewController(context: Context) -> ViewController {
		UIStoryboard(name: "MyStoryBoardView", bundle: nil)
        	.instantiateViewController(withIdentifier: "ViewController") as! ViewController
    }

	func updateUIViewController(_ uiViewController: ViewController, context: Context) { 
    
    } 
}



반응형
import Foundation

/*
 동전 종류 N
 가치의 합 K
 
 K원을 만드는데 필요한 동전 개수의 최솟값은?
 */

let firstInputItems = readLine()!.components(separatedBy: " ").map { Int($0)! }
let kinds = firstInputItems[0]
var sum = firstInputItems[1]
var elements = [Int]()

elements = Range(0 ... kinds - 1)
  .map { _ in Int(readLine()!)! }
  .reversed()

var count = 0

elements
  .forEach { element in
    let value = sum / element
    
    if value > 0 {
      count += value
      sum -= element * value
    }
    
    if sum == 0 {
      return
    }
  }

print(count)

 

해설

입력값을 받아놓고 큰 값부터 처리하기 위해 reversed()를 사용했고 큰값으로 나눈 몫을 동전의 총 가치에서 빼주는 작업을 sum이 0이 될때 까지 진행합니다.

반응형

알고리즘 문제를 풀어보려고 하는데 문제를 풀어도 어떤식으로 제출을 해야 하는지에 대한 글입니다.

 

1. 문제 풀기 위한 Xcode 세팅

1. 먼저 xcode를 열어 new project를 만듭니다.

2. macOS에서 Commend Line Tool을 선택합니다.

3. main.swift 파일에서 문제를 푸시면 됩니다!

 

Playground로 하지 않고 Command Line Tool로 하는 이유는 아래를 보면 알 수 있습니다.

 

2. 입력값을 받는 문제

문제중에 입력값을 받는 문제들이 있습니다. 이 입력값을 받기 위해 일반 Playground를 사용하지 않고 Command Line Tool을 사용합니다.

 

입력값을 받기 위해서는 readLine()을 호출하면 됩니다.

실행을 하게되면 먼저

1. Hello, World!가 찍힘

2. 해당 콘솔창에 insert!!!를 입력

3. 옵셔널로 insert!!!가 print

 

가 되는 것을 볼 수 있습니다.

 

반응형

'Algorithm > BackJoon' 카테고리의 다른 글

[Swift] 백준 11047 - 동전 0  (0) 2022.01.24
[Swift] 백준 11399 - ATM  (0) 2022.01.23
[Swift] 백준 2839 - 설탕 배달  (0) 2022.01.23
import Foundation

let count = readLine()
let insertPersonTimes = readLine()

var personTimes = insertPersonTimes!.components(separatedBy: " ").map { Int($0)! }

personTimes.sort()
var sum = 0
for i in 0 ..< personTimes.count {
  sum += personTimes[i] * (personTimes.count - i)
}

print(sum)

2개의 입력값을 받는 문제입니다 사실 첫번째의 count는 안받아도 될거 같은데... ㅎㅎ

ios 개발을 하면서 커맨드 라인으로 입력값을 받은 적이 없어 약간 해맸네요...

Xcode Swift로 커맨드 라인 입력값 받기

해설

굳이 이전의 값들을 따로 빼서 합을 구해주지 않고 최종적으로 한 사람이 몇 명에게 시간을 주느냐에 관점으로 접근했습니다.

간단하게 첫번째 사람은 한번, 두번째 사람은 두번 ... 이런식이기 때문에 자신이 걸리는 시간 * (인원수 - 자신의 순번) 으로 처리했습니다.

반응형

시간 날때마다 알고리즘 문제를 풀어볼까 합니다! 실무에 중요한 그리디 유형부터 진행할 예정입니다!

 

var amount = Int(readLine()!)!
var bag = 0

while(amount >= 0) {
    if amount % 5 == 0 {
        bag += amount / 5
        print(bag)
        break
    }
    bag += 1
    amount -= 3

    if 1..<3 ~= amount {
        print(-1)
        break
    }
}

while문을 사용하지 않고서는 도저히 쉽게 해결할 방법이 안떠올라 결국 while문으로 풀게 됬네요.

 

해설

그냥 최대한 단순하게 5로 나누어 떨어질 때 까지 3을 빼주며 1봉지씩 추가하는 방법입니다. while문 도중 3씩 빼고 있는데 남은 수가 1이나 2가 될 경우 -1을 출력합니다.

 

반응형

Back pressure

Combine은 구독자가 데이터의 흐름을 제어하도록 설계되어 있습니다. 그래서 구독자는 파이프라인에서 처리가 발생하는 시기와 대상도 제어합니다. 구독자가 얼마나 많은 정보를 원하거나 수용할 수 있는지에 대한 정보를 제공함으로써 파이프라인 내에서 처리를 주도한다는 것을 의미합니다. 이러한 요청은 구성된 파이프라인을 통해 전파되며 각 Operator는 차례대로 데이터 요청을 수락하고 연결된 Publisher에게 정보를 요청합니다.
이 것을 백 프레셔 라고 불리는 Combine의 기능이라고 합니다!

파이프라인이 취소되면 해당 파이프라인은 다시 시작되지 않습니다. 취소된 파이프라인 대신 새로운 파이프라인을 만들어야 합니다.

생명주기(Life Cycle)

lifeCycle

1. 구독자가 게시자에게 연결되면 구독자의 호출로 시작됩니다. .subscribe(_: Subscriber

2. 게시자는 차례대로 구독을 호출을 확인합니다. receive:subscription: Subscription

3. 구독이 승인된 후 구독자는 값을 요청합니다 request(_: Demand)

4. 게시자가 값이 있다면 값을 보내게 됩니다. 게시자는 요청 한 양보다 더 많은 값을 줄 수 없습니다. receive(_: Input)

5. 구독이 완료된 후 언제든지 구독자는 다음과 같이 구독을 취소할 수 있습니다. .cancel()

6. 게시자는 선택적으로 완료가 되었다는것을 보냅니다. 정상적인 종료일 수도 있고 오류 유형을 알려주는 완료일 수도 있습니다. 취소된 파이프라인은 완료를 보내지 않습니다. receive(completion:)

반응형

Publisher(게시자)

  • 요청 시 데이터를 제공해줌
  • 구독이 없는 경우 Publisher는 데이터를 제공하지 않음
  • 두 가지 유형을 제공함(Outpt Type, Failure Type)

publisher

Subscriber(구독자)

  • 구독자는 데이터를 요청하고 Publisher가 제공한 데이터(및 오류)를 처리해야 함
  • 입력에 대한 유형과 실패에 대한 유형 두 가지 연관된 유형
  • 구독자는 데이터를 요청을 시작하고 수신하는 데이터의 양을 제어함
  • Subscriber가 없으면 게시가 아예 되지 않기 때문에 Subscriber는 작업을 주도하는 것으로 생각할 수 있습니다.
    subscriber

Operator(연산자)

  • 연산자는 Publisher Protocol과 Subscriber Protocol을 모두 채택하는 클래스
  • 게시자 구독 및 모든 구독자에게 결과 보내기를 지원
  • 게시자가 데이터를 제공하고 구독자가 요청한 데이터를 처리, 반응 및 변환하기 위해 체인을 만들 수 있음
    operator

연산자는 값 또는 유형을 변환하는데 사용되며 스트림을 분할 또는 복제하거나 스트림을 병합할 수도 있습니다. 그리고 항상 (출력/실패) 유형의 조합으로 정렬되어야 합니다. 만약 유형이 올바르지 않으면 컴파일러에서 오류가 발생합니다!


아래는 간단한 Combine 파이프라인 입니다.

let _ = Just(5)                     // 1
    .map { value -> String in     // 2
        return "a string"
    }
    .sink { receivedValue in      // 3
        print("The end result was \(receivedValue)")
    }

1) Just 파이프라인은 정의되어있는 값으로 응답하는 게시자입니다. 이미 정의되어있는 값이기 때문에 실패 유형이 없죠? 그래서 Error 유형은 NEVER가 됩니다.
2) map을 통해 기존의 값을 기반으로 한 새로운 유형의 값을 반환할 수 있습니다. 예제에서는 기존 값을 무시하고 새로운 String 값을 반환합니다.
3) sink 구독자로 인해 파이프라인이 종료됩니다.

파이프라인은 출력 유형과 실패 유형 두 가지에 의해 연결된 일련의 작업입니다. 파이프라인을 생성할 때 최종 목표를 달성하기 위해 데이터, 유형(스트림의 성공 여부 등)을 변환하는 데 연산자를 사용하게 됩니다. 여기서 말하는 최종 목표는 대부분 사용자 인터페이스 요소를 변화시키는 작업이겠죠? 그렇기에 이러한 변환을 돕기 위한 게 바로 Combine의 연산자입니다.

Combine의 대표 연산자 tryMap

Combine의 연산자를 보다 보면 try###라는 이름의 연산자들이 있습니다. 모두 기존의 함수와 비슷한 동작을 하지만 실패 유형을 가지고 있어 실패 유형에 대한 처리를 도와줍니다. map은 위의 예제에서처럼 String만을 반환하지만 tryMap의 경우 유형을 제공하는 게시자를 <String, Never>을 사용하는 구독자로 끝납니다. 간단하게 throw를 해야 한다면 try가 붙은 연산자를 사용하면 됩니다.

let _ = Just(5) 
    .map { value -> String in 
        switch value {
        case _ where value < 1:
            return "none"
        case _ where value == 1:
            return "one"
        case _ where value == 2:
            return "couple"
        case _ where value == 3:
            return "few"
        case _ where value > 8:
            return "many"
        default:
            return "some"
        }
    }
    .sink { receivedValue in 
        print("The end result was \(receivedValue)")
    }
  • Just<Int, Never> 유형의 조합을 만들었고 정의된 단일 값을 제공합니다.
  • .map() 함수를 통해 Int를 받아 String으로 반환합니다. 실패 유형인 Never는 변경되지 않으므로 통과됩니다.
  • sink를 통해 <String, Never> 조합을 수신합니다.
반응형

+ Recent posts