본문으로 건너뛰기

2025 KWDC 톺아보기

소개

FE conf 내용 정리

한글과 사과밭

한글은 초성(ㄱ, ㄴ, …), 중성(ㅏ, ㅑ, …), **종성(ㄱ, ㄹ, …)**을 조합하여 문자를 형성합니다. 유니코드에서는 이를 표현하는 두 가지 방법이 있습니다.

  • NFC (Normalization Form C): ‘가’를 하나의 완성형 코드 포인트(U+AC00)로 저장
  • NFD (Normalization Form D): ‘가’를 초성(U+1100) + 중성(U+1161)으로 분해해 저장

이 차이는 운영체제에서 파일명 충돌 문제로 이어집니다.

  • macOS: 기본적으로 NFD 사용 → ‘가’는 두 글자로 저장됨
  • Windows/Linux: NFC 사용 → ‘가’는 하나의 코드로 저장됨

한글 분리 애플 커뮤니티

따라서 Dropbox, Google Drive 등 클라우드 동기화에서 같은 이름의 파일이 중복 생성되거나, 문자열 비교가 실패하는 경우가 발생합니다. Python, Swift 등 대부분 언어에서 제공하는 normalize("NFC", text)를 사용하면 문제를 예방할 수 있습니다.


actor boundary를 넘어서

Swift는 5.5부터 async/awaitactor 모델을 도입했습니다. Swift 6에서는 이 모델을 더욱 엄격히 적용하여, 레거시 스레드 기반 API(DispatchQueue, NSThread 등)와 충돌할 수 있습니다.

Actor 경계 문제

actor는 상태를 격리해 동시 접근 문제를 방지하지만, 레거시 API는 이를 고려하지 않고 동기 호출을 수행합니다. 따라서 actor 메서드를 직접 호출하면 Swift 6에서 컴파일 오류가 발생합니다.

해결 방법 비교

  1. 커스텀 Executor: actor 실행을 특정 스케줄러(예: DispatchQueue)와 연결해 고성능 제어 가능하지만, 복잡한 구현이 필요합니다.
  2. DispatchQueue → Task 브리지: DispatchQueue.async { Task { await actor.method() } } 방식으로 actor isolation을 안전하게 유지합니다. 일반 앱 개발에서 가장 권장됩니다.
  3. 락 기반 접근: NSLock이나 pthread_mutex를 활용해 상태를 보호합니다. 기존 코드를 최소 수정으로 유지할 수 있지만, Swift 동시성 철학에는 맞지 않으며 권장되지 않습니다.

SharePlay, 어떻게 쓰죠?

What is SharePlay?

SharePlay는 FaceTime 세션 중 앱의 콘텐츠(영상, 음악, 문서 등)를 동기화하는 기능이며, GroupActivities는 이를 지원하는 프레임워크입니다.

적용 방법

  • Xcode 타깃의 Signing & Capabilities에 Group Activities(또는 “Group Activity”)를 추가(→ 필요한 엔타이틀(entitlement)과 프로비저닝 업데이트).
  • 앱에 GroupActivity 타입(프로토콜 준수) 정의 → prepareForActivation() / activate() 흐름 구현.
  • GroupSession(sessions async sequence)을 수신하여 join() 하고 세션을 관리.
  • 커스텀 데이터 동기화는 GroupSessionMessenger 사용.
  • 미디어 동기화(AVPlayer) 필요하면 AVPlayerPlaybackCoordinator / AVPlayerPlaybackCoordinator.coordinateWithSession 사용.

