<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>IOS on @yeniful blog</title><link>http://yeniful.github.io/tags/ios/</link><description>Recent content in IOS on @yeniful blog</description><generator>Hugo -- 0.155.3</generator><language>en-us</language><lastBuildDate>Sun, 08 Feb 2026 00:00:00 +0900</lastBuildDate><atom:link href="http://yeniful.github.io/tags/ios/index.xml" rel="self" type="application/rss+xml"/><item><title>[Apple Platforms] scenePhase</title><link>http://yeniful.github.io/posts/2026/apple-scenephase/</link><pubDate>Sun, 08 Feb 2026 00:00:00 +0900</pubDate><guid>http://yeniful.github.io/posts/2026/apple-scenephase/</guid><description>&lt;h2 id="motivation"&gt;Motivation&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;앱 개발 중 네트워크 상태 확인이나 인증 토큰 갱신 같은 로직을 포그라운드 복귀 시점에 실행해야하는 경우
&lt;ul&gt;
&lt;li&gt;UIKit에서는 &lt;code&gt;SceneDelegate&lt;/code&gt;의 &lt;code&gt;sceneWillEnterForeground&lt;/code&gt;, &lt;code&gt;sceneDidBecomeActive&lt;/code&gt;, &lt;code&gt;sceneDidEnterBackground&lt;/code&gt; 등 구현 필요&lt;/li&gt;
&lt;li&gt;SwiftUI에서는 &lt;code&gt;\.scenePhase&lt;/code&gt;라는 Environment 값으로 간단하게 처리할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;h2 id="scenephase란"&gt;scenePhase란?&lt;/h2&gt;
&lt;p&gt;SwiftUI가 제공하는 &lt;code&gt;Environment&lt;/code&gt; 값으로, 현재 Scene의 상태를 나타낸다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.active&lt;/code&gt; 앱이 포그라운드에 있고 사용자와 상호작용 가능&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.inactive&lt;/code&gt; 앱이 포그라운드에 있지만 상호작용 불가 (예: 멀티태스킹 전환 중)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.background&lt;/code&gt; 앱이 백그라운드로 이동한 상태&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="사용"&gt;사용&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@Environment(&lt;span style="color:#960050;background-color:#1e0010"&gt;\&lt;/span&gt;.scenePhase) &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; scenePhase
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; body: some View {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ContentView()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; .onChange(of: scenePhase) { oldPhase, newPhase &lt;span style="color:#66d9ef"&gt;in&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;switch&lt;/span&gt; newPhase {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; .active:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#34;앱 활성화&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; .inactive:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#34;앱 비활성화&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt; .background:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; print(&lt;span style="color:#e6db74"&gt;&amp;#34;백그라운드로 이동&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; @unknown &lt;span style="color:#66d9ef"&gt;default&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;break&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;참고
&lt;code&gt;onChange(of:)&lt;/code&gt; 클로저에서 &lt;code&gt;oldPhase&lt;/code&gt;, &lt;code&gt;newPhase&lt;/code&gt; 두 파라미터를 받는 형태는 &lt;strong&gt;iOS 17+&lt;/strong&gt; 문법이다. iOS 16 이하를 지원해야 한다면 단일 파라미터 형태(&lt;code&gt;{ phase in ... }&lt;/code&gt;)를 사용해야 한다.&lt;/p&gt;</description></item><item><title>[Apple Platforms] Testing 🖋️</title><link>http://yeniful.github.io/posts/2026/apple-testing/</link><pubDate>Fri, 23 Jan 2026 00:00:00 +0900</pubDate><guid>http://yeniful.github.io/posts/2026/apple-testing/</guid><description>&lt;h2 id="motivation"&gt;Motivation&lt;/h2&gt;
&lt;h3 id="기능을-완전하게-구현하려면"&gt;기능을 완전하게 구현하려면?&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;최근 과제 전형을 마치고 제출했던 코드를 다시 살펴보았다.&lt;/li&gt;
&lt;li&gt;요구사항에 따라 동작하게 만들었지만 에러 핸들링, 예외 처리, 효율 측면에서 놓친 부분이 많았다는 걸 깨달았다.&lt;/li&gt;
&lt;li&gt;단순히 기능을 구현하는 것과, 예상하지 못한 동작과 상태를 대비해서 잘 만드는 건 전혀 다른 문제였다.&lt;/li&gt;
&lt;li&gt;과제에서 크게 신경을 쓰지 못한 Testing 영역이 눈에 들어왔고 &amp;lsquo;코드과 테스트 코드의 순서를 바꿨었더라면?&amp;lsquo;이라는 생각이 들었다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="code-first"&gt;Code First&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;요구사항 확인 → 기능 개발 → 테스트 코드 작성 → 테스트&lt;/p&gt;</description></item><item><title>[Apple Platforms] Apple 플랫폼 개발에서의 캐싱 (Caching) 🖋️</title><link>http://yeniful.github.io/posts/2026/apple-caching/</link><pubDate>Sat, 17 Jan 2026 00:00:00 +0900</pubDate><guid>http://yeniful.github.io/posts/2026/apple-caching/</guid><description>iOS ViewController의 생명주기 메서드와 Push/Pop, Present/Dismiss 상황별 호출 순서를 정리합니다.</description></item><item><title>[UIKit] ViewController 생명주기 (View Controller Life Cycle)</title><link>http://yeniful.github.io/posts/2026/uikit-view-controller-life-cycle/</link><pubDate>Sat, 17 Jan 2026 00:00:00 +0900</pubDate><guid>http://yeniful.github.io/posts/2026/uikit-view-controller-life-cycle/</guid><description>iOS ViewController의 생명주기 메서드와 Push/Pop, Present/Dismiss 상황별 호출 순서를 정리합니다.</description></item><item><title>[Apple Platforms] 앱 생명 주기 (App Life Cycle) 🖋️</title><link>http://yeniful.github.io/posts/2026/apple-app-life-cycle/</link><pubDate>Thu, 01 Jan 2026 00:00:00 +0900</pubDate><guid>http://yeniful.github.io/posts/2026/apple-app-life-cycle/</guid><description>&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;앱 생명주기: 앱이 실행되는 시점부터 종료되는 시점까지 거치는 여러 상태의 순환 과정&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="ios-앱의-5가지-상태"&gt;iOS 앱의 5가지 상태&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Not Running (실행되지 않음)&lt;/li&gt;
&lt;li&gt;Inactive (비활성)&lt;/li&gt;
&lt;li&gt;Active (활성)&lt;/li&gt;
&lt;li&gt;Background (백그라운드)&lt;/li&gt;
&lt;li&gt;Suspended (일시 중지)&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="swiftui에서의-앱-생명주기"&gt;SwiftUI에서의 앱 생명주기&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;SwiftUI에서 앱은 &lt;code&gt;@main&lt;/code&gt; attribute로 표시된 구조체에서 시작.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;UIApplicationMain&lt;/code&gt;의 대체&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-Swift" data-lang="Swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@main
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;struct&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;MyApp&lt;/span&gt;: App {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;var&lt;/span&gt; body: some Scene {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; WindowGroup {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ContentView()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description></item><item><title>[Swift] weak self 🖋️</title><link>http://yeniful.github.io/posts/2026/swift-weak-self/</link><pubDate>Thu, 01 Jan 2026 00:00:00 +0900</pubDate><guid>http://yeniful.github.io/posts/2026/swift-weak-self/</guid><description>&lt;h2 id="motivation"&gt;Motivation&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;클로저 안의 weak self&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;self: 클래스 인스턴스 참조&lt;/li&gt;
&lt;li&gt;약한 참조&lt;/li&gt;
&lt;li&gt;ARC&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="note"&gt;Note&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;일반적으로 클로저는 클로저 내부에서 변수를 사용할 때 암시적으로 변수를 캡처하지만, 이 경우에는 명시적으로 작성해야 합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;self&lt;/code&gt;를 캡처하려면, 사용할 때 명시적으로 &lt;code&gt;self&lt;/code&gt;를 작성하거나, 클로저의 캡처 리스트에 &lt;code&gt;self&lt;/code&gt;를 포함합니다. &lt;/li&gt;
&lt;li&gt;&lt;code&gt;self&lt;/code&gt;를 명시적으로 작성하는 것은 의도를 분명하게 표현하고, 참조 순환이 없음을 확인하도록 유도하는 역할도 합니다&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="capture-values"&gt;Capture Values&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;클로저는 정의된 주변 컨텍스트로부터 상수와 변수를 캡처할 수 있음.&lt;/li&gt;
&lt;li&gt;상수와 변수를 정의한 원래 범위가 더이상 존재하지 않더라도 본문 내에서 상수와 변수의 값을 참조하고 수정할 수 있음.&lt;/li&gt;
&lt;li&gt;값을 캡처할 수 있는 가장 간단한 클로저 형태는 다른 함수의 본문 내에 작성하는 중첩 함수
&lt;ul&gt;
&lt;li&gt;중첩 함수는 바깥 함수의 어떠한 인자도 캡처할 수 있고 바깥 함수 내에 정의된 상수와 변수를 캡처할 수도 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="references-"&gt;References 👀&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://bbiguduk.github.io/swift-book-korean/documentation/the-swift-programming-language-korean/closures/#%ED%83%88%EC%B6%9C-%ED%81%B4%EB%A1%9C%EC%A0%80-Escaping-Closures"&gt;Swift Programming Language - 탈출 클로저&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>[UIKit] Scene Delegate</title><link>http://yeniful.github.io/posts/2026/uikit-scene-delegate/</link><pubDate>Thu, 01 Jan 2026 00:00:00 +0900</pubDate><guid>http://yeniful.github.io/posts/2026/uikit-scene-delegate/</guid><description>iOS 13부터 도입된 SceneDelegate의 역할, 도입 배경, 각 메서드의 동작 원리 알아보기.</description></item><item><title>[SwiftUI] struct View vs @ViewBuilder 함수, 뭐가 다를까?</title><link>http://yeniful.github.io/posts/2025/20250301_swiftuiview/</link><pubDate>Sat, 01 Mar 2025 00:00:00 +0900</pubDate><guid>http://yeniful.github.io/posts/2025/20250301_swiftuiview/</guid><description>&lt;h2 id="모티베이션"&gt;모티베이션&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;재사용되는 View를 구조체로 빼야 하나, 아니면 그냥 함수로 만들어도 될까?&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;View를 만들 때 특별한 기준 없이 View를 만들 때 습관적으로 구조체를 만들거나, 간단한 건 함수로 처리하곤 했는데요. 앱의 구조와 성능, 유지보수 방식에 꽤 중요한 영향을 준다는 것을 알게 되었고, 간단한 내용이지만 한 번 정리해보고 싶었습니다.&lt;/p&gt;
&lt;p&gt;그래서 이번 글에서는 Apple 공식 문서와 WWDC 세션에서 강조한 원리를 바탕으로 &lt;strong&gt;struct View vs. @ViewBuilder 함수&lt;/strong&gt;의 차이를 정리해보려고 합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="두-가지-방식-살펴보기"&gt;두 가지 방식 살펴보기&lt;/h2&gt;
&lt;p&gt;먼저 동일한 UI를 두 가지 방식으로 만들어봤습니다.&lt;/p&gt;</description></item></channel></rss>