[번역] UNUserNotifications / Generating a Remote Notification (애플 공식 문서)

Overview 푸시 알림은 JSON 페이로드 형태로 사용자에게 중요한 정보를 전달합니다. 페이로드에서 수행하려는 사용자 상호작용의 종류(알림, 사운드, 배지)가 지정되며, 앱이 알림에 응답하는 데 필요한 모든 커스텀 데이터가 포함됩니다. « figure src=“media-2953613.png” align=“center” » 푸시 알림 페이로드에는 Apple이 정의한 키와 그에 해당하는 커스텀 값이 포함됩니다. 또한 알림에 맞게 직접 정의한 커스텀 키와 값을 추가할 수도 있습니다. Apple 푸시 알림 서버(APNs)는 페이로드의 전체 크기가 다음 제한을 초과하면 알림을 거부합니다. VolP(인터넷 전화) 알림의 경우, 최대 페이로드의 크기는 5KB (5120바이트)입니다. ...

September 30, 2025 · 8 min · 1530 words · Me

[번역] UNUserNotifications / Registering Your App With APNs (애플 공식 문서)

Overview Apple 푸시 알림 서비스 (APNs)가 특정 사용자의 기기로 알림을 전송하려면, 먼저 그 기기의 주소를 알아야 합니다. 이 주소는 기기와 앱 모두에 고유한 디바이스 토큰(device token)의 형태로 제공됩니다. 앱이 실행될 때, 앱은 APNs와 통신하여 디바이스 토큰을 받고, 이 토큰을 여러분의 제공자 서버(provider server)로 전달합니다. 이후 서버는 알림을 전송할 때 토큰을 함께 포함시켜야 합니다. Note: 같은 기기라 하더라도 여러 앱이 하나의 디바이스 토큰을 함께 사용할 수는 없습니다. 각 앱은 반드시 자신만의 고유한 디바이스 토큰을 요청해 받아야 하며, 그 토큰을 제공자 서버로 전달해야 합니다. ...

September 25, 2025 · 3 min · 542 words · Me

[번역] UNUserNotifications / Handling Notifications and Notification Related Actions (애플 공식 문서)

Overview 알림은 주로 사용자에게 정보를 보여주기 위한 수단이지만, 앱이 알림에 응답할 수도 있습니다. 예를 들어, 다음과 같은 상황에 응답할 수 있습니다: 사용자가 알림 인터페이스에서 선택한 동작 앱이 포그라운드에서 실행 중일때 도착한 알림 무음(Slient) 알림 (Pushing background updates to your App을 참고) PushKit 프레임워크와 관련된 알림 (예를 들어, VolP나 WatchOS의 컴플리케이션(complication) 관련 알림) Handle user-selected actions 동작 가능한 알림은 사용자가 알림 인터페이스에서 직접 응답할 수 있게 해줍니다. 알림의 콘텐츠 외에도, 동작 가능한 알림은 사용자가 선택할 수 있는 하나 이상의 버튼을 표시합니다. 사용자가 버튼 중 하나를 탭하면 앱이 포그라운드로 전환되지 않고, 선택된 동작이 앱으로 전달됩니다. 앱이 동작 가능한 알림 타입을 지원한다면, 반드시 그에 연결된 동작을 처리해야 합니다. ...

September 20, 2025 · 3 min · 581 words · Me

[번역] UNUserNotifications / Declaring your actionable notification types (애플 공식 문서)

Overview 동작 가능한 알림(actionable notification)은 사용자가 해당 앱을 실행하지 않고도 전달된 알림에 응답할 수 있게 합니다. 일반 알림은 알림 인터페이스에 정보를 표시하고, 이 경우 사용자가 취할 수 있는 유일한 동작은 앱을 실행하는 것이 됩니다. 동작 가능한 알림의 경우, 시스템은 알림 인터페이스 외에도 하나 이상의 버튼을 표시합니다. 버튼을 누르면 선택된 동작이 앱으로 전달되고, 앱은 이를 백그라운드에서 처리합니다. Note: Apple Watch Series 9 또는 Apple Watch Ultra 2에서 알림을 보고 있는 동안 이중 탭(Double Tap) 제스처를 수행하면, 시스템은 첫 번째 비파괴(Non-Desctructive) 동작을 실행합니다. 비파괴 동작이란 destructive 옵션을 포함하지 않으며, 사용자가 데이터를 삭제하거나, 다시 되돌리기가 어렵지 않은 동작을 의미합니다. ...