자주 발생하는 이슈 & 해결법

  • 엔타이틀먼트/프로비저닝 오류 (code signing / provisioning)

    • 증상: 빌드/배포 시 “provisioning profile doesn’t include …” 또는 ITMS 에러. 원인: Group Activities capability를 추가한 뒤 프로비저닝 파일/앱 ID가 갱신되지 않았거나 수동 서명 설정 불일치.
    • 해결: Xcode에서 Group Activities 추가 → Apple Developer (Identifiers)에서 해당 App ID에 capability 허용 확인 → 프로비저닝 프로파일 재생성(또는 자동 관리 사용) → Clean & rebuild. (실제 사례/해결 스레드 참고).
  • 사용자 단말/설정 문제 (SharePlay 자체가 꺼져 있거나 OS 버전 불일치)

    • 증상: 초대 UI가 뜨지 않거나 동작이 아예 안 됨.
    • 해결: 참가자 모두 OS 최소 버전(SharePlay 도입 이후 버전, FaceTime 연동 등) 충족 확인·업데이트, FaceTime → SharePlay 설정이 활성화되어 있는지 확인. 또한 네트워크(인터넷) 연결 안정성 확인.
  • 동기화/재생 제어가 제대로 안 됨 (플레이백 비동기화, 일시정지/재생 불일치)

    • 원인: AVPlayer와 GroupSession 연결 누락 또는 AVPlaybackCoordinator 미사용.
    • 해결: GroupSession이 join()된 후 AVPlayerPlaybackCoordinator(또는 AVPlayer의 관련 API)를 사용해 플레이어를 세션에 연결하여 재생/일시정지/seek를 조율. WWDC 샘플/문서에 따라 playbackCoordinator.coordinateWithSession(...) 식으로 연결.
  • 커스텀 AVPlayer/SwiftUI 통합 문제 (플레이어가 @State나 바인딩 문제로 재생 제어 누락)

    • 증상: 커스텀 플레이어 뷰에서 원격 제어(다른 참가자 액션)가 반영되지 않음.
    • 해결: AVPlayer 인스턴스 생명주기(예: @State var player: AVPlayer?)와 GroupSession/Coordinator를 올바른 컨텍스트(메인 스레드/적절한 Actor)에서 연결. Apple 샘플과 StackOverflow 패턴을 참고.
  • 컨텐츠/권한(DRM, 구독) 관련 제약

    • 증상: Apple Music, 일부 유료/DRM 콘텐츠는 SharePlay로 공유 불가 또는 제한.
    • 해결: 서비스 별 정책 확인(일부 미디어는 참가자가 구독자여야 하거나 지역 제한 있음). 컨텐츠가 DRM/서버 제한을 가지면 SharePlay 경험 설계 시 예외 처리(대체 콘텐츠, 초대 거부 메시지 등) 필요.
  • 시스템 없이 앱만으로 바로 시작하고 싶을 때 (FaceTime이 없거나 호출 없이 시작)

    • SharePlay은 전통적으로 FaceTime 연결을 통해 시작되지만, 앱 내부에서 직접 시작(share sheet / group activity sharing controller) 할 수 있는 방법도 제공됨(문서·기술노트 참조). 즉 “앱에서 바로 시작” 흐름 구현 가능.

샘플 코드

import GroupActivities
import AVKit

// 1) Activity 정의
struct VideoActivity: GroupActivity, Codable {
let url: URL
static var activityIdentifier: String { "com.example.app.video" }

var metadata: GroupActivityMetadata {
var m = GroupActivityMetadata()
m.title = "Watch together"
m.type = .watchTogether
m.fallbackURL = url
return m
}
}

// 2) 사용자가 '공유'를 누를 때: prepareForActivation() -> activate() 흐름
func startSharePlay(with url: URL) async {
let activity = VideoActivity(url: url)
switch await activity.prepareForActivation() {
case .activationDisabled:
// FaceTime 없음 또는 시스템이 로컬 재생 권장
return
case .activationPreferred:
do {
// activate() 또는 prepareForActivation 후 sessions()로 세션 수신
try await activity.activate()
} catch {
print("활성화 실패:", error)
}
case .canceled:
return
}
}

