| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | ||||||
| 2 | 3 | 4 | 5 | 6 | 7 | 8 |
| 9 | 10 | 11 | 12 | 13 | 14 | 15 |
| 16 | 17 | 18 | 19 | 20 | 21 | 22 |
| 23 | 24 | 25 | 26 | 27 | 28 | 29 |
| 30 | 31 |
- combine
- authentication
- Animation
- app
- RxSwift
- UIKit
- arkit
- swift
- ios
- sheet
- iphone
- modular
- CS
- firebase
- visionOS
- SwiftData
- 아키텍쳐
- stateobject
- withAnimation
- DateFormatter
- date
- dataflow
- auth
- SwiftUI
- gesture
- foundation
- GCD
- async
- realitykit
- TCA
- Today
- Total
목록전체 글 (71)
XLOG
회사에서 visionOS용 앱을 만들고 있다. 사수 없이 혼자 고민하고 개발하고, 개인적으로 사이드 프로젝트도 진행하다 보니 자연스럽게 알게 된 것들이 꽤 많아졌다. 그런데 정작 그 내용을 따로 정리해볼 생각은 하지 못했다. 최근 회사에서 부사수에게 업무 방법에 관해 이야기하다가 자연스럽게 "나는 기능을 개발할 때 왜 이런 구조를 먼저 고민하는가" 를 설명하게 되었다. 이야기를 하다 보니 내가 처음부터 아키텍처에 대한 명확한 기준을 가지고 있었던 것은 아니었다. Protocol을 왜 이렇게 많이 사용하는지 Dependency Injection은 왜 필요한지 같은 데이터를 왜 DTO와..
최근 회사에서 로그인 인증 토큰 관리를 할 일이 없어 잊어먹을까 싶어서 이전에 했던 공부들을 정리해보기로 했다.로그인 인증 토큰은 사용자의 세션을 유지하는 핵심 정보이기 때문에 단순히 앱 내부 저장소에 넣어두기보다는 Apple 플랫폼에서 제공하는 Keychain을 통해 안전하게 관리하는 편이 좋다. 이번 글에서는 Keychain이 무엇인지, Apple 플랫폼의 Keychain 저장 체계가 Safari 자동완성에 쓰이는 Keychain과 어떤 관계인지, 그리고 Security 프레임워크의 C 스타일 API를 Swift 래퍼로 감싸 토큰 저장소를 구현하는 과정을 정리한다.1. Keychain이란?Keychain은 Apple 플랫폼에서 비밀번호, 토큰, 인증서, 암호화 키처럼 작고 민감한 데이터를 저장하기 위..
모듈러 아키텍처를 적용하다 보면 모듈을 나누는 일보다, 나뉜 모듈을 다시 연결하는 일이 더 어려울 때가 있다.각 모듈은 독립적이어야 하지만 실제 애플리케이션에서는 다른 모듈의 상태 변화나 사용자 이벤트를 알아야 하는 순간이 생긴다. 로그인 완료를 상위 화면에 알려야 하고, 하위 화면에서 발생한 저장 결과에 따라 다른 화면으로 이동해야 하며, 여러 기능이 하나의 공통 이벤트에 반응해야 할 수도 있다.이런 요구를 처리할 때 나는 주로 Event Bus를 두고 Container를 bridge 삼아 이벤트를 전파했다.Feature A │ event ▼Container / Event Bus │ ├─ Feature B └─ Feature C이 방식은 당장의 연결 문제를 해결해 준다. 그러..
1. “물을 좀 더 리얼하게 표현할 수 있을까요?”아트팀이 없는 상태에서 받은 요청이었다. 준비된 물 머티리얼이나 전용 엔진은 없었고, iOS 네이티브 스택 안에서 답을 찾아야 했다.처음에는 RealityKit + Metal + LowLevelTexture 조합으로 접근했다. 사용자가 건드린 월드 좌표를 물 표면의 UV로 변환하고, Metal에서 해당 위치의 height map을 갱신했다.현재 높이와 주변 높이의 차이를 속도에 누적하고 감쇠를 적용하자 한 번의 disturb가 동심원 파동으로 퍼졌다. 표면의 움직임 자체는 원하는 수준까지 만들 수 있었다.문제는 그다음이었다. 면은 움직이는데 물속은 물처럼 보이지 않았다. Normal map으로 빛을 흔드는 것만으로는 물의 부피감이 생기지 않았다. 수면 아..
이전 글에서는 hoverEffect 내부에서 @State를 바꾸려다가, 오히려 view update와 commit이 반복되면서 원하는 결과가 나오지 않았던 경험을 정리했었다.그래서 이번에는 접근을 완전히 바꿨다. hoverEffect를 상태 변경 지점으로 쓰는 대신, hover 상태에 따라 이미 존재하는 UI를 어떻게 보여줄지만 계산하는 방식으로 TabBar를 구성해봤다.이번에 참고한 방향은 Apple이 소개하는 custom hover effect의 개념과도 잘 맞는다. Apple은 custom hover effect를 “hover 이벤트를 직접 받아 처리하는 방식”이 아니라, 기본 상태와 hovered 상태를 정의해두고 시스템이 그 사이를 애니메이션하는 방식으로 설명한다. 이 관점으로 보면 hoverE..
오랜만에 포스팅이다.어쩌다 보니 다시 visionOS를 만지게 됐고, 예전에 다뤘던 HoverEffect와 Custom TabBar 이야기도 다시 떠올랐다.처음 시도했을 때는 .onHover를 써보려고 했지만, onHover는 macOS 쪽에 더 가까운 API라는 점이 생각나서 hoverEffect modifier를 사용하는 방향으로 바꿨다.내가 하려던 건 단순했다.hoverEffect에서 넘겨주는 isActive 값을 받아서 @State를 바꾸고, 그 값으로 View의 layout을 바꾸는 것이었다. Button("Hello, world!") { print("button") } .hoverEffect { hover, isActive, _ in hover.animation(.eas..
JSONDecoder 구조를 이해하며 직접 CSVDecoder를 만들어본 기록업무 중 CSV 데이터를 Decodable로 변환해야 하는 일이 생겼다.처음에는 Third-party 라이브러리를 사용할지, 직접 구현할지 고민했는데,이 과정에서 문득 JSONDecoder는 어떻게 동작할까? 라는 궁금증이 생겼다.남는 시간에 “직접 CSVDecoder를 만들어보면서 Decodable/Decoder의 동작을 이해해보자”라고 마음먹었고, 이 글은 그 과정에서 공부한 내용을 정리한 것이다.1. JSONDecoder는 단순한 클래스다… 그런데?공식 문서를 보면 JSONDecoder 자체는 그냥 public class다.public class JSONDecoder { public func decode(_ type:..
— 앱등이에서 iOS 개발자가 된 내가 요즘 느끼는 불안함👋 앱등이에서 개발자가 되기까지Apple 제품에 빠있다가 현재는 iOS 개발자까지 되었다. 처음엔 단순히 ‘좋은 제품을 만드는 회사’라고만 생각했다. 하지만 개발자가 되기 위해 공부를 하면서 HIG(Human Interface Guidelines) 를 비롯해 Apple이 유저를 대하는 철학을 접하게 되었고, 그 세심함에 감탄했다.그런데, 나에게 처음으로 실망을 준 제품이 있었다. 바로 Vision Pro였다.🧠 Vision Pro, 기술은 놀라운데 ‘애플스럽지 않았다’Apple은 언제나 기술을 가장 먼저 선보이는 회사는 아니었다. 하지만 늘 ‘유저가 진짜 필요로 하는 것’을 찾아내 경험으로 혁신을 만들었다.스마트폰은 최초가 아니었지만 “사용성”..
서버 개발자가 "UTC로 주고받자"고 했을 때...처음 서버 개발자와 협업할 때 "시간은 UTC로 주고받겠습니다"라는 말을 들었을 때의 제 반응은 이랬습니다."UTC? 왜 한국시간대가 아니지?"하지만 이유를 잘 몰라도 일단 규칙이니까 맞춰서 작업했죠. 그냥 서버에서 요구하는 형식으로 보내고, 받은 데이터를 화면에 표시하면 되는 거 아닌가 싶었어요.사이드 프로젝트에서 만난 현실의 벽사이드 프로젝트에서 반복 스케줄 기능을 구현하게 되었을 때, 시간의 복잡성을 본격적으로 체감했습니다. "매주 화요일 오후 3시에 알림" 같은 기능 말이죠.첫 번째 깨달음: Date는 절대 시점이다let now = Date()print(now) // 2024-01-15 05:30:00 +0000let formatter = Date..
왜 이 구조를 도입했나앱 기획이 바뀌고 기능이 추가될 때마다 navigationDestination, sheet, fullScreenCover가 군데군데 늘어나고, 상태 변수도 화면마다 따로 생기곤 합니다. 화면 수가 많아질수록 가독성은 떨어지고 실수가 늘죠.저는 “어떤 View에서든 안전하게 시트를 띄우고, 스택을 쌓고, 쉽게 닫을 수 있는 단일 API”를 목표로 라우터/코디네이터를 도입했습니다. 결과적으로 화면 전환 코드가 뷰 구현에서 분리되어 테스트 가능하고 확장 가능한 구조를 갖게 되었습니다.설계 목표관심사 분리: 화면 전환(네비게이션)은 뷰 로직에서 분리단일 소스: push/pop, present/dismiss를 한 곳에서 관리모달 독립성: 시트/풀스크린 내부도 자체 네비게이션을 가질 수 있게확..