September 15, 2025 · 5 min · 879 words · Me

ESTsoft KDT 부트캠프 (iOS 2기) 수강 후기 및 회고

안녕하세요. 김소월입니다. 2025년 6월부터 9월까지 약 4개월 동안 ESTsoft KDT 부트캠프 iOS 2기를 수료하며, 그 소회를 간단하게 정리하고자 합니다. 처음 KDT 과정 소식을 접하고 많은 고민이 있었습니다. 초심자를 대상으로 하는 과정이라는 점에서 우려가 있었고, 무엇보다 국비 출신 개발자라는 꼬리표가 달라붙을까 두려웠던 것도 사실입니다. 하지만 결론적으로 말씀드리자면, 매우 만족스럽고 유익한 시간이었습니다. 그동안 영어 원서와 Udemy 강의로만 UIKit과 SwiftUI를 독학했는데, 이번 과정을 통해 내가 올바른 길을 걷고 있는지, 놓친 부분은 없는지 확실하게 점검할 수 있었습니다. 또한 빠른 속도로 핵심 개념을 익히고, Photos, AVFoundation, ActivityKit처럼 독학하기 어려운 영역도 체계적으로 학습할 수 있었습니다. ...

September 15, 2025 · 8 min · 1537 words · Me

[번역] UNUserNotifications / Asking permission to use notifications (애플 공식 문서)

Overview 로컬 및 원격 알림은 경고을 표시하거나, 사운드를 재생하거나, 앱 아이콘에 배지를 표시하여 사용자의 주의를 끌 수 있습니다. 이러한 상호작용은 앱이 실행 중이 아니거나 백그라운드에 있을 때 발생합니다. 이를 통해 사용자는 앱에 자신과 관련된 정보가 있다는 것을 알 수 있습니다. 그러나 알림 기반 상호작용은 사용자에게 방해 요소로 여겨질 수 있으므로, 이를 사용하려면 반드시 권한을 얻어야 합니다. Explicitly request autorization in context 권한을 요청하려면, UNUserNotificationCenter 공유 인스턴스를 가져와 requestAuthorization(options:completionHandler:) 메서드를 호출하세요. 앱이 사용하는 모든 상호작용 유형을 지정해야 합니다. 예를 들어, 알림을 표시하거나, 앱 아이콘에 배지를 추가하거나, 사운드를 재생할 수 있도록 권한을 요청할 수 있습니다: ...

September 10, 2025 · 4 min · 693 words · Me

Data Race vs. Race Condition (Swift)

동시성 프로그래밍(Concurrent Programming)은 작업이 언제 끝날지 알 수 없는 비동기 작업(예: 네트워크 통신, 파일 I/O 등)을 효율적으로 처리하는 기술입니다. 이 기법은 여러 작업을 번갈아 실행하여 마치 동시에 수행되는 것처럼 보이도록 하는 방식으로 동작합니다. 이를 통해 시간이 오래 걸리는 작업이 진행되는 동안에도 다른 작업을 실행할 수 있어 애플리케이션의 응답성을 향상시킬 수 있습니다. 예를 들어, 네트워크에서 데이터를 가져오는 동안 UI가 멈추지 않고 사용자가 원활하게 앱을 조작할 수 있도록 하려면 동시성 프로그래밍이 필수적입니다. ...

March 13, 2025 · 5 min · 963 words · Me

CALayer의 anchorPoint 톺아보기