// 3) 세션 수신/관리 (앱의 Coordinator 등에서)
Task {
for await session in VideoActivity.sessions() {
// session: GroupSession<VideoActivity>
await session.join() // join -> 네트워크/메시지 연결이 시작됨

// 메시지(커스텀 동기화)를 위해 Messenger 사용
let messenger = GroupSessionMessenger(session: session)
// messenger.send(...) / for await messages(of: MyMsg.self) { ... }

// AVPlayer 동기화
let player = AVPlayer(url: session.activity.url)
let coordinator = AVPlayerPlaybackCoordinator()
coordinator.coordinate(player, with: session) // 또는 적절한 API 사용
// UI에 player 연결 등...
}
}

Array로부터 이해하는 Swift의 성능: 동기, 진화, 그리고 미래

Swift의 표준 배열은 항상 Heap에 저장됩니다. 이로 인해 작은 배열도 불필요한 Heap 할당이 발생하고, 성능 저하와 캐시 미스 문제가 생깁니다.

SE-0453 제안Inline Array를 도입해 고정 크기 배열을 Stack에 저장하는 방식입니다.

  • 효과: 할당/해제 비용 감소, CPU 캐시 효율성 증가
  • 활용 사례: 좌표·벡터, 소규모 행렬 연산, 네트워크 패킷 헤더, IoT 센서 데이터 등

요약

무엇?

  • Swift 표준 라이브러리에 **고정 크기 배열 타입(InlineArray)**을 추가하는 제안. 요소는 구조체 내부에 인라인으로 연속 저장됨 → 힙 할당 없이 스택/힙 객체 내부에 직접 포함.

왜?

  • 기존 Array는 가변 크기 + 힙 할당 + COW → 작은 고정 크기 데이터에 비효율적
  • 성능·메모리 최적화를 위해 정해진 개수의 요소를 타입 수준에서 표현

어떻게? (특징)

  • 타입 예: InlineArray<3, Float> (3개짜리 Float 배열)
  • 크기는 컴파일 타임에 고정
  • 항상 완전히 초기화되어야 함
  • append 같은 가변 연산 없음 (정적 크기)
  • 기본 접근: 인덱스(subscript)
  • 초기 버전에서는 Collection/Sequence 채택 ❌ (noncopyable 요소 지원 때문)

어디에 유용?

  • 게임, 그래픽스, DSP 같은 작은 고정 크기 벡터/행렬 연산
  • 임베디드·실시간 처리 등 힙 할당 최소화 필요한 환경
  • C interop에서 고정 배열 매핑

사용 예시

var coords: InlineArray<3, Float> = [0.0, 1.0, 2.0]  // 3개짜리 고정 배열
coords[1] = 1.5
let x = coords[0]

진행상황

  • SE-0453는 수락(accept with modifications) 되었고 이후 Swift 소스(및 표준 라이브러리)에 구현 PR들이 올라가있음

  • 구현·릴리스 노트나 여러 블로그 포스트에 따르면 Swift 주요 릴리스(예: Swift 6.2) 쪽에 반영된 것으로 보임(구현 PR 번호들이 토론에 링크되어 있음)


셰이더 몰라도 괜찮아, Metal 파이프라인은 이렇게 생겼어

Metal이란?

Metal은 애플이 제공하는 저수준 그래픽 & 연산 API입니다. GPU에 직접 접근할 수 있고, 병렬 연산을 효율적으로 다룰 수 있어서 게임뿐만 아니라 다양한 앱에서 성능을 크게 끌어올릴 수 있습니다.

비게임 앱에서의 Metal 활용

  • PDF 뷰어에서 수천 페이지를 빠르게 렌더링
  • 라이브 영상에 실시간 자막 표시
  • 비디오 플레이어에서 알파 채널 처리
  • SwiftUI에서 커스텀 UI 효과 구현

Metal Render Pipeline 구조

  • Metal에서 그리기(drawing)는 다음과 같은 객체들을 중심으로 이루어집니다:
  • MTLDevice, MTLCommandQueue, MTLCommandBuffer
  • MTLRenderPipelineState, MTLRenderPassDescriptor
  • MTLRenderCommandEncoder

