<?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>Observer Pattern on Kelly Dev</title><link>https://kelly-chui.github.io/tags/observer-pattern/</link><description>Recent content in Observer Pattern on Kelly Dev</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Fri, 24 Jul 2026 17:41:15 +0900</lastBuildDate><atom:link href="https://kelly-chui.github.io/tags/observer-pattern/index.xml" rel="self" type="application/rss+xml"/><item><title>SwiftUI. Discover Observation in SwiftUI - WWDC23</title><link>https://kelly-chui.github.io/posts/wwdc-swiftui-discover-observation-in-swiftui/</link><pubDate>Fri, 24 Jul 2026 17:41:15 +0900</pubDate><guid>https://kelly-chui.github.io/posts/wwdc-swiftui-discover-observation-in-swiftui/</guid><description>&lt;p&gt;SwiftUI의 Observation은 모델의 프로퍼티 변화를 추적하고, 그 변화에 맞춰 UI를 업데이트하는 기능이다. &lt;code&gt;@Observable&lt;/code&gt; 매크로를 사용하면 별도의 &lt;code&gt;ObservableObject&lt;/code&gt;, &lt;code&gt;@Published&lt;/code&gt;, &lt;code&gt;@ObservedObject&lt;/code&gt; 없이도 일반 Swift 타입에 가까운 형태로 관찰 가능한 모델을 만들 수 있다.&lt;/p&gt;
&lt;p&gt;핵심은 간단하다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;View가 읽은 프로퍼티가 바뀌면, 그 View가 다시 계산된다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;이 글에서는 Observation의 동작 방식, &lt;code&gt;@State&lt;/code&gt;, &lt;code&gt;@Environment&lt;/code&gt;, &lt;code&gt;@Bindable&lt;/code&gt;을 언제 써야 하는지, 그리고 기존 &lt;code&gt;ObservableObject&lt;/code&gt; 기반 코드를 &lt;code&gt;@Observable&lt;/code&gt;로 옮기는 방법을 정리한다.&lt;/p&gt;
&lt;h2 id="observation"&gt;Observation&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;@Observable&lt;/code&gt;은 Swift 매크로다. 타입에 이 매크로를 붙이면 컴파일러가 해당 타입을 관찰할 수 있도록 코드를 확장한다.&lt;/p&gt;</description></item><item><title>Combine. Combine in Practice - WWDC19</title><link>https://kelly-chui.github.io/posts/wwdc-combine-in-practice/</link><pubDate>Mon, 18 Mar 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/wwdc-combine-in-practice/</guid><description>&lt;h2 id="a-unified-declarative-api-for-processing-values-over-time"&gt;A unified, declarative API for processing values over time&lt;/h2&gt;
&lt;p&gt;Combine에서는 값이 시간의 흐름에 따라 전달되는 과정을 Publisher로 표현하고, 여러 연산자를 연결해 데이터가 변환되는 흐름을 선언적으로 작성한다. 아래 예제에서는 Notification으로 전달된 Data를 &lt;code&gt;MagicTrick&lt;/code&gt;으로 디코딩한다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;trickNamePublisher&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;NotificationCenter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;publisher&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;newTrickDownloaded&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="bp"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;notification&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;notification&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;userInfo&lt;/span&gt;&lt;span class="p"&gt;?[&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;data&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="n"&gt;Data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// Output: Data, Failure: Never&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tryMap&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;decoder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;JSONDecoder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="n"&gt;decoder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MagicTrick&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kc"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// Output: MagicTrick, Failure: Error&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;decode&lt;/code&gt; 연산자를 사용하면 위 변환을 다음과 같이 줄여서 작성할 수 있다.&lt;/p&gt;
&lt;div class="code-theme-github"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;trickNamePublisher&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;NotificationCenter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;publisher&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;newTrickDownloaded&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="bp"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;notification&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;notification&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;userInfo&lt;/span&gt;&lt;span class="p"&gt;?[&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;data&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="n"&gt;Data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// Output: Data, Failure: Never&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MagicTrick&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kc"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;JSONDecoder&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="c1"&gt;// Output: MagicTrick, Failure: Error&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id="error-handling"&gt;Error Handling&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;모든 Publisher는 자신이 발생시킬 수 있는 실패의 종류를 명확하게 정의한다.&lt;/li&gt;
&lt;li&gt;실패가 발생하지 않거나 이미 처리된 경우에는 &lt;code&gt;Never&lt;/code&gt;를 Failure 타입으로 사용한다.&lt;/li&gt;
&lt;li&gt;Combine은 실패를 감지하고 복구할 수 있는 다양한 연산자를 제공한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Combine의 Publisher는 전달하는 값의 타입인 &lt;code&gt;Output&lt;/code&gt;과 실패할 때 전달하는 오류의 타입인 &lt;code&gt;Failure&lt;/code&gt;를 함께 가진다. 두 타입이 연산자를 거치며 어떻게 바뀌는지 확인하면 데이터 흐름과 오류 흐름을 함께 추적할 수 있다.&lt;/p&gt;</description></item><item><title>Combine. Introducing Combine - WWDC19</title><link>https://kelly-chui.github.io/posts/wwdc-combine-introducing-combine/</link><pubDate>Sun, 17 Mar 2024 00:00:00 +0000</pubDate><guid>https://kelly-chui.github.io/posts/wwdc-combine-introducing-combine/</guid><description>&lt;h2 id="combine"&gt;Combine&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Customize handling of asynchronous events by combining event-processing operators.&lt;/p&gt;
&lt;p&gt;결합된 이벤트 처리 연산자를 이용하여 비동기 이벤트 처리를 커스터마이즈 하는 방법&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Combine은 데이터 흐름을 간편하게 처리하고 비동기 이벤트를 관리하기 위한 프레임워크다. 다양한 소스에서 발생하는 이벤트를 같은 방식으로 다루고, 이벤트 사이의 상호작용을 연산자로 조합할 수 있다.&lt;/p&gt;
&lt;h2 id="특징"&gt;특징&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Generic: 제네릭을 사용해 다양한 타입의 데이터 흐름을 표현한다.&lt;/li&gt;
&lt;li&gt;Type safe: Publisher의 출력 타입과 실패 타입을 컴파일 타임에 확인한다.&lt;/li&gt;
&lt;li&gt;Composition first: 작은 Publisher와 연산자를 조합해 더 큰 흐름을 만든다.&lt;/li&gt;
&lt;li&gt;Request driven: Subscriber가 필요한 만큼의 값을 요청하는 방식으로 흐름을 제어한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="핵심-개념"&gt;핵심 개념&lt;/h2&gt;
&lt;h3 id="publisher"&gt;Publisher&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;값과 에러가 어떻게 생성되는지를 정의한다.&lt;/p&gt;</description></item></channel></rss>