SwiftUI. The Swiftui Cookbook for Navigation - WWDC22

The SwiftUI cookbook for navigation SwiftUI의 새로운 내비게이션 API를 발표한 WWDC 세션을 정리했다. 이 내비게이션 API는 각각의 NavigationLink가 관리하는 대신, 스택 전체의 상태를 데이터로 표현하고 직접 조작할 수 있게 만든다. 이 구조를 사용하면 버튼을 눌러 이동하는 기본적인 내비게이션뿐만 아니라, 딥 링크나 특정 화면으로 바로 이동하기, 루트 화면으로 돌아가기, 현재 내비게이션 상태 저장까지 같은 모델로 처리할 수 있다. New naviation API: 새로운 Data-driven 내비게이션 API Recipes for navigation: 탐색을 프로그래밍 방식으로 완전히 제어하기 Persistent state: 새로운 API를 이용하여 앱의 내비게이션 상태를 유지하기 i갑자기 프로그래밍 방식? SwiftUI는 처음부터 코드로 UI를 작성하는 프레임워크였기 때문에, 기존 NavigationView도 isActive나 selection을 이용해 화면을 프로그래밍 방식으로 전환할 수 있었다. ...

July 23, 2026

iOS. Demystify SwiftUI (3) - WWDC21

Dependencies: SwiftUI는 무엇이 바뀌었는지 어떻게 알까? 앞선 글에서는 SwiftUI가 View를 구분하는 방식인 Identity와, Identity가 유지되는 기간인 Lifetime을 정리했다. 이번에는 SwiftUI가 View를 업데이트하는 기준인 Dependencies를 살펴본다. 먼저 결론부터 말하면 SwiftUI의 업데이트 과정은 다음과 같다. Dependency 변경 ↓ 관련된 View 무효화 ↓ body 재평가 ↓ 새로운 View Value와 이전 Value 비교 ↓ 실제로 변경된 화면만 업데이트 Identity는 같은 View인지 판단하고, Lifetime은 상태를 유지하며, Dependency는 어떤 View를 다시 계산해야 하는지 결정한다. 이 세 가지를 함께 이해하면 단순히 API 사용법을 외우는 것보다 SwiftUI의 동작을 더 잘 예측할 수 있다. ...

July 22, 2026

SwiftUI. Demystify SwiftUI (2) - WWDC21

Lifetime 1편에서는 SwiftUI가 View를 구분하는 방식인 Identity를 정리했다. 이번에는 Identity가 유지되는 시간인 Lifetime과, 그 안에서 State가 어떻게 보존되는지 살펴본다. View Value는 계속 새로 만들어질 수 있지만, Identity가 유지되는 동안에는 같은 View의 Lifetime 안에 있다고 볼 수 있다. 그리고 State와 StateObject는 이 Lifetime에 연결되어 있기 때문에 Identity가 바뀌면 함께 교체된다. 고양이가 하루 동안 이곳저곳 움직이더라도 우리는 계속 같은 고양이라고 생각한다. 이처럼 Identity는 시간에 따라 달라지는 여러 값을 하나의 안정적인 존재로 연결한다. 시간의 흐름 속에서 연속성을 만들어 주는 셈이다. ...

July 21, 2026

DevOps. 로컬 LLM 모델 설치하고 UI 붙여보기

Codex는 iOS 개발할 때만 사용하고, 다른 작업은 주로 무료 모델로 처리했다. dev-data-server-light를 개발할 때는 Cursor를 사용했는데, 개발 도중 사용량이 모두 소진돼 Antigravity로 옮겨야 했다. 그래서 로컬에서 직접 실행하는 LLM 환경을 찾았고, 생각보다는 쉽게 환경을 구축할 수 있었다., 맥미니에서 만족스럽게 사용하고 있다. 이번 글에서는 맥북 에어에도 같은 환경을 설치한 과정을 정리한다. 맥북 에어 사양 설치 ollama 설치하고 서버 켜기 맥에서는 Homebrew로 쉽게 설치할 수 있다. brew install ollama 설치가 끝났으면 Ollama 서버를 켜야 한다. Ollama는 단순히 실행하는 앱이 아니라, 서버 형태로 동작한다. ...

July 21, 2026

SwiftUI. Demystify SwiftUI (1) - WWDC21

i시작하기 전에 Identity는 화면에 띄워지는 UI 요소들이 같은 요소인지, 다른 요소인지 구분하는 방식이다. 이 WWDC 세션에서 가장 중요한건, View 프로토콜을 채택하여 작성하는 View Structure가 실제 화면에 보이는 요소가 아니라 그냥 그 요소의 설계도일 뿐이라는 것이다. (UIKit과 많이 다르다) Swift에서 ‘Value Type은 Immutablity를 가진다.’ 이라는 말이 가장 크게 체감되는 부분이기도 한데, SwiftUI에서 코드로 작성한 View도 Value Type이고 당연히 Immutable하다. 따라서 한 번 생성된 값은 변하지 않아야 한다. 만약 내부의 값이 변해야 하면 UIKit의 View Controller 처럼 은근슬쩍 내부 프로퍼티만 바꾸지 않고, Value 전체를 새로 만든다. ...

July 20, 2026

dev-data-server-light. 4. File Storage