단순하게 정리하면, 버텍스 처리 → 프래그먼트 처리 → 화면 출력의 파이프라인이 반복

Metal 4와 최적화 팁

  • 리소스는 미리 만들어두고 재사용하기
  • 트리플 버퍼링(Triple Buffering) 활용하기
  • Drawable은 늦게 얻고 빨리 해제하기
  • 렌더 타겟의 Load/Store 동작을 적절히 설정하기 (clear, load, dontCare 등)
  • Argument Buffer, Indirect Buffer 활용으로 GPU 자원 관리 효율화

PassKit / ID Verifier로 검증 프로세스 구축하기

**mDL(mobile Driving License)**과 **mdocs(mobile documents)**는 운전면허증, 신분증 등 공인 문서를 모바일에 저장·활용할 수 있게 하는 기술입니다.

  • 표준: ISO/IEC 18013-5는 mDL을, ISO/IEC 23220 시리즈는 mdocs를 정의합니다.

  • Apple API: PassKit 기반으로 앱 내 인증과 대면 인증을 지원합니다.

    • 앱 내 인증: 필요한 속성만 요청하고 Face ID/Touch ID로 승인
    • 대면 인증: NFC/QR 단말기와 Wallet을 연동
  • 일본 사례: 편의점 성인 인증, 행정 서비스 로그인 등에서 도입

지원방법

항목설명
발급자(issuer)DMV 혹은 정부 기관 등 공식 발급자가 mDL 파일을 만들어 Wallet에 추가할 수 있도록 시스템을 갖춤. 사용자 인증, 서명 키 관리, 발급 데이터 요소 정의 등이 필요.
PassKit entitlement / 인증서App ID / Wallet 식별자, 적절한 인증서(certificate)가 필요. Wallet에 ID 저장 / 읽기 요청이 가능하도록 Apple로부터 허가를 받아야 함.
데이터 형식 / 요소 (ISO 18013-5 스키마)어느 데이터 요소들이 포함되는지 정의 (예: 이름, 생년월일, 주소, 사진, 운전 자격 등). 요구하는 리더 요청(request) 시 해당 요소들이 제공될 수 있게 해야 함. (Apple Developer)
선택적 공개(Selective Disclosure)리더가 요청하는 특정 요소만 제공하고, 사용자가 동의(consent)하도록 UI를 제공해야 함. (Apple Developer)
검증 (Signature, Device Binding)발급자의 서명, 기기 바인딩 (private key stored in Secure Element), 전송 암호화, reader 인증 등의 메커니즘 구현/준수. (애플 지원)
요청 API 활용 (“Verify with Wallet”)외부 앱이나 웹 서비스가 사용자의 모바일 ID로부터 특정 데이터 요소를 요청할 수 있도록 Apple이 제공하는 API를 사용. 요청-응답 흐름이 ISO 18013-5 규격과 맞도록 설계됨. (Apple Developer)
보안 / 프라이버시 정책 및 사용자 인터페이스사용자 동의 절차, 데이터 보호, 네트워크 보안, 인증서 검증, PII 보호 등을 포함한 정책 마련 및 사용자 인터페이스 설계. (애플 지원)

적용예시(흐름)

  1. 발급기관이 mDL 데이터를 준비 (ISO 18013-5 스키마 따라), 사용자에게 발급 → Wallet 앱에 추가.
  2. Wallet에서 발급자 서명 포함, 기기 바인딩, Secure Element 저장.
  3. 앱 또는 웹 서비스가 Verify with Wallet API를 통해 사용자가 제공할 동의(consent)를 받고, 필요한 데이터 요소(requested elements)를 명시하여 요청.
  4. Wallet 사용자 디바이스가 UI를 통해 “어느 데이터 요소를 제공할 것인지” 사용자에게 보여주고 승인 얻음.
  5. 승인 후, 데이터가 암호화/서명된 형태로 앱/web에 전달. 6.앱/web은 응답을 받아 발급자 서명, 기기 서명, IACA 인증서 검증, 세션 무결성(session transcript) 검증 등의 절차를 수행.
  6. 이후 해당 데이터 요소를 사용 (예: 신분 확인, 나이 인증 등)하거나 필요 시 화면에만 표시(safe display)하거나 저장.