개요 CALayer는 이미지 기반의 콘텐츠를 관리하고, 해당 콘텐츠에 애니메이션을 적용할 수 있도록 하는 객체입니다. 레이어는 뷰의 백킹-스토어(backing-store) 역할을 할 뿐만 아니라, 뷰 없이도 콘텐츠를 직접 표시할 수 있습니다. 레이어의 주요 역할은 제공된 시각적 콘텐츠를 관리하는 것이지만, 배경 색상, 테두리와 그림자를 설정할 수 있는 자체적인 시각적 속성도 가지고 있습니다. 이뿐만 아니라 CALayer는 다양한 속성을 활용하여 이동(Translate), 크기(Scale)나 회전(Roate) 등 레어어에 변형을 가할 수 있습니다. 그리고 이러한 변형은 모두 기본적으로 레이어의 정중앙을 기준으로 일어나게 됩니다. 일반적으로 이 기준은 크게 문제가 되지 않지만, 항상 예외가 존재하기 마련입니다. 이 기준점을 변경하는 데 도움을 주는 anchorPoint와 position 속성 및 그 관계에 대해 자세히 살펴보겠습니다. ...

February 28, 2025 · 4 min · 675 words · Me

[번역] XCTest / Defining Test Cases and Test Methods (애플 공식 문서)

Overview 코드의 특정 측면을 검증하고자 하나 이상의 테스트 메소드를 작성하여 Xcode 프로젝트에 테스트를 추가하세요. 관련된 테스트 메서드들은 XCTestCase의 서브 클래스인 테스트 케이스로 그룹화하세요. 프로젝트에 테스트를 추가하려면: 테스트 타겟에 새로운 XCTestCase의 서브 클래스를 생성하세요. 테스트 케이스에 하나 이상의 테스트 메서드를 작성하세요. 각 테스트 메서드에 하나 이상의 테스트 검증(Assertion)을 작성하세요. 테스트 메서드는 XCTestCase 서브 클래스의 인스턴스 메서드로 매개변수와 반환값이 없으며, test라는 소문자 이름으로 시작합니다. 테스트 메서드는 XCTest 프레임워크에 의해 자동으로 감지됩니다. class TableValidationTests: XCTestCase { /// Tests that a new table instane has zero rows and columns. func testEmptyTableRowAndColumnCount() { let table = Table() XCAssertEqual(table.rowCount, 0, "Row count was not zero.") XCAssertEqual(table.columnCount, 0, "Column count was not zero.") } } 위 예제는 TableValidationTests라 불리는 XCTestCase 서브 클래스를 정의하고, 해당 클래스는 *testEmptyTableRowAndColumnCount()*라 불리는 단일 테스트 메서드가 포함되어 있습니다. 이 테스트 메서드는 Table이라 불리는 새로운 클래스 인스턴스를 생성하며, 해당 인스턴스가 초기화된 이후 rowCount와 columnCount 프로퍼티가 모두 0인지 확인합니다. ...

December 17, 2024 · 2 min · 251 words · Me

[번역] The Nested Closure Trap (Besher AI Maleh)

DispatchWorkItem 내부에 중첩된 애니메이션 클로저를 실행하는 코드가 있다고 가정해보겠습니다. 여기 세 가지 버전의 코드가 있습니다. 어느 코드가 순환 참조(retained cycle)를 유발하는지 말해주실 수 있나요? class ViewControllerA: UIViewController { var workItem: DispatchWorkItem? override func viewDidLoad() { let workItem = DispatchWorkItem { UIView.animate(withDuration: 1.0) { self.view.backgroundColor = .red } } self.workItem = workItem } } class ViewControllerB: UIViewController { var workItem: DispatchWorkItem? override func viewDidLoad() { let view = self.view let workItem = DispatchWorkItem { UIView.animte(withDuration: 1.0) { [weak self] in view?.backgroundColor = .red } } self.workItem = workItem } } class ViewControllerC: UIViewController { var workItem: DispatchWorkItem? override func viewDidLoad() { let workItem = DispatchWorkItem { UIView.animate(withDuration: 1.0) { [weak self] in self?.view.backgroundColor = .red } } self.workItem = workItem } } 정답은 세 가지 버전 모두입니다! 심지어 클로저 바깥에서 _view_에 대한 참조를 생성하는 버전 B도 순환 참조를 유발합니다. ...

November 5, 2024 · 3 min · 511 words · Me