DB 모듈을 마무리하고, 다음으로 구현한 것은 File Storage 모듈이다. DB 모듈과 크게 다르지 않을 것이라고 생각했다. 우선 CRUD 비슷한 메소드를 처리하고, 구조는 DB 모듈에서 충분히 다듬었기 때문이다. 하지만 실제로는 DB보다 인터페이스를 어떻게 정의할 것인지에 대한 고민이 더 많았다. 인터페이스 만들기 처음 작성한 프롬프트는 다음과 같다. Create the initial FileStorage contract in src/storage. Requirements: - Define a FileStorage interface. - The interface is responsible only for storing and retrieving binary file contents. - It should not manage file metadata, ids, ownership, permissions, or database records. - Use Buffer for file contents. - Include only the minimal operations required for file storage: - save(path: string, content: Buffer): Promise<void> - read(path: string): Promise<Buffer> - delete(path: string): Promise<void> - exists(path: string): Promise<boolean> - Add minimal domain errors if necessary. For this step, create only the contract and related types. Do not implement any storage implementation yet. 로컬 파일 시스템을 의식하고 있어서 의심 없이 path라는 이름을 사용했는데, 이 때문에 인터페이스가 구현체를 닮아버리게 되었다. path는 과연 인터페이스를 대표할 수 있는 네이밍인가? ...

July 2, 2026

dev-data-server-light. 3. Database Implementation

DB 모듈의 인터페이스와 서비스 레이어를 만들었으므로, 실제 구현체를 만들어야 한다. 우선 인 메모리(In-Memory)로 가볍게 구현체를 만들었다. 인 메모리 데이터 저장소 인 메모리 방식을 선택한 이유는 첫째로 처음부터 SQL이나 JSON 파일 기반 저장소를 이용해서 구현체를 만드는 것 보다는, 가장 단순한 구현체를 만들어서 DB 기능을 검증하고 빠르게 다음 기능을 만들기 위해서이다. 외부 의존성도 없고, 설정도 필요 없고, 테스트도 쉽다. 구현하기 RecordStore 인터페이스를 다시 보면 다음과 같다. export interface RecordStore { list(collection: string): Promise<StoredRecord[]>; get(collection: string, id: string): Promise<StoredRecord | undefined>; create(collection: string, data: RecordData): Promise<StoredRecord>; replace(collection: string, id: string, data: RecordData): Promise<void>; delete(collection: string, id: string): Promise<boolean>; } 구현체는 이 계약을 그대로 만족하면 된다. 중요한 것은 구현체는 Express를 몰라야하고 순수하게 TypeScript 코드로 짜여야 한다. HTTP 요청이나 라우팅 같은 것은 Router가 책임져야 한다. ...

July 2, 2026

dev-data-server-light. 2. Database CRUD

시스템 모듈을 만든 이후에, 아마도 가장 많이 쓰게 될 DB 모듈을 만들었다. 당시에는 구조도 시스템 모듈과 동일하다고 생각했다. Router가 DB 인터페이스에 의존하고, 이를 구현한 구현체를 주입받는 방식으로 DIP와 DI를 동시에 적용했다. 이 과정 중에서 naming bias 해결하기 id 생성 책임 위치 기존 아키텍처의 문제점 -> 서비스 레이어 도입해서 해결하기 에 대한 고민을 했다. 아래는 고민과 해결 과정이다. CRUD부터 만들기 Mock Server라도 최소한 CRUD는 제공해야 한다. 처음부터 구현체를 만들 필요는 없으므로, 라우터와 인터페이스까지만 만들도록 프롬프트를 작성했다. ...

June 30, 2026

Archive. System Programming 정리 노트

학부연구원 시절 FPGA랑 임베디드 살짝 하면서 적어놨던 노트를 최근 클라우드 정리할 때 발견해서, 간단하게 블로그에 포스팅함. RTOS RTOS(Real-Time Operating System)는 정해진 시간 안에 작업을 수행하는 것을 보장하도록 설계된 운영체제이다. 일반적인 운영체제와 다르게 RTOS는 작업이 정해진 시간 내에 반드시 수행되는 예측 가능성을 가장 중요하게 생각한다. 산업용 장비, 자동차, 드론, 의료기기와 같은 임베디드 시스템에서 주로 사용된다. UART UART(Universal Asynchronous Receiver/Transmitter)는 가장 널리 사용되는 직렬 통신 방식 중 하나이다. 구조가 단순하고 구현이 쉬워 디버깅 콘솔, 센서, 마이크로컨트롤러 간 통신 등에 자주 사용된다. 다만 송신과 수신 장치가 동일한 통신 속도(Baud Rate)를 사용해야 한다. ...

June 29, 2026

dev-data-server-light. 1. System

프로젝트에서 제일 간단한 기능과 구조를 가지기 때문에 가장 먼저 System 모듈을 만들었다. System 모듈의 기능 System 모듈이 제공하는 기능은 단 두 가지뿐이다. GET /system/status GET /system/uptime status는 서버가 정상적으로 동작하는지 알려주고, uptime은 서버가 실행된 이후 얼마나 시간이 지났는지를 반환한다. 비즈니스 로직도 없고, 데이터베이스도 필요하지 않으며, 파일 시스템도 다루지 않기 때문에 구조를 검증하는데 가장 좋다고 판단했다. 구조 검증 System 모듈을 만들면서 확인하고 싶었던 것은 기능이 아니라 구조였다. 당시에 생각했던 구조는 다음과 같았다. ...

June 25, 2026