Swift Testing으로 작성한 테스트 코드를 어떻게 찾고 수행할 수 있을까?

Swift Testing은 XCTest의 한계를 보완하며, 런타임과 Mach-O 구조를 활용해 테스트 함수를 자동 수집합니다.

Swift Testing: 런타임 & Mach-O 기반 테스트 자동 수집

Swift 5.9 이후 등장한 Swift Testing은 XCTest의 한계를 보완하는 새로운 테스트 프레임워크입니다. @Test 매크로와 표현력 있는 어서션(#expect, #require)으로 더 단순하고 강력한 테스트 작성이 가능합니다.

어떻게 동작할까?

런타임 활용: 실행 시 함수 메타데이터를 스캔 → @Test가 붙은 함수 자동 수집

Mach-O 구조: 실행 파일의 메타데이터 섹션에 테스트 정보 기록 → 런타임이 이를 불러 실행

장점: 별도 등록 코드 불필요, 병렬 실행 및 트레잇 기반 제어 가능

예시 코드

import Testing

@Test("정수 덧셈은 교환법칙을 따른다")
func addition_commutes() {
let a = 1, b = 2
#expect(a + b == b + a)
}

@Test(arguments: [(2, 4), (3, 9)])
func square_pairs((x, y): (Int, Int)) {
#expect(x * x == y)
}

사용 방법

  • 플러그인 아키텍처: 런타임 메타데이터 탐색으로 자동 등록
  • 코드 분석 도구: 테스트 커버리지, 태그/트레잇 사용 리포트
  • DevOps 최적화: 태그 기반 셀렉티브 실행, 병렬 샤딩, flaky 테스트 관리
# 특정 태그만 실행 (예시)
swift test --filter "tags=unit"

Apple의 컨테이너화 프레임워크 이해하기 - 기초부터 시작하기

Apple이 공개한 apple/container는 데이터/리소스를 안전하게 캡슐화하는 Swift 패키지

TL;DR

  • container: 맥에서 OCI 이미지를 경량 VM(가상머신) 로 실행·빌드하는 Swift 기반 CLI. Docker 대안이라기보다 맥에 최적화된 런타임.
  • Containerization: 위 CLI가 사용하는 Swift 패키지(API). 이미지/레지스트리/파일시스템/프로세스 관리 등 저수준 기능 제공.
  • 특징: 보안·격리 강화(컨테이너=각자 VM), Apple Silicon 최적화, amd64 이미지는 Rosetta 2로 실행 지원.

왜 또 다른 “컨테이너”인가?

맥에서 리눅스 워크로드를 돌릴 땐 전통적으로 Docker Desktop을 썼습니다. container는 여기에 애플 실리콘/가상화 스택과 맞물린 가벼운 대안을 제시합니다.

  • 보안/프라이버시: 컨테이너마다 별도의 경량 VM을 부팅해 커널을 분리. 호스트와 자원 경계가 더 명확합니다.
  • 성능/일관성: Apple Silicon 최적화 + Virtualization.framework 사용. OCI 호환이라 기존 이미지/레지스트리 그대로 사용 가능.
  • 호환성: Apple Silicon에서 linux/amd64 이미지도 Rosetta 2로 구동 가능(이식 여지↑).

WWDC25 Meet Containerization

프런트엔드 관점: 어떻게 써먹을까?

container는 프런트엔드 자체를 바꾸는 라이브러리는 아니지만, 개발·배포 워크플로를 매끄럽게 만듭니다.

1) 로컬 풀스택 개발(SSR/RSC) 환경 표준화

React Server Components(예: Next.js), Remix, SvelteKit 등 서버 컴포넌트/SSR 프레임워크는 리눅스 런타임에서 테스트하는 걸 권장하는 경우가 많습니다.

