WWDC의 Demystify SwiftUI를 정리한 내용입니다.SwiftUI는 선언적UI로서 고수준의 앱이 원하는 것을 Describe하면 SwiftUI가 이를 구현하는 방법을 정확히 결정.대부분의 경우 잘 작동하지만, 예상하지 못한 동작을 하는 순간은 생겨나는데,이런 순간에 원하는 결과를 얻기 위해 SwiftUI가 뒤에서 무엇을 하는지 이해하는 것이 도움이 됨. SwiftUI가 코드를 볼때 무엇을 보는가Identity: SwiftUI가 앱의 여러 업데이트에서 element를 동일하거나 별개로 인식하는 방법Lifetime: SwiftUI가 시간이 지남에 따라 View와 데이터의 존재를 추적하는 방법의존성: SwiftUI가 인터페이스를 업데이트해야하는 시기와 이유를 이해하는 방법위 세가지 개념이 Swift..
시퀀스 연산자들은 Publisher자체가 시퀀스라고 보면됨. 시퀀스 연산자들은 개별 방출값이 아닌 Publisher 전체를 다룸. 값 찾기 min() Publisher가 Finish될 때까지 기다렸다가, 최소값만 방출시켜줌. Comparable 프로토콜을 따르는 경우 별도의 파라미터없이 최소값을 찾아줌. var subscriptions = Set() // 1. 숫자를 방출하는 Publisher let publisher = [1, -50, 246, 0].publisher // 2. min 연산자로 최소값을 찾아서 print publisher .print("publisher") .min() .sink(receiveValue: { print("최소값은 \($0)") }) .store(in: &subscript..
반응형 프로그래밍의 핵심 아이디어는 시간에 따른 비동기 이벤트 흐름을 모델링하는 것. Combine에서는 시퀀스가 시간에 따라 값에 반응하고 변환하는 다양한 연산자들을 제공. Time shifting delay(for:tolerance:scheduler:options) (Rx의 delay) Upstream Publisher가 값을 내보낼 때마다 delay 연산자는 잠시 동안 값을 유지한 다음 사용자가 지정한 스케줄러에서 요청한 지연 시간 후에 값을 내보냄. 초마다 하나의 값을 내보내는 퍼블리셔를 만든 다음 1.5초씩 지연시키고 두 타임라인을 동시에 표시하여 비교. import Combine import SwiftUI import PlaygroundSupport var subscriptions = Set(..
https://developer.apple.com/documentation/swift/collection/count-4l4qk Collection의 Element를 세어주는 count의 복잡도는 기본적으로 O(n) 연산. RandomAccessCollection을 준수하는 경우 O(1) 연산. Collection이 비어있는지 여부를 체크할 때는 Collection.count == 0 으로 체크하는 것보다, Collection.isEmpty 로 체크하는 것이 더 좋음. if someArray.count == 0 { // ❌ ... } if someArray.isEmpty { // ⭕️ ... }
Generic 모델링에서 시작합니다. 아래와 같은 Animal 프로토콜이 있을 때, 이를 사용하는 Farm struct의 메서드에서 Animal의 Concrete 타입으로 대체될 타입파라미터적합성을 따르도록 적용할 수 있습니다. protocol Animal { associatedtype Feed: AnimalFeed func eat(_ food: Feed) } struct Farm { func feed(_ animal: A) { // ... } } 혹은 아래처럼 후행 where절에서 프로토콜 적합성을 지정할 수 있습니다. where절은 디테일하게 requirement와 타입 관계를 작성할 수 있게 해줍니다. struct Farm { func feed(_ animal: A) where A: Animal {..
프로토콜 extension 프로토콜 자체를 확장하여 프로토콜 member의 기본 구현을 제공할 수 있습니다. extension Localizable { static var supportedLanguages: [Language] { return [.english] } } 여기서는 supportedLanguages의 기본 구현으로 Localizable을 확장합니다. Localizable을 준수하는 각 타입은 이제 해당 구현에 액세스할 수 있으므로 자체 정의할 필요가 없습니다. struct Image: Localizable { // no need to add `supportedLanguages` here } 위까지는 코드의 모든 유형이 구현할 수 있는 프로토콜로 작업했습니다. 특정 class에 의해서만 준수되..
Public-Key Cryptography 이전 글에서 정리했던 HMAC, Sealed Box암호화는 Sender와 Receiver모두 키를 알고 있는 대칭키를 사용합니다. 대칭키는 대역 외(Out of band)로 전송되어야 하고, 이 작업을 안전하게 수행할 수 없는 경우 공개키 암호화(public-key cryptography)를 사용합니다. 실제로 인터넷에서 일상적으로 사용하는 대부분의 암호화는 공개키 암호화를 사용하고, Xcode가 앱에 서명을 할 때에도 동일합니다. 공개키 암호화는 수학적으로 연결된 두개의 키를 생성합니다. 개인키는 비밀로 유지하고 해당 공개키 Data를 게시합니다. 개인키로 Data 혹은 Data Digest에 서명한 다음 전송합니다. Receiver는 공개키 Data에서 공개..
Hasher와 Cryptographic Hashing Hashable 프로토콜 타입의 객체를 Hasher로 hashing하면 무작위로 생성된 시드를 사용해서 해시값을 생성하여 실행될 때마다 다른 해시값을 생성시켜줍니다. func hashItem(item: String) -> Int { var hasher = Hasher() item.hash(into: &hasher) return hasher.finalize() } // Hashing data let hashValue = hashItem(item: "Hasher로 hash한 Data") // 실행시 마다 다른 해시값 Cryptographic Hashing은 Hasher와 같이 거의 유일한 해시값을 생성하고, 입력값을 조금만 변경해도 해시값이 크게 변합니다..
SSL Pinning(이하 Pinning, 피닝)은? 호스트를 인증서 또는 공개키와 연결하는 프로세스입니다. 호스트의 인증서 또는 공개키를 알고 있으면 해당 호스트에 고정(Pinning)합니다. 즉, 미리 정의된 인증서 또는 공개키 중 하나 또는 몇 개를 제외한 모든 인증서를 거부하도록 앱을 구성합니다. 앱이 서버에 연결할 때마다 서버 인증서를 고정된 인증서 또는 공개키와 비교합니다. 둘이 일치하는 경우에만 앱이 서버를 신뢰하고 연결을 설정합니다. 일반적으로 개발 시 서비스의 인증서 또는 공개키를 추가합니다. 즉, 모바일 앱은 앱 번들 내에 디지털 인증서 또는 공개키를 포함해야 합니다. 공격자가 핀을 오염시킬 수 없기 때문에 이 방법이 선호됩니다. SSL 인증서 Pinning이 필요한 이유? 일반적으로 ..
https://developer.apple.com/videos/play/wwdc2022/110352/ Generic 모델링에 some/any를 적용하는 방법을 설명한 WWDC22 영상입니다. Farm을 시뮬레이션 하기 위한 예시. 추상화 도구들을 사용하기 전의 Concrete 타입의 예시부터 작성. Concrete 타입으로 먼저 모델링 Cow 구조체는 Hay(건초) 타입의 매개변수를 받는 eat()이라는 메서드가 존재하고, Hay 구조체는 Alfalfa 종류의 작물을 재배하기 위한 grow()라는 static 메서드가 존재. Alfalfa 구조체는 Alfalfa인스턴스에서 Hay를 수확할 수 있는 harvest() 메서드가 존재. Farm 구조체는 Cow에게 먹이를 줄 수 있는 feed() 메서드가 있음..
Combining Operator을 사용하면 서로 다른 Publisher가 방출한 이벤트를 결합(combine)하고 결합 코드에서 의미 있는 데이터 조합을 만들 수 있습니다. 예를 들어서 사용자 이름, 비밀번호, 체크박스 등의 입력이 필요한 양식의 경우 각각의 Publisher를 조합해서 동작하도록 만들 수 있습니다. 먼저 prepend 연산자 시리즈입니다. prepend는 '앞에 붙이다'라는 뜻처럼 Publisher에서 나오는 값보다 먼저 나오는 값을 지정해줄 수 있습니다. (Rx의 concat과 유사) prepend 연산자 시리즈 prepend(Output...) prepend(Output)는 ... 구문을 사용하여 다양한 값 리스트를 받습니다. 즉, 원래 Publisher와 동일한 출력 타입인 값을..
Building ifelse 아래에서는 R이 사용하는 통계 프로그래밍 언어와 같은 ifelse() 문을 구현. // R ifelse(condition, valueTrue, valueFalse) Swift 삼항 연산자 condition ? valueTrue : valueFalse 과 동일한 작업을 수행. 플레이그라운드에 아래 코드를 작성. func ifelse(condition: Bool, valueTrue: Int, valueFalse: Int) -> Int { if condition { return valueTrue } else { return valueFalse } } let value = ifelse( condition: Bool.random(), valueTrue: 100, valueFalse: ..
LLVM 프로젝트는 모듈식의 재사용 가능한 컴파일러와 툴체인의 집합. LLVM이라는 이름은 약자가 아니며 그것이 오픈소스 프로젝트의 풀 네임. (LLVM은 Swift 뿐만 아니라 Kotlin, Rust 등에서도 사용중) Swift 툴체인의 핵심은 Swift 컴파일러이며 소스 코드(.swift)를 실행 파일에 연결할 수 있는 object코드(.o)로 변환하는 역할을 함. LLVM 컴파일러 인프라에서 실행되는 데이터 흐름. Parse(구문 분석): Swift 소스 코드는 먼저 토큰으로 Parse되고 Abstract Syntax Tree(AST. 추상 구문 트리)에 입력됨. 이것은 각 표현식이 노드인 트리라고 생각할 수 있음. 노드는 또한 소스 위치 정보를 가지고 있어서 error가 감지되면 노드는 문제가 발..
Publisher가 내보내는 값이나 이벤트를 제한하고 그 중 일부만 소비하고 싶을 때 유용한 Filtering Operator입니다. 💡 Filtering Operator에는 try 접두사가 붙은 유사 Operator(예: filter와 tryFilter)가 있습니다. 유일한 차이점은 끝에서 throw하는 클로저를 제공한다는 것. 클로저 내에서 던지는 모든 오류는 던진 오류와 함께 Publisher를 종료합니다. 여기서는 non-throwing Operator에 대해서만 정리합니다. filter (= RxSwift의 filter) Swift 표준 라이브러리에도 있고 모두가 익숙한 Filtering Operator의 기본입니다. Bool을 반환하는 클로저에 일치하는 값만 전달시킵니다. filter의 예시입..
이번 WWDC23의 Expand on Macros 세션의 전반부 정리. (https://developer.apple.com/wwdc23/10167) Swift Macro는 컴파일러를 수정하지 않고 Swift 패키지에 배포할 수 있는 방식으로 boilerplate코드를 제거하고 Swift에 고유 언어기능을 추가 가능. 4가지 목적 1. Macro를 사용할 때 매우 명확해야 할 것. 2종류의 Macro. FreeStanding Macro: 코드에서 다른 항목을 대신함. #(pound)기호로 시작 Attached Macro: 코드 선언에서 attribute로 사용됨. @(at)기호로 시작 Swift는 이미 #과 @를 사용해서 특정 컴파일러 동작을 나타내고 있지만, Macro로 이를 확장할 수 있게 만듦. #이..