What’s new in Swift - WWDC23 - Videos - Apple Developer Join us for an update on Swift. We'll show you how APIs are becoming more extensible and expressive with features like parameter packs... developer.apple.com if/else문의 향상 복잡한 조건을 기반으로한 let 변수를 초기화하려면 아래와 같은 복잡한 삼항 표현식이 나올수도 있습니다(있나!?). let bullet = isRoot && (count == 0 || !willExpand) ? "" : count == 0 ? "- " : maxDepth (R1, R2) func evalu..
Platforms State of the Union을 훝고 갑니다. 추후 각 세션 정리 예정입니다. Swift Swift Macros Boilerplate 코드를 좀 더 깔끔하게 만들어 줄 수 있는 방법입니다. 위처럼 @가 붙은 attribute일 수도 있고, 독립적으로 #이 붙은 형태일 수도 있습니다. 이 #URL Macro는 URL을 초기화하여 언래핑시켜주는 코드인데, 해당 Macro에서 Expand Macro를 통해 확인이 됩니다. 그 뿐만 아니라 유효한 URL String인지도 컴파일 타임에 체크해주고, 올바른 코드를 작성할 수 있도록 커스텀 피드백을 할 수 있게 해줍니다. fetchContent(_:completion:) 함수에 async/await을 사용하고 싶을 땐, 위처럼 @AddAsync..
클래스로 묶으면 함수들이 공유하는 공통 환경을 더 명확하게 표현할 수 있고, 각 함수에 전달되는 인수를 줄여서 객체 안에서의 함수 호출을 간결하게 만들 수 있습니다. 그리고 이런 객체를 시스템의 다른 부분에 전달하기 위한 참조를 제공할 수 있습니다. 클라이언트가 객체의 핵심 데이터를 변경할 수 있고, 파생 객체들을 일관되게 관리할 수도 있습니다. (1) 함수들이 공유하는 공통 데이터 레코드를 캡슐화: 공통 데이터가 레코드 구조로 묶여 있지 않다면 '매개변수 객체 만들기'로 데이터를 하나로 묶는 레코드를 만들기 (2) 공통 레코드를 사용하는 함수 각각을 새 클래스로 옮기기: 공통 레코드의 멤버는 함수 호출문의 인수 목록에서 제거 (3) 데이터를 조작하는 로직들을 '함수로 추출'해서 새 클래스로 옮기기 아래..
Operator는 Publisher가 내보내는 value에 대해 작업을 수행하는 메서드입니다. 각 Combine Operator는 Publisher를 반환합니다. 보통 Operator들은 Upstream의 이벤트를 받아서 이를 조작한 뒤, 조작된 이벤트를 소비할 Downstream으로 보냅니다. collect() ( = RxSwift의 toArray()) collect() operator는 여러개의 value 시퀀스를 하나의 배열 결과값으로 변환해줍니다. 아래는 collect() operator를 나타내는 마블다이어그램입니다. 마블다이어그램에 대한 설명은 RxSwift의 그것과 동일하기 때문에 지난글([RxSwift] Lifecycle과 마블다이어그램)로 대체합니다. 아래는 collect()의 예시입니다..
( = RxSwift의 .asObservable()) Subscriber가 Publisher의 어떤 추가적인 세부정보를 알 필요가 없이 Publisher로부터 값만 수신하도록 하고 싶을 수 있습니다. 이럴 때는 .eraseToAnyPublisher() operator를 통해 Subscriber가 AnyPublisher로 인식하도록 만들어줄 수 있습니다. 아래는 예시입니다. var subscriptions = Set() // 1. PassthroughSubject를 생성 let subject = PassthroughSubject() // 2. subject에서 type-erase된 publisher를 생성 let publisher = subject.eraseToAnyPublisher() // 3. type..
Subject는 non-Combine 코드로부터 값을 받아서 Subscriber에게 값을 방출시키는 Publisher입니다. PassthroughtSubject로 value를 전달하는 방식은 명령형 코드를 Combine을 통한 선언형 코드로 연결하는 좋은 방법입니다. (@published를 마킹한 프로퍼티와 유사한 징검다리 역할입니다. non-Combine 코드로부터 값을 받아, sink를 통해 값을 내보낼 수 있죠) PassthroughSubject ( = RxSwift의 PublishSubject) Subject의 가장 기본형입니다. 아래는 우선 커스텀 Subscriber의 예시입니다(Custom Subscriber는 이전글 참조) // 1. Error 타입을 정의 enum MyError: Error..
이전 글([Combine] Publisher, Subscriber, Cancellable)에서 Subscribe하자마자 단일값을 방출하고 Complete시키는 Publisher의 예시로 Just를 작성했었습니다. Future를 사용하면 단일값을 비동기적으로 생성하고 Complete하는 Publisher를 정의할 수 있습니다. 아래는 Int, Never의 Future를 생성하여 반환하는 factory함수입니다. (Never는 failure를 절대 반환하지 않음. 이전글 참조) func futureIncrement( integer: Int, afterDelay delay: TimeInterval) -> Future { } Future를 반환하는 함수 본문을 채워봅니다. 함수 호출부가 전달해 준 afterDe..
매개변수 객체 만들기 데이터 항목 여러개를 함수로 넘겨주게 되면, 데이터 구조를 묶어서 보내주면 좋습니다. 데이터 뭉치를 데이터 구조로 묶으면 데이터 사이의 관계가 명확해짐 함수는 데이터 구조를 받음으로써 매개변수 수가 줄어듦 같은 데이터 구조를 사용하는 모든 함수가 원소를 참조할 때 같은 이름을 사용하기 때문에 일관성을 높여줌 (1) 적당한 데이터 구조가 없으면 새로 만들기 (2) 테스트 (3) 함수 선언 바꾸기로 데이터 구조를 매개변수로 추가 (4) 테스트 (5) 함수 호출시 새로운 데이터 구조 인스턴스를 넘겨주도록 수정하고, 수정할 때마다 테스트 (6) 기존 매개변수를 사용하던 코드를 새 데이터 구조의 원소를 사용하도록 변경 (7) 기존 매개변수를 제거하고 테스트 아래는 온도측정값(reading) ..
변수 캡슐화하기 데이터는 참조하는 모든 부분을 한 번에 바꿔야 코드가 제대로 동작하는 까닭에 함수보다 까다롭습니다. 유효범위가 넓어질수록 다루기 어려워집니다. 전역 데이터가 골칫거리인 이유. 그래서 접근 범위가 넓은 데이터를 옮길 때는 먼저 그 데이터로의 접근을 독점하는 식의 '캡슐화'하는 것이 좋을 때가 많습니다. 캡슐화를 하면 데이터를 변경하고 사용하는 코드를 감시할 수 있는 확실한 통로가 되어주기 때문에 데이터 변경 전 검증이나, 변경 후 추가로직을 쉽게 끼워 넣을 수 있습니다. (Swift에서는 프로퍼티들에 willSet, didSet을 제공하기 때문에 통로를 이유로 캡슐화를 하지는 않습니다) '불변 데이터'는 가변 데이터보다 캡슐화할 이유가 적습니다. 데이터가 변경될 일이 없어서 갱신 전 검증 ..
함수 선언 바꾸기 함수의 이름이 좋으면 함수의 구현 코드를 볼 필요도 없이 호출문만 보고도 무슨일을 하는지 파악이 가능합니다. 💡 좋은 이름을 떠올리는 효과적인 방법은 '주석으로 함수의 목적을 설명해보기'. 주석이 멋진 이름으로 바뀌어 되돌아 올 때가 있음. 매개변수도 마찬가지. 함수를 사용하는 문맥을 설정하는 것. 함수 선언 바꾸기를 할 때는 변경사항을 보고 함수 선언과 호출문들을 단번에 고칠 수 있을지 가늠해보고 가능해 보이면 간단한 절차로 수행할 수 있습니다. [간단한 절차] (1) 매개변수를 제거하려거든 먼저 함수 본문에서 제거 대상 매개변수를 대상 매개변수를 참조하는 곳은 없는지 확인 (2) 메서드 선언을 원하는 형태로 변경 (3) 기존 메서드 선언을 참조하는 부분을 모두 찾아서 바뀐 형태로 수..
변수 추출하기 Extract Variable 표현식이 복잡하여 이해하기 어려울 땐, 지역 변수로 표현식을 쪼개어 관리하기 쉽게 만들수 있습니다. 추가한 변수는 디버거에 breakpoint를 지정하거나, 상태를 출력하거나, 상태를 임의로 변경할 수 있어 디버깅에도 많은 도움이 됩니다. (1) 추출하려는 표현식에 부작용은 없는지 확인 (2) 상수를 하나 선언하고 이름을 붙일 표현식의 복제본을 대입 (3) 원본 표현식을 만든 변수로 교체 (4) 테스트 (5) 표현식을 여러 곳에서 사용한다면 각각을 새로 만든 변수로 교체. 하나 교체할 때마다 테스트. 아래에 딱 봐도 복잡한 주석이 꼭 필요해보이는 계산식의 예시가 있습니다. func price(order: Order) -> Double { // 가격(price)..
함수 추출하기 Extract Function 코드 조각을 찾아 무슨 일을 하는지 파악한 다음, 독립된 함수로 추출하고 목적에 맞는 이름을 붙이는 작업입니다. '목적과 구현을 분리'하는 방식이 가장 합리적인 기준. 코드를 보고 무슨 일을 하는지 파악하는 데 한참이 걸린다면 그 부분을 함수로 추출한 뒤 '무슨 일'에 걸 맞는 이름을 짓습니다. (1) 함수를 새로 만들고, 목적을 잘 드러내는 이름을 붙임('어떻게'가 아닌 '무엇을' 하는지가 드러나야 함): 대상 코드가 함수 호출문 하나처럼 간단하더라도 함수로 뽑아서 목적이 더 잘 드러나는 이름을 붙일수 있다면 추출할 것(이런 이름이 떠오르지 않는다면 추출하면 안 된다는 신호) (2) 추출한 코드를 원본 함수에서 복사하여 새 함수에 붙여넣음 (3) 추출한 코드..
Foundation Package Preview Now Available I’m pleased to announce that a preview of the future of Foundation is now available on GitHub! www.swift.org 드디어 Swift로 작성된 Foundation Package의 Preview가 Github에 공개됐습니다. 아직 모두 완성된 것은 아니지만 초기 테스트와 컨트리뷰트를 위해 빠르게 공개되었다고 합니다. 공개된 요소들은 아래와 같습니다. FoundationEssentials AttributedString Data Date DateInterval JSONEncoder JSONDecoder Predicate String extensions UUID..
Xcode 14.3이 릴리즈되면서 Swift 5.8도 업데이트되었습니다. 변경점들을 간단하게 정리해봅니다. Function back deployment (SE-0376) @backDeployed(before:) attribute를 통해 이전 버전의 프레임워크에서 새 API를 사용할 수 있게 해줍니다. 함수에 대한 코드를 앱의 바이너리에 작성 후 런타임 시 검사하여 수행됩니다. 사용자가 적절한 새 OS를 사용하는 경우 시스템 자체 버전의 함수가 사용되고, 아닌 경우 앱 바이너리에 복사된 버전에 대신 사용됩니다. 단, @backDeployed는 함수, 메서드, 서브스크립트, 계산프로퍼티에만 적용됩니다. 당연하게도 만능으로 새 기능을 이전 OS에서 쓸 수 있게 한다던가 하는건 아닌거죠. 아래는 예시입니다. @..
아래는 Publisher와 Subscriber 사이의 흐름을 나타내는 UML다이어그램입니다. subscriber가 publisher를 subscribe합니다. publisher가 subscription을 생성해서 subscriber에게 제공합니다. subscriber가 value를 요청합니다. publisher가 value를 보냅니다. publisher가 completion을 보냅니다. 위 흐름에 맞춰서 아래의 Publisher와 Subscriber의 프로토콜을 살펴봅시다. 먼저 Publisher 프로토콜을 살펴보면 아래와 같습니다. public protocol Publisher { // [1] Publisher가 생성할 수 있는 값의 타입 // = Subscriber의 Input이 맞춰야 할 타입 as..