맥에서 container로 Node/Bun 런타임 컨테이너를 띄우면, 실제 배포 환경과 거의 동일한 Linux 유저랜드에서 RSC/SSR 빌드·실행을 검증할 수 있습니다.

# Next.js(RSC) 개발 서버 컨테이너
container run -it --publish 3000:3000 \
--volume $PWD:/workspace \
docker.io/library/node:20 \
bash -lc "cd /workspace && corepack enable && pnpm i && pnpm dev"

장점

팀 전체가 동일한 이미지로 개발 → “내 맥에서는 되는데…” 줄이기

포트 포워딩으로 로컬 브라우저에서 바로 확인(예: http://localhost:3000)

2) 프런트엔드가 의존하는 백엔드/미들웨어 동시 구동

PostgreSQL/Redis/MinIO/Mock SSO 등을 각각 컨테이너로 띄워 Next.js(서버 컴포넌트) 앱과 함께 구동.

컨테이너마다 분리된 VM 덕에 자원·네트워크 경계가 명확하고 충돌을 줄입니다.

3) 이미지 기반 프리뷰/CI 캐시

PR마다 프리뷰 이미지를 빌드해 레지스트리에 올리고, 맥에서 똑같이 내려 받아 구동 → 디자이너/기획자도 동일 환경에서 확인 가능.

SwiftPM Swift Container Plugin을 쓰면 Swift 서비스 쪽 이미지는 패키지 빌드와 컨테이너 빌드를 한 흐름으로 묶을 수 있습니다. (프런트엔드가 Swift 백엔드와 맞물릴 때 유용)


AI as Apple & AI as a Developer

  • Apple의 AI 전략: 프라이버시 중심, 온디바이스 모델(Core ML, Neural Engine), UX 강화
  • 개발자 관점: 생산성 도구(Xcode), 앱 기능 강화(Core ML, Vision, Speech), SiriKit/Shortcuts 연계
  • 교차점: Apple은 인프라 제공, 개발자는 이를 활용해 신뢰성 있는 앱 경험 구현

사려 깊은 공간 디자인: 세포에서 원자까지 생물학 탐구

홈페이지

CellWalk은 세포부터 원자까지 직관적으로 탐색할 수 있는 앱으로, Apple Design Awards 비주얼·그래픽 부문 파이널리스트에 선정되었습니다.

  • 기술: visionOS RealityKit + Metal, 멀티 스케일 시각화
  • UX 원칙: 사용자 편안함 유지(높은 FPS), 복잡성 단순화(계층적 시각화), 직관적 제스처(시선 추적, 핀치 줌)
  • 교육적 활용: 생명과학·화학 학습, 연구 커뮤니케이션, K-12 교육

이 사례는 공간 컴퓨팅과 교육의 결합 가능성을 보여주는 대표적 예시입니다.


디자이너가 말하는 디자인 시스템

LY corp. Tech Blog 디자인 시스템 Github VOC solution Github

소규모 팀(디자이너 1, 개발자 2)이 다음과 같은 접근으로 강력한 디자인 시스템을 구축

  • 문제 작은 팀에서 디자인 ↔ 개발 간 단절, 유지보수 어려움

  • 해결책 3단계 토큰 구조로 단순하고 유연한 디자인 시스템 구축

    • Primitive: 색상·크기 같은 기초 값
    • Semantic: 의미 있는 맥락 이름(예: text-primary)
    • Component-specific: 버튼 등 특정 컴포넌트/상태별 토큰
  • 적용 Figma Variables + React/Tailwind → 디자인과 코드 명칭 규칙 일치

  • 효과 테마 전환 용이, 토큰 수 감소, 재사용성·일관성·생산성 향상

  • 성과 제품의 컴포넌트 80% 이상이 시스템을 활용, 오픈소스 공개(Def)

핵심 교훈은 시스템적 사고와 협업 언어만 있으면 작은 팀도 큰 성과를 낼 수 있다는 점입니다.