<?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>Swift on @yeniful blog</title><link>http://yeniful.github.io/tags/swift/</link><description>Recent content in Swift on @yeniful blog</description><generator>Hugo -- 0.155.3</generator><language>en-us</language><lastBuildDate>Fri, 30 Jan 2026 00:00:00 +0900</lastBuildDate><atom:link href="http://yeniful.github.io/tags/swift/index.xml" rel="self" type="application/rss+xml"/><item><title>[Swift] MainActor 🖋️</title><link>http://yeniful.github.io/posts/2026/swift-mainactor/</link><pubDate>Fri, 30 Jan 2026 00:00:00 +0900</pubDate><guid>http://yeniful.github.io/posts/2026/swift-mainactor/</guid><description>&lt;h2 id="motivation"&gt;Motivation&lt;/h2&gt;
&lt;p&gt;iOS 개발에서 UI 업데이트는 &lt;strong&gt;반드시 메인 스레드&lt;/strong&gt;에서 해야 하지만, Swift Concurrency 도입 후 백그라운드 Task 내에서 UI를 직접 업데이트하는 실수가 쉬워졌다. @MainActor는 컴파일 타임부터 이 문제를 구조적으로 해결해 준다. 이 글에서 MainActor에 대해 다뤄보려고 한다.&lt;/p&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;Task { &lt;span style="color:#75715e"&gt;// 백그라운드 Task (Global Actor)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; data = await fetchUser()
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; userNameLabel.text = data.name &lt;span style="color:#75715e"&gt;// UI 업데이트 (MainActor 필요!)&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;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;h2 id="1-mainactor는-언제-필요할까-문제-상황"&gt;1. MainActor는 언제 필요할까? (문제 상황)&lt;/h2&gt;
&lt;h3 id="1-1-uikit의-메인-스레드-제약"&gt;1-1. UIKit의 메인 스레드 제약&lt;/h3&gt;
&lt;h3 id="1-2-gcd의-한계-dispatchqueuemainasync"&gt;1-2. GCD의 한계 (DispatchQueue.main.async)&lt;/h3&gt;
&lt;h3 id="1-3-swift-concurrency의-함정-task--ui-섞기"&gt;1-3. Swift Concurrency의 함정 (Task + UI 섞기)&lt;/h3&gt;
&lt;h2 id="2-mainactor-기본-개념"&gt;2. MainActor 기본 개념&lt;/h2&gt;
&lt;h3 id="2-1-mainactor-알기-전-actor가-무엇인지"&gt;2-1. MainActor 알기 전 Actor가 무엇인지&lt;/h3&gt;
&lt;h3 id="2-2-global-actor와-mainactor"&gt;2-2. Global Actor와 MainActor&lt;/h3&gt;
&lt;h3 id="2-3-mainactor-속성의-의미"&gt;2-3. &lt;code&gt;@MainActor&lt;/code&gt; 속성의 의미&lt;/h3&gt;
&lt;h2 id="3-사용법"&gt;3. 사용법&lt;/h2&gt;
&lt;h3 id="3-1-함수프로퍼티에-적용"&gt;3-1. 함수/프로퍼티에 적용&lt;/h3&gt;
&lt;h3 id="3-2-클래스-전체에-적용-viewmodel-패턴"&gt;3-2. 클래스 전체에 적용 (ViewModel 패턴)&lt;/h3&gt;
&lt;h3 id="3-3-swiftui와의-완벽-호환-published"&gt;3-3. SwiftUI와의 완벽 호환 (@Published)&lt;/h3&gt;
&lt;h2 id="4-task와-함께-사용"&gt;4. Task와 함께 사용&lt;/h2&gt;
&lt;h3 id="4-1-task--mainactor-in-"&gt;4-1. &lt;code&gt;Task { @MainActor in }&lt;/code&gt;&lt;/h3&gt;
&lt;h3 id="4-2-await-mainactorrun--"&gt;4-2. &lt;code&gt;await MainActor.run { }&lt;/code&gt;&lt;/h3&gt;
&lt;h3 id="4-3-taskdetached--mainactor-전환"&gt;4-3. &lt;code&gt;Task.detached&lt;/code&gt; + MainActor 전환&lt;/h3&gt;
&lt;h2 id="5-더-알아보기"&gt;5. 더 알아보기&lt;/h2&gt;
&lt;h3 id="5-1-nonisolated-탈출구"&gt;5-1. &lt;code&gt;nonisolated&lt;/code&gt; 탈출구&lt;/h3&gt;
&lt;h3 id="5-2-sendable과-데이터-전달"&gt;5-2. &lt;code&gt;@Sendable&lt;/code&gt;과 데이터 전달&lt;/h3&gt;
&lt;h3 id="5-3-mainactor-호핑-최적화"&gt;5-3. MainActor 호핑 최적화&lt;/h3&gt;
&lt;h2 id="6-mainactor와-dispatchqueue-비교"&gt;6. MainActor와 DispatchQueue 비교&lt;/h2&gt;
&lt;h3 id="6-1-mainactor-vs-dispatchqueuemain"&gt;6-1. &lt;code&gt;@MainActor&lt;/code&gt; vs &lt;code&gt;DispatchQueue.main&lt;/code&gt;&lt;/h3&gt;
&lt;h3 id="6-2-다른-글로벌-액터와-비교"&gt;6-2. 다른 글로벌 액터와 비교&lt;/h3&gt;
&lt;h3 id="references-"&gt;References 👀&lt;/h3&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>[Swift] 딕셔너리 (Dictionary) 🖋️</title><link>http://yeniful.github.io/posts/2026/swift-dictionary/</link><pubDate>Thu, 01 Jan 2026 00:00:00 +0900</pubDate><guid>http://yeniful.github.io/posts/2026/swift-dictionary/</guid><description>&lt;h2 id="설명"&gt;설명&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Key-Value 저장하는 컬렉션 타입&lt;/li&gt;
&lt;li&gt;해시 테이블로 구현되어있음
&lt;ul&gt;
&lt;li&gt;빠른 속도로 접근, 수정, 추가, 키 존재 여부 확인 가능 O(1)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;let scores = [&amp;#34;roy&amp;#34;: 95, &amp;#34;gucci&amp;#34;: 82, &amp;#34;yeni&amp;#34;: 90]
// 모두 O(1) 시간
let royScore = scores[&amp;#34;roy&amp;#34;] // 95
let gucciScore = scores[&amp;#34;gucci&amp;#34;] // 82
scores[&amp;#34;terry&amp;#34;] = 75 // 추가
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="유의"&gt;유의&lt;/h2&gt;
&lt;h3 id="제거시-on의-가능성"&gt;제거시 O(n)의 가능성&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;값 제거 (removeValue(forKey: key))의 경우 기술적으로는 O(1)로 구현되어 있음&lt;/li&gt;
&lt;li&gt;하지만 Copy-On-Write 최적화 때문에 O(n) 복잡도를 가질 수 있음.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;// 첫 번째 Dictionary
var dict1 = [&amp;#34;a&amp;#34;: 1, &amp;#34;b&amp;#34;: 2, &amp;#34;c&amp;#34;: 3]
// dict2는 dict1과 메모리를 공유 (Copy-on-Write)
var dict2 = dict1
// 이 제거 연산은 dict1을 수정하기 전에 전체 복사가 필요할 수 있음 (O(n))
dict1.removeValue(forKey: &amp;#34;a&amp;#34;)
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="활용"&gt;활용&lt;/h2&gt;
&lt;h3 id="key-존재-확인"&gt;Key 존재 확인&lt;/h3&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;// 👍 O(1) : 직접 접근해서 확인
if dict[&amp;#34;key&amp;#34;] != nil { ... }
// 😱 O(n) : 배열로 변환 후 순회하기 때문에 비효율적이다.
if dict.keys.contains(&amp;#34;yeni&amp;#34;) { ... }
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="value-조회"&gt;Value 조회&lt;/h3&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;// 👍 O(1) : 해시 기반 직접 조회
let value = scores[&amp;#34;yeni&amp;#34;]
// 🤩 값이 없을 수도 있으므로 Optional 처리가 필요하다.
if let score = scores[&amp;#34;yeni&amp;#34;] {
print(&amp;#34;Alice&amp;#39;s score: \(score)&amp;#34;)
}
&lt;/code&gt;&lt;/pre&gt;</description></item></channel></rss>