<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Hohyeon Moon</title>
    <description>매끄러운 사용자 경험을 만드는데 집중합니다. 코딩 그 자체와 영향력을 좋아합니다.</description>
    <link>https://www.hohyeonmoon.com</link>
    <language>ko</language>
    <lastBuildDate>Sat, 08 Nov 2025 10:11:53 GMT</lastBuildDate>
    <pubDate>Sat, 08 Nov 2025 10:11:53 GMT</pubDate>
    <ttl>250</ttl>
    <atom:link href="https://www.hohyeonmoon.com/feed" rel="self" type="application/rss+xml"/>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swift-concurrency</guid>
      <title>Swift Concurrency</title>
      <description>async, await, task, actor 등 Swift Concurrency 알아보기</description>
      <link>https://www.hohyeonmoon.com/blog/swift-concurrency</link>
      <pubDate>Wed, 10 Sep 2025 18:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<h2 id="async">async</h2>
<h3 id="async-1">async</h3>
<ul>
<li>함수 정의 뒷부분에 async를 붙이면 해당 함수는 비동기라는 것을 나타냄</li>
<li>async 함수는 concurrent context 내부 즉, 다른 async 함수 내부 혹은 Task 내부에서 사용 가능</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">listPhotos</span><span class="token punctuation">(</span>inGallery name<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token operator">-></span> <span class="token punctuation">[</span><span class="token class-name">String</span><span class="token punctuation">]</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> result <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">asyncFunction</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">return</span> result
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>일반 함수뿐만이 아니라, read-only 프로퍼티나 생성자에도 async 사용 가능</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">UIImage</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> thumbnail<span class="token punctuation">:</span> <span class="token class-name">UIImage</span><span class="token operator">?</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">get</span> <span class="token keyword">async</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">let</span> size <span class="token operator">=</span> <span class="token class-name">CGSize</span><span class="token punctuation">(</span>width<span class="token punctuation">:</span> <span class="token number">40</span><span class="token punctuation">,</span> height<span class="token punctuation">:</span> <span class="token number">40</span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token keyword">return</span> <span class="token keyword">await</span> <span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">byPreparingThumbnail</span><span class="token punctuation">(</span>ofSize<span class="token punctuation">:</span> size<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">init</span><span class="token punctuation">(</span>userID<span class="token punctuation">:</span> <span class="token class-name">Int</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token keyword">throws</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> fetchedUser <span class="token operator">=</span> <span class="token keyword">try</span> <span class="token keyword">await</span> <span class="token class-name">UserManager</span><span class="token punctuation">.</span><span class="token function">fetchUserData</span><span class="token punctuation">(</span>id<span class="token punctuation">:</span> userID<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">self</span><span class="token punctuation">.</span>user <span class="token operator">=</span> fetchedUser
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h3 id="async-let">async let</h3>
<ul>
<li>아래와 같은 코드는 한 번에 하나의 비동기 코드만 실행</li>
<li>비동기 코드가 실행되는 동안, 호출자는 다음 코드를 실행하기 전에 해당 코드가 완료될 때까지 기다림</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">fetchOneThumbnail</span><span class="token punctuation">(</span>withID id<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token keyword">throws</span> <span class="token operator">-></span> <span class="token class-name">UIImage</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> imageReq <span class="token operator">=</span> <span class="token function">imageRequest</span><span class="token punctuation">(</span><span class="token keyword">for</span><span class="token punctuation">:</span> id<span class="token punctuation">)</span><span class="token punctuation">,</span> metadataReq <span class="token operator">=</span> <span class="token function">metadataRequest</span><span class="token punctuation">(</span><span class="token keyword">for</span><span class="token punctuation">:</span> id<span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">let</span> <span class="token punctuation">(</span>data<span class="token punctuation">,</span> <span class="token omit keyword">_</span><span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token keyword">try</span> <span class="token keyword">await</span> <span class="token class-name">URLSession</span><span class="token punctuation">.</span>shared<span class="token punctuation">.</span><span class="token function">data</span><span class="token punctuation">(</span><span class="token keyword">for</span><span class="token punctuation">:</span> imageReq<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">let</span> <span class="token punctuation">(</span>metadata<span class="token punctuation">,</span> <span class="token omit keyword">_</span><span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token keyword">try</span> <span class="token keyword">await</span> <span class="token class-name">URLSession</span><span class="token punctuation">.</span>shared<span class="token punctuation">.</span><span class="token function">data</span><span class="token punctuation">(</span><span class="token keyword">for</span><span class="token punctuation">:</span> metadataReq<span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">guard</span> <span class="token keyword">let</span> size <span class="token operator">=</span> <span class="token function">parseSize</span><span class="token punctuation">(</span>from<span class="token punctuation">:</span> metadata<span class="token punctuation">)</span><span class="token punctuation">,</span>
</span><span class="code-line">          <span class="token keyword">let</span> image <span class="token operator">=</span> <span class="token class-name">UIImage</span><span class="token punctuation">(</span>data<span class="token punctuation">:</span> data<span class="token punctuation">)</span><span class="token operator">?</span><span class="token punctuation">.</span><span class="token function">byPreparingThumbnail</span><span class="token punctuation">(</span>ofSize<span class="token punctuation">:</span> size<span class="token punctuation">)</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">throw</span> <span class="token class-name">ThumbnailFailedError</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">return</span> image
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>비동기 함수를 호출하고 주변 코드와 병렬로 실행 하는것도 가능</li>
<li>정의할 때 let 앞에 async를 작성한 다음 상수를 사용할때 await를 사용</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">fetchOneThumbnail</span><span class="token punctuation">(</span>withID id<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token keyword">throws</span> <span class="token operator">-></span> <span class="token class-name">UIImage</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> imageReq <span class="token operator">=</span> <span class="token function">imageRequest</span><span class="token punctuation">(</span><span class="token keyword">for</span><span class="token punctuation">:</span> id<span class="token punctuation">)</span><span class="token punctuation">,</span> metadataReq <span class="token operator">=</span> <span class="token function">metadataRequest</span><span class="token punctuation">(</span><span class="token keyword">for</span><span class="token punctuation">:</span> id<span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">async</span> <span class="token keyword">let</span> <span class="token punctuation">(</span>data<span class="token punctuation">,</span> <span class="token omit keyword">_</span><span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token class-name">URLSession</span><span class="token punctuation">.</span>shared<span class="token punctuation">.</span><span class="token function">data</span><span class="token punctuation">(</span><span class="token keyword">for</span><span class="token punctuation">:</span> imageReq<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">async</span> <span class="token keyword">let</span> <span class="token punctuation">(</span>metadata<span class="token punctuation">,</span> <span class="token omit keyword">_</span><span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token class-name">URLSession</span><span class="token punctuation">.</span>shared<span class="token punctuation">.</span><span class="token function">data</span><span class="token punctuation">(</span><span class="token keyword">for</span><span class="token punctuation">:</span> metadataReq<span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">guard</span> <span class="token keyword">let</span> size <span class="token operator">=</span> <span class="token function">parseSize</span><span class="token punctuation">(</span>from<span class="token punctuation">:</span> <span class="token keyword">try</span> <span class="token keyword">await</span> metadata<span class="token punctuation">)</span><span class="token punctuation">,</span>
</span><span class="code-line">          <span class="token keyword">let</span> image <span class="token operator">=</span> <span class="token keyword">try</span> <span class="token keyword">await</span> <span class="token class-name">UIImage</span><span class="token punctuation">(</span>data<span class="token punctuation">:</span> data<span class="token punctuation">)</span><span class="token operator">?</span><span class="token punctuation">.</span><span class="token function">byPreparingThumbnail</span><span class="token punctuation">(</span>ofSize<span class="token punctuation">:</span> size<span class="token punctuation">)</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">throw</span> <span class="token class-name">ThumbnailFailedError</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">return</span> image
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>async let을 사용하면 해당 코드는 바로 실행 되지만 대기하지는 않음</li>
<li>await을 통해 실행을 기다림</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">execute</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token comment">// 실행을 시작하지만 대기하지는 않음</span>
</span><span class="code-line">    <span class="token keyword">async</span> <span class="token keyword">let</span> one <span class="token operator">=</span> <span class="token function">sleepOne</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">async</span> <span class="token keyword">let</span> two <span class="token operator">=</span> <span class="token function">sleepTwo</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"await: "</span></span><span class="token punctuation">,</span> <span class="token keyword">await</span> one<span class="token punctuation">)</span> <span class="token comment">// one 대기</span>
</span><span class="code-line">    <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"await: "</span></span><span class="token punctuation">,</span> <span class="token keyword">await</span> two<span class="token punctuation">)</span> <span class="token comment">// two 대기</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">sleepOne</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token operator">-></span> <span class="token class-name">Int</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">try</span><span class="token operator">?</span> <span class="token keyword">await</span> <span class="token class-name">Task</span><span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span><span class="token keyword">for</span><span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">seconds</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"sleepOne completed"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">return</span> <span class="token number">1</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">sleepTwo</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token operator">-></span> <span class="token class-name">Int</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">try</span><span class="token operator">?</span> <span class="token keyword">await</span> <span class="token class-name">Task</span><span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span><span class="token keyword">for</span><span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">seconds</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"sleepTwo completed"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">return</span> <span class="token number">2</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="await">await</h2>
<h3 id="await-1">await</h3>
<p><img src="/images/swift-concurrency-1.png" alt="swift-concurrency"></p>
<ul>
<li>async 함수를 호출하기 위해 await이 필요함</li>
<li>await는 potential suspension point로 지정 된다는 것을 의미</li>
<li>suspend 된다는 것은 해당 thread에 대한 control을 포기한다는 것</li>
<li>해당 코드를 돌리고 있던 thread에 대한 control은 system에게 가고, system은 해당 thread를 사용하여 다른 작업 가능</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"비동기 함수 호출 전"</span></span><span class="token punctuation">)</span> <span class="token comment">// Thread A에서 실행</span>
</span><span class="code-line"><span class="token keyword">await</span> <span class="token function">asyncFunction</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// Thread A 제어권 시스템에게 줌</span>
</span><span class="code-line"><span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"비동기 함수 호출 후"</span></span><span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>await로 인한 중단은 해당 thread에서 다른 코드의 실행을 막지 않음</li>
<li>function은 suspend 되고, 다른 것들이 먼저 실행 될 수 있고 그렇기에 그 동안 앱의 상태가 크게 변할 수 있음</li>
<li>thread를 차단하는 대신 control을 포기해 작업을 중지 및 재개할 수 있는 개념을 도입</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"비동기 함수 호출 전"</span></span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token keyword">await</span> <span class="token function">asyncFunction</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"비동기 함수 호출 후"</span></span><span class="token punctuation">)</span> <span class="token comment">// Thread B에서 이어서 실행</span>
</span></code></pre>
<ul>
<li>정리하자면, await로 async 함수를 호출하는 순간 해당 thread control 포기</li>
<li>따라서 async 작업 및 같은 블럭에 있는 다음 코드들을 바로 실행하지 못함</li>
<li>thread control을 system에게 넘기면서, system에게 해당 async 작업도 schedule</li>
<li>system은 다른 중요한 작업이 있다면 먼저 실행하고, 특정 thread control을 줘서 async 함수와 나머지 코드를 resume</li>
</ul>
<h3 id="for-await">for await</h3>
<ul>
<li>for loop에서도 await 사용 가능</li>
<li>기본적으로 for await은 element를 순차적으로 처리함</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">for</span> <span class="token keyword">await</span> item <span class="token keyword">in</span> asyncSequence <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">await</span> <span class="token function">processItem</span><span class="token punctuation">(</span>item<span class="token punctuation">)</span> <span class="token comment">// 각 항목이 하나씩 차례로 처리됨</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>하지만 taskGroup이나 async let을 사용하여 병렬적으로 처리할수 있음</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">await</span> <span class="token function">withTaskGroup</span><span class="token punctuation">(</span>of<span class="token punctuation">:</span> <span class="token class-name">Void</span><span class="token punctuation">.</span><span class="token keyword">self</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> group <span class="token keyword">in</span>
</span><span class="code-line">    <span class="token keyword">for</span> <span class="token keyword">await</span> item <span class="token keyword">in</span> asyncSequence <span class="token punctuation">{</span>
</span><span class="code-line">        group<span class="token punctuation">.</span>addTask <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">await</span> <span class="token function">processItem</span><span class="token punctuation">(</span>item<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>AsyncStream과 같은 일부 AsyncSequence 구현은 요소들을 동시에 생성함</li>
<li>for await loop은 여전히 요소들이 사용 가능해지는 순서대로 하나씩 소비하지만, 병렬적으로 처리가 가능해짐</li>
<li>핵심은 for await 자체는 순차적으로 반복하지만, 필요에 따라 그 주변에 병렬 처리를 구현할 수 있다는것</li>
</ul>
<h2 id="task">task</h2>
<blockquote>
<p><a href="/blog/swiftui-task-modifier/">SwiftUI task에서 비동기 작업하기</a></p>
</blockquote>
<p><img src="/images/swift-concurrency-2.png" alt="swift-concurrency"></p>
<h3 id="task-1">Task</h3>
<ul>
<li>Task는 비동기 작업 단위: A unit of asynchronous work</li>
<li>격리되어(isolated), 독립적으로(independently) 비동기 작업을 수행</li>
<li>값이 공유될 상황이 있을때는 Sendable 체킹을 통해 Task가 격리된 상태로 남아있는지 체크</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">Task</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token comment">// 비동기 코드</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>Task 안에서의 작업은 처음부터 끝까지 순차적으로 실행</li>
<li>await를 만나면 작업은 몇번이고 중단될 수는 있지만, 실행 순서가 변경되지는 않음</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">Task</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token comment">// 순서대로 실행되는 비동기 context</span>
</span><span class="code-line">    <span class="token keyword">let</span> fish <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">catchFish</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">let</span> dinner <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">cook</span><span class="token punctuation">(</span>fish<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">await</span> <span class="token function">eat</span><span class="token punctuation">(</span>dinner<span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h3 id="task-cancellation">Task Cancellation</h3>
<ul>
<li><code>isCancelled</code>는 Bool을 리턴하는 단순히 cancel 되었는지 확인하는 플래그</li>
<li><code>checkCancellation()</code>은 cancel 되었으면 CancellationError을 throw 함</li>
<li>둘다 synchronous 혹은 asynchronous 코드 어디서나 사용할수 있음</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">if</span> <span class="token class-name">Task</span><span class="token punctuation">.</span>isCancelled <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token keyword">try</span> <span class="token class-name">Task</span><span class="token punctuation">.</span><span class="token function">checkCancellation</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>부모 Task를 cancel 하면, 자식 Task는 isCancelled 플래그가 true가 될뿐 코드 실행을 멈추지는 않음</li>
<li>그래서 Task가 cancel 되어도 코드가 즉시 멈추지는 않을 수 있음</li>
<li>예를들어, 아래 코드에서 1번 지점 전에 cancel이 호출 되었다면 throw를 하고 코드가 멈출것임</li>
<li>하지만 2번 지점 이후 cancel이 호출 되었다면, 코드 실행이 그대로 진행될것임</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">makeSoup</span><span class="token punctuation">(</span>order<span class="token punctuation">:</span> <span class="token class-name">Order</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token keyword">throws</span> <span class="token operator">-></span> <span class="token class-name">Soup</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">async</span> <span class="token keyword">let</span> pot <span class="token operator">=</span> stove<span class="token punctuation">.</span><span class="token function">boilBroth</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token comment">// 1</span>
</span><span class="code-line">    <span class="token keyword">guard</span> <span class="token operator">!</span><span class="token class-name">Task</span><span class="token punctuation">.</span>isCancelled <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">throw</span> <span class="token class-name">SoupCancellationError</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token comment">// 2</span>
</span><span class="code-line">    <span class="token keyword">async</span> <span class="token keyword">let</span> choppedIngredients <span class="token operator">=</span> <span class="token function">chopIngredients</span><span class="token punctuation">(</span>order<span class="token punctuation">.</span>ingredients<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">async</span> <span class="token keyword">let</span> meat <span class="token operator">=</span> <span class="token function">marinate</span><span class="token punctuation">(</span>meat<span class="token punctuation">:</span> <span class="token punctuation">.</span>chicken<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">let</span> soup <span class="token operator">=</span> <span class="token keyword">try</span> <span class="token keyword">await</span> <span class="token class-name">Soup</span><span class="token punctuation">(</span>meat<span class="token punctuation">:</span> meat<span class="token punctuation">,</span> ingredients<span class="token punctuation">:</span> choppedIngredients<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">return</span> <span class="token keyword">try</span> <span class="token keyword">await</span> stove<span class="token punctuation">.</span><span class="token function">cook</span><span class="token punctuation">(</span>pot<span class="token punctuation">:</span> pot<span class="token punctuation">,</span> soup<span class="token punctuation">:</span> soup<span class="token punctuation">,</span> duration<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">minutes</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h3 id="task-thread">Task Thread</h3>
<ul>
<li>아래의 example 1, 2 모두 doWork는 메인 쓰레드에서 호출된다</li>
<li>그래서 doWork의 초기 sync 코드는 메인 쓰레드에서 실행된다</li>
<li>하지만 async 코드를 만나면서 suspension &#x26; continuation이 이뤄진다</li>
<li>그래서 example 2는 메인 쓰레드가 아닌 다른 쓰레드에서 재개될수 있다</li>
<li>즉, example 2의 두번째 print 코드는 메인 쓰레드에서 재개된다는 보장이 없다</li>
<li>하지만 Swift 6.2 부터 이 경우에도 메인 쓰레드 재개를 보장할수 있다</li>
<li>non-isolated async 함수가 호출자의 actor를 따르도록 동작할 수 있기 때문이다 (<a href="https://www.avanderlee.com/concurrency/concurrent-explained-with-code-examples/">참고</a>)</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token comment">// example 1</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token class-name">Task</span> <span class="token punctuation">{</span> <span class="token attribute atrule">@MainActor</span> <span class="token keyword">in</span>
</span><span class="code-line">    <span class="token keyword">await</span> <span class="token function">doWork</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token attribute atrule">@MainActor</span>
</span><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">doWork</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"before await main? ->"</span></span><span class="token punctuation">,</span> <span class="token class-name">Thread</span><span class="token punctuation">.</span>isMainThread<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">await</span> <span class="token class-name">Task</span><span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">500_000_000</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"after await main? ->"</span></span><span class="token punctuation">,</span> <span class="token class-name">Thread</span><span class="token punctuation">.</span>isMainThread<span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token comment">// example 2</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token class-name">Task</span> <span class="token punctuation">{</span> <span class="token attribute atrule">@MainActor</span> <span class="token keyword">in</span>
</span><span class="code-line">    <span class="token keyword">await</span> <span class="token function">doWork</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">doWork</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"before await main? ->"</span></span><span class="token punctuation">,</span> <span class="token class-name">Thread</span><span class="token punctuation">.</span>isMainThread<span class="token punctuation">)</span> 
</span><span class="code-line">    <span class="token keyword">await</span> <span class="token class-name">Task</span><span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">500_000_000</span><span class="token punctuation">)</span> 
</span><span class="code-line">    <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"after await main? ->"</span></span><span class="token punctuation">,</span> <span class="token class-name">Thread</span><span class="token punctuation">.</span>isMainThread<span class="token punctuation">)</span>  
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h3 id="structured-task">Structured Task</h3>
<ul>
<li>Task가 부모-자식 관계의 계층적 구조를 형성하는것</li>
<li>자동으로 cancel, error, completion 등이 관리됨</li>
<li><code>async let</code> 혹은 <code>TaskGroup</code>이 이에 해당함</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">downloadUserData</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token keyword">throws</span> <span class="token operator">-></span> <span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token class-name">String</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">async</span> <span class="token keyword">let</span> profile <span class="token operator">=</span> <span class="token function">fetchUserProfile</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">async</span> <span class="token keyword">let</span> friends <span class="token operator">=</span> <span class="token function">fetchFriendsList</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">return</span> <span class="token keyword">try</span> <span class="token keyword">await</span> <span class="token punctuation">(</span>profile<span class="token punctuation">,</span> friends<span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">downloadImages</span><span class="token punctuation">(</span>urls<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token constant">URL</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token keyword">throws</span> <span class="token operator">-></span> <span class="token punctuation">[</span><span class="token class-name">Data</span><span class="token punctuation">]</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">try</span> <span class="token keyword">await</span> <span class="token function">withThrowingTaskGroup</span><span class="token punctuation">(</span>of<span class="token punctuation">:</span> <span class="token class-name">Data</span><span class="token punctuation">.</span><span class="token keyword">self</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> group <span class="token keyword">in</span>
</span><span class="code-line">        <span class="token keyword">var</span> images<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">Data</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">for</span> url <span class="token keyword">in</span> urls <span class="token punctuation">{</span>
</span><span class="code-line">            group<span class="token punctuation">.</span>addTask <span class="token punctuation">{</span>
</span><span class="code-line">                <span class="token keyword">let</span> <span class="token punctuation">(</span>data<span class="token punctuation">,</span> <span class="token omit keyword">_</span><span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token keyword">try</span> <span class="token keyword">await</span> <span class="token class-name">URLSession</span><span class="token punctuation">.</span>shared<span class="token punctuation">.</span><span class="token function">data</span><span class="token punctuation">(</span>from<span class="token punctuation">:</span> url<span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token keyword">return</span> data
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">for</span> <span class="token keyword">try</span> <span class="token keyword">await</span> image <span class="token keyword">in</span> group <span class="token punctuation">{</span>
</span><span class="code-line">            images<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>image<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">return</span> images
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h3 id="unstructured-task">Unstructured Task</h3>
<ul>
<li>명확한 계층 구조가 없거나, 단일 스코프의 제약을 벗어나는 생명주기를 가진 작업에 사용됨</li>
<li>동기 코드에서 비동기 작업을 시작해야 하거나, 한 메서드에서 시작해서 다른 메서드에서 취소해야 하는 작업에 사용함</li>
<li><code>Task</code> 혹은 <code>Task.detached</code>가 이에 해당함</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">Task</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> thumbnails <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">fetchThumbnails</span><span class="token punctuation">(</span><span class="token keyword">for</span><span class="token punctuation">:</span> ids<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token function">display</span><span class="token punctuation">(</span>thumbnails<span class="token punctuation">,</span> <span class="token keyword">in</span><span class="token punctuation">:</span> cell<span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token class-name">Task</span><span class="token punctuation">.</span><span class="token function">detached</span><span class="token punctuation">(</span>priority<span class="token punctuation">:</span> <span class="token punctuation">.</span>background<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token function">writeToLocalCache</span><span class="token punctuation">(</span>thumbnails<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li><code>Task</code>는 MainActor 혹은 부모 Task 등의 context 상태를 상속받아 실행됨</li>
<li><code>Task.detached</code>는 상속받는 context 없이 완전히 독립적으로 동작하는 태스크를 생성</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token attribute atrule">@MainActor</span>
</span><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">example</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token comment">// MainActor context를 상속 받음</span>
</span><span class="code-line">    <span class="token class-name">Task</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">for</span> i <span class="token keyword">in</span> <span class="token number">1</span><span class="token operator">...</span><span class="token number">10000</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"In Task 1: </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">i</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token comment">// MainActor context를 상속 받지 않음</span>
</span><span class="code-line">    <span class="token class-name">Task</span><span class="token punctuation">.</span>detached <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">for</span> i <span class="token keyword">in</span> <span class="token number">1</span><span class="token operator">...</span><span class="token number">10000</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"In Task 2: </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">i</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>아래 코드는 Unstructured Task를 딕셔너리에 담고 있다가, 불필요해지면 취소하는 예시</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token attribute atrule">@MainActor</span>
</span><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">MyDelegate</span><span class="token punctuation">:</span> <span class="token class-name">UICollectionViewDelegate</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> thumbnailTasks<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">IndexPath</span><span class="token punctuation">:</span> <span class="token class-name">Task</span><span class="token operator">&#x3C;</span><span class="token class-name">Void</span><span class="token punctuation">,</span> <span class="token class-name">Never</span><span class="token operator">></span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">:</span><span class="token punctuation">]</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">collectionView</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> view<span class="token punctuation">:</span> <span class="token class-name">UICollectionView</span><span class="token punctuation">,</span> willDisplay cell<span class="token punctuation">:</span> <span class="token class-name">UICollectionViewCell</span><span class="token punctuation">,</span> forItemAt item<span class="token punctuation">:</span> <span class="token class-name">IndexPath</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">let</span> ids <span class="token operator">=</span> <span class="token function">getThumbnailIDs</span><span class="token punctuation">(</span><span class="token keyword">for</span><span class="token punctuation">:</span> item<span class="token punctuation">)</span>
</span><span class="code-line">        thumbnailTasks<span class="token punctuation">[</span>item<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token class-name">Task</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">defer</span> <span class="token punctuation">{</span> thumbnailTasks<span class="token punctuation">[</span>item<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token nil constant">nil</span> <span class="token punctuation">}</span>
</span><span class="code-line">            <span class="token keyword">let</span> thumbnails <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">fetchThumbnails</span><span class="token punctuation">(</span><span class="token keyword">for</span><span class="token punctuation">:</span> ids<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token function">display</span><span class="token punctuation">(</span>thumbnails<span class="token punctuation">,</span> <span class="token keyword">in</span><span class="token punctuation">:</span> cell<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">collectionView</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> view<span class="token punctuation">:</span> <span class="token class-name">UICollectionView</span><span class="token punctuation">,</span> didEndDisplay cell<span class="token punctuation">:</span> <span class="token class-name">UICollectionViewCell</span><span class="token punctuation">,</span> forItemAt item<span class="token punctuation">:</span> <span class="token class-name">IndexPath</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        thumbnailTasks<span class="token punctuation">[</span>item<span class="token punctuation">]</span><span class="token operator">?</span><span class="token punctuation">.</span><span class="token function">cancel</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>아래 코드는 Detached Task를 통해 별도로 백그라운드에서 Task를 실행하는 코드</li>
<li>캐싱은 Main Thread에서 할 필요가 없고, 다른 썸네일이 fetch에 실패해도 캐싱은 안할 이유가 없음</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token attribute atrule">@MainActor</span>
</span><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">MyDelegate</span><span class="token punctuation">:</span> <span class="token class-name">UICollectionViewDelegate</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> thumbnailTasks<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">IndexPath</span><span class="token punctuation">:</span> <span class="token class-name">Task</span><span class="token operator">&#x3C;</span><span class="token class-name">Void</span><span class="token punctuation">,</span> <span class="token class-name">Never</span><span class="token operator">></span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">:</span><span class="token punctuation">]</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">collectionView</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> view<span class="token punctuation">:</span> <span class="token class-name">UICollectionView</span><span class="token punctuation">,</span> willDisplay cell<span class="token punctuation">:</span> <span class="token class-name">UICollectionViewCell</span><span class="token punctuation">,</span> forItemAt item<span class="token punctuation">:</span> <span class="token class-name">IndexPath</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">let</span> ids <span class="token operator">=</span> <span class="token function">getThumbnailIDs</span><span class="token punctuation">(</span><span class="token keyword">for</span><span class="token punctuation">:</span> item<span class="token punctuation">)</span>
</span><span class="code-line">        thumbnailTasks<span class="token punctuation">[</span>item<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token class-name">Task</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">defer</span> <span class="token punctuation">{</span> thumbnailTasks<span class="token punctuation">[</span>item<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token nil constant">nil</span> <span class="token punctuation">}</span>
</span><span class="code-line">            <span class="token keyword">let</span> thumbnails <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">fetchThumbnails</span><span class="token punctuation">(</span><span class="token keyword">for</span><span class="token punctuation">:</span> ids<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token class-name">Task</span><span class="token punctuation">.</span><span class="token function">detached</span><span class="token punctuation">(</span>priority<span class="token punctuation">:</span> <span class="token punctuation">.</span>background<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">                <span class="token function">writeToLocalCache</span><span class="token punctuation">(</span>thumbnails<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">            <span class="token function">display</span><span class="token punctuation">(</span>thumbnails<span class="token punctuation">,</span> <span class="token keyword">in</span><span class="token punctuation">:</span> cell<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h3 id="taskgroup">TaskGroup</h3>
<ul>
<li>TaskGroup으로 동적으로 병렬 작업을 합쳐 모든 작업이 완료되면 결과를 반환 받을 수 있음</li>
<li><code>withTaskGroup</code>, <code>withThrowingTaskGroup</code></li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">let</span> images <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">withTaskGroup</span><span class="token punctuation">(</span>of<span class="token punctuation">:</span> <span class="token class-name">UIImage</span><span class="token punctuation">.</span><span class="token keyword">self</span><span class="token punctuation">,</span> returning<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">UIImage</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token keyword">self</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> taskGroup <span class="token keyword">in</span>
</span><span class="code-line">    <span class="token keyword">let</span> photoURLs <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">loadPhotoUrls</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">for</span> photoURL <span class="token keyword">in</span> photoURLs <span class="token punctuation">{</span>
</span><span class="code-line">        taskGroup<span class="token punctuation">.</span>addTask <span class="token punctuation">{</span> <span class="token keyword">await</span> <span class="token function">downloadPhoto</span><span class="token punctuation">(</span>url<span class="token punctuation">:</span> photoURL<span class="token punctuation">)</span> <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">var</span> images <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token class-name">UIImage</span><span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">for</span> <span class="token keyword">await</span> result <span class="token keyword">in</span> taskGroup <span class="token punctuation">{</span>
</span><span class="code-line">        images<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>result<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">return</span> images
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h3 id="taskgroup-vs-array-of-tasks">TaskGroup vs Array of Tasks</h3>
<ul>
<li><code>TaskGroup</code>은 Structured Concurrency 제공</li>
<li>모든 자식 작업이 완료될 때까지 그룹이 대기함</li>
<li><code>group.addTask</code>로 생성된 자식 작업은 매우 가벼움</li>
<li>메모리와 스케줄링 측면에서 효율적임</li>
<li>완료 순서대로 결과를 수집할 수 있음</li>
<li><code>for await</code> 구문으로 효율적으로 결과를 처리함</li>
<li>동시 실행 작업 수를 쉽게 제한할 수 있음</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token function">withTaskGroup</span><span class="token punctuation">(</span>of<span class="token punctuation">:</span> <span class="token class-name">T</span><span class="token punctuation">.</span><span class="token keyword">self</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> group <span class="token keyword">in</span>
</span><span class="code-line">    <span class="token keyword">for</span> t <span class="token keyword">in</span> tasks <span class="token punctuation">{</span>
</span><span class="code-line">        group<span class="token punctuation">.</span>addTask <span class="token punctuation">{</span> <span class="token keyword">await</span> t <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>Array of Tasks는 Unstructured Concurrency</li>
<li>작업들이 독립적으로 실행됨</li>
<li>모든 작업 완료를 보장하기 어려움</li>
<li>더 많은 메모리와 스케줄링 리소스를 사용함</li>
<li>결과 수집을 위한 추가 동기화 메커니즘이 필요함</li>
<li>모든 작업이 한 번에 스케줄러에 전달됨</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">for</span> work <span class="token keyword">in</span> works <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">Task</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">let</span> t <span class="token operator">=</span> <span class="token keyword">await</span> work<span class="token punctuation">.</span><span class="token function">work</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token keyword">await</span> <span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>t<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h3 id="core-vs-thread-vs-task">Core vs Thread vs Task</h3>
<p><strong>Core</strong></p>
<ul>
<li>물리적인 하드웨어 처리 장치로, CPU 내부에 있는 독립적인 연산 유닛</li>
<li>멀티코어 프로세서는 여러 개의 코어를 가지고 있어 진정한 병렬 처리가 가능</li>
<li>코어 수는 하드웨어에 의해 고정되며, 소프트웨어로 늘릴 수 없음</li>
</ul>
<p><strong>Thread</strong></p>
<ul>
<li>운영체제가 관리하는 실행 단위로, 프로세스 내에서 독립적으로 실행되는 흐름</li>
<li>각 스레드는 자체적인 스택, 레지스터 상태, 프로그램 카운터를 가지지만 프로세스의 메모리 공간은 공유함</li>
<li>커널 스레드는 운영체제 스케줄러가 직접 관리하며, 코어에 할당되어 실행됨</li>
<li>컨텍스트 스위칭을 통해 여러 스레드가 하나의 코어를 시분할하여 사용 가능</li>
<li>생성과 전환에 상당한 오버헤드가 있음</li>
</ul>
<p><strong>Task</strong></p>
<ul>
<li>Swift Concurrency에서 사용하는 경량 실행 단위</li>
<li>커널이 직접 관리하지 않고, 런타임 라이브러리가 관리하는 사용자 수준의 실행 단위</li>
<li>실제 OS 스레드 위에서 협력적으로 실행되며, await 지점에서 다른 Task로 전환 가능</li>
<li>스레드보다 훨씬 적은 메모리를 사용하고 전환 비용이 낮음</li>
<li>Task로 thread explosion을 방지하고 컨텍스트 스위칭를 최소화해 성능 개선 가능</li>
</ul>
<h3 id="task-warning">Task Warning</h3>
<ul>
<li>Concurrency를 사용하는 것은 추가적인 리소스 비용이 듬</li>
<li>Concurrency의 이점이 리소스 비용을 넘어설때만 사용하는 것을 추천</li>
<li>await 이전의 코드를 실행한 쓰레드가 계속해서 continuation 코드를 실행할 것이라는 보장은 없음</li>
<li>작업을 자발적으로 스케줄링에서 제외함으로써 atomic을 깨뜨림</li>
<li>await를 사용하는 동안 Lock을 유지할 수 없음</li>
<li>await를 지나면 쓰레드 전용 데이터가 유지되지 않음</li>
</ul>
<h2 id="actor">actor</h2>
<h3 id="data-race">Data Race</h3>
<ul>
<li>여러 Task가 동시에 일을 하고 있지만 동일한 객체를 참조하기 때문에 발생</li>
<li>동일한 객체에 동시에 접근해서 crash가 나거나, 예상밖의 순서로 작업이 진행됨</li>
</ul>
<h3 id="actor-1">Actor</h3>
<ul>
<li>공유되는 데이터에 접근해야 하는 여러 Task를 조정하기 위해 존재</li>
<li>데이터를 isolate 하고, 한 번에 하나의 Task만 내부 상태를 변경하도록 허용</li>
<li>동시 변경으로 인한 Data Race를 피함</li>
<li>Actor는 mutable state를 shared 한다는 목적이기 때문에 class와 같은 reference 타입</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">actor</span> <span class="token class-name">SharedWallet</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> name <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"공유 지갑"</span></span>
</span><span class="code-line">    <span class="token keyword">var</span> amount <span class="token operator">=</span> <span class="token number">0</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">init</span><span class="token punctuation">(</span>amount<span class="token punctuation">:</span> <span class="token class-name">Int</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">self</span><span class="token punctuation">.</span>amount <span class="token operator">=</span> amount
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">spendMoney</span><span class="token punctuation">(</span>ammount<span class="token punctuation">:</span> <span class="token class-name">Int</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">self</span><span class="token punctuation">.</span>amount <span class="token operator">-=</span> ammount <span class="token comment">// 1</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token class-name">Task</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> wallet <span class="token operator">=</span> <span class="token class-name">SharedWallet</span><span class="token punctuation">(</span>amount<span class="token punctuation">:</span> <span class="token number">10000</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">let</span> name <span class="token operator">=</span> wallet<span class="token punctuation">.</span>name <span class="token comment">// 2</span>
</span><span class="code-line">    <span class="token keyword">let</span> amount <span class="token operator">=</span> <span class="token keyword">await</span> wallet<span class="token punctuation">.</span>amount <span class="token comment">// 3</span>
</span><span class="code-line">    <span class="token keyword">await</span> wallet<span class="token punctuation">.</span><span class="token function">spendMoney</span><span class="token punctuation">(</span>ammount<span class="token punctuation">:</span> <span class="token number">100</span><span class="token punctuation">)</span> <span class="token comment">// 4</span>
</span><span class="code-line">    <span class="token keyword">await</span> wallet<span class="token punctuation">.</span>amount <span class="token operator">+=</span> <span class="token number">100</span> <span class="token comment">// 5</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>1: actor 내부에서 변수 접근시 await 불필요</li>
<li>2: 상수는 변경 불가능하기 때문에 actor 외부에서도 바로 접근 가능</li>
<li>3: actor 외부에서 변수 접근시 await 필요</li>
<li>4: actor 외부에서 메서드 호출시 await 필요</li>
<li>5: 컴파일 에러, actor 외부에서 actor 내부의 변수를 변경할 수 없음</li>
</ul>
<h3 id="mainactor">MainActor</h3>
<ul>
<li>MainActor는 main thread를 나타내는 특별한 global actor</li>
<li>await이 사용되었다는 것은, 해당 thread에서 다른 코드가 실행될 수 있도록 실행 중인 함수가 중지될 수 있다는 의미</li>
<li>따라서 메인 스레드에서 한꺼번에 작업이 이뤄지길 원하는 경우에는 관련 함수를 run block에 그룹화 해야함</li>
<li>그래야 해당 함수들 사이에는 일시 중단 없이 호출이 실행되도록 할 수 있음</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">await</span> <span class="token class-name">MainActor</span><span class="token punctuation">.</span>run <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token comment">// UI 관련 코드 1</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line"><span class="token keyword">await</span> <span class="token class-name">MainActor</span><span class="token punctuation">.</span>run <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token comment">// UI 관련 코드 2</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">await</span> <span class="token class-name">MainActor</span><span class="token punctuation">.</span>run <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token comment">// UI 관련 코드 1</span>
</span><span class="code-line">    <span class="token comment">// UI 관련 코드 2</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>Main Thread에서 실행되어야 하는 코드를 @MainActor 표시로 타입, 함수, 클로저, 프로퍼티 등에 적용 가능</li>
<li>class, struct, enum 같은 타입에 붙으면, 내부에 있는 모든 property와 method가 isolated 되고 main thread에서 동작</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token attribute atrule">@MainActor</span>
</span><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">Example</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> value<span class="token punctuation">:</span> <span class="token class-name">Int</span> <span class="token operator">=</span> <span class="token number">0</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">updateValue</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Running on main thread? </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation"><span class="token class-name">Thread</span><span class="token punctuation">.</span>isMainThread</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        value <span class="token operator">+=</span> <span class="token number">1</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">actor</span> <span class="token class-name">SomeActor</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> id <span class="token operator">=</span> <span class="token function">UUID</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>uuidString
</span><span class="code-line">    <span class="token attribute atrule">@MainActor</span> <span class="token keyword">var</span> myProperty<span class="token punctuation">:</span> <span class="token class-name">String</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">init</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> myProperty<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">self</span><span class="token punctuation">.</span>myProperty <span class="token operator">=</span> myProperty
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token attribute atrule">@MainActor</span> <span class="token keyword">func</span> <span class="token function-definition function">changeMyProperty</span><span class="token punctuation">(</span>to newValue<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">self</span><span class="token punctuation">.</span>myProperty <span class="token operator">=</span> newValue
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">changePropertyToName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">Task</span> <span class="token punctuation">{</span> <span class="token attribute atrule">@MainActor</span> <span class="token keyword">in</span>
</span><span class="code-line">            myProperty <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"hohyeon"</span></span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h3 id="globalactor">GlobalActor</h3>
<ul>
<li>MainActor 외에도 커스텀 글로벌 액터를 정의할 수 있음</li>
<li>특정 리소스에 대한 전역적인 동시성 제어가 필요할 때 유용함</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token comment">// 정의</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token attribute atrule">@globalActor</span>
</span><span class="code-line"><span class="token keyword">actor</span> <span class="token class-name">DatabaseActor</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">static</span> <span class="token keyword">let</span> shared <span class="token operator">=</span> <span class="token class-name">DatabaseActor</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token comment">// 함수에 적용</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token attribute atrule">@DatabaseActor</span>
</span><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">saveUserData</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> user<span class="token punctuation">:</span> <span class="token class-name">User</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Saving user: </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">user<span class="token punctuation">.</span>name</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token comment">// 클래스에 적용</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token attribute atrule">@DatabaseActor</span>
</span><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">UserRepository</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">var</span> users<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">String</span><span class="token punctuation">:</span> <span class="token class-name">User</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">:</span><span class="token punctuation">]</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">save</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> user<span class="token punctuation">:</span> <span class="token class-name">User</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        users<span class="token punctuation">[</span>user<span class="token punctuation">.</span>id<span class="token punctuation">]</span> <span class="token operator">=</span> user
</span><span class="code-line">        <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"User </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">user<span class="token punctuation">.</span>name</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string"> saved"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token comment">// 프로퍼티에 적용</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">AppState</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token attribute atrule">@DatabaseActor</span>
</span><span class="code-line">    <span class="token keyword">var</span> userCache<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">String</span><span class="token punctuation">:</span> <span class="token class-name">User</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">:</span><span class="token punctuation">]</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h3 id="sendable">Sendable</h3>
<ul>
<li>Sendable 프로토콜을 준수하는 타입은 동시성 컨텍스트 간에 값을 공유할 수 있음</li>
<li>Value 타입: struct나 enum은, 모든 저장 프로퍼티나 연관 값이 Sendable이면 Sendable</li>
<li>Actor 타입: 모든 actor는 암시적으로 Sendable</li>
<li>Class 타입: final 키워드로 표시, Immutable 프로퍼티만 포함, @MainActor로 표시된 클래스</li>
<li>함수 및 클로저: @Sendable로 표시된 함수나 클로저도 Sendable, 캡처하는 모든 값이 Sendable이어야 함</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token comment">// Sendable Class</span>
</span><span class="code-line"><span class="token keyword">final</span> <span class="token keyword">class</span> <span class="token class-name">User</span><span class="token punctuation">:</span> <span class="token class-name">Sendable</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> id<span class="token punctuation">:</span> <span class="token class-name">Int</span>
</span><span class="code-line">    <span class="token keyword">let</span> name<span class="token punctuation">:</span> <span class="token class-name">String</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">init</span><span class="token punctuation">(</span>id<span class="token punctuation">:</span> <span class="token class-name">Int</span><span class="token punctuation">,</span> name<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">self</span><span class="token punctuation">.</span>id <span class="token operator">=</span> id
</span><span class="code-line">        <span class="token keyword">self</span><span class="token punctuation">.</span>name <span class="token operator">=</span> name
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token comment">// Sendable closure</span>
</span><span class="code-line"><span class="token keyword">actor</span> <span class="token class-name">Calculator</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">calculate</span><span class="token punctuation">(</span>operation<span class="token punctuation">:</span> <span class="token attribute atrule">@Sendable</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Int</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Int</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">return</span> <span class="token function">operation</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h3 id="actor-reentrancy">actor reentrancy</h3>
<p><strong>원인</strong></p>
<ul>
<li>actor가 race condition를 완전히 방지하지는 못함</li>
<li>actor 메서드가 await를 만나는 순간 다른 Task가 해당 actor의 메서드를 실행할 수 있음</li>
<li>deadlock을 방지하고 성능을 향상하기 위한 설계지만</li>
<li>이는 actor의 isolation을 일시적으로 해제하여 문제 발생 가능</li>
</ul>
<p><strong>문제</strong></p>
<ul>
<li>데이터 일관성 훼손: await 하는 동안 actor의 상태가 변경될 수 있음</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">actor</span> <span class="token class-name">BankAccount</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">var</span> balance<span class="token punctuation">:</span> <span class="token class-name">Int</span> <span class="token operator">=</span> <span class="token number">1000</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">withdraw</span><span class="token punctuation">(</span>amount<span class="token punctuation">:</span> <span class="token class-name">Int</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token operator">-></span> <span class="token class-name">Bool</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"인출 시작: </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">amount</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">, 현재 잔액: </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">balance</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">guard</span> balance <span class="token operator">>=</span> amount <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"잔액 부족"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token keyword">return</span> <span class="token boolean">false</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">await</span> <span class="token function">validateWithBank</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// ⚠️ 여기서 reentrancy 발생!</span>
</span><span class="code-line">        
</span><span class="code-line">        balance <span class="token operator">-=</span> amount
</span><span class="code-line">        <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"인출 완료: </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">amount</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">, 남은 잔액: </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">balance</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token keyword">return</span> <span class="token boolean">true</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">func</span> <span class="token function-definition function">validateWithBank</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">try</span><span class="token operator">?</span> <span class="token keyword">await</span> <span class="token class-name">Task</span><span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span>nanoseconds<span class="token punctuation">:</span> <span class="token number">1_000_000_000</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token comment">// 문제 발생 시나리오</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">let</span> account <span class="token operator">=</span> <span class="token class-name">BankAccount</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token class-name">Task</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">await</span> account<span class="token punctuation">.</span><span class="token function">withdraw</span><span class="token punctuation">(</span>amount<span class="token punctuation">:</span> <span class="token number">800</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line"><span class="token class-name">Task</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">await</span> account<span class="token punctuation">.</span><span class="token function">withdraw</span><span class="token punctuation">(</span>amount<span class="token punctuation">:</span> <span class="token number">800</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>순서 보장 문제: 비즈니스 로직이 의도한 순서대로 실행되지 않을 수 있음</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">actor</span> <span class="token class-name">OrderProcessor</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">var</span> orders<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">String</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">var</span> isProcessing <span class="token operator">=</span> <span class="token boolean">false</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">processOrder</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> order<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"주문 접수: </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">order</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        orders<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>order<span class="token punctuation">)</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">if</span> <span class="token operator">!</span>isProcessing <span class="token punctuation">{</span>
</span><span class="code-line">            isProcessing <span class="token operator">=</span> <span class="token boolean">true</span>
</span><span class="code-line">            <span class="token keyword">await</span> <span class="token function">fulfillOrders</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token comment">// ⚠️ reentrancy 지점</span>
</span><span class="code-line">            isProcessing <span class="token operator">=</span> <span class="token boolean">false</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">func</span> <span class="token function-definition function">fulfillOrders</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">while</span> <span class="token operator">!</span>orders<span class="token punctuation">.</span>isEmpty <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">let</span> order <span class="token operator">=</span> orders<span class="token punctuation">.</span><span class="token function">removeFirst</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"처리 시작: </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">order</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">            
</span><span class="code-line">            <span class="token keyword">await</span> <span class="token function">processWithExternalService</span><span class="token punctuation">(</span>order<span class="token punctuation">)</span> <span class="token comment">// ⚠️ 또 다른 reentrancy 지점</span>
</span><span class="code-line">            
</span><span class="code-line">            <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"처리 완료: </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">order</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">func</span> <span class="token function-definition function">processWithExternalService</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> order<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">try</span><span class="token operator">?</span> <span class="token keyword">await</span> <span class="token class-name">Task</span><span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span>nanoseconds<span class="token punctuation">:</span> <span class="token number">500_000_000</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token comment">// 문제 발생 시나리오</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">let</span> processor <span class="token operator">=</span> <span class="token class-name">OrderProcessor</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token class-name">Task</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">await</span> processor<span class="token punctuation">.</span><span class="token function">processOrder</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"A"</span></span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line"><span class="token class-name">Task</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">await</span> processor<span class="token punctuation">.</span><span class="token function">processOrder</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"B"</span></span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><strong>해결</strong></p>
<ul>
<li>Actor 내부에 await 최소화</li>
<li>플래그를 사용던지, 고려해서 코드 작성</li>
<li>global actor 사용</li>
</ul>
<h2 id="others">others</h2>
<h3 id="continuation">Continuation</h3>
<ul>
<li>async한 메서드를 호출할 때 thread의 제어권을 포기한 상태를 suspended 상태라고 함</li>
<li>suspended 상태 이후 다시 제어권을 돌려 받았을때 어디서부터 실행할지를 아는것이 필요함</li>
<li>suspension point에서 실행하는데 필요한 context를 heap에 저장해 제어권을 돌려받았을때 어디서 실행할지 알수있음</li>
<li>이것을 continuation이라고 부름</li>
</ul>
<p><img src="/images/swift-concurrency-3.png" alt="swift-concurrency"></p>
<ul>
<li><code>withCheckedContinuation</code>, <code>withCheckedThrowingContinuation</code></li>
<li>클로저 기반의 completion handler 비동기 처리를 async/await 형태로 바꿀때 자주 사용</li>
<li>continuation이 두 번 이상 resume을 호출하면 안됨</li>
<li>resume을 호출하지 않아도 Task가 무기한 일시 중단된 상태로 유지</li>
<li>즉, resume은 정확히 한번 호출되어야 함</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">fetch</span><span class="token punctuation">(</span>completion<span class="token punctuation">:</span> <span class="token attribute atrule">@escaping</span> <span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token class-name">String</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Void</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> url <span class="token operator">=</span> <span class="token function">URL</span><span class="token punctuation">(</span>string<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"https://www.hohyeonmoon.com"</span></span><span class="token punctuation">)</span><span class="token operator">!</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token class-name">URLSession</span><span class="token punctuation">.</span>shared<span class="token punctuation">.</span><span class="token function">dataTask</span><span class="token punctuation">(</span>with<span class="token punctuation">:</span> url<span class="token punctuation">)</span> <span class="token punctuation">{</span> data<span class="token punctuation">,</span> <span class="token omit keyword">_</span><span class="token punctuation">,</span> <span class="token omit keyword">_</span> <span class="token keyword">in</span>
</span><span class="code-line">        <span class="token keyword">if</span> <span class="token keyword">let</span> data <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">if</span> <span class="token keyword">let</span> something <span class="token operator">=</span> <span class="token keyword">try</span><span class="token operator">?</span> <span class="token class-name">JSONDecoder</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">decode</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token class-name">String</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token keyword">self</span><span class="token punctuation">,</span> from<span class="token punctuation">:</span> data<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">                <span class="token function">completion</span><span class="token punctuation">(</span>something<span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token keyword">return</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token function">completion</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span><span class="token punctuation">.</span><span class="token function">resume</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">fetch</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token operator">-></span> <span class="token punctuation">[</span><span class="token class-name">String</span><span class="token punctuation">]</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">await</span> withCheckedContinuation <span class="token punctuation">{</span> continuation <span class="token keyword">in</span>
</span><span class="code-line">        fetch <span class="token punctuation">{</span> something <span class="token keyword">in</span>
</span><span class="code-line">            continuation<span class="token punctuation">.</span><span class="token function">resume</span><span class="token punctuation">(</span>returning<span class="token punctuation">:</span> something<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">let</span> something <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>delegate 패턴에서 async를 사용할때도 <code>withCheckedContinuation</code>을 사용</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">ViewController</span><span class="token punctuation">:</span> <span class="token class-name">UIViewController</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">var</span> activeContinuation<span class="token punctuation">:</span> <span class="token class-name">CheckedContinuation</span><span class="token operator">&#x3C;</span><span class="token punctuation">[</span><span class="token class-name">Post</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token class-name">Error</span><span class="token operator">>?</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">sharedPostsFromPeer</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token keyword">throws</span> <span class="token operator">-></span> <span class="token punctuation">[</span><span class="token class-name">Post</span><span class="token punctuation">]</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">try</span> <span class="token keyword">await</span> withCheckedThrowingContinuation <span class="token punctuation">{</span> continuation <span class="token keyword">in</span>
</span><span class="code-line">            <span class="token keyword">self</span><span class="token punctuation">.</span>activeContinuation <span class="token operator">=</span> continuation
</span><span class="code-line">            <span class="token keyword">self</span><span class="token punctuation">.</span>peerManager<span class="token punctuation">.</span><span class="token function">syncSharedPosts</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">ViewController</span><span class="token punctuation">:</span> <span class="token class-name">PeerSyncDelegate</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">peerManager</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> manager<span class="token punctuation">:</span> <span class="token class-name">PeerManager</span><span class="token punctuation">,</span> received posts<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">Post</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">self</span><span class="token punctuation">.</span>activeContinuation<span class="token operator">?</span><span class="token punctuation">.</span><span class="token function">resume</span><span class="token punctuation">(</span>returning<span class="token punctuation">:</span> posts<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token keyword">self</span><span class="token punctuation">.</span>activeContinuation <span class="token operator">=</span> <span class="token nil constant">nil</span> <span class="token comment">// 중복 resume 호출 방지</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">peerManager</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> manager<span class="token punctuation">:</span> <span class="token class-name">PeerManager</span><span class="token punctuation">,</span> hadError error<span class="token punctuation">:</span> <span class="token class-name">Error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">self</span><span class="token punctuation">.</span>activeContinuation<span class="token operator">?</span><span class="token punctuation">.</span><span class="token function">resume</span><span class="token punctuation">(</span>throwing<span class="token punctuation">:</span> error<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token keyword">self</span><span class="token punctuation">.</span>activeContinuation <span class="token operator">=</span> <span class="token nil constant">nil</span> <span class="token comment">// 중복 resume 호출 방지</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h3 id="asyncstream">AsyncStream</h3>
<ul>
<li>Swift Concurrency를 데이터 스트림 형태에서 사용할수 있게해줌</li>
<li>yield로 스트림에 element를 제공하고, finish로 정상적으로 스트림을 종료</li>
<li><code>AsyncStream</code>, <code>AsyncThrowingStream</code></li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">QuakeMonitor</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> quakeHandler<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token class-name">Quake</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Void</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">startMonitoring</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">stopMonitoring</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">let</span> quakes <span class="token operator">=</span> <span class="token class-name">AsyncStream</span><span class="token punctuation">(</span><span class="token class-name">Quake</span><span class="token punctuation">.</span><span class="token keyword">self</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> continuation <span class="token keyword">in</span>
</span><span class="code-line">    <span class="token keyword">let</span> monitor <span class="token operator">=</span> <span class="token class-name">QuakeMonitor</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line">    monitor<span class="token punctuation">.</span>quakeHandler <span class="token operator">=</span> <span class="token punctuation">{</span> quake <span class="token keyword">in</span>
</span><span class="code-line">        continuation<span class="token punctuation">.</span><span class="token function">yield</span><span class="token punctuation">(</span>quake<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    continuation<span class="token punctuation">.</span>onTermination <span class="token operator">=</span> <span class="token punctuation">{</span> termination <span class="token keyword">in</span>
</span><span class="code-line">        <span class="token keyword">switch</span> termination <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">case</span> <span class="token punctuation">.</span>finished<span class="token punctuation">:</span>
</span><span class="code-line">            <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"finished"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token keyword">case</span> <span class="token punctuation">.</span>cancelled<span class="token punctuation">:</span>
</span><span class="code-line">            <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"cancelled"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        
</span><span class="code-line">        monitor<span class="token punctuation">.</span><span class="token function">stopMonitoring</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    monitor<span class="token punctuation">.</span><span class="token function">startMonitoring</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">let</span> significantQuakes <span class="token operator">=</span> quakes<span class="token punctuation">.</span>filter <span class="token punctuation">{</span> quake <span class="token keyword">in</span>
</span><span class="code-line">    quake<span class="token punctuation">.</span>magnitude <span class="token operator">></span> <span class="token number">3</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">for</span> <span class="token keyword">await</span> quake <span class="token keyword">in</span> significantQuakes <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token operator">...</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="참고">참고</h2>
<ul>
<li><a href="https://developer.apple.com/videos/play/wwdc2021/10132/">Meet async/await in Swift</a></li>
<li><a href="https://developer.apple.com/videos/play/wwdc2021/10134">Explore structured concurrency in Swift</a></li>
<li><a href="https://developer.apple.com/videos/play/wwdc2021/10254">Swift concurrency: Behind the scenes</a></li>
<li><a href="https://developer.apple.com/documentation/swift/updating_an_app_to_use_swift_concurrency">Updating an App to Use Swift Concurrency</a></li>
<li><a href="https://developer.apple.com/documentation/swift/asyncstream">AsyncStream Apple document</a></li>
<li><a href="https://forums.swift.org/t/taskgroup-vs-an-array-of-tasks/53931">TaskGroup vs Array of Tasks</a></li>
<li><a href="https://www.reddit.com/r/swift/comments/wm3get/whats_the_difference_between_a_thread_and_a_task/">Difference between a Thread and a Task</a></li>
<li><a href="https://www.avanderlee.com/concurrency/task-groups-in-swift/">Task Groups in Swift explained</a></li>
<li><a href="https://www.avanderlee.com/concurrency/concurrent-explained-with-code-examples/">concurrent explained with code examples</a></li>
<li><a href="https://www.hackingwithswift.com/quick-start/concurrency/how-to-use-continuations-to-convert-completion-handlers-into-async-functions">Convert closures into async functions</a></li>
<li><a href="https://engineering.linecorp.com/ko/blog/about-swift-concurrency">Swift Concurrency에 대해서</a></li>
<li><a href="https://engineering.linecorp.com/ko/blog/about-swift-concurrency-performance">Swift Concurrency 성능 조사</a></li>
<li><a href="https://zeddios.tistory.com/1341">Swift AsyncStream/AsyncThrowingStream</a></li>
<li><a href="https://sujinnaljin.medium.com/ios-%EC%B0%A8%EA%B7%BC%EC%B0%A8%EA%B7%BC-%EC%8B%9C%EC%9E%91%ED%95%98%EB%8A%94-gcd-grand-dispatch-queue-1-397db16d0305">차근차근 시작하는 GCD</a></li>
<li><a href="https://sujinnaljin.medium.com/swift-async-await-concurrency-bd7bcf34e26f">Swift async/await</a></li>
<li><a href="https://sujinnaljin.medium.com/swift-actor-%EB%BF%8C%EC%8B%9C%EA%B8%B0-249aee2b732d">Swift Actor 뿌시기</a></li>
</ul>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swiftui-mv-pattern</guid>
      <title>SwiftUI MV 패턴</title>
      <description>SwiftUI에 어울리는 ViewModel 없는 확장 가능한 MV 패턴</description>
      <link>https://www.hohyeonmoon.com/blog/swiftui-mv-pattern</link>
      <pubDate>Fri, 06 Jun 2025 22:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<h2 id="mvvm">MVVM</h2>
<h3 id="사용-배경">사용 배경</h3>
<ul>
<li>많은 iOS 개발자는 SwiftUI에 UIKit에서의 경험과 습관을 가져왔다.</li>
<li>UIKit에서 MVVM이 유용했기 때문에, SwiftUI에도 당연하게 사용되기 시작했다.</li>
<li>게다가 ObservableObject 혹은 Observable Macro는 이를 더욱 쉽도록 해줬다.</li>
<li>하지만 SwiftUI는 UIKit과는 다르게 설계된 프레임워크이다.</li>
</ul>
<h3 id="문제점">문제점</h3>
<p><img src="/images/swiftui-mv-pattern-1.png" alt="swiftui-mv-pattern"></p>
<p>설계 원칙</p>
<ul>
<li>SwiftUI의 View는 가벼운 구조체로 설계되어 자주 재생성되지만, ViewModel은 이런 근본적인 설계 원칙과 충돌한다.</li>
<li>SwiftUI에서 제공하는 @State, @Environment와 같은 프로퍼티 래퍼 활용을 포기하게 된다.</li>
<li>SwiftData와 같은 SwiftUI와 함께 사용하기 위해 만들어진 다른 프레임워크를 SwiftUI와 함께 사용해보면, SwiftUI가 ViewModel 개념으로 사용하기 힘들다는 것을 더욱 절실하게 느낄 수 있다.</li>
</ul>
<p>복잡도 생성</p>
<ul>
<li>Apple이 의도한 Single Source of Truth 철학을 무시하고 불필요한 간접층을 추가 하는것이다.</li>
<li>각 화면마다 ViewModel 생성으로 불필요한 Source of Truth를 추가한다.</li>
<li>ViewModel의 주요 역할인 바인딩은 SwiftUI 프로퍼티 래퍼로 View내에서 직접 처리가 가능하다.</li>
</ul>
<p>테스팅</p>
<ul>
<li>SwiftUI의 선언적 특성을 살린 단순한 View 테스팅 방식을 포기해야 한다.</li>
<li>View는 최대한 단순해야 하는데 ViewModel 테스트를 위해 불필요한 복잡성이 추가된다.</li>
<li>실제 테스트해야 할 Business Logic과 Service에 집중하지 못하게 된다.</li>
</ul>
<h2 id="mv">MV</h2>
<p><img src="/images/swiftui-mv-pattern-2.png" alt="swiftui-mv-pattern"></p>
<p>MVVM에서 ViewModel을 제거하면 MV 형태가 된다. Swift Package를 통해 크게 Model과 View로 나눌수 있고, 각 Package의 레이어는 Library로 다시 분리할수 있다.</p>
<ul>
<li>Models: Data structure와 Business logic</li>
<li>Services: Auth, Network, Router 등 (Observable 할 수 있고, Environment로 주입)</li>
<li>Views: 온전히 State를 나타내며 사용자 인터랙션 관리</li>
</ul>
<h2 id="views">Views</h2>
<h3 id="state-expression">State Expression</h3>
<ul>
<li>View는 State를 나타내기 위한 수단으로 사용한다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">FeedView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token attribute atrule">@Environment</span><span class="token punctuation">(</span><span class="token class-name">Client</span><span class="token punctuation">.</span><span class="token keyword">self</span><span class="token punctuation">)</span> <span class="token keyword">private</span> <span class="token keyword">var</span> client
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">enum</span> <span class="token class-name">ViewState</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">case</span> loading
</span><span class="code-line">        <span class="token keyword">case</span> <span class="token function">error</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token keyword">case</span> <span class="token function">loaded</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token class-name">Post</span><span class="token punctuation">]</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token attribute atrule">@State</span> <span class="token keyword">private</span> <span class="token keyword">var</span> viewState<span class="token punctuation">:</span> <span class="token class-name">ViewState</span> <span class="token operator">=</span> <span class="token punctuation">.</span>loading
</span><span class="code-line">    <span class="token attribute atrule">@State</span> <span class="token keyword">private</span> <span class="token keyword">var</span> isRefreshing <span class="token operator">=</span> <span class="token boolean">false</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">NavigationStack</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token class-name">List</span> <span class="token punctuation">{</span>
</span><span class="code-line">                <span class="token keyword">switch</span> viewState <span class="token punctuation">{</span>
</span><span class="code-line">                <span class="token keyword">case</span> <span class="token punctuation">.</span>loading<span class="token punctuation">:</span>
</span><span class="code-line">                    <span class="token class-name">ProgressView</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Loading feed..."</span></span><span class="token punctuation">)</span>
</span><span class="code-line">                        <span class="token punctuation">.</span><span class="token function">frame</span><span class="token punctuation">(</span>maxWidth<span class="token punctuation">:</span> <span class="token punctuation">.</span>infinity<span class="token punctuation">)</span>
</span><span class="code-line">                        <span class="token punctuation">.</span><span class="token function">listRowSeparator</span><span class="token punctuation">(</span><span class="token punctuation">.</span>hidden<span class="token punctuation">)</span>
</span><span class="code-line">                        
</span><span class="code-line">                <span class="token keyword">case</span> <span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token keyword">let</span> message<span class="token punctuation">)</span><span class="token punctuation">:</span>
</span><span class="code-line">                    <span class="token class-name">ErrorStateView</span><span class="token punctuation">(</span>
</span><span class="code-line">                        message<span class="token punctuation">:</span> message<span class="token punctuation">,</span>
</span><span class="code-line">                        retryAction<span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token keyword">await</span> <span class="token function">loadFeed</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span>
</span><span class="code-line">                    <span class="token punctuation">)</span>
</span><span class="code-line">                    <span class="token punctuation">.</span><span class="token function">listRowSeparator</span><span class="token punctuation">(</span><span class="token punctuation">.</span>hidden<span class="token punctuation">)</span>
</span><span class="code-line">                    
</span><span class="code-line">                <span class="token keyword">case</span> <span class="token punctuation">.</span><span class="token function">loaded</span><span class="token punctuation">(</span><span class="token keyword">let</span> posts<span class="token punctuation">)</span><span class="token punctuation">:</span>
</span><span class="code-line">                    <span class="token class-name">ForEach</span><span class="token punctuation">(</span>posts<span class="token punctuation">)</span> <span class="token punctuation">{</span> post <span class="token keyword">in</span>
</span><span class="code-line">                        <span class="token class-name">PostRowView</span><span class="token punctuation">(</span>post<span class="token punctuation">:</span> post<span class="token punctuation">)</span>
</span><span class="code-line">                            <span class="token punctuation">.</span><span class="token function">listRowInsets</span><span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token keyword">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">                    <span class="token punctuation">}</span>
</span><span class="code-line">                <span class="token punctuation">}</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">listStyle</span><span class="token punctuation">(</span><span class="token punctuation">.</span>plain<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">.</span>refreshable <span class="token punctuation">{</span> <span class="token keyword">await</span> <span class="token function">refreshFeed</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span>
</span><span class="code-line">            <span class="token punctuation">.</span>task <span class="token punctuation">{</span> <span class="token keyword">await</span> <span class="token function">loadFeed</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h3 id="small-and-simple">Small and Simple</h3>
<ul>
<li>SwiftUI에서 View는 비교적 쉽게 분리할수 있다.</li>
<li>View에 버그가 있다면, 즉시 드러날 정도로 각 View는 작아야 한다.</li>
<li>하나의 파일에 담기에 View가 너무 커질 때가 있는데, 이때가 View를 분리 해야하는 시점이다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">PostDetailView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> post<span class="token punctuation">:</span> <span class="token class-name">Post</span>
</span><span class="code-line">    <span class="token attribute atrule">@State</span> <span class="token keyword">private</span> <span class="token keyword">var</span> isExpanded<span class="token punctuation">:</span> <span class="token class-name">Bool</span> <span class="token operator">=</span> <span class="token boolean">false</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">ScrollView</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token class-name">LazyVStack</span><span class="token punctuation">(</span>spacing<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">                <span class="token class-name">PostHeaderView</span><span class="token punctuation">(</span>post<span class="token punctuation">:</span> post<span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token class-name">PostContentView</span><span class="token punctuation">(</span>post<span class="token punctuation">:</span> post<span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token class-name">PostActionsView</span><span class="token punctuation">(</span>post<span class="token punctuation">:</span> post<span class="token punctuation">,</span> isExpanded<span class="token punctuation">:</span> $isExpanded<span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token class-name">PostRepliesView</span><span class="token punctuation">(</span>postId<span class="token punctuation">:</span> post<span class="token punctuation">.</span>id<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>Screen: 한 화면을 담당하는 풀스크린, 데이터를 fetch 혹은 filter 하는 등의 로직 포함</li>
<li>Component: 화면의 일부를 담당하는 컴포넌트, 재사용 가능하게 부모 뷰로부터만 데이터 전달 받음</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">enum</span> <span class="token class-name">Events</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">case</span> <span class="token function">onChecked</span><span class="token punctuation">(</span><span class="token class-name">Int</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">case</span> <span class="token function">onDelete</span><span class="token punctuation">(</span><span class="token class-name">Int</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">SomeScreen</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">List</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token operator">...</span><span class="token number">20</span><span class="token punctuation">,</span> id<span class="token punctuation">:</span> <span class="token punctuation">\</span><span class="token punctuation">.</span><span class="token keyword">self</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> index <span class="token keyword">in</span>
</span><span class="code-line">            <span class="token class-name">SomeComponent</span><span class="token punctuation">(</span>index<span class="token punctuation">:</span> index<span class="token punctuation">)</span> <span class="token punctuation">{</span> event <span class="token keyword">in</span>
</span><span class="code-line">                <span class="token keyword">switch</span> event <span class="token punctuation">{</span>
</span><span class="code-line">                    <span class="token keyword">case</span> <span class="token punctuation">.</span><span class="token function">onChecked</span><span class="token punctuation">(</span><span class="token keyword">let</span> index<span class="token punctuation">)</span><span class="token punctuation">:</span>
</span><span class="code-line">                        <span class="token function">print</span><span class="token punctuation">(</span>index<span class="token punctuation">)</span>
</span><span class="code-line">                    <span class="token keyword">case</span> <span class="token punctuation">.</span><span class="token function">onDelete</span><span class="token punctuation">(</span><span class="token keyword">let</span> index<span class="token punctuation">)</span><span class="token punctuation">:</span>
</span><span class="code-line">                        <span class="token function">print</span><span class="token punctuation">(</span>index<span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token punctuation">}</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">SomeComponent</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> index<span class="token punctuation">:</span> <span class="token class-name">Int</span>
</span><span class="code-line">    <span class="token keyword">let</span> onEvent<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token class-name">Events</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Void</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">HStack</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token class-name">Image</span><span class="token punctuation">(</span>systemName<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"square"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token punctuation">.</span>onTapGesture <span class="token punctuation">{</span>
</span><span class="code-line">                    <span class="token function">onEvent</span><span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token function">onChecked</span><span class="token punctuation">(</span>index<span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token punctuation">}</span>
</span><span class="code-line">            <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"</span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">index</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token class-name">Spacer</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token class-name">Image</span><span class="token punctuation">(</span>systemName<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"trash"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token punctuation">.</span>onTapGesture <span class="token punctuation">{</span>
</span><span class="code-line">                    <span class="token function">onEvent</span><span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token function">onDelete</span><span class="token punctuation">(</span>index<span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="services">Services</h2>
<h3 id="service-역할">Service 역할</h3>
<ul>
<li>Service는 Auth, Network, Router 등이 해당된다.</li>
<li>Service 객체는 Observable 할 수 있고, Environment로 주입된다.</li>
<li>Serive에 포함될 Network Layer에 대한 자세한 내용은 <a href="https://www.hohyeonmoon.com/blog/swift-network-layer">Swift Network Layer</a>를 참고하자.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">final</span> <span class="token keyword">class</span> <span class="token class-name">Network</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> baseURL<span class="token punctuation">:</span> <span class="token constant">URL</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token keyword">throws</span> <span class="token operator">-></span> <span class="token punctuation">[</span><span class="token class-name">Example</span><span class="token punctuation">]</span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">update</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> example<span class="token punctuation">:</span> <span class="token class-name">Example</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token keyword">throws</span> <span class="token operator">-></span> <span class="token class-name">Example</span><span class="token operator">?</span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token operator">...</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token attribute atrule">@MainActor</span>
</span><span class="code-line"><span class="token attribute atrule">@Observable</span>
</span><span class="code-line"><span class="token keyword">final</span> <span class="token keyword">class</span> <span class="token class-name">Router</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">var</span> paths <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token class-name">Path</span><span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token operator">...</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h3 id="environment-주입">Environment 주입</h3>
<ul>
<li>ViewModel을 사용할때는 의존성을 일일히 주입했다면, MV 패턴에서는 Environment를 적극 활용한다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token attribute atrule">@Environment</span><span class="token punctuation">(</span><span class="token class-name">Client</span><span class="token punctuation">.</span><span class="token keyword">self</span><span class="token punctuation">)</span> <span class="token keyword">private</span> <span class="token keyword">var</span> client
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">private</span> <span class="token keyword">func</span> <span class="token function-definition function">loadFeed</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">do</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">let</span> posts <span class="token operator">=</span> <span class="token keyword">try</span> <span class="token keyword">await</span> client<span class="token punctuation">.</span><span class="token function">getFeed</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        viewState <span class="token operator">=</span> <span class="token punctuation">.</span><span class="token function">loaded</span><span class="token punctuation">(</span>posts<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">{</span>
</span><span class="code-line">        viewState <span class="token operator">=</span> <span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>error<span class="token punctuation">.</span>localizedDescription<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">private</span> <span class="token keyword">func</span> <span class="token function-definition function">refreshFeed</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">defer</span> <span class="token punctuation">{</span> isRefreshing <span class="token operator">=</span> <span class="token boolean">false</span> <span class="token punctuation">}</span>
</span><span class="code-line">    isRefreshing <span class="token operator">=</span> <span class="token boolean">true</span>
</span><span class="code-line">    <span class="token keyword">await</span> <span class="token function">loadFeed</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="models">Models</h2>
<ul>
<li>Model은 Data structure와 Business logic을 담당한다.</li>
<li>주로 Codable, Identifiable, Equatable, Hashable 등을 준수하는 struct 형태가 될 것이다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">FeedItem</span><span class="token punctuation">:</span> <span class="token class-name">Codable</span><span class="token punctuation">,</span> <span class="token class-name">Equatable</span><span class="token punctuation">,</span> <span class="token class-name">Identifiable</span><span class="token punctuation">,</span> <span class="token class-name">Hashable</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> id<span class="token punctuation">:</span> <span class="token class-name">String</span> <span class="token punctuation">{</span> uri <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">let</span> uri<span class="token punctuation">:</span> <span class="token class-name">String</span>
</span><span class="code-line">    <span class="token keyword">let</span> displayName<span class="token punctuation">:</span> <span class="token class-name">String</span>
</span><span class="code-line">    <span class="token keyword">let</span> description<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token operator">?</span>
</span><span class="code-line">    <span class="token keyword">let</span> avatarImageURL<span class="token punctuation">:</span> <span class="token constant">URL</span><span class="token operator">?</span>
</span><span class="code-line">    <span class="token keyword">let</span> likesCount<span class="token punctuation">:</span> <span class="token class-name">Int</span>
</span><span class="code-line">    <span class="token keyword">let</span> liked<span class="token punctuation">:</span> <span class="token class-name">Bool</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">hash</span><span class="token punctuation">(</span>into hasher<span class="token punctuation">:</span> <span class="token keyword">inout</span> <span class="token class-name">Hasher</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        hasher<span class="token punctuation">.</span><span class="token function">combine</span><span class="token punctuation">(</span>uri<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">FeedItem</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token attribute atrule">@MainActor</span>
</span><span class="code-line">    <span class="token keyword">static</span> <span class="token keyword">var</span> placeholders<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">FeedItem</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token class-name">Array</span><span class="token punctuation">(</span>repeating<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> count<span class="token punctuation">:</span> <span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">.</span>map <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token keyword">init</span><span class="token punctuation">(</span>
</span><span class="code-line">            uri<span class="token punctuation">:</span> <span class="token function">UUID</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>uuidString<span class="token punctuation">,</span>
</span><span class="code-line">            displayName<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Placeholder"</span></span>
</span><span class="code-line">            description<span class="token punctuation">:</span> <span class="token nil constant">nil</span>
</span><span class="code-line">            avatarImageURL<span class="token punctuation">:</span> <span class="token nil constant">nil</span><span class="token punctuation">,</span>
</span><span class="code-line">            likesCount<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
</span><span class="code-line">            liked<span class="token punctuation">:</span> <span class="token boolean">false</span>
</span><span class="code-line">        <span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>ViewState는 View 내의 프로퍼티나 로직이 많이 필요할때 사용할 수 있다.</li>
<li>하나의 <code>@State</code> 프로퍼티로 만들면 된다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ExampleView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token attribute atrule">@State</span> <span class="token keyword">private</span> <span class="token keyword">var</span> state <span class="token operator">=</span> <span class="token class-name">ExampleState</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token operator">...</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ExampleState</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> name <span class="token operator">=</span> <span class="token string-literal"><span class="token string">""</span></span>
</span><span class="code-line">    <span class="token keyword">var</span> exampleName <span class="token operator">=</span> <span class="token string-literal"><span class="token string">""</span></span>
</span><span class="code-line">    <span class="token keyword">var</span> errors <span class="token operator">=</span> <span class="token class-name">ExampleError</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">mutating</span> <span class="token keyword">func</span> <span class="token function-definition function">isValid</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Bool</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">if</span> name<span class="token punctuation">.</span>isEmpty <span class="token punctuation">{</span>
</span><span class="code-line">            errors<span class="token punctuation">.</span>name <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"Name cannot be empty!"</span></span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">if</span> exampleName<span class="token punctuation">.</span>isEmpty <span class="token punctuation">{</span>
</span><span class="code-line">            errors<span class="token punctuation">.</span>exampleName <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"Coffee name cannot be empty"</span></span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">return</span> errors<span class="token punctuation">.</span>name<span class="token punctuation">.</span>isEmpty <span class="token operator">&#x26;&#x26;</span> errors<span class="token punctuation">.</span>exampleName<span class="token punctuation">.</span>isEmpty
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="testing">Testing</h2>
<h3 id="view">View</h3>
<ul>
<li>View는 작은 단위로 테스트 할 수 있어야 한다.</li>
<li>작은 단위로 분리된 View와 Preview를 통해 빠르고 반복적으로 View를 확인할수 있다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token other-directive property">#Preview</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">let</span> service <span class="token operator">=</span> <span class="token class-name">Service</span><span class="token punctuation">(</span>baseURL<span class="token punctuation">:</span> <span class="token function">URL</span><span class="token punctuation">(</span>string<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"https://url.com"</span></span><span class="token punctuation">)</span><span class="token operator">!</span><span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token class-name">ExampleView</span><span class="token punctuation">(</span>example<span class="token punctuation">:</span> <span class="token nil constant">nil</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">environment</span><span class="token punctuation">(</span>service<span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>View를 테스트하고 싶다면, end-to-end UI 테스트를 진행하는 편이 낫다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">import</span> <span class="token class-name">XCTest</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">ExampleAppUITests</span><span class="token punctuation">:</span> <span class="token class-name">XCTestCase</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">testExampleViewInteraction</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">let</span> app <span class="token operator">=</span> <span class="token class-name">XCUIApplication</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        app<span class="token punctuation">.</span><span class="token function">launch</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">let</span> nameField <span class="token operator">=</span> app<span class="token punctuation">.</span>textFields<span class="token punctuation">[</span><span class="token string-literal"><span class="token string">"Name"</span></span><span class="token punctuation">]</span>
</span><span class="code-line">        <span class="token keyword">let</span> exampleNameField <span class="token operator">=</span> app<span class="token punctuation">.</span>textFields<span class="token punctuation">[</span><span class="token string-literal"><span class="token string">"Example name"</span></span><span class="token punctuation">]</span>
</span><span class="code-line">        
</span><span class="code-line">        nameField<span class="token punctuation">.</span><span class="token function">tap</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        nameField<span class="token punctuation">.</span><span class="token function">typeText</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"John Doe"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        
</span><span class="code-line">        exampleNameField<span class="token punctuation">.</span><span class="token function">tap</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        exampleNameField<span class="token punctuation">.</span><span class="token function">typeText</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"SwiftUI"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        
</span><span class="code-line">        app<span class="token punctuation">.</span>buttons<span class="token punctuation">[</span><span class="token string-literal"><span class="token string">"Update"</span></span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">tap</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token class-name">XCTAssertTrue</span><span class="token punctuation">(</span>app<span class="token punctuation">.</span>staticTexts<span class="token punctuation">[</span><span class="token string-literal"><span class="token string">"Update Successful"</span></span><span class="token punctuation">]</span><span class="token punctuation">.</span>exists<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h3 id="model">Model</h3>
<ul>
<li>View보다 테스트가 중요한 부분은 Model 및 Service이다.</li>
<li>코드가 분리되어 있기 때문에 Unit test를 하기 용이하다.</li>
</ul>
<h2 id="참고">참고</h2>
<ul>
<li><a href="https://dimillian.medium.com/swiftui-in-2025-forget-mvvm-262ff2bbd2ed">SwiftUI in 2025: Forget MVVM</a></li>
<li><a href="https://azamsharp.com/2023/02/28/building-large-scale-apps-swiftui.html">Building Large-Scale Apps with SwiftUI</a></li>
<li><a href="https://medium.com/@karamage/stop-using-mvvm-with-swiftui-2c46eb2cc8dc">Stop using MVVM with SwiftUI</a></li>
</ul>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/uikit-ribs</guid>
      <title>iOS RIBs 아키텍처</title>
      <description>iOS에 적용 가능한 RIBs 아키텍처 소개 및 예시 살펴보기</description>
      <link>https://www.hohyeonmoon.com/blog/uikit-ribs</link>
      <pubDate>Fri, 28 Feb 2025 18:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<h2 id="ribs-유래">RIBs 유래</h2>
<ul>
<li>RIBs는 우버에서 개발한 크로스 플랫폼 아키텍처 프레임워크이다</li>
<li>기존 VIPER 패턴을 개선하여, 비즈니스 로직만 있는 모듈을 쉽게 구현할 수 있다</li>
<li><a href="https://www.uber.com/en-KR/blog/new-rider-app-architecture/">RIBs 관련 공식 블로그 글</a>, <a href="https://github.com/uber/ribs-ios">RIBs 레포지토리</a></li>
</ul>
<h3 id="viper">VIPER</h3>
<p><img src="/images/uikit-ribs-1.png" alt="uikit-ribs"></p>
<ul>
<li>VIPER는 View, Interactor, Presenter, Entity, Router로 구성</li>
<li>VIPER는 View Driven이기 때문에 비즈니스 로직만 있는 VIPER 노드 구현에 어려움이 있음</li>
</ul>
<h3 id="ribs">RIBs</h3>
<p><img src="/images/uikit-ribs-2.png" alt="uikit-ribs"></p>
<ul>
<li>RIBs는 Router, Interactor, Builder의 약자</li>
<li>하나의 RIB은 Router, Interactor, Builder는 필수적으로 구성된다</li>
<li>필요에 따라 Presenter와 View까지 추가적으로 구성한다</li>
<li>VIPER와 달리 View가 포함되지 않고 비즈니스 로직으로만 구성된 Viewless RIB 생성이 가능하다</li>
</ul>
<h2 id="ribs-구성">RIBs 구성</h2>
<h3 id="builder">Builder</h3>
<ul>
<li>RIBs의 모든 구성 요소를 생성</li>
<li>Router, Interactor, Presenter, View, Component 모두 생성</li>
</ul>
<h3 id="dependency">Dependency</h3>
<ul>
<li>Dependency는 RIB이 올바르게 초기화 되기 위해 부모로부터 필요로 하는 의존성을 나열하는 프로토콜</li>
</ul>
<h3 id="component">Component</h3>
<ul>
<li>Component는 Dependency 프로토콜을 구현하는 클래스</li>
<li>Component는 RIB의 Builder에 부모 의존성을 제공하는 것 외에도, RIB이 자체적으로 생성하거나 자식 RIB을 위해 생성하는 의존성을 소유하는 역할도 담당</li>
</ul>
<h3 id="router">Router</h3>
<ul>
<li>자식 RIB을 attach 혹은 detach하여 RIBs의 논리적 트리 구조 형성</li>
</ul>
<h3 id="interactor">Interactor</h3>
<ul>
<li>비즈니스 로직을 수행하여 Router로 라우팅 호출</li>
<li>RIBs의 attach와 detach를 요청</li>
<li>Presenter로 data model을 전달</li>
</ul>
<h3 id="view">View</h3>
<ul>
<li>UI를 생성하고 구성</li>
<li>UI 이벤트를 Presenter로 전달</li>
<li>ViewModel을 받아서 UI를 업데이트</li>
</ul>
<h3 id="presenter">Presenter</h3>
<ul>
<li>Interactor와 View간의 통신을 담당</li>
<li>Business Model을 ViewModel로 변환하는 역할</li>
<li>상태를 갖고 있지 않은 클래스</li>
<li>Presenter를 생략하는 경우 ViewModel 변환은 View 또는 Interactor가 함</li>
</ul>
<h2 id="ribs-트리">RIBs 트리</h2>
<p><img src="/images/uikit-ribs-3.png" alt="uikit-ribs"></p>
<ul>
<li>RIBs는 트리 구조를 형성하여, 부모 RIB과 자식 RIB 간 통신을 함</li>
<li>RIBs간의 통신은 각 RIB의 Interactor가 담당</li>
<li>부모에서 자식으로의 통신은 Stream을 넘겨주어서 데이터를 전달</li>
<li>자식에서 부모로의 통신은 자식 Interactor에서 부모 Interactor를 Listener로 접근</li>
</ul>
<h2 id="ribs-예시">RIBs 예시</h2>
<h3 id="board-rib">Board RIB</h3>
<ul>
<li>게시판의 게시물이 리스트 형태로 표시되는 화면</li>
<li>부모 RIB</li>
</ul>
<p><img src="/images/uikit-ribs-4.png" alt="uikit-ribs"></p>
<h3 id="postdetail-rib">PostDetail RIB</h3>
<ul>
<li>게시물의 상세 내용을 표시하는 화면</li>
<li>자식 RIB</li>
</ul>
<p><img src="/images/uikit-ribs-5.png" alt="uikit-ribs"></p>
<h3 id="파일-구조">파일 구조</h3>
<ul>
<li>Board, PostDetail RIBs의 파일 구조는 다음과 같다</li>
</ul>
<p><img src="/images/uikit-ribs-6.png" alt="uikit-ribs"></p>
<h2 id="board-rib-1">Board RIB</h2>
<h3 id="boardbuilder">BoardBuilder</h3>
<ul>
<li>BoardBuilder는 RIB의 모든 구성요소를 생성하고 의존성을 주입하는 역할</li>
<li>postsStream을 통해 게시물 데이터를 관리하고 필요하다면 자식 RIB과 공유</li>
<li>자식 RIB인 PostDetailBuilder를 생성하는 역할까지 함</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">protocol</span> <span class="token class-name">BoardDependency</span><span class="token punctuation">:</span> <span class="token class-name">Dependency</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token operator">...</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">final</span> <span class="token keyword">class</span> <span class="token class-name">BoardComponent</span><span class="token punctuation">:</span> <span class="token class-name">Component</span><span class="token operator">&#x3C;</span><span class="token class-name">BoardDependency</span><span class="token operator">></span><span class="token punctuation">,</span> <span class="token class-name">PostDetailDependency</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> postsStream<span class="token punctuation">:</span> <span class="token class-name">BehaviorRelay</span><span class="token operator">&#x3C;</span><span class="token punctuation">(</span>posts<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">Post</span><span class="token punctuation">]</span><span class="token punctuation">,</span> initial<span class="token punctuation">:</span> <span class="token class-name">Bool</span><span class="token punctuation">,</span> reload<span class="token punctuation">:</span> <span class="token class-name">Bool</span><span class="token punctuation">)</span><span class="token operator">></span> <span class="token operator">=</span> <span class="token punctuation">.</span><span class="token keyword">init</span><span class="token punctuation">(</span>value<span class="token punctuation">:</span> <span class="token punctuation">(</span>posts<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">,</span> initial<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> reload<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">protocol</span> <span class="token class-name">BoardBuildable</span><span class="token punctuation">:</span> <span class="token class-name">Buildable</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">build</span><span class="token punctuation">(</span>withListener listener<span class="token punctuation">:</span> <span class="token class-name">BoardListener</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">ViewableRouting</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">final</span> <span class="token keyword">class</span> <span class="token class-name">BoardBuilder</span><span class="token punctuation">:</span> <span class="token class-name">Builder</span><span class="token operator">&#x3C;</span><span class="token class-name">BoardDependency</span><span class="token operator">></span><span class="token punctuation">,</span> <span class="token class-name">BoardBuildable</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">build</span><span class="token punctuation">(</span>withListener listener<span class="token punctuation">:</span> <span class="token class-name">BoardListener</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">ViewableRouting</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">let</span> component <span class="token operator">=</span> <span class="token class-name">BoardComponent</span><span class="token punctuation">(</span>dependency<span class="token punctuation">:</span> dependency<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token keyword">let</span> viewController <span class="token operator">=</span> <span class="token class-name">BoardViewController</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token keyword">let</span> interactor <span class="token operator">=</span> <span class="token class-name">BoardInteractor</span><span class="token punctuation">(</span>
</span><span class="code-line">            presenter<span class="token punctuation">:</span> viewController<span class="token punctuation">,</span>
</span><span class="code-line">            postsStream<span class="token punctuation">:</span> component<span class="token punctuation">.</span>postsStream
</span><span class="code-line">        <span class="token punctuation">)</span>
</span><span class="code-line">        
</span><span class="code-line">        interactor<span class="token punctuation">.</span>listener <span class="token operator">=</span> listener
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">let</span> postDetailBuilder <span class="token operator">=</span> <span class="token class-name">PostDetailBuilder</span><span class="token punctuation">(</span>dependency<span class="token punctuation">:</span> component<span class="token punctuation">)</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">return</span> <span class="token class-name">BoardRouter</span><span class="token punctuation">(</span>
</span><span class="code-line">            interactor<span class="token punctuation">:</span> interactor<span class="token punctuation">,</span>
</span><span class="code-line">            viewController<span class="token punctuation">:</span> viewController<span class="token punctuation">,</span>
</span><span class="code-line">            postDetailBuilder<span class="token punctuation">:</span> postDetailBuilder
</span><span class="code-line">        <span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h3 id="boardinteractor">BoardInteractor</h3>
<ul>
<li>게시판의 비즈니스 로직을 담당</li>
<li>게시물 목록을 fetch 하는 네트워크 요청 처리</li>
<li>postsStream을 구독하여 데이터 변경 시 View 업데이트</li>
<li>PostDetail RIB 라우팅 호출</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">protocol</span> <span class="token class-name">BoardRouting</span><span class="token punctuation">:</span> <span class="token class-name">ViewableRouting</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">routeToPostDetail</span><span class="token punctuation">(</span>post<span class="token punctuation">:</span> <span class="token class-name">PostEntity</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">detachPostDetail</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">protocol</span> <span class="token class-name">BoardPresentable</span><span class="token punctuation">:</span> <span class="token class-name">Presentable</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> listener<span class="token punctuation">:</span> <span class="token class-name">BoardPresentableListener</span><span class="token operator">?</span> <span class="token punctuation">{</span> <span class="token keyword">get</span> <span class="token keyword">set</span> <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">update</span><span class="token punctuation">(</span>posts<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">Post</span><span class="token punctuation">]</span><span class="token punctuation">,</span> initial<span class="token punctuation">:</span> <span class="token class-name">Bool</span><span class="token punctuation">,</span> reload<span class="token punctuation">:</span> <span class="token class-name">Bool</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">protocol</span> <span class="token class-name">BoardListener</span><span class="token punctuation">:</span> <span class="token class-name">AnyObject</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token operator">...</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">final</span> <span class="token keyword">class</span> <span class="token class-name">BoardInteractor</span><span class="token punctuation">:</span> <span class="token class-name">PresentableInteractor</span><span class="token operator">&#x3C;</span><span class="token class-name">BoardPresentable</span><span class="token operator">></span><span class="token punctuation">,</span> <span class="token class-name">BoardInteractable</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">weak</span> <span class="token keyword">var</span> router<span class="token punctuation">:</span> <span class="token class-name">BoardRouting</span><span class="token operator">?</span>
</span><span class="code-line">    <span class="token keyword">weak</span> <span class="token keyword">var</span> listener<span class="token punctuation">:</span> <span class="token class-name">BoardListener</span><span class="token operator">?</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">let</span> disposeBag <span class="token operator">=</span> <span class="token class-name">DisposeBag</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">let</span> postsStream<span class="token punctuation">:</span> <span class="token class-name">BehaviorRelay</span><span class="token operator">&#x3C;</span><span class="token punctuation">(</span>posts<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">Post</span><span class="token punctuation">]</span><span class="token punctuation">,</span> initial<span class="token punctuation">:</span> <span class="token class-name">Bool</span><span class="token punctuation">,</span> reload<span class="token punctuation">:</span> <span class="token class-name">Bool</span><span class="token punctuation">)</span><span class="token operator">></span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">var</span> selectedBoardId<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token operator">?</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token operator">...</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">init</span><span class="token punctuation">(</span>
</span><span class="code-line">        presenter<span class="token punctuation">:</span> <span class="token class-name">BoardPresentable</span><span class="token punctuation">,</span>
</span><span class="code-line">        postsStream<span class="token punctuation">:</span> <span class="token class-name">BehaviorRelay</span><span class="token operator">&#x3C;</span><span class="token punctuation">(</span>posts<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">Post</span><span class="token punctuation">]</span><span class="token punctuation">,</span> initial<span class="token punctuation">:</span> <span class="token class-name">Bool</span><span class="token punctuation">,</span> reload<span class="token punctuation">:</span> <span class="token class-name">Bool</span><span class="token punctuation">)</span><span class="token operator">></span>
</span><span class="code-line">    <span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">self</span><span class="token punctuation">.</span>postsStream <span class="token operator">=</span> postsStream
</span><span class="code-line">        <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token keyword">init</span><span class="token punctuation">(</span>presenter<span class="token punctuation">:</span> presenter<span class="token punctuation">)</span>
</span><span class="code-line">        presenter<span class="token punctuation">.</span>listener <span class="token operator">=</span> <span class="token keyword">self</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">override</span> <span class="token keyword">func</span> <span class="token function-definition function">didBecomeActive</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token function">didBecomeActive</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token class-name">Task</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">do</span> <span class="token punctuation">{</span>
</span><span class="code-line">                <span class="token keyword">try</span> <span class="token keyword">await</span> <span class="token function">fetchPosts</span><span class="token punctuation">(</span>initial<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">{</span>
</span><span class="code-line">                <span class="token function">logError</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Error fetching initial data: </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">error</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        
</span><span class="code-line">        postsStream
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">subscribe</span><span class="token punctuation">(</span>onNext<span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token punctuation">[</span><span class="token keyword">weak</span> <span class="token keyword">self</span><span class="token punctuation">]</span> posts <span class="token keyword">in</span>
</span><span class="code-line">                <span class="token keyword">self</span><span class="token operator">?</span><span class="token punctuation">.</span>presenter<span class="token punctuation">.</span><span class="token function">update</span><span class="token punctuation">(</span>posts<span class="token punctuation">:</span> posts<span class="token punctuation">.</span>posts<span class="token punctuation">,</span> initial<span class="token punctuation">:</span> posts<span class="token punctuation">.</span>initial<span class="token punctuation">,</span> reload<span class="token punctuation">:</span> posts<span class="token punctuation">.</span>reload<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">}</span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">disposed</span><span class="token punctuation">(</span>by<span class="token punctuation">:</span> disposeBag<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">BoardInteractor</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">func</span> <span class="token function-definition function">fetchPosts</span><span class="token punctuation">(</span>initial<span class="token punctuation">:</span> <span class="token class-name">Bool</span> <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">,</span> reload<span class="token punctuation">:</span> <span class="token class-name">Bool</span> <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token keyword">throws</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">let</span> endpoint <span class="token operator">=</span> <span class="token class-name">PostEndpoint</span><span class="token punctuation">.</span><span class="token function">fetchPosts</span><span class="token punctuation">(</span>boardId<span class="token punctuation">:</span> selectedBoardId<span class="token punctuation">,</span> reload<span class="token punctuation">:</span> reload<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token keyword">let</span> response<span class="token punctuation">:</span> <span class="token class-name">FetchPostsResponse</span> <span class="token operator">=</span> <span class="token keyword">try</span> <span class="token keyword">await</span> <span class="token class-name">Network</span><span class="token punctuation">.</span>shared<span class="token punctuation">.</span><span class="token function">request</span><span class="token punctuation">(</span>endpoint<span class="token punctuation">:</span> endpoint<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token keyword">let</span> posts <span class="token operator">=</span> response<span class="token punctuation">.</span>data
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">self</span><span class="token punctuation">.</span>postsStream<span class="token punctuation">.</span><span class="token function">accept</span><span class="token punctuation">(</span><span class="token punctuation">(</span>posts<span class="token punctuation">:</span> posts<span class="token punctuation">,</span> initial<span class="token punctuation">:</span> initial<span class="token punctuation">,</span> reload<span class="token punctuation">:</span> reload<span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">BoardInteractor</span><span class="token punctuation">:</span> <span class="token class-name">BoardPresentableListener</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">postDetailButtonDidTap</span><span class="token punctuation">(</span>post<span class="token punctuation">:</span> <span class="token class-name">PostEntity</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        router<span class="token operator">?</span><span class="token punctuation">.</span><span class="token function">routeToPostDetail</span><span class="token punctuation">(</span>post<span class="token punctuation">:</span> post<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">BoardInteractor</span><span class="token punctuation">:</span> <span class="token class-name">PostDetailListener</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">detachPostDetail</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        router<span class="token operator">?</span><span class="token punctuation">.</span><span class="token function">detachPostDetail</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h3 id="boardviewcontroller">BoardViewController</h3>
<ul>
<li>게시판 UI를 담당하며, UITableView를 통해 게시물 목록 표시</li>
<li>NavigationController를 통해 화면 이동 기능 구현 (push / pop)</li>
<li>Interactor와 통신하여 사용자 이벤트 전달</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">protocol</span> <span class="token class-name">BoardPresentableListener</span><span class="token punctuation">:</span> <span class="token class-name">AnyObject</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">postDetailButtonDidTap</span><span class="token punctuation">(</span>post<span class="token punctuation">:</span> <span class="token class-name">PostEntity</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">final</span> <span class="token keyword">class</span> <span class="token class-name">BoardViewController</span><span class="token punctuation">:</span> <span class="token class-name">UIViewController</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">weak</span> <span class="token keyword">var</span> listener<span class="token punctuation">:</span> <span class="token class-name">BoardPresentableListener</span><span class="token operator">?</span>
</span><span class="code-line"> 
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">var</span> posts <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token class-name">PostEntity</span><span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token operator">...</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">override</span> <span class="token keyword">func</span> <span class="token function-definition function">viewDidLoad</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token function">viewDidLoad</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token function">setup</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token operator">...</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">BoardViewController</span><span class="token punctuation">:</span> <span class="token class-name">BoardPresentable</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">update</span><span class="token punctuation">(</span>posts<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">Post</span><span class="token punctuation">]</span><span class="token punctuation">,</span> initial<span class="token punctuation">:</span> <span class="token class-name">Bool</span><span class="token punctuation">,</span> reload<span class="token punctuation">:</span> <span class="token class-name">Bool</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">Task</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">self</span><span class="token punctuation">.</span>posts <span class="token operator">=</span> <span class="token keyword">try</span> <span class="token keyword">await</span> <span class="token function">withThrowingTaskGroup</span><span class="token punctuation">(</span>of<span class="token punctuation">:</span> <span class="token class-name">PostEntity</span><span class="token punctuation">.</span><span class="token keyword">self</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> group <span class="token keyword">in</span>
</span><span class="code-line">                <span class="token operator">...</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">            
</span><span class="code-line">            <span class="token comment">// UI 업데이트</span>
</span><span class="code-line">            <span class="token keyword">await</span> <span class="token class-name">MainActor</span><span class="token punctuation">.</span>run <span class="token punctuation">{</span>
</span><span class="code-line">                <span class="token operator">...</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">BoardViewController</span><span class="token punctuation">:</span> <span class="token class-name">BoardViewControllable</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">push</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> viewControllable<span class="token punctuation">:</span> <span class="token class-name">ViewControllable</span><span class="token punctuation">,</span> animated<span class="token punctuation">:</span> <span class="token class-name">Bool</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">DispatchQueue</span><span class="token punctuation">.</span>main<span class="token punctuation">.</span><span class="token keyword">async</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">self</span><span class="token punctuation">.</span>navigationController<span class="token operator">?</span><span class="token punctuation">.</span><span class="token function">pushViewController</span><span class="token punctuation">(</span>viewControllable<span class="token punctuation">.</span>uiviewController<span class="token punctuation">,</span> animated<span class="token punctuation">:</span> animated<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">pop</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> viewControllable<span class="token punctuation">:</span> <span class="token class-name">ViewControllable</span><span class="token punctuation">,</span> animated<span class="token punctuation">:</span> <span class="token class-name">Bool</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">DispatchQueue</span><span class="token punctuation">.</span>main<span class="token punctuation">.</span><span class="token keyword">async</span> <span class="token punctuation">{</span>
</span><span class="code-line">            viewControllable<span class="token punctuation">.</span>uiviewController<span class="token punctuation">.</span>navigationController<span class="token operator">?</span><span class="token punctuation">.</span><span class="token function">popViewController</span><span class="token punctuation">(</span>animated<span class="token punctuation">:</span> animated<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">BoardViewController</span><span class="token punctuation">:</span> <span class="token class-name">UITableViewDelegate</span><span class="token punctuation">,</span> <span class="token class-name">UITableViewDataSource</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token operator">...</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">tableView</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> tableView<span class="token punctuation">:</span> <span class="token class-name">UITableView</span><span class="token punctuation">,</span> didSelectRowAt indexPath<span class="token punctuation">:</span> <span class="token class-name">IndexPath</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token operator">...</span>
</span><span class="code-line">
</span><span class="code-line">        <span class="token keyword">let</span> post <span class="token operator">=</span> posts<span class="token punctuation">[</span>indexPath<span class="token punctuation">.</span>row<span class="token punctuation">]</span>
</span><span class="code-line">        listener<span class="token operator">?</span><span class="token punctuation">.</span><span class="token function">postDetailButtonDidTap</span><span class="token punctuation">(</span>post<span class="token punctuation">:</span> post<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h3 id="boardrouter">BoardRouter</h3>
<ul>
<li>Board RIB과 PostDetail RIB 간의 라우팅 담당</li>
<li>PostDetail RIB의 attach 및 detach 관리</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">protocol</span> <span class="token class-name">BoardInteractable</span><span class="token punctuation">:</span> <span class="token class-name">Interactable</span><span class="token punctuation">,</span> <span class="token class-name">PostDetailListener</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> router<span class="token punctuation">:</span> <span class="token class-name">BoardRouting</span><span class="token operator">?</span> <span class="token punctuation">{</span> <span class="token keyword">get</span> <span class="token keyword">set</span> <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token keyword">var</span> listener<span class="token punctuation">:</span> <span class="token class-name">BoardListener</span><span class="token operator">?</span> <span class="token punctuation">{</span> <span class="token keyword">get</span> <span class="token keyword">set</span> <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">protocol</span> <span class="token class-name">BoardViewControllable</span><span class="token punctuation">:</span> <span class="token class-name">ViewControllable</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">push</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> viewControllable<span class="token punctuation">:</span> <span class="token class-name">ViewControllable</span><span class="token punctuation">,</span> animated<span class="token punctuation">:</span> <span class="token class-name">Bool</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">pop</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> viewControllable<span class="token punctuation">:</span> <span class="token class-name">ViewControllable</span><span class="token punctuation">,</span> animated<span class="token punctuation">:</span> <span class="token class-name">Bool</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">final</span> <span class="token keyword">class</span> <span class="token class-name">BoardRouter</span><span class="token punctuation">:</span> <span class="token class-name">ViewableRouter</span><span class="token operator">&#x3C;</span><span class="token class-name">BoardInteractable</span><span class="token punctuation">,</span> <span class="token class-name">BoardViewControllable</span><span class="token operator">></span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">let</span> postDetailBuilder<span class="token punctuation">:</span> <span class="token class-name">PostDetailBuildable</span>
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">var</span> postDetailRouter<span class="token punctuation">:</span> <span class="token class-name">PostDetailRouting</span><span class="token operator">?</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">init</span><span class="token punctuation">(</span>
</span><span class="code-line">        interactor<span class="token punctuation">:</span> <span class="token class-name">BoardInteractable</span><span class="token punctuation">,</span>
</span><span class="code-line">        viewController<span class="token punctuation">:</span> <span class="token class-name">BoardViewControllable</span><span class="token punctuation">,</span>
</span><span class="code-line">        postDetailBuilder<span class="token punctuation">:</span> <span class="token class-name">PostDetailBuildable</span>
</span><span class="code-line">    <span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">self</span><span class="token punctuation">.</span>postDetailBuilder <span class="token operator">=</span> postDetailBuilder
</span><span class="code-line">        <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token keyword">init</span><span class="token punctuation">(</span>interactor<span class="token punctuation">:</span> interactor<span class="token punctuation">,</span> viewController<span class="token punctuation">:</span> viewController<span class="token punctuation">)</span>
</span><span class="code-line">        interactor<span class="token punctuation">.</span>router <span class="token operator">=</span> <span class="token keyword">self</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">BoardRouter</span><span class="token punctuation">:</span> <span class="token class-name">BoardRouting</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">routeToPostDetail</span><span class="token punctuation">(</span>post<span class="token punctuation">:</span> <span class="token class-name">PostEntity</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">let</span> router <span class="token operator">=</span> postDetailBuilder<span class="token punctuation">.</span><span class="token function">build</span><span class="token punctuation">(</span>withListener<span class="token punctuation">:</span> interactor<span class="token punctuation">,</span> post<span class="token punctuation">:</span> post<span class="token punctuation">)</span>
</span><span class="code-line">        postDetailRouter <span class="token operator">=</span> router
</span><span class="code-line">        <span class="token function">attachChild</span><span class="token punctuation">(</span>router<span class="token punctuation">)</span>
</span><span class="code-line">        viewController<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>router<span class="token punctuation">.</span>viewControllable<span class="token punctuation">,</span> animated<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">detachPostDetail</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">guard</span> <span class="token keyword">let</span> router <span class="token operator">=</span> postDetailRouter <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">}</span>
</span><span class="code-line">        viewController<span class="token punctuation">.</span><span class="token function">pop</span><span class="token punctuation">(</span>router<span class="token punctuation">.</span>viewControllable<span class="token punctuation">,</span> animated<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token function">detachChild</span><span class="token punctuation">(</span>router<span class="token punctuation">)</span>
</span><span class="code-line">        postDetailRouter <span class="token operator">=</span> <span class="token nil constant">nil</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="postdetail-rib-1">PostDetail RIB</h2>
<h3 id="postdetailbuilder">PostDetailBuilder</h3>
<ul>
<li>PostDetail RIB의 구성요소 생성</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">protocol</span> <span class="token class-name">PostDetailDependency</span><span class="token punctuation">:</span> <span class="token class-name">Dependency</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token operator">...</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">final</span> <span class="token keyword">class</span> <span class="token class-name">PostDetailComponent</span><span class="token punctuation">:</span> <span class="token class-name">Component</span><span class="token operator">&#x3C;</span><span class="token class-name">PostDetailDependency</span><span class="token operator">></span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token operator">...</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">protocol</span> <span class="token class-name">PostDetailBuildable</span><span class="token punctuation">:</span> <span class="token class-name">Buildable</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">build</span><span class="token punctuation">(</span>withListener listener<span class="token punctuation">:</span> <span class="token class-name">PostDetailListener</span><span class="token punctuation">,</span> post<span class="token punctuation">:</span> <span class="token class-name">PostEntity</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">PostDetailRouting</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">final</span> <span class="token keyword">class</span> <span class="token class-name">PostDetailBuilder</span><span class="token punctuation">:</span> <span class="token class-name">Builder</span><span class="token operator">&#x3C;</span><span class="token class-name">PostDetailDependency</span><span class="token operator">></span><span class="token punctuation">,</span> <span class="token class-name">PostDetailBuildable</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">override</span> <span class="token keyword">init</span><span class="token punctuation">(</span>dependency<span class="token punctuation">:</span> <span class="token class-name">PostDetailDependency</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token keyword">init</span><span class="token punctuation">(</span>dependency<span class="token punctuation">:</span> dependency<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">build</span><span class="token punctuation">(</span>withListener listener<span class="token punctuation">:</span> <span class="token class-name">PostDetailListener</span><span class="token punctuation">,</span> post<span class="token punctuation">:</span> <span class="token class-name">PostEntity</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">PostDetailRouting</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">let</span> component <span class="token operator">=</span> <span class="token class-name">PostDetailComponent</span><span class="token punctuation">(</span>dependency<span class="token punctuation">:</span> dependency<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token keyword">let</span> viewController <span class="token operator">=</span> <span class="token class-name">PostDetailViewController</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token keyword">let</span> interactor <span class="token operator">=</span> <span class="token class-name">PostDetailInteractor</span><span class="token punctuation">(</span>presenter<span class="token punctuation">:</span> viewController<span class="token punctuation">,</span> post<span class="token punctuation">:</span> post<span class="token punctuation">)</span>
</span><span class="code-line">        
</span><span class="code-line">        interactor<span class="token punctuation">.</span>listener <span class="token operator">=</span> listener
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">return</span> <span class="token class-name">PostDetailRouter</span><span class="token punctuation">(</span>interactor<span class="token punctuation">:</span> interactor<span class="token punctuation">,</span> viewController<span class="token punctuation">:</span> viewController<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span> 
</span></code></pre>
<h3 id="postdetailinteractor">PostDetailInteractor</h3>
<ul>
<li>게시물 상세 화면의 비즈니스 로직 담당</li>
<li>게시물 데이터를 View에 전달</li>
<li>PostDetail RIB 라우팅을 부모 RIB에 호출</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">protocol</span> <span class="token class-name">PostDetailRouting</span><span class="token punctuation">:</span> <span class="token class-name">ViewableRouting</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token operator">...</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">protocol</span> <span class="token class-name">PostDetailPresentable</span><span class="token punctuation">:</span> <span class="token class-name">Presentable</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> listener<span class="token punctuation">:</span> <span class="token class-name">PostDetailPresentableListener</span><span class="token operator">?</span> <span class="token punctuation">{</span> <span class="token keyword">get</span> <span class="token keyword">set</span> <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">update</span><span class="token punctuation">(</span>post<span class="token punctuation">:</span> <span class="token class-name">PostEntity</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">protocol</span> <span class="token class-name">PostDetailListener</span><span class="token punctuation">:</span> <span class="token class-name">AnyObject</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">detachPostDetail</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">final</span> <span class="token keyword">class</span> <span class="token class-name">PostDetailInteractor</span><span class="token punctuation">:</span> <span class="token class-name">PresentableInteractor</span><span class="token operator">&#x3C;</span><span class="token class-name">PostDetailPresentable</span><span class="token operator">></span><span class="token punctuation">,</span> <span class="token class-name">PostDetailInteractable</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">weak</span> <span class="token keyword">var</span> router<span class="token punctuation">:</span> <span class="token class-name">PostDetailRouting</span><span class="token operator">?</span>
</span><span class="code-line">    <span class="token keyword">weak</span> <span class="token keyword">var</span> listener<span class="token punctuation">:</span> <span class="token class-name">PostDetailListener</span><span class="token operator">?</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">let</span> post<span class="token punctuation">:</span> <span class="token class-name">PostEntity</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">init</span><span class="token punctuation">(</span>presenter<span class="token punctuation">:</span> <span class="token class-name">PostDetailPresentable</span><span class="token punctuation">,</span> post<span class="token punctuation">:</span> <span class="token class-name">PostEntity</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">self</span><span class="token punctuation">.</span>post <span class="token operator">=</span> post
</span><span class="code-line">        <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token keyword">init</span><span class="token punctuation">(</span>presenter<span class="token punctuation">:</span> presenter<span class="token punctuation">)</span>
</span><span class="code-line">        presenter<span class="token punctuation">.</span>listener <span class="token operator">=</span> <span class="token keyword">self</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">override</span> <span class="token keyword">func</span> <span class="token function-definition function">didBecomeActive</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token function">didBecomeActive</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        presenter<span class="token punctuation">.</span><span class="token function">update</span><span class="token punctuation">(</span>post<span class="token punctuation">:</span> post<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">PostDetailInteractor</span><span class="token punctuation">:</span> <span class="token class-name">PostDetailPresentableListener</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">backButtonDidTap</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        listener<span class="token operator">?</span><span class="token punctuation">.</span><span class="token function">detachPostDetail</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h3 id="postdetailviewcontroller">PostDetailViewController</h3>
<ul>
<li>게시물 상세 화면 UI 담당하여, 게시물 정보 표시</li>
<li>뒤로가기 버튼 등 UI 이벤트 처리</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">protocol</span> <span class="token class-name">PostDetailPresentableListener</span><span class="token punctuation">:</span> <span class="token class-name">AnyObject</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">backButtonDidTap</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">final</span> <span class="token keyword">class</span> <span class="token class-name">PostDetailViewController</span><span class="token punctuation">:</span> <span class="token class-name">UIViewController</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">weak</span> <span class="token keyword">var</span> listener<span class="token punctuation">:</span> <span class="token class-name">PostDetailPresentableListener</span><span class="token operator">?</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token operator">...</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">override</span> <span class="token keyword">func</span> <span class="token function-definition function">viewDidLoad</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token function">viewDidLoad</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token function">setup</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">PostDetailViewController</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token operator">...</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token attribute atrule">@objc</span> <span class="token keyword">private</span> <span class="token keyword">func</span> <span class="token function-definition function">backButtonTapped</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        listener<span class="token operator">?</span><span class="token punctuation">.</span><span class="token function">backButtonDidTap</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">PostDetailViewController</span><span class="token punctuation">:</span> <span class="token class-name">PostDetailViewControllable</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token operator">...</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">PostDetailViewController</span><span class="token punctuation">:</span> <span class="token class-name">PostDetailPresentable</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">update</span><span class="token punctuation">(</span>post<span class="token punctuation">:</span> <span class="token class-name">PostEntity</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token comment">// UI 업데이트</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h3 id="postdetailrouter">PostDetailRouter</h3>
<ul>
<li>PostDetail RIB의 라우팅 담당</li>
<li>필요한 경우 추가적인 자식 RIB 연결 가능</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">protocol</span> <span class="token class-name">PostDetailInteractable</span><span class="token punctuation">:</span> <span class="token class-name">Interactable</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> router<span class="token punctuation">:</span> <span class="token class-name">PostDetailRouting</span><span class="token operator">?</span> <span class="token punctuation">{</span> <span class="token keyword">get</span> <span class="token keyword">set</span> <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token keyword">var</span> listener<span class="token punctuation">:</span> <span class="token class-name">PostDetailListener</span><span class="token operator">?</span> <span class="token punctuation">{</span> <span class="token keyword">get</span> <span class="token keyword">set</span> <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">protocol</span> <span class="token class-name">PostDetailViewControllable</span><span class="token punctuation">:</span> <span class="token class-name">ViewControllable</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token operator">...</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">final</span> <span class="token keyword">class</span> <span class="token class-name">PostDetailRouter</span><span class="token punctuation">:</span> <span class="token class-name">ViewableRouter</span><span class="token operator">&#x3C;</span><span class="token class-name">PostDetailInteractable</span><span class="token punctuation">,</span> <span class="token class-name">PostDetailViewControllable</span><span class="token operator">></span><span class="token punctuation">,</span> <span class="token class-name">PostDetailRouting</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">override</span> <span class="token keyword">init</span><span class="token punctuation">(</span>interactor<span class="token punctuation">:</span> <span class="token class-name">PostDetailInteractable</span><span class="token punctuation">,</span> viewController<span class="token punctuation">:</span> <span class="token class-name">PostDetailViewControllable</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token keyword">init</span><span class="token punctuation">(</span>interactor<span class="token punctuation">:</span> interactor<span class="token punctuation">,</span> viewController<span class="token punctuation">:</span> viewController<span class="token punctuation">)</span>
</span><span class="code-line">        interactor<span class="token punctuation">.</span>router <span class="token operator">=</span> <span class="token keyword">self</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span> 
</span></code></pre>
<h2 id="deeplink">DeepLink</h2>
<h3 id="deeplink란">DeepLink란</h3>
<p>DeepLink는 앱 내의 특정 화면으로 직접 이동할 수 있게 해주는 링크. 웹처럼 앱에서도 특정 리소스에 대한 고유한 주소를 가질 수 있으며, 다음과 같은 형태로 구성.</p>
<ul>
<li>Custom URL Scheme (앱 고유의 스킴 사용): <code>myapp://product/123</code></li>
<li>Universal Link (앱과 웹 모두에서 동작): <code>https://example.com/product/123</code></li>
</ul>
<h3 id="deep-link-활용-예시">Deep Link 활용 예시</h3>
<ul>
<li>게임 초대: <code>ribs-training://launchGame?gameId=ticTacToe&#x26;inviteCode=ABC123</code></li>
<li>특정 화면 이동: <code>ribs-training://profile?userId=12345</code></li>
<li>프로모션 연결: <code>ribs-training://promotion?code=SUMMER2024</code></li>
</ul>
<h3 id="workflow란">Workflow란</h3>
<p>Workflow는 RIBs 트리에서 비동기 작업의 시퀀스를 나타내는 패턴으로, DeepLink 처리에 이상적인 도구. 콜백 지옥이나 복잡한 상태 관리 코드 없이 복잡한 플로우를 Workflow로 구현할수 있다.</p>
<ul>
<li>RIBs 트리에서 비동기 작업의 시퀀스를 나타내는 패턴</li>
<li>여러 RIB을 거쳐가며 복잡한 네비게이션을 처리</li>
<li>Reactive Stream을 사용하여 단계별 진행 관리</li>
</ul>
<h3 id="workflow-동작-원리">Workflow 동작 원리</h3>
<ul>
<li>Step 정의: 각 단계에서 수행할 작업을 정의</li>
<li>ActionableItem 전달: 각 RIB의 Interactor가 ActionableItem 프로토콜을 구현</li>
<li>비동기 처리: Observable을 반환하여 비동기 작업 지원</li>
<li>상태 전이: ReplaySubject를 사용하여 ActionableItem 전달</li>
</ul>
<h3 id="ribs에서의-구현">RIBs에서의 구현</h3>
<p>URLHandler:</p>
<ul>
<li>URL을 처리하는 프로토콜을 정의</li>
<li>AppDelegate에서 구현하여 URL 수신 및 라우팅 담당</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">protocol</span> <span class="token class-name">UrlHandler</span><span class="token punctuation">:</span> <span class="token class-name">AnyObject</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">handle</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> url<span class="token punctuation">:</span> <span class="token constant">URL</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p>AppDelegate:</p>
<ul>
<li>iOS에서 URL 스킴을 통해 앱이 열릴 때 호출</li>
<li>URL을 RootInteractor로 전달하여 처리</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">AppDelegate</span><span class="token punctuation">:</span> <span class="token class-name">UIResponder</span><span class="token punctuation">,</span> <span class="token class-name">UIApplicationDelegate</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">var</span> urlHandler<span class="token punctuation">:</span> <span class="token class-name">UrlHandler</span><span class="token operator">?</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">application</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> app<span class="token punctuation">:</span> <span class="token class-name">UIApplication</span><span class="token punctuation">,</span> <span class="token keyword">open</span> url<span class="token punctuation">:</span> <span class="token constant">URL</span><span class="token punctuation">,</span> options<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">UIApplication</span><span class="token punctuation">.</span><span class="token class-name">OpenURLOptionsKey</span> <span class="token punctuation">:</span> <span class="token keyword">Any</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">:</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Bool</span> <span class="token punctuation">{</span>
</span><span class="code-line">        urlHandler<span class="token operator">?</span><span class="token punctuation">.</span><span class="token function">handle</span><span class="token punctuation">(</span>url<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token keyword">return</span> <span class="token boolean">true</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p>RootInteractor:</p>
<ul>
<li>앱의 최상위 RIB의 Interactor로, 앱 전체의 진입점 역할</li>
<li>UrlHandler를 통해 DeepLink 처리를 담당</li>
<li>Workflow를 시작하고 구독하여 DeepLink 네비게이션 실행</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">RootInteractor</span><span class="token punctuation">:</span> <span class="token class-name">UrlHandler</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">handle</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> url<span class="token punctuation">:</span> <span class="token constant">URL</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">let</span> launchGameWorkflow <span class="token operator">=</span> <span class="token class-name">LaunchGameWorkflow</span><span class="token punctuation">(</span>url<span class="token punctuation">:</span> url<span class="token punctuation">)</span>
</span><span class="code-line">        
</span><span class="code-line">        launchGameWorkflow
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">subscribe</span><span class="token punctuation">(</span><span class="token keyword">self</span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">disposeOnDeactivate</span><span class="token punctuation">(</span>interactor<span class="token punctuation">:</span> <span class="token keyword">self</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p>LaunchGameWorkflow:</p>
<ul>
<li>DeepLink를 처리하는 Workflow 클래스로, 복잡한 네비게이션을 단계별로 관리</li>
<li>로그인 상태를 확인하고 URL에서 게임 ID를 추출해서 게임을 실행하는 플로우 구현</li>
<li>Observable 체인을 통해 비동기 작업의 순서를 보장</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">LaunchGameWorkflow</span><span class="token punctuation">:</span> <span class="token class-name">Workflow</span><span class="token operator">&#x3C;</span><span class="token class-name">RootActionableItem</span><span class="token operator">></span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">let</span> url<span class="token punctuation">:</span> <span class="token constant">URL</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">public</span> <span class="token keyword">init</span><span class="token punctuation">(</span>url<span class="token punctuation">:</span> <span class="token constant">URL</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">self</span><span class="token punctuation">.</span>url <span class="token operator">=</span> url
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token keyword">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">self</span>
</span><span class="code-line">            <span class="token punctuation">.</span>onStep <span class="token punctuation">{</span> <span class="token punctuation">(</span>rootItem<span class="token punctuation">:</span> <span class="token class-name">RootActionableItem</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Observable</span><span class="token operator">&#x3C;</span><span class="token punctuation">(</span><span class="token class-name">LoggedInActionableItem</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token operator">></span> <span class="token keyword">in</span>
</span><span class="code-line">                <span class="token comment">// 1단계: 로그인 대기</span>
</span><span class="code-line">                rootItem<span class="token punctuation">.</span><span class="token function">waitForLogin</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">            <span class="token punctuation">.</span>onStep <span class="token punctuation">{</span> <span class="token punctuation">(</span>loggedInItem<span class="token punctuation">:</span> <span class="token class-name">LoggedInActionableItem</span><span class="token punctuation">,</span> <span class="token omit keyword">_</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Observable</span><span class="token operator">&#x3C;</span><span class="token punctuation">(</span><span class="token class-name">LoggedInActionableItem</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token operator">></span> <span class="token keyword">in</span>
</span><span class="code-line">                <span class="token comment">// 2단계: 게임 ID 파싱 및 게임 실행</span>
</span><span class="code-line">                <span class="token keyword">guard</span> <span class="token keyword">let</span> gameId <span class="token operator">=</span> <span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">extractGameId</span><span class="token punctuation">(</span>from<span class="token punctuation">:</span> <span class="token keyword">self</span><span class="token punctuation">.</span>url<span class="token punctuation">)</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">                    <span class="token keyword">return</span> <span class="token class-name">Observable</span><span class="token punctuation">.</span><span class="token function">empty</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token punctuation">}</span>
</span><span class="code-line">                
</span><span class="code-line">                <span class="token keyword">return</span> loggedInItem<span class="token punctuation">.</span><span class="token function">launchGame</span><span class="token punctuation">(</span>with<span class="token punctuation">:</span> gameId<span class="token punctuation">)</span>
</span><span class="code-line">                    <span class="token punctuation">.</span>map <span class="token punctuation">{</span> <span class="token punctuation">(</span>loggedInItem<span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">}</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">commit</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">func</span> <span class="token function-definition function">extractGameId</span><span class="token punctuation">(</span>from url<span class="token punctuation">:</span> <span class="token constant">URL</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">String</span><span class="token operator">?</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">let</span> components <span class="token operator">=</span> <span class="token class-name">URLComponents</span><span class="token punctuation">(</span>url<span class="token punctuation">:</span> url<span class="token punctuation">,</span> resolvingAgainstBaseURL<span class="token punctuation">:</span> <span class="token boolean">false</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token keyword">return</span> components<span class="token operator">?</span><span class="token punctuation">.</span>queryItems<span class="token operator">?</span><span class="token punctuation">.</span><span class="token function">first</span><span class="token punctuation">(</span><span class="token keyword">where</span><span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token short-argument">$0</span><span class="token punctuation">.</span>name <span class="token operator">==</span> <span class="token string-literal"><span class="token string">"gameId"</span></span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">?</span><span class="token punctuation">.</span>value
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p>ActionableItem:</p>
<ul>
<li>Workflow가 각 RIB에서 수행할 수 있는 작업을 정의하는 프로토콜</li>
<li>각 RIB의 Interactor가 이 프로토콜을 구현하여 Workflow와 통신</li>
<li>Observable을 반환하여 비동기 작업의 완료를 알리고 다음 단계로 진행</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token comment">// Root 레벨 ActionableItem</span>
</span><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">RootInteractor</span><span class="token punctuation">:</span> <span class="token class-name">RootActionableItem</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">waitForLogin</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Observable</span><span class="token operator">&#x3C;</span><span class="token punctuation">(</span><span class="token class-name">LoggedInActionableItem</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token operator">></span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">return</span> loggedInActionableItemSubject
</span><span class="code-line">            <span class="token punctuation">.</span>map <span class="token punctuation">{</span> <span class="token punctuation">(</span><span class="token short-argument">$0</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token comment">// LoggedIn 레벨 ActionableItem  </span>
</span><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">LoggedInInteractor</span><span class="token punctuation">:</span> <span class="token class-name">LoggedInActionableItem</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">launchGame</span><span class="token punctuation">(</span>with gameId<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Observable</span><span class="token operator">&#x3C;</span><span class="token class-name">Void</span><span class="token operator">></span> <span class="token punctuation">{</span>
</span><span class="code-line">        router<span class="token operator">?</span><span class="token punctuation">.</span><span class="token function">routeToGame</span><span class="token punctuation">(</span>with<span class="token punctuation">:</span> gameId<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token keyword">return</span> <span class="token class-name">Observable</span><span class="token punctuation">.</span><span class="token function">just</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p>ActionableItemSubject:</p>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">RootInteractor</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">let</span> loggedInActionableItemSubject <span class="token operator">=</span> <span class="token class-name">ReplaySubject</span><span class="token operator">&#x3C;</span><span class="token class-name">LoggedInActionableItem</span><span class="token operator">></span><span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span>bufferSize<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">func</span> <span class="token function-definition function">routeToLoggedIn</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">let</span> router <span class="token operator">=</span> loggedInBuilder<span class="token punctuation">.</span><span class="token function">build</span><span class="token punctuation">(</span>withListener<span class="token punctuation">:</span> <span class="token keyword">self</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token keyword">self</span><span class="token punctuation">.</span>loggedInRouter <span class="token operator">=</span> router
</span><span class="code-line">        <span class="token function">attachChild</span><span class="token punctuation">(</span>router<span class="token punctuation">)</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token comment">// Workflow에 ActionableItem 전달</span>
</span><span class="code-line">        loggedInActionableItemSubject<span class="token punctuation">.</span><span class="token function">onNext</span><span class="token punctuation">(</span>router<span class="token punctuation">.</span>interactable<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="swiftui">SwiftUI</h2>
<p>UIKit 기반의 RIBs 아키텍처에 SwiftUI를 사용하는 방법</p>
<p><img src="/images/uikit-ribs-7.png" alt="uikit-ribs"></p>
<h3 id="flow">Flow</h3>
<ul>
<li>State: Interactor → Presenter → ViewModel → View</li>
<li>Action: View → ViewModel → Interactor</li>
</ul>
<h3 id="state--action">State &#x26; Action</h3>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ProfileViewState</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> member<span class="token punctuation">:</span> <span class="token class-name">EntityMember</span><span class="token operator">?</span>
</span><span class="code-line">    <span class="token keyword">var</span> logoutAlert <span class="token operator">=</span> <span class="token boolean">false</span>
</span><span class="code-line">    <span class="token keyword">var</span> deleteAlert <span class="token operator">=</span> <span class="token boolean">false</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">enum</span> <span class="token class-name">ProfileViewAction</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">case</span> logout
</span><span class="code-line">    <span class="token keyword">case</span> deleteAccount
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h3 id="viewmodel">ViewModel</h3>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token attribute atrule">@Observable</span>
</span><span class="code-line"><span class="token keyword">final</span> <span class="token keyword">class</span> <span class="token class-name">ProfileViewModel</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">typealias</span> <span class="token class-name">State</span> <span class="token operator">=</span> <span class="token class-name">ProfileViewState</span>
</span><span class="code-line">    <span class="token keyword">typealias</span> <span class="token class-name">Action</span> <span class="token operator">=</span> <span class="token class-name">ProfileViewAction</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">var</span> state<span class="token punctuation">:</span> <span class="token class-name">State</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">weak</span> <span class="token keyword">var</span> listener<span class="token punctuation">:</span> <span class="token class-name">ProfilePresentableListener</span><span class="token operator">?</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">init</span><span class="token punctuation">(</span>state<span class="token punctuation">:</span> <span class="token class-name">State</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">self</span><span class="token punctuation">.</span>state <span class="token operator">=</span> state
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">update</span><span class="token punctuation">(</span>state<span class="token punctuation">:</span> <span class="token class-name">State</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">self</span><span class="token punctuation">.</span>state <span class="token operator">=</span> state
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">request</span><span class="token punctuation">(</span>action<span class="token punctuation">:</span> <span class="token class-name">Action</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        listener<span class="token operator">?</span><span class="token punctuation">.</span><span class="token function">request</span><span class="token punctuation">(</span>action<span class="token punctuation">:</span> action<span class="token punctuation">)</span>        
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">ProfileViewModel</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">handleLogout</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token function">request</span><span class="token punctuation">(</span>action<span class="token punctuation">:</span> <span class="token punctuation">.</span>logout<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">handleDelete</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token function">request</span><span class="token punctuation">(</span>action<span class="token punctuation">:</span> <span class="token punctuation">.</span>deleteAccount<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h3 id="view-1">View</h3>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ProfileView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token attribute atrule">@State</span> <span class="token keyword">var</span> viewModel<span class="token punctuation">:</span> <span class="token class-name">ProfileViewModel</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">init</span><span class="token punctuation">(</span>viewModel<span class="token punctuation">:</span> <span class="token class-name">ProfileViewModel</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">self</span><span class="token punctuation">.</span>_viewModel <span class="token operator">=</span> <span class="token punctuation">.</span><span class="token keyword">init</span><span class="token punctuation">(</span>initialValue<span class="token punctuation">:</span> viewModel<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">VStack</span><span class="token punctuation">(</span>spacing<span class="token punctuation">:</span> <span class="token punctuation">.</span>zero<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token class-name">Button</span> <span class="token punctuation">{</span>
</span><span class="code-line">                viewModel<span class="token punctuation">.</span>state<span class="token punctuation">.</span>logoutAlert <span class="token operator">=</span> <span class="token boolean">true</span>
</span><span class="code-line">            <span class="token punctuation">}</span> label<span class="token punctuation">:</span> <span class="token punctuation">{</span>
</span><span class="code-line">                <span class="token operator">...</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">            <span class="token operator">...</span>
</span><span class="code-line">            
</span><span class="code-line">            <span class="token class-name">Button</span> <span class="token punctuation">{</span>
</span><span class="code-line">                viewModel<span class="token punctuation">.</span>state<span class="token punctuation">.</span>deleteAlert <span class="token operator">=</span> <span class="token boolean">true</span>
</span><span class="code-line">            <span class="token punctuation">}</span> label<span class="token punctuation">:</span> <span class="token punctuation">{</span>
</span><span class="code-line">                <span class="token operator">...</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">alert</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"정말 로그아웃하시겠습니까?"</span></span><span class="token punctuation">,</span> isPresented<span class="token punctuation">:</span> $viewModel<span class="token punctuation">.</span>state<span class="token punctuation">.</span>logoutAlert<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token class-name">Button</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"확인"</span></span><span class="token punctuation">,</span> role<span class="token punctuation">:</span> <span class="token punctuation">.</span>destructive<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">                viewModel<span class="token punctuation">.</span><span class="token function">handleLogout</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">            <span class="token class-name">Button</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"취소"</span></span><span class="token punctuation">,</span> role<span class="token punctuation">:</span> <span class="token punctuation">.</span>cancel<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">alert</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"정말 탈퇴하시겠습니까?"</span></span><span class="token punctuation">,</span> isPresented<span class="token punctuation">:</span> $viewModel<span class="token punctuation">.</span>state<span class="token punctuation">.</span>deleteAlert<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token class-name">Button</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"확인"</span></span><span class="token punctuation">,</span> role<span class="token punctuation">:</span> <span class="token punctuation">.</span>destructive<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">                viewModel<span class="token punctuation">.</span><span class="token function">handleDelete</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">            <span class="token class-name">Button</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"취소"</span></span><span class="token punctuation">,</span> role<span class="token punctuation">:</span> <span class="token punctuation">.</span>cancel<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h3 id="presenter-1">Presenter</h3>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">protocol</span> <span class="token class-name">ProfilePresentable</span><span class="token punctuation">:</span> <span class="token class-name">Presentable</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> listener<span class="token punctuation">:</span> <span class="token class-name">ProfilePresentableListener</span><span class="token operator">?</span> <span class="token punctuation">{</span> <span class="token keyword">get</span> <span class="token keyword">set</span> <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">update</span><span class="token punctuation">(</span>state<span class="token punctuation">:</span> <span class="token class-name">ProfileViewState</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">final</span> <span class="token keyword">class</span> <span class="token class-name">ProfileViewController</span><span class="token punctuation">:</span> <span class="token class-name">UIViewController</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> viewModel<span class="token punctuation">:</span> <span class="token class-name">ProfileViewModel</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">weak</span> <span class="token keyword">var</span> listener<span class="token punctuation">:</span> <span class="token class-name">ProfilePresentableListener</span><span class="token operator">?</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">didSet</span> <span class="token punctuation">{</span>
</span><span class="code-line">            viewModel<span class="token punctuation">.</span>listener <span class="token operator">=</span> listener
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">let</span> disposeBag <span class="token operator">=</span> <span class="token class-name">DisposeBag</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">let</span> memberStream<span class="token punctuation">:</span> <span class="token class-name">BehaviorRelay</span><span class="token operator">&#x3C;</span><span class="token class-name">EntityMember</span><span class="token operator">?></span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">init</span><span class="token punctuation">(</span>memberStream<span class="token punctuation">:</span> <span class="token class-name">BehaviorRelay</span><span class="token operator">&#x3C;</span><span class="token class-name">EntityMember</span><span class="token operator">?></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">self</span><span class="token punctuation">.</span>memberStream <span class="token operator">=</span> memberStream
</span><span class="code-line">        <span class="token keyword">self</span><span class="token punctuation">.</span>viewModel <span class="token operator">=</span> <span class="token class-name">ProfileViewModel</span><span class="token punctuation">(</span>state<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token keyword">init</span><span class="token punctuation">(</span>myself<span class="token punctuation">:</span> memberStream<span class="token punctuation">.</span>value<span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token keyword">init</span><span class="token punctuation">(</span>nibName<span class="token punctuation">:</span> <span class="token nil constant">nil</span><span class="token punctuation">,</span> bundle<span class="token punctuation">:</span> <span class="token nil constant">nil</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token operator">...</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">override</span> <span class="token keyword">func</span> <span class="token function-definition function">viewDidLoad</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token function">viewDidLoad</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token function">bindMemberStream</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">ProfileViewController</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">func</span> <span class="token function-definition function">bindMemberStream</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        memberStream
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">observe</span><span class="token punctuation">(</span>on<span class="token punctuation">:</span> <span class="token class-name">MainScheduler</span><span class="token punctuation">.</span>instance<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">subscribe</span><span class="token punctuation">(</span>onNext<span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token punctuation">[</span><span class="token keyword">weak</span> <span class="token keyword">self</span><span class="token punctuation">]</span> member <span class="token keyword">in</span>
</span><span class="code-line">                <span class="token keyword">guard</span> <span class="token keyword">let</span> <span class="token keyword">self</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">}</span>
</span><span class="code-line">                <span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">update</span><span class="token punctuation">(</span>state<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token keyword">init</span><span class="token punctuation">(</span>myself<span class="token punctuation">:</span> member<span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">}</span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">disposed</span><span class="token punctuation">(</span>by<span class="token punctuation">:</span> disposeBag<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">ProfileViewController</span><span class="token punctuation">:</span> <span class="token class-name">ProfilePresentable</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">update</span><span class="token punctuation">(</span>state<span class="token punctuation">:</span> <span class="token class-name">ProfileViewState</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        viewModel<span class="token punctuation">.</span><span class="token function">update</span><span class="token punctuation">(</span>state<span class="token punctuation">:</span> state<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h3 id="interactor-1">Interactor</h3>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">final</span> <span class="token keyword">class</span> <span class="token class-name">ProfileInteractor</span><span class="token punctuation">:</span> <span class="token class-name">PresentableInteractor</span><span class="token operator">&#x3C;</span><span class="token class-name">ProfilePresentable</span><span class="token operator">></span><span class="token punctuation">,</span> <span class="token class-name">ProfileInteractable</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">weak</span> <span class="token keyword">var</span> router<span class="token punctuation">:</span> <span class="token class-name">ProfileRouting</span><span class="token operator">?</span>
</span><span class="code-line">    <span class="token keyword">weak</span> <span class="token keyword">var</span> listener<span class="token punctuation">:</span> <span class="token class-name">ProfileListener</span><span class="token operator">?</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">override</span> <span class="token keyword">init</span><span class="token punctuation">(</span>presenter<span class="token punctuation">:</span> <span class="token class-name">ProfilePresentable</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token keyword">init</span><span class="token punctuation">(</span>presenter<span class="token punctuation">:</span> presenter<span class="token punctuation">)</span>
</span><span class="code-line">        presenter<span class="token punctuation">.</span>listener <span class="token operator">=</span> <span class="token keyword">self</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">ProfileInteractor</span><span class="token punctuation">:</span> <span class="token class-name">ProfilePresentableListener</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">request</span><span class="token punctuation">(</span>action<span class="token punctuation">:</span> <span class="token class-name">ProfileViewAction</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">switch</span> action <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">case</span> <span class="token punctuation">.</span>logout<span class="token punctuation">:</span>
</span><span class="code-line">            <span class="token function">handleLogout</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token keyword">case</span> <span class="token punctuation">.</span>deleteAccount<span class="token punctuation">:</span>
</span><span class="code-line">            <span class="token function">handleDeleteAccount</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>        
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">func</span> <span class="token function-definition function">handleLogout</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token operator">...</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">func</span> <span class="token function-definition function">handleDeleteAccount</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token operator">...</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="참고">참고</h2>
<ul>
<li><a href="https://www.uber.com/en-KR/blog/new-rider-app-architecture/">Engineering the Architecture Behind Uber’s New Rider App</a></li>
<li><a href="https://blog.mathpresso.com/1-ios-ribs-architecture-af9834956daf">RIBs Architecture 도입 시리즈</a></li>
<li><a href="https://github.com/uber/ribs/wiki/iOS-Tutorial-4">RIBs Wiki, iOS Tutorial 4</a></li>
<li><a href="https://minsone.github.io/swiftui-ribs">RIBs + SwiftUI</a></li>
</ul>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/uikit-clean-swift</guid>
      <title>UIKit Clean Swift</title>
      <description>iOS UIKit에 Clean Swift 아키텍처 일명 VIP 적용하기</description>
      <link>https://www.hohyeonmoon.com/blog/uikit-clean-swift</link>
      <pubDate>Fri, 22 Nov 2024 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<h2 id="clean-swift">Clean Swift</h2>
<ul>
<li>Clean Swift는 Clean Architecture를 iOS 앱 개발에 적용한 것입니다.</li>
<li>VIP를 포함하는 각 Scene은 기능별로 만들어지고, 아래의 컴포넌트로 이뤄져 있습니다.</li>
</ul>
<p><img src="/images/uikit-clean-swift-1.png" alt="uikit-clean-swift"></p>
<p>VIP와 Models, Router, Worker 정도로 이뤄져 있습니다.</p>
<ul>
<li>ViewController(+ View)</li>
<li>Interactor</li>
<li>Presenter</li>
<li>Models</li>
<li>Router</li>
<li>Worker</li>
<li>Configurator</li>
</ul>
<h2 id="views">Views</h2>
<ul>
<li>ViewController는 Interactor에 Request하고 Presenter로부터 Response를 전달 받습니다.</li>
<li>전환이 필요한 경우에는 Router와 통신하기도 합니다.</li>
</ul>
<p>ViewController의 역할은 두 가지 있습니다:</p>
<ul>
<li>사용자의 액션을 받습니다.</li>
<li>데이터를 화면에 보여줍니다.</li>
</ul>
<p>ViewController은 Display Logic 프로토콜을 가지고 있습니다:</p>
<ul>
<li>해당 프로토콜은 화면에 데이터를 바인딩 해주는 역할을 합니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">protocol</span> <span class="token class-name">MunziDisplayLogic</span><span class="token punctuation">:</span> <span class="token class-name">AnyObject</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">displayWithoutData</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">displayWithData</span><span class="token punctuation">(</span>viewModel<span class="token punctuation">:</span> <span class="token class-name">MunziModel</span><span class="token punctuation">.</span><span class="token class-name">Air</span><span class="token punctuation">.</span><span class="token class-name">ViewModel</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">final</span> <span class="token keyword">class</span> <span class="token class-name">MunziViewController</span><span class="token punctuation">:</span> <span class="token class-name">UIViewController</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> interactor<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token class-name">MunziBusinessLogic</span> <span class="token operator">&#x26;</span> <span class="token class-name">MunziDataStore</span><span class="token punctuation">)</span><span class="token operator">?</span>
</span><span class="code-line">    <span class="token keyword">var</span> router<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token class-name">NSObjectProtocol</span> <span class="token operator">&#x26;</span> <span class="token class-name">MunziRoutingLogic</span> <span class="token operator">&#x26;</span> <span class="token class-name">MunziDataPassing</span><span class="token punctuation">)</span><span class="token operator">?</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token operator">...</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">required</span> <span class="token keyword">init</span><span class="token operator">?</span><span class="token punctuation">(</span>coder<span class="token punctuation">:</span> <span class="token class-name">NSCoder</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token keyword">init</span><span class="token punctuation">(</span>coder<span class="token punctuation">:</span> coder<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token function">setup</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">override</span> <span class="token keyword">func</span> <span class="token function-definition function">viewDidLoad</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token function">viewDidLoad</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        interactor<span class="token operator">?</span><span class="token punctuation">.</span><span class="token function">fetch</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token operator">...</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">func</span> <span class="token function-definition function">setup</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">let</span> viewController <span class="token operator">=</span> <span class="token keyword">self</span>
</span><span class="code-line">        <span class="token keyword">let</span> interactor <span class="token operator">=</span> <span class="token class-name">MunziInteractor</span><span class="token punctuation">(</span>networkWorker<span class="token punctuation">:</span> <span class="token class-name">NetworkWorker</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token keyword">let</span> presenter <span class="token operator">=</span> <span class="token class-name">MunziPresenter</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token keyword">let</span> router <span class="token operator">=</span> <span class="token class-name">MunziRouter</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        
</span><span class="code-line">        viewController<span class="token punctuation">.</span>interactor <span class="token operator">=</span> interactor
</span><span class="code-line">        viewController<span class="token punctuation">.</span>router <span class="token operator">=</span> router
</span><span class="code-line">        interactor<span class="token punctuation">.</span>presenter <span class="token operator">=</span> presenter
</span><span class="code-line">        presenter<span class="token punctuation">.</span>viewController <span class="token operator">=</span> viewController
</span><span class="code-line">        router<span class="token punctuation">.</span>viewController <span class="token operator">=</span> viewController
</span><span class="code-line">        router<span class="token punctuation">.</span>dataStore <span class="token operator">=</span> interactor
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">MunziViewController</span><span class="token punctuation">:</span> <span class="token class-name">MunziDisplayLogic</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">reloadWithoutData</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">DispatchQueue</span><span class="token punctuation">.</span>main<span class="token punctuation">.</span><span class="token keyword">async</span> <span class="token punctuation">{</span> <span class="token punctuation">[</span><span class="token keyword">weak</span> <span class="token keyword">self</span><span class="token punctuation">]</span> <span class="token keyword">in</span>
</span><span class="code-line">            <span class="token comment">// UI 관련 코드</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">reloadWithData</span><span class="token punctuation">(</span>viewModel<span class="token punctuation">:</span> <span class="token class-name">MunziModel</span><span class="token punctuation">.</span><span class="token class-name">Air</span><span class="token punctuation">.</span><span class="token class-name">ViewModel</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">DispatchQueue</span><span class="token punctuation">.</span>main<span class="token punctuation">.</span><span class="token keyword">async</span> <span class="token punctuation">{</span> <span class="token punctuation">[</span><span class="token keyword">weak</span> <span class="token keyword">self</span><span class="token punctuation">]</span> <span class="token keyword">in</span>
</span><span class="code-line">            <span class="token comment">// UI 관련 코드</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="interactor">Interactor</h2>
<ul>
<li>Interactor는 중재자의 역할을 합니다.</li>
</ul>
<p>Interactor의 역할에는 3가지가 있습니다:</p>
<ul>
<li>ViewController와 통신해서 Worker에 필요한 Request를 받아옵니다.</li>
<li>Worker에서 일을 진행하기 전에 모든 값이 제대로 전송 되었는지 확인합니다.</li>
<li>Worker로부터 Response를 받으면 Presenter로 전달합니다.</li>
</ul>
<p>Interactor는 두 가지 포로토콜을 가지고 있습니다:</p>
<ul>
<li>Business Logic 프로토콜에는 ViewController에서 사용하고 싶은 Interactor의 함수가 있습니다.</li>
<li>Data Store 프로토콜에는 상태 프로퍼티들이 있고, Router와 ViewController 사이에 통신하는데 사용됩니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">protocol</span> <span class="token class-name">MunziBusinessLogic</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">fetch</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token operator">...</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">protocol</span> <span class="token class-name">MunziDataStore</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> location<span class="token punctuation">:</span> <span class="token class-name">LocationModel</span> <span class="token punctuation">{</span> <span class="token keyword">get</span> <span class="token keyword">set</span> <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token operator">...</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">final</span> <span class="token keyword">class</span> <span class="token class-name">MunziInteractor</span><span class="token punctuation">:</span> <span class="token class-name">MunziDataStore</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> presenter<span class="token punctuation">:</span> <span class="token class-name">MunziPresentationLogic</span><span class="token operator">?</span>
</span><span class="code-line">    <span class="token keyword">var</span> networkWorker<span class="token punctuation">:</span> <span class="token class-name">NetworkProtocol</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">var</span> location <span class="token operator">=</span> <span class="token class-name">LocationModel</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token operator">...</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">MunziInteractor</span><span class="token punctuation">:</span> <span class="token class-name">MunziBusinessLogic</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">fetch</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">Task</span> <span class="token punctuation">{</span>
</span><span class="code-line">            presenter<span class="token operator">?</span><span class="token punctuation">.</span><span class="token function">presentWithoutData</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token keyword">let</span> result <span class="token operator">=</span> <span class="token keyword">await</span> networkWorker<span class="token punctuation">.</span><span class="token function">fetch</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token operator">...</span>
</span><span class="code-line">            presenter<span class="token operator">?</span><span class="token punctuation">.</span><span class="token function">presentWithData</span><span class="token punctuation">(</span>response<span class="token punctuation">:</span> air<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token operator">...</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="presenter">Presenter</h2>
<p>Presenter의 역할은 두 가지 있습니다:</p>
<ul>
<li>Interactor에서 받은 Response를 ViewModel로 포맷해서 ViewController로 전달합니다.</li>
<li>데이터가 사용자에게 표시되는 방법을 결정합니다.</li>
</ul>
<p>Presenter의 프로토콜에서는:</p>
<ul>
<li>ViewController에서 선언된 델리게이트 메서드를 호출하여, 이를 통해 ViewModel를 전달합니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">protocol</span> <span class="token class-name">MunziPresentationLogic</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">presentWithoutData</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">presentWithData</span><span class="token punctuation">(</span>response<span class="token punctuation">:</span> <span class="token class-name">MunziModel</span><span class="token punctuation">.</span><span class="token class-name">Air</span><span class="token punctuation">.</span><span class="token class-name">Response</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">final</span> <span class="token keyword">class</span> <span class="token class-name">MunziPresenter</span><span class="token punctuation">:</span> <span class="token class-name">MunziPresentationLogic</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">weak</span> <span class="token keyword">var</span> viewController<span class="token punctuation">:</span> <span class="token class-name">MunziDisplayLogic</span><span class="token operator">?</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">presentWithoutData</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        viewController<span class="token operator">?</span><span class="token punctuation">.</span><span class="token function">reloadWithoutData</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">presentWithData</span><span class="token punctuation">(</span>response<span class="token punctuation">:</span> <span class="token class-name">MunziModel</span><span class="token punctuation">.</span><span class="token class-name">Air</span><span class="token punctuation">.</span><span class="token class-name">Response</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token operator">...</span>
</span><span class="code-line">        viewController<span class="token operator">?</span><span class="token punctuation">.</span><span class="token function">displayWithData</span><span class="token punctuation">(</span>viewModel<span class="token punctuation">:</span> viewModel<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="model">Model</h2>
<p>각 Model은 Request, Response, ViewModel을 포함합니다:</p>
<ul>
<li>Request: API request (ViewController → Interactor)</li>
<li>Response: API response (Interactor → Presenter)</li>
<li>ViewModel: UI를 구성하는데 필요한 데이터들 (Presenter → ViewController)</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">enum</span> <span class="token class-name">MunziModel</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">struct</span> <span class="token class-name">AirModel</span><span class="token punctuation">:</span> <span class="token class-name">Decodable</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">let</span> response<span class="token punctuation">:</span> <span class="token class-name">Body</span>
</span><span class="code-line">
</span><span class="code-line">        <span class="token keyword">struct</span> <span class="token class-name">Body</span><span class="token punctuation">:</span> <span class="token class-name">Decodable</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">let</span> body<span class="token punctuation">:</span> <span class="token class-name">Content</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">        <span class="token keyword">struct</span> <span class="token class-name">Content</span><span class="token punctuation">:</span> <span class="token class-name">Decodable</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">let</span> items<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">Item</span><span class="token punctuation">]</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">        <span class="token keyword">struct</span> <span class="token class-name">Item</span><span class="token punctuation">:</span> <span class="token class-name">Decodable</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">let</span> pm10Value<span class="token punctuation">:</span> <span class="token class-name">String</span>
</span><span class="code-line">            <span class="token keyword">let</span> pm25Value<span class="token punctuation">:</span> <span class="token class-name">String</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">enum</span> <span class="token class-name">Air</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">struct</span> <span class="token class-name">Request</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
</span><span class="code-line">                
</span><span class="code-line">        <span class="token keyword">struct</span> <span class="token class-name">Response</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">let</span> pm10<span class="token punctuation">:</span> <span class="token class-name">Double</span>
</span><span class="code-line">            <span class="token keyword">let</span> pm25<span class="token punctuation">:</span> <span class="token class-name">Double</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">struct</span> <span class="token class-name">ViewModel</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">let</span> pm10<span class="token punctuation">:</span> <span class="token class-name">Double</span>
</span><span class="code-line">            <span class="token keyword">let</span> pm25<span class="token punctuation">:</span> <span class="token class-name">Double</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="router">Router</h2>
<ul>
<li>Router는 ViewController 간의 전환과 데이터 전달을 처리합니다.</li>
</ul>
<p>Router는 두 가지 포로토콜을 갖고 있습니다:</p>
<ul>
<li>Routing Logic 프로토콜은 화면 전환에 사용되는 함수를 갖고 있습니다.</li>
<li>Data Passing 프로토콜은 ViewController 사이에 전달해야 하는 데이터를 갖고 있습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">protocol</span> <span class="token class-name">MunziRoutingLogic</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">routeToSettings</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">protocol</span> <span class="token class-name">MunziDataPassing</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> dataStore<span class="token punctuation">:</span> <span class="token class-name">MunziDataStore</span><span class="token operator">?</span> <span class="token punctuation">{</span> <span class="token keyword">get</span> <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">final</span> <span class="token keyword">class</span> <span class="token class-name">MunziRouter</span><span class="token punctuation">:</span> <span class="token class-name">NSObject</span><span class="token punctuation">,</span> <span class="token class-name">MunziRoutingLogic</span><span class="token punctuation">,</span> <span class="token class-name">MunziDataPassing</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">weak</span> <span class="token keyword">var</span> viewController<span class="token punctuation">:</span> <span class="token class-name">MunziViewController</span><span class="token operator">?</span>
</span><span class="code-line">    <span class="token keyword">var</span> dataStore<span class="token punctuation">:</span> <span class="token class-name">MunziDataStore</span><span class="token operator">?</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">routeToSettings</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">let</span> destinationVC <span class="token operator">=</span> <span class="token class-name">SettingsViewController</span><span class="token punctuation">.</span><span class="token function">configure</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token operator">...</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token function">passDataToSettings</span><span class="token punctuation">(</span>source<span class="token punctuation">:</span> dataStore<span class="token punctuation">,</span> destination<span class="token punctuation">:</span> <span class="token operator">&#x26;</span>destinationDS<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token function">navigateToSettings</span><span class="token punctuation">(</span>source<span class="token punctuation">:</span> viewController<span class="token punctuation">,</span> destination<span class="token punctuation">:</span> destinationVC<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">navigateToSettings</span><span class="token punctuation">(</span>source<span class="token punctuation">:</span> <span class="token class-name">MunziViewController</span><span class="token punctuation">,</span> destination<span class="token punctuation">:</span> <span class="token class-name">SettingsViewController</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token operator">...</span>
</span><span class="code-line">        source<span class="token punctuation">.</span><span class="token function">show</span><span class="token punctuation">(</span>destination<span class="token punctuation">,</span> sender<span class="token punctuation">:</span> <span class="token nil constant">nil</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">passDataToSettings</span><span class="token punctuation">(</span>source<span class="token punctuation">:</span> <span class="token class-name">MunziDataStore</span><span class="token punctuation">,</span> destination<span class="token punctuation">:</span> <span class="token keyword">inout</span> <span class="token class-name">SettingsDataStore</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token operator">...</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="worker">Worker</h2>
<blockquote>
<p>자세한 구현은 <a href="/blog/swift-network-layer">Swift의 Network Layer</a>을 참고해주세요</p>
</blockquote>
<ul>
<li>Worker는 API 혹은 CoreData 등의 데이터 소스에 대한 Request와 Response를 관리합니다.</li>
<li>Interactor에게 데이터를 받아 Request를 요청하거나, Response로 받은 데이터를 넘겨줍니다.</li>
</ul>
<h2 id="참고">참고</h2>
<ul>
<li><a href="https://hackernoon.com/introducing-clean-swift-architecture-vip-770a639ad7bf">Introducing Clean Swift Architecture</a></li>
<li><a href="https://github.com/Clean-Swift/CleanStore">CleanStore on GitHub</a></li>
</ul>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/ios-gcd</guid>
      <title>iOS GCD Concurrency</title>
      <description>iOS의 GCD를 활용한 Concurrency 프로그래밍 알아보기</description>
      <link>https://www.hohyeonmoon.com/blog/ios-gcd</link>
      <pubDate>Wed, 21 Aug 2024 18:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<h2 id="concurrency">Concurrency</h2>
<h3 id="필요성">필요성</h3>
<ul>
<li>가장 강력한 쓰레드인 Main Thread라고 해도 과도한 작업을 할당하면 성능 저하 발생</li>
<li>앱의 빠른 속도와 성능을 원한다면, 작업을 적절히 여러 쓰레드로 분산시켜야 함</li>
</ul>
<h3 id="사용법">사용법</h3>
<ul>
<li>기본적으로 GCD 혹은 Operation을 통해 동시성 프로그래밍을 할 수 있음</li>
<li>Swift 5.5부터 언어단에서 동시성 프로그래밍을 제공하는 Swift Concurrency도 있음</li>
<li>RxSwift 혹은 Combine 같은 반응형 프레임워크를 통해서도 동시성 프로그래밍을 할 수 있음</li>
</ul>
<h3 id="sync-vs-async">Sync vs Async</h3>
<ul>
<li>Sync: Queue로 보낸 작업이 완료 될 때까지 기다림</li>
</ul>
<p><img src="/images/ios-gcd-2.png" alt="swift-concurrency"></p>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">let</span> queue <span class="token operator">=</span> <span class="token class-name">DispatchQueue</span><span class="token punctuation">.</span><span class="token function">global</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">queue<span class="token punctuation">.</span>sync <span class="token punctuation">{</span> <span class="token comment">// 1초 task }</span>
</span><span class="code-line">queue<span class="token punctuation">.</span>sync <span class="token punctuation">{</span> <span class="token comment">// 2초 task }</span>
</span><span class="code-line">queue<span class="token punctuation">.</span>sync <span class="token punctuation">{</span> <span class="token comment">// 3초 task }</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token comment">// 총 6초 더 걸림 (약 6.001초 걸림)</span>
</span></code></pre>
<ul>
<li>Async: Queue로 보낸 작업을 기다리지 않고 다음 코드 실행</li>
</ul>
<p><img src="/images/ios-gcd-3.png" alt="swift-concurrency"></p>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">let</span> queue <span class="token operator">=</span> <span class="token class-name">DispatchQueue</span><span class="token punctuation">.</span><span class="token function">global</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">queue<span class="token punctuation">.</span><span class="token keyword">async</span> <span class="token punctuation">{</span> <span class="token comment">// 1초 task }</span>
</span><span class="code-line">queue<span class="token punctuation">.</span><span class="token keyword">async</span> <span class="token punctuation">{</span> <span class="token comment">// 2초 task }</span>
</span><span class="code-line">queue<span class="token punctuation">.</span><span class="token keyword">async</span> <span class="token punctuation">{</span> <span class="token comment">// 3초 task }</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token comment">// 총 6초 안 걸림 (약 0.001초 걸림)</span>
</span></code></pre>
<h3 id="serial-vs-concurrent">Serial vs Concurrent</h3>
<ul>
<li>Serial queue: 한개의 쓰레드에서 전부 진행. 순서가 보장되어, 순차적 실행이 필요한 작업에 적합.</li>
</ul>
<p><img src="/images/ios-gcd-4.png" alt="swift-concurrency"></p>
<ul>
<li>Concurrent queue: 여러개의 쓰레드에서 진행. 종료 순서가 보장되지 않지만, 빠른 처리가 필요한 독립적인 작업에 적합.</li>
</ul>
<p><img src="/images/ios-gcd-5.png" alt="swift-concurrency"></p>
<h2 id="gcd">GCD</h2>
<p><img src="/images/ios-gcd-1.png" alt="swift-concurrency"></p>
<h3 id="gcd란">GCD란</h3>
<ul>
<li>GCD는 Grand Central Dispatch의 줄임말</li>
<li>작업을 Dispatch Queue에 추가하면 GCD가 자동으로 쓰레드를 생성하고 실행</li>
<li>작업이 완료되면 GCD는 쓰레드를 자동으로 제거해줌</li>
<li>위에서 언급했지만, iOS GCD는 동시성 프로그래밍을 할 수 있는 한 가지 방법</li>
</ul>
<h3 id="기본-요소들">기본 요소들</h3>
<ul>
<li>Queue: FIFO 대기 행렬</li>
<li>GCD: 관리자</li>
<li>Thread: 노동자</li>
<li>Task: 작동할 코드 블럭</li>
</ul>
<h3 id="dispatch-queue-종류">Dispatch Queue 종류</h3>
<ul>
<li>Main Queue: 1개, Serial, Main Thread</li>
<li>Global Queue: Concurrent, QoS 종류 6개</li>
<li>Custom Queue: Serial/Concurrent 선택 가능, QoS 설정 가능</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token comment">// Serial 커스텀 큐 생성</span>
</span><span class="code-line"><span class="token keyword">let</span> serialQueue <span class="token operator">=</span> <span class="token class-name">DispatchQueue</span><span class="token punctuation">(</span>label<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"com.hohyeonmoon.serial"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token comment">// Concurrent 커스텀 큐 생성</span>
</span><span class="code-line"><span class="token keyword">let</span> concurrentQueue <span class="token operator">=</span> <span class="token class-name">DispatchQueue</span><span class="token punctuation">(</span>label<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"com.hohyeonmoon.concurrent"</span></span><span class="token punctuation">,</span> attributes<span class="token punctuation">:</span> <span class="token punctuation">.</span>concurrent<span class="token punctuation">)</span>
</span></code></pre>
<h3 id="qos-종류">QoS 종류</h3>
<ul>
<li>userInteractive: UI 업데이트, 애니메이션 등 즉각적인 반응이 필요한 작업</li>
<li>userInitiated: 문서 열기 등 즉시 필요하지만 약간의 대기 가능한 작업</li>
<li>default: 일반적인 작업</li>
<li>utility: 데이터 다운로드 등 시간이 걸리는 작업</li>
<li>background: 백업, 동기화 등 당장 필요 없는 작업</li>
<li>unspecified: QoS 정보가 없는 작업</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">let</span> queue <span class="token operator">=</span> <span class="token class-name">DispatchQueue</span><span class="token punctuation">(</span>label<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"com.hohyeonmoon.concurrent"</span></span><span class="token punctuation">,</span> qos<span class="token punctuation">:</span> <span class="token punctuation">.</span>userInitiated<span class="token punctuation">,</span> attributes<span class="token punctuation">:</span> <span class="token punctuation">.</span>concurrent<span class="token punctuation">)</span>
</span></code></pre>
<h3 id="dispatchgroup">DispatchGroup</h3>
<ul>
<li>여러 쓰레드로 분배된 작업을 그룹으로 묶어서 관리할 수 있다</li>
<li>작업이 모두 완료되었을 때 콜백을 통해 알림을 받을 수 있다</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">let</span> group <span class="token operator">=</span> <span class="token class-name">DispatchGroup</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">someQueue<span class="token punctuation">.</span><span class="token keyword">async</span><span class="token punctuation">(</span>group<span class="token punctuation">:</span> group<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span>
</span><span class="code-line">someQueue<span class="token punctuation">.</span><span class="token keyword">async</span><span class="token punctuation">(</span>group<span class="token punctuation">:</span> group<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span>
</span><span class="code-line">someOtherQueue<span class="token punctuation">.</span><span class="token keyword">async</span><span class="token punctuation">(</span>group<span class="token punctuation">:</span> group<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">group<span class="token punctuation">.</span><span class="token function">notify</span><span class="token punctuation">(</span>queue<span class="token punctuation">:</span> <span class="token class-name">DispatchQueue</span><span class="token punctuation">.</span>main<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token comment">// 모든 작업이 완료되었을 때 실행될 코드</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li><code>wait(timeout:)</code>을 통해 synchronous 하게 작업이 완료될 때까지 기다릴 수 있다</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">let</span> group <span class="token operator">=</span> <span class="token class-name">DispatchGroup</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">someQueue<span class="token punctuation">.</span><span class="token keyword">async</span><span class="token punctuation">(</span>group<span class="token punctuation">:</span> group<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span>
</span><span class="code-line">someQueue<span class="token punctuation">.</span><span class="token keyword">async</span><span class="token punctuation">(</span>group<span class="token punctuation">:</span> group<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span>
</span><span class="code-line">someOtherQueue<span class="token punctuation">.</span><span class="token keyword">async</span><span class="token punctuation">(</span>group<span class="token punctuation">:</span> group<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">if</span> group<span class="token punctuation">.</span><span class="token function">wait</span><span class="token punctuation">(</span>timeout<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token number">60</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token punctuation">.</span>timedOut <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token comment">// 작업이 60초 이상 걸리면 실행될 코드</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li><code>enter()</code>과 <code>leave()</code>를 통해 작업을 시작하고 완료할 수 있다</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">let</span> group <span class="token operator">=</span> <span class="token class-name">DispatchGroup</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">group<span class="token punctuation">.</span><span class="token function">enter</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">someQueue<span class="token punctuation">.</span><span class="token keyword">async</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token comment">// 작업 진행</span>
</span><span class="code-line">    group<span class="token punctuation">.</span><span class="token function">leave</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h3 id="dispatchworkitem">DispatchWorkItem</h3>
<ul>
<li>클로저로 전달하는 방법 외에도 DispatchQueue에 작업을 제출하는 방법이 있다</li>
<li>DispatchWorkItem은 큐에 제출하려는 코드를 보관할 실제 객체를 제공하는 클래스</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">let</span> queue <span class="token operator">=</span> <span class="token class-name">DispatchQueue</span><span class="token punctuation">(</span>label<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"com.hohyeonmoon.concurrent"</span></span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token keyword">let</span> workItem <span class="token operator">=</span> <span class="token class-name">DispatchWorkItem</span> <span class="token punctuation">{</span> <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"실행됨"</span></span><span class="token punctuation">)</span> <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">queue<span class="token punctuation">.</span><span class="token keyword">async</span><span class="token punctuation">(</span>execute<span class="token punctuation">:</span> workItem<span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li><code>cancel()</code>을 통해 작업을 취소할 수도 있다</li>
<li><code>notify(queue:execute:)</code>을 통해 작업이 완료되면 콜백을 통해 알림을 받을 수도 있다</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">let</span> queue <span class="token operator">=</span> <span class="token class-name">DispatchQueue</span><span class="token punctuation">(</span>label<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"com.hohyeonmoon.concurrent"</span></span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token keyword">let</span> backgroundWorkItem <span class="token operator">=</span> <span class="token class-name">DispatchWorkItem</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token keyword">let</span> updateUIWorkItem <span class="token operator">=</span> <span class="token class-name">DispatchWorkItem</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">backgroundWorkItem<span class="token punctuation">.</span><span class="token function">notify</span><span class="token punctuation">(</span>queue<span class="token punctuation">:</span> <span class="token class-name">DispatchQueue</span><span class="token punctuation">.</span>main<span class="token punctuation">,</span> execute<span class="token punctuation">:</span> updateUIWorkItem<span class="token punctuation">)</span>
</span><span class="code-line">queue<span class="token punctuation">.</span><span class="token keyword">async</span><span class="token punctuation">(</span>execute<span class="token punctuation">:</span> backgroundWorkItem<span class="token punctuation">)</span>
</span></code></pre>
<h3 id="dispatchsemaphore">DispatchSemaphore</h3>
<ul>
<li>동시에 실행할 수 있는 작업의 최대 수를 제한하는 객체</li>
<li><code>wait()</code>을 통해 신호를 기다리고, <code>signal()</code>을 통해 신호를 보낸다</li>
<li>최대 동시 실행 수를 제한하여 작업 수를 제어할 수 있다</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">let</span> semaphore <span class="token operator">=</span> <span class="token class-name">DispatchSemaphore</span><span class="token punctuation">(</span>value<span class="token punctuation">:</span> <span class="token number">2</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">for</span> i <span class="token keyword">in</span> <span class="token number">1</span><span class="token operator">...</span><span class="token number">10</span> <span class="token punctuation">{</span>
</span><span class="code-line">    queue<span class="token punctuation">.</span><span class="token keyword">async</span> <span class="token punctuation">{</span>
</span><span class="code-line">        semaphore<span class="token punctuation">.</span><span class="token function">wait</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token keyword">defer</span> <span class="token punctuation">{</span> semaphore<span class="token punctuation">.</span><span class="token function">signal</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">        <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Downloading image </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">i</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">        <span class="token comment">// Simulate a network wait</span>
</span><span class="code-line">        <span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span>forTimeInterval<span class="token punctuation">:</span> <span class="token number">3</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">        <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Downloaded image </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">i</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h3 id="dispatch-barrier">Dispatch Barrier</h3>
<ul>
<li>여러 읽기 연산은 동시에 수행하면서, 쓰기 연산 시에는 큐를 독점해야 할 때 사용</li>
<li>이미지 배열에 다수 스레드가 동시 읽기를 수행하다가 새로운 이미지를 추가할 때</li>
<li>barrier 플래그를 사용해 기존 읽기 연산이 모두 끝날 때까지 대기 후 독점적으로 쓰기 처리</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">BarrierImages</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">let</span> queue <span class="token operator">=</span> <span class="token class-name">DispatchQueue</span><span class="token punctuation">(</span>label<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"..."</span></span><span class="token punctuation">,</span> attributes<span class="token punctuation">:</span> <span class="token punctuation">.</span>concurrent<span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">var</span> _images<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">Image</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">var</span> images<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">Image</span><span class="token punctuation">]</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">var</span> copied<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">Image</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
</span><span class="code-line">        
</span><span class="code-line">        queue<span class="token punctuation">.</span>sync <span class="token punctuation">{</span>
</span><span class="code-line">            copied <span class="token operator">=</span> _images
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">return</span> copied
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">add</span><span class="token punctuation">(</span>image<span class="token punctuation">:</span> <span class="token class-name">Image</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        queue<span class="token punctuation">.</span><span class="token function">sync</span><span class="token punctuation">(</span>flags<span class="token punctuation">:</span> <span class="token punctuation">.</span>barrier<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">[</span><span class="token keyword">weak</span> <span class="token keyword">self</span><span class="token punctuation">]</span> <span class="token keyword">in</span>
</span><span class="code-line">            <span class="token keyword">self</span><span class="token operator">?</span><span class="token punctuation">.</span>_images<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>image<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">remove</span><span class="token punctuation">(</span>at index<span class="token punctuation">:</span> <span class="token class-name">Int</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Image</span><span class="token operator">?</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">var</span> removed<span class="token punctuation">:</span> <span class="token class-name">Image</span><span class="token operator">?</span> <span class="token operator">=</span> <span class="token nil constant">nil</span>
</span><span class="code-line">        
</span><span class="code-line">        queue<span class="token punctuation">.</span><span class="token function">sync</span><span class="token punctuation">(</span>flags<span class="token punctuation">:</span> <span class="token punctuation">.</span>barrier<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">[</span><span class="token keyword">weak</span> <span class="token keyword">self</span><span class="token punctuation">]</span> <span class="token keyword">in</span>
</span><span class="code-line">            removed <span class="token operator">=</span> <span class="token keyword">self</span><span class="token operator">?</span><span class="token punctuation">.</span>_images<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span>at<span class="token punctuation">:</span> index<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">return</span> removed
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="operation">Operation</h2>
<h3 id="operation-1">Operation</h3>
<ul>
<li>GCD 기반으로 동작하는 상위 레벨 프레임워크</li>
<li>동시에 실행할 수 있는 동작의 최대 수 지정 가능</li>
<li>동작 일시 중지 및 취소 가능</li>
<li>작업 간 의존성 설정 가능</li>
</ul>
<h3 id="gcd-vs-operation">GCD vs Operation</h3>
<ul>
<li>GCD: 가볍고 효율적인 구현, 간단한 작업에 적합, 빠른 성능</li>
<li>Operation: 복잡한 작업 관리, 작업 상태 모니터링, 작업 간 의존성 관리, 작업 취소 및 재시도 기능</li>
</ul>
<h3 id="작업-상태-관리">작업 상태 관리</h3>
<ul>
<li>isReady: 작업이 실행 준비가 되었는지</li>
<li>isExecuting: 현재 실행 중인지</li>
<li>isFinished: 작업이 완료되었는지</li>
<li>isCancelled: 작업이 취소되었는지</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">let</span> operation <span class="token operator">=</span> <span class="token class-name">BlockOperation</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"작업 실행 중..."</span></span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token function">print</span><span class="token punctuation">(</span>operation<span class="token punctuation">.</span>isReady<span class="token punctuation">)</span>     <span class="token comment">// true</span>
</span><span class="code-line"><span class="token function">print</span><span class="token punctuation">(</span>operation<span class="token punctuation">.</span>isExecuting<span class="token punctuation">)</span> <span class="token comment">// false</span>
</span><span class="code-line"><span class="token function">print</span><span class="token punctuation">(</span>operation<span class="token punctuation">.</span>isFinished<span class="token punctuation">)</span>  <span class="token comment">// false</span>
</span></code></pre>
<h3 id="의존성-관리">의존성 관리</h3>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">let</span> downloadOperation <span class="token operator">=</span> <span class="token class-name">BlockOperation</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"이미지 다운로드"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span>forTimeInterval<span class="token punctuation">:</span> <span class="token number">2</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">let</span> filterOperation <span class="token operator">=</span> <span class="token class-name">BlockOperation</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"이미지 필터 적용"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span>forTimeInterval<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">let</span> uploadOperation <span class="token operator">=</span> <span class="token class-name">BlockOperation</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"이미지 업로드"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span>forTimeInterval<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token comment">// 의존성 설정: 다운로드 → 필터 → 업로드 순서로 실행</span>
</span><span class="code-line">filterOperation<span class="token punctuation">.</span><span class="token function">addDependency</span><span class="token punctuation">(</span>downloadOperation<span class="token punctuation">)</span>
</span><span class="code-line">uploadOperation<span class="token punctuation">.</span><span class="token function">addDependency</span><span class="token punctuation">(</span>filterOperation<span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">let</span> queue <span class="token operator">=</span> <span class="token class-name">OperationQueue</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">queue<span class="token punctuation">.</span><span class="token function">addOperations</span><span class="token punctuation">(</span><span class="token punctuation">[</span>uploadOperation<span class="token punctuation">,</span> filterOperation<span class="token punctuation">,</span> downloadOperation<span class="token punctuation">]</span><span class="token punctuation">,</span> waitUntilFinished<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">)</span>
</span></code></pre>
<h3 id="동시-실행-수-제한">동시 실행 수 제한</h3>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">let</span> queue <span class="token operator">=</span> <span class="token class-name">OperationQueue</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">queue<span class="token punctuation">.</span>maxConcurrentOperationCount <span class="token operator">=</span> <span class="token number">3</span> <span class="token comment">// 최대 3개 작업만 동시 실행</span>
</span></code></pre>
<h3 id="큐-일시-중지-및-재개">큐 일시 중지 및 재개</h3>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line">queue<span class="token punctuation">.</span>isSuspended <span class="token operator">=</span> <span class="token boolean">true</span>  <span class="token comment">// 큐 일시 중지</span>
</span><span class="code-line">queue<span class="token punctuation">.</span>isSuspended <span class="token operator">=</span> <span class="token boolean">false</span> <span class="token comment">// 큐 재개</span>
</span></code></pre>
<h3 id="작업-취소">작업 취소</h3>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token comment">// 모든 작업 취소</span>
</span><span class="code-line">queue<span class="token punctuation">.</span><span class="token function">cancelAllOperations</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token comment">// 특정 작업 취소</span>
</span><span class="code-line">operation<span class="token punctuation">.</span><span class="token function">cancel</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span></code></pre>
<h3 id="custom-operation">Custom Operation</h3>
<ul>
<li>복잡한 작업을 위해 Operation을 상속받은 커스텀 클래스를 만들 수 있음</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">ImageProcessingOperation</span><span class="token punctuation">:</span> <span class="token class-name">Operation</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">let</span> imageURL<span class="token punctuation">:</span> <span class="token constant">URL</span>
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">var</span> task<span class="token punctuation">:</span> <span class="token class-name">URLSessionDataTask</span><span class="token operator">?</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">init</span><span class="token punctuation">(</span>imageURL<span class="token punctuation">:</span> <span class="token constant">URL</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">self</span><span class="token punctuation">.</span>imageURL <span class="token operator">=</span> imageURL
</span><span class="code-line">        <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token keyword">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">override</span> <span class="token keyword">func</span> <span class="token function-definition function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token comment">// 취소 상태 확인</span>
</span><span class="code-line">        <span class="token keyword">guard</span> <span class="token operator">!</span>isCancelled <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">}</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token comment">// 실제 작업 수행</span>
</span><span class="code-line">        <span class="token keyword">let</span> semaphore <span class="token operator">=</span> <span class="token class-name">DispatchSemaphore</span><span class="token punctuation">(</span>value<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">)</span>
</span><span class="code-line">        
</span><span class="code-line">        task <span class="token operator">=</span> <span class="token class-name">URLSession</span><span class="token punctuation">.</span>shared<span class="token punctuation">.</span><span class="token function">dataTask</span><span class="token punctuation">(</span>with<span class="token punctuation">:</span> imageURL<span class="token punctuation">)</span> <span class="token punctuation">{</span> data<span class="token punctuation">,</span> response<span class="token punctuation">,</span> error <span class="token keyword">in</span>
</span><span class="code-line">            <span class="token keyword">defer</span> <span class="token punctuation">{</span> semaphore<span class="token punctuation">.</span><span class="token function">signal</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span>
</span><span class="code-line">            
</span><span class="code-line">            <span class="token keyword">guard</span> <span class="token operator">!</span><span class="token keyword">self</span><span class="token punctuation">.</span>isCancelled <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">}</span>
</span><span class="code-line">            
</span><span class="code-line">            <span class="token keyword">if</span> <span class="token keyword">let</span> data <span class="token operator">=</span> data <span class="token punctuation">{</span>
</span><span class="code-line">                <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"이미지 다운로드 완료: </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">data<span class="token punctuation">.</span>count</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string"> bytes"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        
</span><span class="code-line">        task<span class="token operator">?</span><span class="token punctuation">.</span><span class="token function">resume</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        semaphore<span class="token punctuation">.</span><span class="token function">wait</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">override</span> <span class="token keyword">func</span> <span class="token function-definition function">cancel</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        task<span class="token operator">?</span><span class="token punctuation">.</span><span class="token function">cancel</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token function">cancel</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="주의사항">주의사항</h2>
<h3 id="main-thread">Main Thread</h3>
<ul>
<li>UI 업데이트는 반드시 Main Thread에서 이루어져야 함</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">DispatchQueue</span><span class="token punctuation">.</span>main<span class="token punctuation">.</span><span class="token keyword">async</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token comment">// UI 업데이트</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>Main Queue에서 다른 Queue로 작업을 보낼 때 sync 사용 금지</li>
<li>버벅이는 현상 발생 가능</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token comment">// 메인 쓰레드</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token class-name">DispatchQueue</span><span class="token punctuation">.</span><span class="token function">global</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>sync <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token comment">// 금지</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h3 id="retain-cycle">Retain cycle</h3>
<ul>
<li>객체에 대한 캡처 현상 주의, retain cycle 발생 가능</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">DispatchQueue</span><span class="token punctuation">.</span><span class="token function">global</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token keyword">async</span> <span class="token punctuation">{</span> <span class="token punctuation">[</span><span class="token keyword">weak</span> <span class="token keyword">self</span><span class="token punctuation">]</span> <span class="token keyword">in</span>
</span><span class="code-line">    <span class="token comment">// 캡처 방지</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h3 id="deadlock">Deadlock</h3>
<ul>
<li>데드락(= 교착 상태)이란 서로의 리소스를 기다리느라 작업이 영원히 대기 상태로 빠지는 현상</li>
<li>Main Thread에서 DispatchQueue.main.sync 사용하면 데드락 발생</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token comment">// 메인 쓰레드</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token class-name">DispatchQueue</span><span class="token punctuation">.</span>main<span class="token punctuation">.</span>sync <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token comment">// 금지</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>현재와 같은 Queue에 sync로 작업을 보내면 안됨</li>
<li>Serial Queue에서 자기 자신에게 sync로 작업을 보내면 데드락 발생 가능</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">let</span> serialQueue <span class="token operator">=</span> <span class="token class-name">DispatchQueue</span><span class="token punctuation">(</span>label<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"com.example.serial"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">serialQueue<span class="token punctuation">.</span><span class="token keyword">async</span> <span class="token punctuation">{</span>
</span><span class="code-line">    serialQueue<span class="token punctuation">.</span>sync <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token comment">// 데드락 발생: Serial Queue에서 자기 자신에게 sync 작업 전송</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h3 id="race-condition">Race Condition</h3>
<ul>
<li>Shared property에 여러 스레드가 동시에 접근하고 수정하려 할 때 발생</li>
<li>방지하기 위해, 해당 변수를 하나의 Serial 큐를 통해서만 접근하도록 보장</li>
<li>읽기 및 쓰기를 모두 안전하게 감싸는 클래스 구현</li>
</ul>
<h3 id="priority-inversion">Priority Inversion</h3>
<ul>
<li>우선순위가 높은 큐의 작업이, 우선순위가 낮은 큐의 작업 때문에 뒤로 밀리는 상황</li>
<li><code>.userInteractive</code>(높음) 큐와 <code>.utility</code>(낮음) 큐가 같은 리소스를 잠근 경우</li>
<li>먼저 잠근 쪽이 낮은 우선순위 큐라면, 높은 우선순위 작업도 잠금이 풀릴 때까지 대기해야 함</li>
<li>우선순위 역전을 방지하기 위해, 정말 필요한 경우가 아니면 서로 다른 QoS끼리 자원을 공유하는 상황을 피해야함</li>
<li>높은 우선순위가 필요한 작업은 따로 전용 큐로 분리</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">let</span> high <span class="token operator">=</span> <span class="token class-name">DispatchQueue</span><span class="token punctuation">.</span><span class="token function">global</span><span class="token punctuation">(</span>qos<span class="token punctuation">:</span> <span class="token punctuation">.</span>userInteractive<span class="token punctuation">)</span>
</span><span class="code-line"><span class="token keyword">let</span> low <span class="token operator">=</span> <span class="token class-name">DispatchQueue</span><span class="token punctuation">.</span><span class="token function">global</span><span class="token punctuation">(</span>qos<span class="token punctuation">:</span> <span class="token punctuation">.</span>utility<span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">let</span> semaphore <span class="token operator">=</span> <span class="token class-name">DispatchSemaphore</span><span class="token punctuation">(</span>value<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">high<span class="token punctuation">.</span><span class="token keyword">async</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span>forTimeInterval<span class="token punctuation">:</span> <span class="token number">2</span><span class="token punctuation">)</span>
</span><span class="code-line">    semaphore<span class="token punctuation">.</span><span class="token function">wait</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">defer</span> <span class="token punctuation">{</span> semaphore<span class="token punctuation">.</span><span class="token function">signal</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"High priority task is now running"</span></span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">low<span class="token punctuation">.</span><span class="token keyword">async</span> <span class="token punctuation">{</span>
</span><span class="code-line">    semaphore<span class="token punctuation">.</span><span class="token function">wait</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">defer</span> <span class="token punctuation">{</span> semaphore<span class="token punctuation">.</span><span class="token function">signal</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Running long, lowest priority task"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span>forTimeInterval<span class="token punctuation">:</span> <span class="token number">5</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="참고">참고</h2>
<ul>
<li><a href="https://developer.apple.com/library/archive/documentation/General/Conceptual/ConcurrencyProgrammingGuide/Introduction/Introduction.html">Concurrency Programming Guide</a></li>
<li><a href="https://sujinnaljin.medium.com/ios-%EC%B0%A8%EA%B7%BC%EC%B0%A8%EA%B7%BC-%EC%8B%9C%EC%9E%91%ED%95%98%EB%8A%94-gcd-grand-dispatch-queue-1-397db16d0305">iOS 차근차근 시작하는 GCD</a></li>
<li><a href="https://velog.io/@nnnyeong/iOS-GCD-Grand-Central-Dispatch-%EC%97%90-%EB%8C%80%ED%95%98%EC%97%AC">iOS Grand Central Dispatch에 대하여</a></li>
</ul>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/ios-starting-tdd</guid>
      <title>iOS Test와 TDD</title>
      <description>iOS에서 사용하는 테스트에 대해 알아보고 테스트 주도 개발 시작하기</description>
      <link>https://www.hohyeonmoon.com/blog/ios-starting-tdd</link>
      <pubDate>Thu, 20 Jun 2024 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<h2 id="테스트-종류">테스트 종류</h2>
<p><img src="/images/ios-starting-tdd-1.png" alt="ios-starting-tdd"></p>
<h3 id="unit-test">Unit Test</h3>
<ul>
<li>단위 코드의 로직적인 부분을 테스트</li>
<li>예를들어, 개별적인 함수가 예상대로 작동하는지 등을 확인</li>
<li>각 테스트 케이스는 독립적으로 실행되어야 함</li>
<li>Given → When → Then 순서로 테스트 작성</li>
</ul>
<h3 id="integration-test">Integration Test</h3>
<ul>
<li>모듈이나 시스템의 부분들이 상호작용을 잘 하는지 검증</li>
<li>Unit 테스트와 비슷하지만, 테스트하는 코드의 범위가 더 큼</li>
<li>이 단계에서 Reference와 비교하는 Snapshot 테스팅을 하기도 함</li>
<li>Snapshot 테스팅을 위해 <a href="https://github.com/pointfreeco/swift-snapshot-testing"><code>swift-snapshot-testing</code></a>와 같은 라이브러리 활용</li>
</ul>
<h3 id="ui-test">UI Test</h3>
<ul>
<li>앱의 UI가 사용자와의 상호작용 중에 올바르게 작동하는지 검증</li>
<li>사용자의 상호작용을 자동화하고 시뮬레이션하여 UI의 요소들이 예상대로 작동하는지 확인</li>
<li><a href="https://github.com/lyft/Hammer"><code>Hammer</code></a>와 같은 라이브러리 활용</li>
</ul>
<h2 id="테스트의-기본">테스트의 기본</h2>
<h3 id="xctestcase">XCTestCase</h3>
<ul>
<li><code>XCTestCase</code>는 XCTest 프레임워크에서 제공하는 클래스</li>
<li>모든 테스트 케이스의 기본이 되는 클래스이다</li>
<li><code>XCTestCase</code>를 상속 받아서 테스트 작성하기 시작</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">import</span> <span class="token class-name">XCTest</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">final</span> <span class="token keyword">class</span> <span class="token class-name">MyUITests</span><span class="token punctuation">:</span> <span class="token class-name">XCTestCase</span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li><code>setUp()</code>와 <code>tearDown()</code>으로 테스트 라이프 사이클 관리</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">override</span> <span class="token keyword">func</span> <span class="token function-definition function">setUp</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token keyword">override</span> <span class="token keyword">func</span> <span class="token function-definition function">tearDown</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li><code>setUpWithError()</code>와 <code>tearDownWithError()</code>로 에러 핸들링 가능</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">override</span> <span class="token keyword">func</span> <span class="token function-definition function">setUpWithError</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token keyword">override</span> <span class="token keyword">func</span> <span class="token function-definition function">tearDownWithError</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>다음 <code>setUp</code>과 <code>tearDown</code>으로 async 코드도 사용 가능</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">override</span> <span class="token keyword">func</span> <span class="token function-definition function">setUp</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token keyword">throws</span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token keyword">override</span> <span class="token keyword">func</span> <span class="token function-definition function">tearDown</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token keyword">throws</span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span>
</span></code></pre>
<h3 id="testable">@testable</h3>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token attribute atrule">@testable</span> <span class="token keyword">import</span> <span class="token class-name">MyApp</span>
</span></code></pre>
<ul>
<li><code>@testable</code>을 사용해 <code>import</code> 하면 테스트 클래스에서 <code>open</code>, <code>public</code>, <code>internal</code>에 접근 가능</li>
<li>UI 테스트에서는 의도적으로 이를 사용하지 않아 내부 코드를 접근하지 않고, UI 컴포넌트만 접근</li>
</ul>
<h3 id="assert-메소드">Assert 메소드</h3>
<ul>
<li>동일성: <code>XCTAssertEqual</code>, <code>XCTAssertNotEqual</code></li>
<li>Boolean: <code>XCTAssertTrue</code>, <code>XCTAssertFalse</code></li>
<li>Nullable: <code>XCTAssertNil</code>, <code>XCTAssertNotNil</code></li>
<li>비교: <code>XCTAssertLessThan</code>, <code>XCTAssertGreaterThan</code>, <code>XCTAssertLessThanOrEqual</code>, <code>XCTAssertGreaterThanOrEqual</code></li>
<li>에러: <code>XCTAssertThrowsError</code>, <code>XCTAssertNoThrow</code></li>
</ul>
<h3 id="ui-가져오기">UI 가져오기</h3>
<ul>
<li><code>accessibilityIdentifier</code>를 사용해 접근성 ID를 지정할수 있다</li>
<li>이 ID로 테스트에서 해당 UI를 접근할수 있다</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token comment">// SwiftUI 코드</span>
</span><span class="code-line"><span class="token class-name">ProfileHomeMomentView</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">accessibilityIdentifier</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"ProfileHomeMomentView"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token comment">// UIKit 코드</span>
</span><span class="code-line">uiview<span class="token punctuation">.</span>accessibilityIdentifier <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"ProfileHomeMomentView"</span></span>
</span><span class="code-line">
</span><span class="code-line"><span class="token comment">// 테스트 코드</span>
</span><span class="code-line">app<span class="token punctuation">.</span>otherElements<span class="token punctuation">[</span><span class="token string-literal"><span class="token string">"ProfileHomeMomentView"</span></span><span class="token punctuation">]</span>
</span></code></pre>
<ul>
<li>Xcode console에서 <code>break point</code>와 <code>po</code> 명령어로 UI id 혹은 label 확인 가능</li>
</ul>
<pre><code class="language-script code-highlight"><span class="code-line">(lldb) po app.otherElements
</span><span class="code-line">
</span><span class="code-line">Output: {
</span><span class="code-line">  Other, 0x105832cb0, {{0.0, 0.0}, {393.0, 852.0}}
</span><span class="code-line">  Other, 0x1058196d0, {{0.0, 0.0}, {393.0, 852.0}}
</span><span class="code-line">  Other, 0x105812c80, {{0.0, 0.0}, {393.0, 852.0}}
</span><span class="code-line">  ...
</span><span class="code-line">  Other, 0x1058103a0, {{16.0, 61.7}, {28.0, 28.0}}, label: 'gearshape.circle.fill'
</span><span class="code-line">  Other, 0x10580f930, {{337.0, 57.7}, {40.0, 36.0}}, label: 'More'
</span><span class="code-line">  Other, 0x105809590, {{0.0, 544.0}, {393.0, 697.0}}, identifier: 'ProfileHomeMomentView'
</span><span class="code-line">}
</span></code></pre>
<h3 id="pageobject-pattern">PageObject Pattern</h3>
<ul>
<li>주로 자동화된 UI 테스트에 사용되는 디자인 패턴</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">import</span> <span class="token class-name">XCTest</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">ProfileHomeScreen</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> app<span class="token punctuation">:</span> <span class="token class-name">XCUIApplication</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">init</span><span class="token punctuation">(</span>app<span class="token punctuation">:</span> <span class="token class-name">XCUIApplication</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">self</span><span class="token punctuation">.</span>app <span class="token operator">=</span> app
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">var</span> profileTab<span class="token punctuation">:</span> <span class="token class-name">XCUIElement</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">let</span> tabBar <span class="token operator">=</span> app<span class="token punctuation">.</span>tabBars<span class="token punctuation">[</span><span class="token string-literal"><span class="token string">"Tab Bar"</span></span><span class="token punctuation">]</span>
</span><span class="code-line">        <span class="token keyword">return</span> tabBar<span class="token punctuation">.</span>buttons<span class="token punctuation">[</span><span class="token string-literal"><span class="token string">"My"</span></span><span class="token punctuation">]</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">var</span> momentView<span class="token punctuation">:</span> <span class="token class-name">XCUIElement</span> <span class="token punctuation">{</span>
</span><span class="code-line">        app<span class="token punctuation">.</span>otherElements<span class="token punctuation">[</span><span class="token string-literal"><span class="token string">"ProfileHomeMomentView"</span></span><span class="token punctuation">]</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h3 id="ui-test-예시">UI Test 예시</h3>
<ul>
<li>PageObject Pattern을 사용한 간단한 UI Test 예시</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">import</span> <span class="token class-name">XCTest</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">final</span> <span class="token keyword">class</span> <span class="token class-name">MyUITests</span><span class="token punctuation">:</span> <span class="token class-name">XCTestCase</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> profileHomeScreen<span class="token punctuation">:</span> <span class="token class-name">ProfileHomeScreen</span><span class="token operator">!</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">override</span> <span class="token keyword">func</span> <span class="token function-definition function">setUpWithError</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token punctuation">{</span>
</span><span class="code-line">        profileHomeScreen <span class="token operator">=</span> <span class="token class-name">ProfileHomeScreen</span><span class="token punctuation">(</span>app<span class="token punctuation">:</span> <span class="token class-name">XCUIApplication</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">        profileHomeScreen<span class="token punctuation">.</span>app<span class="token punctuation">.</span><span class="token function">launch</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">testGivenAccessLevel_whenFriends_thenProfileMomentExists</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        profileHomeScreen<span class="token punctuation">.</span>profileTab<span class="token punctuation">.</span><span class="token function">tap</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token class-name">XCTAssertTrue</span><span class="token punctuation">(</span>profileHomeScreen<span class="token punctuation">.</span>momentView<span class="token punctuation">.</span>exists<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="테스트-팁">테스트 팁</h2>
<h3 id="좋은-테스트-조건">좋은 테스트 조건</h3>
<blockquote>
<p>F.I.R.S.T</p>
</blockquote>
<ul>
<li>Fast: 빠른</li>
<li>Independent: 독립적인</li>
<li>Repeatable: 반복 가능한</li>
<li>Self-Validating: 자체 검증 가능한</li>
<li>Timely: 적시의</li>
</ul>
<h3 id="좋은-명명법">좋은 명명법</h3>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">test_givenAppModel_whenStarted_thenInProgressState</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>모든 테스트는 <code>test</code>로 시작해야 한다</li>
<li><code>givenAppModel</code>: <code>AppModel</code>이 SUT(system under test)임을 나타낸다</li>
<li><code>whenStarted</code>: 테스트의 조건 또는 상태 변화이다</li>
<li><code>thenInProgressState</code>: SUT의 상태가 어떠해야 하는지에 대한 확인이다</li>
</ul>
<h3 id="test-coverage">Test Coverage</h3>
<ul>
<li>좌측 Test Navigator에서 <code>+ 버튼</code>을 눌러 새로운 <code>xctestplan</code> 파일을 만든다</li>
<li>Test Plan의 Tests에서 기존의 Test 타겟 추가</li>
<li>Test Plan의 Configurations에서 Code Coverage를 On으로 변경 및 타겟 설정</li>
<li>메뉴바 <code>Product → Scheme → Edit Scheme</code>의 Test에서 해당 Test Plan을 디폴트로 지정</li>
</ul>
<h3 id="테스트-빌드-확인">테스트 빌드 확인</h3>
<ul>
<li><code>launchArguments</code>를 통해 테스트시에만 필요한 코드를 실행할수 있다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token comment">// 테스트 코드</span>
</span><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">MyAppUITests</span><span class="token punctuation">:</span> <span class="token class-name">XCTestCase</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">override</span> <span class="token keyword">func</span> <span class="token function-definition function">setUp</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">let</span> app <span class="token operator">=</span> <span class="token class-name">XCUIApplication</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        app<span class="token punctuation">.</span>launchArguments <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string-literal"><span class="token string">"UITests"</span></span><span class="token punctuation">]</span>
</span><span class="code-line">        app<span class="token punctuation">.</span><span class="token function">launch</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token comment">// 일반 코드</span>
</span><span class="code-line"><span class="token keyword">if</span> <span class="token class-name">ProcessInfo</span><span class="token punctuation">.</span>processInfo<span class="token punctuation">.</span>arguments<span class="token punctuation">.</span><span class="token function">contains</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"UITests"</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span>
</span></code></pre>
<h3 id="스피드업-팁">스피드업 팁</h3>
<ul>
<li>speed 값을 조절해 테스트를 빠르게 진행할 수 있다</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">application</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> application<span class="token punctuation">:</span> <span class="token class-name">UIApplication</span><span class="token punctuation">,</span> didFinishLaunchingWithOptions launchOptions<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">UIApplicationLaunchOptionsKey</span><span class="token punctuation">:</span> <span class="token keyword">Any</span><span class="token punctuation">]</span><span class="token operator">?</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Bool</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">if</span> <span class="token class-name">ProcessInfo</span><span class="token punctuation">.</span>processInfo<span class="token punctuation">.</span>arguments<span class="token punctuation">.</span><span class="token function">contains</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"UITests"</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">UIApplication</span><span class="token punctuation">.</span>shared<span class="token punctuation">.</span>keyWindow<span class="token operator">?</span><span class="token punctuation">.</span>layer<span class="token punctuation">.</span>speed <span class="token operator">=</span> <span class="token number">100</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">MyAppUITests</span><span class="token punctuation">:</span> <span class="token class-name">XCTestCase</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">override</span> <span class="token keyword">func</span> <span class="token function-definition function">setUp</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">let</span> app <span class="token operator">=</span> <span class="token class-name">XCUIApplication</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        app<span class="token punctuation">.</span>launchArguments <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string-literal"><span class="token string">"UITests"</span></span><span class="token punctuation">]</span>
</span><span class="code-line">        app<span class="token punctuation">.</span><span class="token function">launch</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h3 id="xcuielement-팁">XCUIElement 팁</h3>
<ul>
<li>VoiceOver를 활성화하고 해당 Element를 탭하면 어떤 종류인지 알 수 있다.</li>
<li>Element의 종류를 바꾸고 싶다면 버튼의 <code>accessibilityAddTraits</code>를 사용할 수 있다.</li>
</ul>
<h3 id="시간차-대응">시간차 대응</h3>
<ul>
<li>애니메이션이나 네트워크 통신 등으로 UI가 나타나기까지 시간차가 발생하는 경우가 있다.</li>
<li>그럴때는 <code>waitForExistence</code>를 적절히 사용하자.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">XCTAssertTrue</span><span class="token punctuation">(</span>login<span class="token punctuation">.</span>getStartedButton<span class="token punctuation">.</span><span class="token function">waitForExistence</span><span class="token punctuation">(</span>timeout<span class="token punctuation">:</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span></code></pre>
<h3 id="xcode-cloud">Xcode Cloud</h3>
<ul>
<li>여러 종류의 테스트를 Xcode Cloud로 간편하게 자동화 할 수 있다</li>
<li>기회가 되면 다른 글을 통해 더 자세히 알아보겠다</li>
</ul>
<p><img src="/images/ios-starting-tdd-2.png" alt="ios-starting-tdd"></p>
<p><img src="/images/ios-starting-tdd-3.png" alt="ios-starting-tdd"></p>
<h2 id="tdd-프로세스">TDD 프로세스</h2>
<p><img src="/images/ios-starting-tdd-4.png" alt="ios-starting-tdd"></p>
<ul>
<li>Red Test: 실패하는 테스트를 만든다</li>
<li>Green Test: 테스트가 패스하도록 수정한다</li>
<li>Refactor: 실제 코드와 테스트 코드를 리팩토링 한다</li>
<li>Repeat: 필요한 테스트가 다 만들어질때까지 이 과정을 반복한다</li>
</ul>
<h2 id="참고">참고</h2>
<ul>
<li><a href="https://developer.apple.com/documentation/xcode/testing-your-apps-in-xcode">Testing your apps in Xcode</a></li>
<li><a href="https://www.kodeco.com/books/ios-test-driven-development-by-tutorials">Kodeco TDD 튜토리얼</a></li>
</ul>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swiftui-emoji-keyboard</guid>
      <title>SwiftUI 이모지 키보드</title>
      <description>SwiftUI로 카카오톡 같은 이모지 키보드 만들기</description>
      <link>https://www.hohyeonmoon.com/blog/swiftui-emoji-keyboard</link>
      <pubDate>Wed, 10 Apr 2024 20:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>SwiftUI에서 이모지 키보드를 만들어봤다.</li>
<li>카톡이나 메신저 앱에서 많이 사용되는 UI다.</li>
</ul>
<div style="display: flex; width: 100%; padding-bottom: 8px;">
    <img src="/images/swiftui-emoji-keyboard-1.gif" alt="swiftui-emoji-keyboard" style="flex: 1; max-width: calc(50% - 8px); height: auto; margin-right: 8px;">
    <img src="/images/swiftui-emoji-keyboard-2.gif" alt="swiftui-emoji-keyboard" style="flex: 1; max-width: calc(50% - 8px); height: auto; margin-left: 8px;">
</div>
<h2 id="이모지-데이터">이모지 데이터</h2>
<ul>
<li>데이터를 위한 구조체 Emoji와 Package를 만든다.</li>
<li>실제 이모지 대신 랜덤 색상을 사용 할 것이다.</li>
<li>Emoji와 Package는 SwiftUI의 ForEach에 사용되어서 필요한 프로토콜을 준수했다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">Emoji</span><span class="token punctuation">:</span> <span class="token class-name">Identifiable</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> id <span class="token operator">=</span> <span class="token function">UUID</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">let</span> sample <span class="token operator">=</span> <span class="token class-name">Color</span><span class="token punctuation">.</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">Package</span><span class="token punctuation">:</span> <span class="token class-name">Identifiable</span><span class="token punctuation">,</span> <span class="token class-name">Equatable</span><span class="token punctuation">,</span> <span class="token class-name">Hashable</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> id <span class="token operator">=</span> <span class="token function">UUID</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">let</span> preview <span class="token operator">=</span> <span class="token class-name">Color</span><span class="token punctuation">.</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">let</span> emojis <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">0</span><span class="token operator">..&#x3C;</span><span class="token number">30</span><span class="token punctuation">)</span><span class="token punctuation">.</span>map <span class="token punctuation">{</span> <span class="token omit keyword">_</span> <span class="token keyword">in</span> <span class="token class-name">Emoji</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">static</span> <span class="token keyword">func</span> <span class="token operator">==</span> <span class="token punctuation">(</span>lhs<span class="token punctuation">:</span> <span class="token class-name">Package</span><span class="token punctuation">,</span> rhs<span class="token punctuation">:</span> <span class="token class-name">Package</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Bool</span> <span class="token punctuation">{</span>
</span><span class="code-line">        lhs<span class="token punctuation">.</span>id <span class="token operator">==</span> rhs<span class="token punctuation">.</span>id
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">public</span> <span class="token keyword">func</span> <span class="token function-definition function">hash</span><span class="token punctuation">(</span>into hasher<span class="token punctuation">:</span> <span class="token keyword">inout</span> <span class="token class-name">Hasher</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        hasher<span class="token punctuation">.</span><span class="token function">combine</span><span class="token punctuation">(</span>id<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">Color</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">static</span> <span class="token keyword">func</span> <span class="token function-definition function">random</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Color</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">Color</span><span class="token punctuation">(</span>
</span><span class="code-line">            red<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token keyword">in</span><span class="token punctuation">:</span> <span class="token number">0</span><span class="token operator">...</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
</span><span class="code-line">            green<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token keyword">in</span><span class="token punctuation">:</span> <span class="token number">0</span><span class="token operator">...</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
</span><span class="code-line">            blue<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token keyword">in</span><span class="token punctuation">:</span> <span class="token number">0</span><span class="token operator">...</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
</span><span class="code-line">            opacity<span class="token punctuation">:</span> <span class="token number">1</span>
</span><span class="code-line">        <span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="악세서리-뷰">악세서리 뷰</h2>
<ul>
<li>TextField와 이모지 키보드 활성화 버튼을 추가했다.</li>
<li>TextField를 탭해 키보드를 활성화 하면, keyboardPublisher로 현재 키보드의 높이를 가져온다.</li>
<li>그리고 이모지 키보드 버튼을 누르면, 기존 키보드는 비활성화 되고 같은 높이의 이모지 키보드가 나타난다.</li>
<li>이질감을 줄이기 위해, 이모지 키보드는 기존 키보드와 같은 위치에 표시하고 있다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token attribute atrule">@Environment</span><span class="token punctuation">(</span><span class="token punctuation">\</span><span class="token punctuation">.</span>safeAreaInsets<span class="token punctuation">)</span> <span class="token keyword">var</span> safeAreaInsets
</span><span class="code-line">    
</span><span class="code-line">    <span class="token attribute atrule">@FocusState</span> <span class="token keyword">private</span> <span class="token keyword">var</span> keyboardShown<span class="token punctuation">:</span> <span class="token class-name">Bool</span>
</span><span class="code-line">    <span class="token attribute atrule">@State</span> <span class="token keyword">private</span> <span class="token keyword">var</span> text <span class="token operator">=</span> <span class="token string-literal"><span class="token string">""</span></span>
</span><span class="code-line">    <span class="token attribute atrule">@State</span> <span class="token keyword">private</span> <span class="token keyword">var</span> height<span class="token punctuation">:</span> <span class="token class-name">CGFloat</span> <span class="token operator">=</span> <span class="token number">0</span>
</span><span class="code-line">    <span class="token attribute atrule">@State</span> <span class="token keyword">private</span> <span class="token keyword">var</span> emojiShown <span class="token operator">=</span> <span class="token boolean">false</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">var</span> keyboardPublisher<span class="token punctuation">:</span> <span class="token class-name">NotificationCenter</span><span class="token punctuation">.</span><span class="token class-name">Publisher</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">NotificationCenter</span><span class="token punctuation">.</span><span class="token keyword">default</span><span class="token punctuation">.</span><span class="token function">publisher</span><span class="token punctuation">(</span><span class="token keyword">for</span><span class="token punctuation">:</span> <span class="token class-name">UIResponder</span><span class="token punctuation">.</span>keyboardWillShowNotification<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">GeometryReader</span> <span class="token punctuation">{</span> <span class="token omit keyword">_</span> <span class="token keyword">in</span>
</span><span class="code-line">            <span class="token class-name">VStack</span> <span class="token punctuation">{</span>
</span><span class="code-line">                <span class="token class-name">Spacer</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token class-name">HStack</span> <span class="token punctuation">{</span>
</span><span class="code-line">                    <span class="token class-name">TextField</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Sample emoji keyboard"</span></span><span class="token punctuation">,</span> text<span class="token punctuation">:</span> $text<span class="token punctuation">)</span>
</span><span class="code-line">                        <span class="token punctuation">.</span><span class="token function">focused</span><span class="token punctuation">(</span>$keyboardShown<span class="token punctuation">)</span>
</span><span class="code-line">                    
</span><span class="code-line">                    <span class="token class-name">Image</span><span class="token punctuation">(</span><span class="token punctuation">.</span>emoji<span class="token punctuation">)</span>
</span><span class="code-line">                        <span class="token punctuation">.</span>onTapGesture <span class="token punctuation">{</span>
</span><span class="code-line">                            keyboardShown<span class="token punctuation">.</span><span class="token function">toggle</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">                            emojiShown<span class="token punctuation">.</span><span class="token function">toggle</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">                        <span class="token punctuation">}</span>
</span><span class="code-line">                <span class="token punctuation">}</span>
</span><span class="code-line">                <span class="token class-name">Spacer</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">padding</span><span class="token punctuation">(</span><span class="token punctuation">.</span>horizontal<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">ignoresSafeArea</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">safeAreaInset</span><span class="token punctuation">(</span>edge<span class="token punctuation">:</span> <span class="token punctuation">.</span>bottom<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">if</span> emojiShown <span class="token punctuation">{</span>
</span><span class="code-line">                <span class="token class-name">EmojiKeyboardView</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">                    <span class="token punctuation">.</span><span class="token function">frame</span><span class="token punctuation">(</span>height<span class="token punctuation">:</span> height<span class="token punctuation">)</span>
</span><span class="code-line">                    <span class="token punctuation">.</span><span class="token function">background</span><span class="token punctuation">(</span><span class="token punctuation">.</span>black<span class="token punctuation">)</span>
</span><span class="code-line">                    <span class="token punctuation">.</span>transaction <span class="token punctuation">{</span> trans <span class="token keyword">in</span>
</span><span class="code-line">                        trans<span class="token punctuation">.</span>animation <span class="token operator">=</span> <span class="token nil constant">nil</span>
</span><span class="code-line">                    <span class="token punctuation">}</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">onReceive</span><span class="token punctuation">(</span>keyboardPublisher<span class="token punctuation">)</span> <span class="token punctuation">{</span> notification <span class="token keyword">in</span>
</span><span class="code-line">            <span class="token keyword">guard</span> <span class="token keyword">let</span> size <span class="token operator">=</span> notification<span class="token punctuation">.</span>userInfo<span class="token operator">?</span><span class="token punctuation">[</span><span class="token class-name">UIResponder</span><span class="token punctuation">.</span>keyboardFrameEndUserInfoKey<span class="token punctuation">]</span> <span class="token keyword">as</span><span class="token operator">?</span> <span class="token class-name">CGRect</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">}</span>
</span><span class="code-line">            height <span class="token operator">=</span> size<span class="token punctuation">.</span>height <span class="token operator">-</span> safeAreaInsets<span class="token punctuation">.</span>bottom
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="이모지-키보드">이모지 키보드</h2>
<ul>
<li>이제부터는 이모지 키보드 그 자체에 대한 구현이다.</li>
<li>data는 임의로 생성하고, 필요한 GridItem도 만들었다.</li>
<li>이모지 키보드는 크게 packageView와 emojiView로 이뤄져있다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">EmojiKeyboardView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token attribute atrule">@State</span> <span class="token keyword">private</span> <span class="token keyword">var</span> tabIndex <span class="token operator">=</span> <span class="token number">0</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">let</span> data <span class="token operator">=</span> <span class="token class-name">Array</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token operator">..&#x3C;</span><span class="token number">15</span><span class="token punctuation">)</span><span class="token punctuation">.</span>map <span class="token punctuation">{</span> <span class="token omit keyword">_</span> <span class="token keyword">in</span> <span class="token class-name">Package</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">.</span><span class="token function">enumerated</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">let</span> gridItem <span class="token operator">=</span> <span class="token class-name">GridItem</span><span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token function">adaptive</span><span class="token punctuation">(</span>minimum<span class="token punctuation">:</span> <span class="token number">50</span><span class="token punctuation">)</span><span class="token punctuation">,</span> spacing<span class="token punctuation">:</span> <span class="token number">16</span><span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">VStack</span><span class="token punctuation">(</span>spacing<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            packageView
</span><span class="code-line">            emojiView
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>packageView는 이모지 키보드의 상단에 위치하고, 이모지 패키지의 프리뷰를 보여주는 UI다.</li>
<li>가로 스크롤뷰를 사용해 Package의 preview를 표시하고 있다.</li>
<li>탭 했을때는 아래 나올 emojiView의 탭을 바꿔주고 있다.</li>
<li>tabIndex가 변경 되었을때는 opacity를 통해 선택 여부를 표시해주고 있다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">EmojiKeyboardView</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> packageView<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">ScrollView</span><span class="token punctuation">(</span><span class="token punctuation">.</span>horizontal<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token class-name">HStack</span><span class="token punctuation">(</span>spacing<span class="token punctuation">:</span> <span class="token class-name">AppPadding</span><span class="token punctuation">.</span>xs<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">                <span class="token class-name">ForEach</span><span class="token punctuation">(</span>data<span class="token punctuation">,</span> id<span class="token punctuation">:</span> <span class="token punctuation">\</span><span class="token punctuation">.</span>element<span class="token punctuation">)</span> <span class="token punctuation">{</span> index<span class="token punctuation">,</span> package <span class="token keyword">in</span>
</span><span class="code-line">                    package<span class="token punctuation">.</span>preview
</span><span class="code-line">                        <span class="token punctuation">.</span><span class="token function">frame</span><span class="token punctuation">(</span>width<span class="token punctuation">:</span> <span class="token number">35</span><span class="token punctuation">,</span> height<span class="token punctuation">:</span> <span class="token number">35</span><span class="token punctuation">)</span>
</span><span class="code-line">                        <span class="token punctuation">.</span><span class="token function">clipShape</span><span class="token punctuation">(</span><span class="token class-name">RoundedRectangle</span><span class="token punctuation">(</span>cornerRadius<span class="token punctuation">:</span> <span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">                        <span class="token punctuation">.</span><span class="token function">opacity</span><span class="token punctuation">(</span>index <span class="token operator">==</span> tabIndex <span class="token operator">?</span> <span class="token number">1</span> <span class="token punctuation">:</span> <span class="token number">0.2</span><span class="token punctuation">)</span>
</span><span class="code-line">                        <span class="token punctuation">.</span>onTapGesture <span class="token punctuation">{</span>
</span><span class="code-line">                            tabIndex <span class="token operator">=</span> index
</span><span class="code-line">                        <span class="token punctuation">}</span>
</span><span class="code-line">                <span class="token punctuation">}</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">padding</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">background</span><span class="token punctuation">(</span><span class="token punctuation">.</span>gray<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">scrollIndicators</span><span class="token punctuation">(</span><span class="token punctuation">.</span>hidden<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>emojiView는 실제 이모지들이 보이는 뷰다.</li>
<li>각각의 이모지 패키지를 TabView 안에 넣어, 가로 스와이프로 탐색할수 있도록 했다.</li>
<li>각 이모지 패키지 탭은 세로 스크롤 안의 그리드 형태로 표시되고 있다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">EmojiKeyboardView</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> emojiView<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">TabView</span><span class="token punctuation">(</span>selection<span class="token punctuation">:</span> $tabIndex<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token class-name">ForEach</span><span class="token punctuation">(</span>data<span class="token punctuation">,</span> id<span class="token punctuation">:</span> <span class="token punctuation">\</span><span class="token punctuation">.</span>element<span class="token punctuation">)</span> <span class="token punctuation">{</span> index<span class="token punctuation">,</span> package <span class="token keyword">in</span>
</span><span class="code-line">                <span class="token class-name">ScrollView</span> <span class="token punctuation">{</span>
</span><span class="code-line">                    <span class="token class-name">LazyVGrid</span><span class="token punctuation">(</span>columns<span class="token punctuation">:</span> <span class="token punctuation">[</span>gridItem<span class="token punctuation">]</span><span class="token punctuation">,</span> spacing<span class="token punctuation">:</span> <span class="token number">20</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">                        <span class="token class-name">ForEach</span><span class="token punctuation">(</span>package<span class="token punctuation">.</span>emojis<span class="token punctuation">)</span> <span class="token punctuation">{</span> emoji <span class="token keyword">in</span>
</span><span class="code-line">                            emoji<span class="token punctuation">.</span>sample
</span><span class="code-line">                                <span class="token punctuation">.</span><span class="token function">frame</span><span class="token punctuation">(</span>width<span class="token punctuation">:</span> <span class="token number">50</span><span class="token punctuation">,</span> height<span class="token punctuation">:</span> <span class="token number">50</span><span class="token punctuation">)</span>
</span><span class="code-line">                                <span class="token punctuation">.</span><span class="token function">clipShape</span><span class="token punctuation">(</span><span class="token class-name">RoundedRectangle</span><span class="token punctuation">(</span>cornerRadius<span class="token punctuation">:</span> <span class="token number">15</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">                        <span class="token punctuation">}</span>
</span><span class="code-line">                    <span class="token punctuation">}</span>
</span><span class="code-line">                    <span class="token punctuation">.</span><span class="token function">padding</span><span class="token punctuation">(</span><span class="token class-name">AppPadding</span><span class="token punctuation">.</span>md<span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token punctuation">}</span>
</span><span class="code-line">                <span class="token punctuation">.</span><span class="token function">tag</span><span class="token punctuation">(</span>index<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">tabViewStyle</span><span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token function">page</span><span class="token punctuation">(</span>indexDisplayMode<span class="token punctuation">:</span> <span class="token punctuation">.</span>never<span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">scrollIndicators</span><span class="token punctuation">(</span><span class="token punctuation">.</span>hidden<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">ignoresSafeArea</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/ios-clean-architecture</guid>
      <title>iOS Clean Architecture</title>
      <description>UIKit/SwiftUI를 사용하는 iOS 개발에서 Clean Architecture 사용하기</description>
      <link>https://www.hohyeonmoon.com/blog/ios-clean-architecture</link>
      <pubDate>Wed, 06 Mar 2024 18:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<h2 id="layers">Layers</h2>
<p><img src="/images/ios-clean-architecture-1.png" alt="ios-clean-architecture"></p>
<ul>
<li>Presentation Layer는 Domain Layer에 의존</li>
<li>Data Layer는 Domain Layer에 의존</li>
<li>Domain Layer는 의존성이 없기 때문에 분리해서 다른 프로젝트에서도 사용 가능</li>
</ul>
<p><img src="/images/ios-clean-architecture-2.png" alt="ios-clean-architecture"></p>
<ul>
<li>Presentation: View(SwiftUI/UIKit), ViewModel(Presenter)</li>
<li>Domain: Entity, Use Case(Interactor), Repository 인터페이스</li>
<li>Data: Repository 구현,  Data Source(remote/local), JSON Data 맵핑</li>
</ul>
<h2 id="data-흐름">Data 흐름</h2>
<ul>
<li>View가 ViewModel의 method 호출</li>
<li>ViewModel이 UseCase 실행</li>
<li>UseCase가 Repository의 data를 조합</li>
<li>Repository는 Remote/Local에서 data 받아와 리턴</li>
<li>View에 Information 표시</li>
</ul>
<h2 id="presentation">Presentation</h2>
<blockquote>
<p>SwiftUI는 MVVM 패턴의 클린 아키텍처와 어울리지 않는다는 의견도 많이 있습니다. 단방향 흐름을 갖고 있는 TCA나 MV 패턴이 대세가 되어가고 있지만, 그래도 SwiftUI에도 적용하는 방법을 알아보겠습니다.</p>
</blockquote>
<h3 id="view">View</h3>
<p>SwiftUI View</p>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">DefaultView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token attribute atrule">@StateObject</span> <span class="token keyword">private</span> <span class="token keyword">var</span> viewModel <span class="token operator">=</span> <span class="token class-name">ViewModel</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        
</span><span class="code-line">    <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">List</span><span class="token punctuation">(</span>viewModel<span class="token punctuation">.</span>items<span class="token punctuation">)</span> <span class="token punctuation">{</span> item <span class="token keyword">in</span>
</span><span class="code-line">            <span class="token class-name">Title</span><span class="token punctuation">(</span>item<span class="token punctuation">.</span>title<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">.</span>task <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">await</span> viewModel<span class="token punctuation">.</span><span class="token function">didSearch</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">""</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p>UIKit ViewController</p>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">DefaultViewController</span><span class="token punctuation">:</span> <span class="token class-name">UIViewController</span><span class="token punctuation">,</span> <span class="token class-name">StoryboardInstantiable</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">var</span> viewModel<span class="token punctuation">:</span> <span class="token class-name">ViewModel</span><span class="token operator">!</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">static</span> <span class="token keyword">func</span> <span class="token function-definition function">create</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">DefaultViewController</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">let</span> viewController <span class="token operator">=</span> <span class="token class-name">DefaultViewController</span><span class="token punctuation">.</span><span class="token function">instantiateViewController</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        viewController<span class="token punctuation">.</span>viewModel <span class="token operator">=</span> <span class="token class-name">ViewModel</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token keyword">return</span> viewController
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">override</span> <span class="token keyword">func</span> <span class="token function-definition function">viewDidLoad</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token function">viewDidLoad</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token function">bind</span><span class="token punctuation">(</span>to<span class="token punctuation">:</span> viewModel<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">func</span> <span class="token function-definition function">bind</span><span class="token punctuation">(</span>to viewModel<span class="token punctuation">:</span> <span class="token class-name">ViewModel</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        viewModel<span class="token punctuation">.</span>items<span class="token punctuation">.</span><span class="token function">observe</span><span class="token punctuation">(</span>on<span class="token punctuation">:</span> <span class="token keyword">self</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">[</span><span class="token keyword">weak</span> <span class="token keyword">self</span><span class="token punctuation">]</span> items <span class="token keyword">in</span>
</span><span class="code-line">            <span class="token comment">// items 사용</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        viewModel<span class="token punctuation">.</span>error<span class="token punctuation">.</span><span class="token function">observe</span><span class="token punctuation">(</span>on<span class="token punctuation">:</span> <span class="token keyword">self</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">[</span><span class="token keyword">weak</span> <span class="token keyword">self</span><span class="token punctuation">]</span> error <span class="token keyword">in</span>
</span><span class="code-line">            <span class="token comment">// error 사용</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h3 id="viewmodel">ViewModel</h3>
<p>SwiftUI ViewModel</p>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">ViewModel</span><span class="token punctuation">:</span> <span class="token class-name">ObservableObject</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">let</span> useCase <span class="token operator">=</span> <span class="token class-name">DefaultUseCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token attribute atrule">@Published</span> <span class="token keyword">var</span> items <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token class-name">Item</span><span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token attribute atrule">@Published</span> <span class="token keyword">var</span> error <span class="token operator">=</span> <span class="token string-literal"><span class="token string">""</span></span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">ViewModel</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">didSearch</span><span class="token punctuation">(</span>query<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">let</span> page <span class="token operator">=</span> <span class="token number">0</span>
</span><span class="code-line">        <span class="token keyword">let</span> query <span class="token operator">=</span> <span class="token class-name">Query</span><span class="token punctuation">(</span>query<span class="token punctuation">:</span> query<span class="token punctuation">)</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">await</span> <span class="token function">load</span><span class="token punctuation">(</span>query<span class="token punctuation">:</span> query<span class="token punctuation">,</span> page<span class="token punctuation">:</span> page<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">func</span> <span class="token function-definition function">load</span><span class="token punctuation">(</span>query<span class="token punctuation">:</span> <span class="token class-name">Query</span><span class="token punctuation">,</span> page<span class="token punctuation">:</span> <span class="token class-name">Int</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">do</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">let</span> request <span class="token operator">=</span> <span class="token class-name">Request</span><span class="token punctuation">(</span>query<span class="token punctuation">:</span> query<span class="token punctuation">.</span>query<span class="token punctuation">,</span> page<span class="token punctuation">:</span> page<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token keyword">self</span><span class="token punctuation">.</span>items <span class="token operator">=</span> <span class="token keyword">try</span> <span class="token keyword">await</span> useCase<span class="token punctuation">.</span><span class="token function">execute</span><span class="token punctuation">(</span>request<span class="token punctuation">:</span> request<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">self</span><span class="token punctuation">.</span>error <span class="token operator">=</span> error
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p>UIKit ViewModel</p>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">ViewModel</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">let</span> useCase <span class="token operator">=</span> <span class="token class-name">DefaultUseCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">let</span> items<span class="token punctuation">:</span> <span class="token class-name">Observable</span><span class="token operator">&#x3C;</span><span class="token punctuation">[</span><span class="token class-name">Item</span><span class="token punctuation">]</span><span class="token operator">></span> <span class="token operator">=</span> <span class="token class-name">Observable</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">let</span> error<span class="token punctuation">:</span> <span class="token class-name">Observable</span><span class="token operator">&#x3C;</span><span class="token class-name">String</span><span class="token operator">></span> <span class="token operator">=</span> <span class="token class-name">Observable</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">""</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">func</span> <span class="token function-definition function">load</span><span class="token punctuation">(</span>query<span class="token punctuation">:</span> <span class="token class-name">Query</span><span class="token punctuation">,</span> page<span class="token punctuation">:</span> <span class="token class-name">Int</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">do</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">let</span> request <span class="token operator">=</span> <span class="token class-name">Request</span><span class="token punctuation">(</span>query<span class="token punctuation">:</span> query<span class="token punctuation">.</span>query<span class="token punctuation">,</span> page<span class="token punctuation">:</span> page<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token keyword">self</span><span class="token punctuation">.</span>items <span class="token operator">=</span> <span class="token keyword">try</span> <span class="token keyword">await</span> useCase<span class="token punctuation">.</span><span class="token function">execute</span><span class="token punctuation">(</span>request<span class="token punctuation">:</span> request<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">self</span><span class="token punctuation">.</span>error <span class="token operator">=</span> error<span class="token punctuation">.</span>localizedDescription
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">final</span> <span class="token keyword">class</span> <span class="token class-name">Observable</span><span class="token operator">&#x3C;</span><span class="token class-name">Value</span><span class="token operator">></span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">struct</span> <span class="token class-name">Observer</span><span class="token operator">&#x3C;</span><span class="token class-name">Value</span><span class="token operator">></span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">weak</span> <span class="token keyword">var</span> observer<span class="token punctuation">:</span> <span class="token class-name">AnyObject</span><span class="token operator">?</span>
</span><span class="code-line">        <span class="token keyword">let</span> block<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token class-name">Value</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Void</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">var</span> observers <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token class-name">Observer</span><span class="token operator">&#x3C;</span><span class="token class-name">Value</span><span class="token operator">></span><span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">var</span> value<span class="token punctuation">:</span> <span class="token class-name">Value</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">didSet</span> <span class="token punctuation">{</span> <span class="token function">notifyObservers</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">init</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> value<span class="token punctuation">:</span> <span class="token class-name">Value</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">self</span><span class="token punctuation">.</span>value <span class="token operator">=</span> value
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">observe</span><span class="token punctuation">(</span>on observer<span class="token punctuation">:</span> <span class="token class-name">AnyObject</span><span class="token punctuation">,</span> observerBlock<span class="token punctuation">:</span> <span class="token attribute atrule">@escaping</span> <span class="token punctuation">(</span><span class="token class-name">Value</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Void</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        observers<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span><span class="token class-name">Observer</span><span class="token punctuation">(</span>observer<span class="token punctuation">:</span> observer<span class="token punctuation">,</span> block<span class="token punctuation">:</span> observerBlock<span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token function">observerBlock</span><span class="token punctuation">(</span><span class="token keyword">self</span><span class="token punctuation">.</span>value<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">remove</span><span class="token punctuation">(</span>observer<span class="token punctuation">:</span> <span class="token class-name">AnyObject</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        observers <span class="token operator">=</span> observers<span class="token punctuation">.</span>filter <span class="token punctuation">{</span> <span class="token short-argument">$0</span><span class="token punctuation">.</span>observer <span class="token operator">!==</span> observer <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">func</span> <span class="token function-definition function">notifyObservers</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">for</span> observer <span class="token keyword">in</span> observers <span class="token punctuation">{</span>
</span><span class="code-line">            observer<span class="token punctuation">.</span><span class="token function">block</span><span class="token punctuation">(</span><span class="token keyword">self</span><span class="token punctuation">.</span>value<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h3 id="data-바인딩">Data 바인딩</h3>
<ul>
<li>SwiftUI는 SwiftUI Property Wrappers, Observable Macro, Combine ObservableObject 등 사용</li>
<li>UIKit은 Observable(커스텀), RxSwift, Closure, Delegate 등 사용</li>
</ul>
<h2 id="domain">Domain</h2>
<h3 id="entity">Entity</h3>
<ul>
<li>Business Logic에 사용될 Data 형태</li>
<li>Codable Data를 Entity 형태로 맵핑해서 사용</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">Item</span><span class="token punctuation">:</span> <span class="token class-name">Equatable</span><span class="token punctuation">,</span> <span class="token class-name">Identifiable</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> id <span class="token operator">=</span> <span class="token function">UUID</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">let</span> title<span class="token punctuation">:</span> <span class="token class-name">String</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h3 id="usecase">UseCase</h3>
<ul>
<li>Business Logic을 구현하는 곳</li>
<li>Interactor로 불리기도 함</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">protocol</span> <span class="token class-name">UseCase</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">execute</span><span class="token punctuation">(</span>request<span class="token punctuation">:</span> <span class="token class-name">Request</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token keyword">throws</span> <span class="token operator">-></span> <span class="token punctuation">[</span><span class="token class-name">Item</span><span class="token punctuation">]</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">DefaultUseCase</span><span class="token punctuation">:</span> <span class="token class-name">UseCase</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">let</span> repository <span class="token operator">=</span> <span class="token class-name">DefaultRepository</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">execute</span><span class="token punctuation">(</span>request<span class="token punctuation">:</span> <span class="token class-name">Request</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token keyword">throws</span> <span class="token operator">-></span> <span class="token punctuation">[</span><span class="token class-name">Item</span><span class="token punctuation">]</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">let</span> result <span class="token operator">=</span> <span class="token keyword">try</span> <span class="token keyword">await</span> repository<span class="token punctuation">.</span><span class="token function">fetchList</span><span class="token punctuation">(</span>query<span class="token punctuation">:</span> request<span class="token punctuation">.</span>query<span class="token punctuation">,</span> page<span class="token punctuation">:</span> request<span class="token punctuation">.</span>page<span class="token punctuation">)</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token comment">// result 활용 비즈니스 로직</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">return</span> result
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h3 id="repository-인터페이스">Repository 인터페이스</h3>
<ul>
<li>Dependency Inversion을 위해 필요</li>
<li>간단히 말해, Data Layer가 Domain Layer에 의존하기 위해 필요</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">protocol</span> <span class="token class-name">Repository</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">fetchList</span><span class="token punctuation">(</span>query<span class="token punctuation">:</span> <span class="token class-name">Query</span><span class="token punctuation">,</span> page<span class="token punctuation">:</span> <span class="token class-name">Int</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token keyword">throws</span> <span class="token operator">-></span> <span class="token punctuation">[</span><span class="token class-name">Item</span><span class="token punctuation">]</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="data">Data</h2>
<h3 id="repository-구현부">Repository 구현부</h3>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">DefaultRepository</span><span class="token punctuation">:</span> <span class="token class-name">Repository</span> <span class="token punctuation">{</span>    
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">let</span> networkService <span class="token operator">=</span> <span class="token class-name">NetworkService</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">fetchList</span><span class="token punctuation">(</span>query<span class="token punctuation">:</span> <span class="token class-name">Query</span><span class="token punctuation">,</span> page<span class="token punctuation">:</span> <span class="token class-name">Int</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token keyword">throws</span> <span class="token operator">-></span> <span class="token punctuation">[</span><span class="token class-name">Item</span><span class="token punctuation">]</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">let</span> request <span class="token operator">=</span> <span class="token class-name">Request</span><span class="token punctuation">(</span>query<span class="token punctuation">:</span> query<span class="token punctuation">.</span>query<span class="token punctuation">,</span> page<span class="token punctuation">:</span> page<span class="token punctuation">)</span>        
</span><span class="code-line">        <span class="token keyword">let</span> endpoint <span class="token operator">=</span> <span class="token class-name">APIEndpoints</span><span class="token punctuation">.</span><span class="token keyword">get</span><span class="token punctuation">(</span>with<span class="token punctuation">:</span> request<span class="token punctuation">)</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">let</span> response<span class="token punctuation">:</span> <span class="token class-name">Response</span> <span class="token operator">=</span> <span class="token keyword">try</span> <span class="token keyword">await</span> networkService<span class="token punctuation">.</span><span class="token function">request</span><span class="token punctuation">(</span>with<span class="token punctuation">:</span> endpoint<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token keyword">let</span> result <span class="token operator">=</span> response<span class="token punctuation">.</span><span class="token function">toDomain</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">return</span> result
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h3 id="network-service">Network Service</h3>
<ul>
<li>Remote data source로써 API와 통신하는 역할</li>
<li>Alamofire 같은 써드파티 라이브러리를 사용해도 됨</li>
<li><a href="/blog/swift-network-layer">Network Layer 글</a> 참고해서 자체적인 구현도 가능</li>
</ul>
<h3 id="local-data">Local Data</h3>
<ul>
<li>Local data source로써 CoreData, Realm, Cache 등에 해당</li>
</ul>
<h3 id="json-codable">JSON Codable</h3>
<ul>
<li>JSON을 Codable로 파싱하는 Data 구조체</li>
<li>Domain에서 사용하기 위해 Entity로 맵핑하는 부분도 구현</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">Request</span><span class="token punctuation">:</span> <span class="token class-name">Encodable</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> query<span class="token punctuation">:</span> <span class="token class-name">String</span>
</span><span class="code-line">    <span class="token keyword">let</span> page<span class="token punctuation">:</span> <span class="token class-name">Int</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">Response</span><span class="token punctuation">:</span> <span class="token class-name">Decodable</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> page<span class="token punctuation">:</span> <span class="token class-name">Int</span>
</span><span class="code-line">    <span class="token keyword">let</span> titles<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">String</span><span class="token punctuation">]</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">Response</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">toDomain</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token punctuation">[</span><span class="token class-name">Item</span><span class="token punctuation">]</span> <span class="token punctuation">{</span>
</span><span class="code-line">        titles<span class="token punctuation">.</span>map <span class="token punctuation">{</span> <span class="token class-name">Item</span><span class="token punctuation">(</span>title<span class="token punctuation">:</span> <span class="token short-argument">$0</span><span class="token punctuation">)</span> <span class="token punctuation">}</span>        
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="dependency-injection">Dependency Injection</h2>
<h3 id="swiftui">SwiftUI</h3>
<ul>
<li>SwiftUI에서는 DI 라이브러리가 굳이 필요할까?</li>
<li><code>@Environment</code>, <code>@EnvironmentObject</code>, <code>@ObservedObject</code> 사용</li>
<li>테스트 용이성이나 추가적인 확장을 위해 Point-Free의 <a href="https://github.com/pointfreeco/swift-dependencies"><code>swift-dependencies</code></a>와 같은 라이브러리를 사용하기도 함</li>
</ul>
<h3 id="uikit">UIKit</h3>
<p>Constructor Injection</p>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">protocol</span> <span class="token class-name">NetworkingProtocol</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">request</span><span class="token punctuation">(</span>with request<span class="token punctuation">:</span> <span class="token class-name">URLRequest</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token keyword">throws</span> <span class="token operator">-></span> <span class="token class-name">Response</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">Repository</span><span class="token punctuation">:</span> <span class="token class-name">RepositoryProtocol</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">let</span> networking<span class="token punctuation">:</span> <span class="token class-name">NetworkingProtocol</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">init</span><span class="token punctuation">(</span>networking<span class="token punctuation">:</span> <span class="token class-name">NetworkingProtocol</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">self</span><span class="token punctuation">.</span>networking <span class="token operator">=</span> networking
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p>Property Injection / Method Injection</p>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token comment">// Property Injection</span>
</span><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">Repository</span><span class="token punctuation">:</span> <span class="token class-name">RepositoryProtocol</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> networking<span class="token punctuation">:</span> <span class="token class-name">NetworkingProtocol</span><span class="token operator">?</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token comment">// Method Injection</span>
</span><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">Repository</span><span class="token punctuation">:</span> <span class="token class-name">RepositoryProtocol</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">var</span> networking<span class="token punctuation">:</span> <span class="token class-name">NetworkingProtocol</span><span class="token operator">?</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">set</span><span class="token punctuation">(</span>networking<span class="token punctuation">:</span> <span class="token class-name">NetworkingProtocol</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">self</span><span class="token punctuation">.</span>networking <span class="token operator">=</span> networking
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p>Interface Injection</p>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">protocol</span> <span class="token class-name">NetworkingDependent</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">register</span><span class="token punctuation">(</span>networking<span class="token punctuation">:</span> <span class="token class-name">NetworkingProtocol</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">RepositoryImpl</span><span class="token punctuation">:</span> <span class="token class-name">RepositoryProtocol</span><span class="token punctuation">,</span> <span class="token class-name">NetworkingDependent</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">var</span> networking<span class="token punctuation">:</span> <span class="token class-name">NetworkingProtocol</span><span class="token operator">?</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">register</span><span class="token punctuation">(</span>networking<span class="token punctuation">:</span> <span class="token class-name">NetworkingProtocol</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">self</span><span class="token punctuation">.</span>networking <span class="token operator">=</span> networking
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p>IoC Container</p>
<ul>
<li><a href="https://github.com/Swinject/Swinject">Swinject</a>와 같은 프레임워크</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token comment">// Constructor Injection</span>
</span><span class="code-line"><span class="token keyword">let</span> networking <span class="token operator">=</span> <span class="token class-name">Networking</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token keyword">let</span> repository <span class="token operator">=</span> <span class="token class-name">Repository</span><span class="token punctuation">(</span>networking<span class="token punctuation">:</span> networking<span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token comment">// IoC Container</span>
</span><span class="code-line"><span class="token keyword">let</span> container <span class="token operator">=</span> <span class="token class-name">Container</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">container<span class="token punctuation">.</span><span class="token function">register</span><span class="token punctuation">(</span><span class="token class-name">Networking</span><span class="token punctuation">.</span><span class="token keyword">self</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token omit keyword">_</span> <span class="token keyword">in</span> <span class="token class-name">Networking</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span>
</span><span class="code-line">container<span class="token punctuation">.</span><span class="token function">register</span><span class="token punctuation">(</span><span class="token class-name">Repository</span><span class="token punctuation">.</span><span class="token keyword">self</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> r <span class="token keyword">in</span>
</span><span class="code-line">    <span class="token class-name">Repository</span><span class="token punctuation">(</span>networking<span class="token punctuation">:</span> r<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">let</span> repository <span class="token operator">=</span> container<span class="token punctuation">.</span><span class="token function">resolve</span><span class="token punctuation">(</span><span class="token class-name">Repository</span><span class="token punctuation">.</span><span class="token keyword">self</span><span class="token punctuation">)</span><span class="token operator">!</span>
</span></code></pre>
<p>Hierarchical DI</p>
<ul>
<li><a href="https://github.com/uber/needle">Needle</a>와 같은 프레임워크</li>
</ul>
<h2 id="참고">참고</h2>
<ul>
<li><a href="https://tech.olx.com/clean-architecture-and-mvvm-on-ios-c9d167d9f5b3">Clean Architecture and MVVM on iOS</a></li>
<li><a href="https://nalexn.github.io/clean-architecture-swiftui/?utm_source=nalexn_github">Clean Architecture for SwiftUI</a></li>
</ul>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swift-network-layer</guid>
      <title>Swift Network Layer</title>
      <description>Swift로 API와 통신하는 앱의 Network Layer 구현하기</description>
      <link>https://www.hohyeonmoon.com/blog/swift-network-layer</link>
      <pubDate>Sun, 04 Feb 2024 23:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<h2 id="protocol">Protocol</h2>
<ul>
<li>네트워킹에 필요한 프로토콜을 정의합니다.</li>
<li><code>URLSessionProtocol</code>, <code>NetworkProtocol</code>, <code>EndpointProtocol</code> 정도 있을것 같습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">protocol</span> <span class="token class-name">URLSessionProtocol</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">data</span><span class="token punctuation">(</span><span class="token keyword">for</span> request<span class="token punctuation">:</span> <span class="token class-name">URLRequest</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token keyword">throws</span> <span class="token operator">-></span> <span class="token punctuation">(</span><span class="token class-name">Data</span><span class="token punctuation">,</span> <span class="token class-name">URLResponse</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">URLSession</span><span class="token punctuation">:</span> <span class="token class-name">URLSessionProtocol</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">protocol</span> <span class="token class-name">NetworkProtocol</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> session<span class="token punctuation">:</span> <span class="token class-name">URLSessionProtocol</span> <span class="token punctuation">{</span> <span class="token keyword">get</span> <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">request</span><span class="token operator">&#x3C;</span><span class="token class-name">T</span><span class="token punctuation">:</span> <span class="token class-name">Decodable</span><span class="token operator">></span><span class="token punctuation">(</span>endpoint<span class="token punctuation">:</span> <span class="token class-name">EndpointProtocol</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token keyword">throws</span> <span class="token operator">-></span> <span class="token class-name">T</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">protocol</span> <span class="token class-name">EndpointProtocol</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> baseURL<span class="token punctuation">:</span> <span class="token constant">URL</span><span class="token operator">?</span> <span class="token punctuation">{</span> <span class="token keyword">get</span> <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token keyword">var</span> path<span class="token punctuation">:</span> <span class="token class-name">String</span> <span class="token punctuation">{</span> <span class="token keyword">get</span> <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token keyword">var</span> method<span class="token punctuation">:</span> <span class="token class-name">NetworkMethod</span> <span class="token punctuation">{</span> <span class="token keyword">get</span> <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token keyword">var</span> parameters<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">URLQueryItem</span><span class="token punctuation">]</span><span class="token operator">?</span> <span class="token punctuation">{</span> <span class="token keyword">get</span> <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token keyword">var</span> headers<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">String</span><span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">]</span><span class="token operator">?</span> <span class="token punctuation">{</span> <span class="token keyword">get</span> <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token class-name">Encodable</span><span class="token operator">?</span> <span class="token punctuation">{</span> <span class="token keyword">get</span> <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>NetworkMethod 열거형도 정의합니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">enum</span> <span class="token class-name">NetworkMethod</span><span class="token punctuation">:</span> <span class="token class-name">String</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">case</span> <span class="token keyword">get</span> <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"GET"</span></span>
</span><span class="code-line">    <span class="token keyword">case</span> post <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"POST"</span></span>
</span><span class="code-line">    <span class="token keyword">case</span> put <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"PUT"</span></span>
</span><span class="code-line">    <span class="token keyword">case</span> delete <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"DELETE"</span></span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="endpoint">Endpoint</h2>
<ul>
<li><code>EndpointProtocol</code> 프로토콜을 준수하여 API 엔드포인트를 정의합니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">enum</span> <span class="token class-name">ApiEndpoint</span><span class="token punctuation">:</span> <span class="token class-name">EndpointProtocol</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">case</span> <span class="token function">station</span><span class="token punctuation">(</span>x<span class="token punctuation">:</span> <span class="token class-name">Double</span><span class="token punctuation">,</span> y<span class="token punctuation">:</span> <span class="token class-name">Double</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">case</span> <span class="token function">air</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">var</span> baseURL<span class="token punctuation">:</span> <span class="token constant">URL</span><span class="token operator">?</span> <span class="token punctuation">{</span> <span class="token function">URL</span><span class="token punctuation">(</span>string<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"http://example.com"</span></span><span class="token punctuation">)</span> <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">var</span> path<span class="token punctuation">:</span> <span class="token class-name">String</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">switch</span> <span class="token keyword">self</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">case</span> <span class="token punctuation">.</span>station<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"/station"</span></span>
</span><span class="code-line">        <span class="token keyword">case</span> <span class="token punctuation">.</span>air<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"/air"</span></span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">var</span> method<span class="token punctuation">:</span> <span class="token class-name">NetworkMethod</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">switch</span> <span class="token keyword">self</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">case</span> <span class="token punctuation">.</span>station<span class="token punctuation">,</span> <span class="token punctuation">.</span>air<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token keyword">get</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">var</span> parameters<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">URLQueryItem</span><span class="token punctuation">]</span><span class="token operator">?</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">switch</span> <span class="token keyword">self</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">case</span> <span class="token keyword">let</span> <span class="token punctuation">.</span><span class="token function">station</span><span class="token punctuation">(</span>x<span class="token punctuation">,</span> y<span class="token punctuation">)</span><span class="token punctuation">:</span>
</span><span class="code-line">            <span class="token punctuation">[</span>
</span><span class="code-line">                <span class="token class-name">URLQueryItem</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"tmX"</span></span><span class="token punctuation">,</span> value<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"</span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">x</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span><span class="token punctuation">,</span>
</span><span class="code-line">                <span class="token class-name">URLQueryItem</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"tmY"</span></span><span class="token punctuation">,</span> value<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"</span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">y</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span><span class="token punctuation">,</span>
</span><span class="code-line">                <span class="token operator">...</span>
</span><span class="code-line">            <span class="token punctuation">]</span>
</span><span class="code-line">        <span class="token keyword">case</span> <span class="token keyword">let</span> <span class="token punctuation">.</span><span class="token function">air</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">:</span>
</span><span class="code-line">            <span class="token punctuation">[</span>
</span><span class="code-line">                <span class="token class-name">URLQueryItem</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"stationName"</span></span><span class="token punctuation">,</span> value<span class="token punctuation">:</span> name<span class="token punctuation">)</span><span class="token punctuation">,</span>
</span><span class="code-line">                <span class="token operator">...</span>
</span><span class="code-line">            <span class="token punctuation">]</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">var</span> headers<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">String</span><span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">]</span><span class="token operator">?</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">switch</span> <span class="token keyword">self</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">case</span> <span class="token punctuation">.</span>station<span class="token punctuation">,</span> <span class="token punctuation">.</span>air<span class="token punctuation">:</span>
</span><span class="code-line">            <span class="token punctuation">[</span>
</span><span class="code-line">                <span class="token string-literal"><span class="token string">"Content-Type"</span></span><span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"application/json"</span></span><span class="token punctuation">,</span>
</span><span class="code-line">                <span class="token string-literal"><span class="token string">"Authorization"</span></span><span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Bearer "</span></span> <span class="token operator">+</span> token
</span><span class="code-line">            <span class="token punctuation">]</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token class-name">Encodable</span><span class="token operator">?</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">switch</span> <span class="token keyword">self</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">case</span> <span class="token punctuation">.</span>station<span class="token punctuation">,</span> <span class="token punctuation">.</span>air<span class="token punctuation">:</span> <span class="token nil constant">nil</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="networkservice">NetworkService</h2>
<ul>
<li>다음과 같이 <code>NetworkProtocol</code>를 준수하는 <code>NetworkService</code>를 구현합니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">NetworkService</span><span class="token punctuation">:</span> <span class="token class-name">NetworkProtocol</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> session<span class="token punctuation">:</span> <span class="token class-name">URLSessionProtocol</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">static</span> <span class="token keyword">let</span> shared<span class="token punctuation">:</span> <span class="token class-name">NetworkService</span> <span class="token operator">=</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">let</span> config <span class="token operator">=</span> <span class="token class-name">URLSessionConfiguration</span><span class="token punctuation">.</span><span class="token keyword">default</span>
</span><span class="code-line">        <span class="token keyword">let</span> session <span class="token operator">=</span> <span class="token class-name">URLSession</span><span class="token punctuation">(</span>configuration<span class="token punctuation">:</span> config<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token keyword">return</span> <span class="token class-name">NetworkService</span><span class="token punctuation">(</span>session<span class="token punctuation">:</span> session<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">init</span><span class="token punctuation">(</span>session<span class="token punctuation">:</span> <span class="token class-name">URLSessionProtocol</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">self</span><span class="token punctuation">.</span>session <span class="token operator">=</span> session
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">request</span><span class="token operator">&#x3C;</span><span class="token class-name">T</span><span class="token punctuation">:</span> <span class="token class-name">Decodable</span><span class="token operator">></span><span class="token punctuation">(</span>endpoint<span class="token punctuation">:</span> <span class="token class-name">EndpointProtocol</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token keyword">throws</span> <span class="token operator">-></span> <span class="token class-name">T</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">guard</span> <span class="token keyword">let</span> url <span class="token operator">=</span> <span class="token function">configUrl</span><span class="token punctuation">(</span>endpoint<span class="token punctuation">:</span> endpoint<span class="token punctuation">)</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">throw</span> <span class="token class-name">NetworkError</span><span class="token punctuation">.</span>invalidUrl
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">let</span> request <span class="token operator">=</span> <span class="token function">configRequest</span><span class="token punctuation">(</span>url<span class="token punctuation">:</span> url<span class="token punctuation">,</span> endpoint<span class="token punctuation">:</span> endpoint<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token keyword">let</span> <span class="token punctuation">(</span>data<span class="token punctuation">,</span> response<span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token keyword">try</span> <span class="token keyword">await</span> session<span class="token punctuation">.</span><span class="token function">data</span><span class="token punctuation">(</span><span class="token keyword">for</span><span class="token punctuation">:</span> request<span class="token punctuation">)</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">return</span> <span class="token keyword">try</span> <span class="token function">processResponse</span><span class="token punctuation">(</span>data<span class="token punctuation">:</span> data<span class="token punctuation">,</span> response<span class="token punctuation">:</span> response<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">NetworkService</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">func</span> <span class="token function-definition function">configUrl</span><span class="token punctuation">(</span>endpoint<span class="token punctuation">:</span> <span class="token class-name">EndpointProtocol</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token constant">URL</span><span class="token operator">?</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">guard</span> <span class="token keyword">let</span> url <span class="token operator">=</span> endpoint<span class="token punctuation">.</span>baseURL<span class="token operator">?</span><span class="token punctuation">.</span><span class="token function">appendingPathComponent</span><span class="token punctuation">(</span>endpoint<span class="token punctuation">.</span>path<span class="token punctuation">)</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">return</span> <span class="token nil constant">nil</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">guard</span> <span class="token keyword">var</span> components <span class="token operator">=</span> <span class="token class-name">URLComponents</span><span class="token punctuation">(</span>url<span class="token punctuation">:</span> url<span class="token punctuation">,</span> resolvingAgainstBaseURL<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">)</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">return</span> <span class="token nil constant">nil</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        
</span><span class="code-line">        components<span class="token punctuation">.</span>queryItems <span class="token operator">=</span> endpoint<span class="token punctuation">.</span>parameters
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">return</span> components<span class="token punctuation">.</span>url
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">func</span> <span class="token function-definition function">configRequest</span><span class="token punctuation">(</span>url<span class="token punctuation">:</span> <span class="token constant">URL</span><span class="token punctuation">,</span> endpoint<span class="token punctuation">:</span> <span class="token class-name">EndpointProtocol</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">URLRequest</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">var</span> request <span class="token operator">=</span> <span class="token class-name">URLRequest</span><span class="token punctuation">(</span>url<span class="token punctuation">:</span> url<span class="token punctuation">)</span>
</span><span class="code-line">        request<span class="token punctuation">.</span>httpMethod <span class="token operator">=</span> endpoint<span class="token punctuation">.</span>method<span class="token punctuation">.</span>rawValue
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">if</span> <span class="token keyword">let</span> headers <span class="token operator">=</span> endpoint<span class="token punctuation">.</span>headers <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">for</span> <span class="token punctuation">(</span>key<span class="token punctuation">,</span> value<span class="token punctuation">)</span> <span class="token keyword">in</span> headers <span class="token punctuation">{</span>
</span><span class="code-line">                request<span class="token punctuation">.</span><span class="token function">setValue</span><span class="token punctuation">(</span>value<span class="token punctuation">,</span> forHTTPHeaderField<span class="token punctuation">:</span> key<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">if</span> <span class="token keyword">let</span> body <span class="token operator">=</span> endpoint<span class="token punctuation">.</span>body <span class="token punctuation">{</span>
</span><span class="code-line">            request<span class="token punctuation">.</span>httpBody <span class="token operator">=</span> <span class="token keyword">try</span><span class="token operator">?</span> <span class="token class-name">JSONEncoder</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">encode</span><span class="token punctuation">(</span>body<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">return</span> request
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">func</span> <span class="token function-definition function">processResponse</span><span class="token operator">&#x3C;</span><span class="token class-name">T</span><span class="token punctuation">:</span> <span class="token class-name">Decodable</span><span class="token operator">></span><span class="token punctuation">(</span>data<span class="token punctuation">:</span> <span class="token class-name">Data</span><span class="token punctuation">,</span> response<span class="token punctuation">:</span> <span class="token class-name">URLResponse</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token operator">-></span> <span class="token class-name">T</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">guard</span> <span class="token keyword">let</span> httpResponse <span class="token operator">=</span> response <span class="token keyword">as</span><span class="token operator">?</span> <span class="token class-name">HTTPURLResponse</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">throw</span> <span class="token class-name">NetworkError</span><span class="token punctuation">.</span>invalidResponse
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">guard</span> <span class="token punctuation">(</span><span class="token number">200</span><span class="token operator">...</span><span class="token number">299</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">contains</span><span class="token punctuation">(</span>httpResponse<span class="token punctuation">.</span>statusCode<span class="token punctuation">)</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">throw</span> <span class="token class-name">NetworkError</span><span class="token punctuation">.</span><span class="token function">serverError</span><span class="token punctuation">(</span>statusCode<span class="token punctuation">:</span> httpResponse<span class="token punctuation">.</span>statusCode<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">do</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">let</span> decoder <span class="token operator">=</span> <span class="token class-name">JSONDecoder</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">            decoder<span class="token punctuation">.</span>keyDecodingStrategy <span class="token operator">=</span> <span class="token punctuation">.</span>convertFromSnakeCase
</span><span class="code-line">            
</span><span class="code-line">            <span class="token keyword">return</span> <span class="token keyword">try</span> decoder<span class="token punctuation">.</span><span class="token function">decode</span><span class="token punctuation">(</span><span class="token class-name">T</span><span class="token punctuation">.</span><span class="token keyword">self</span><span class="token punctuation">,</span> from<span class="token punctuation">:</span> data<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">throw</span> <span class="token class-name">NetworkError</span><span class="token punctuation">.</span><span class="token function">decodingError</span><span class="token punctuation">(</span>error<span class="token punctuation">.</span>localizedDescription<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="error-handling">Error Handling</h2>
<ul>
<li>Custom 에러 타입을 정의합니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">enum</span> <span class="token class-name">NetworkError</span><span class="token punctuation">:</span> <span class="token class-name">Error</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">case</span> invalidUrl
</span><span class="code-line">    <span class="token keyword">case</span> invalidResponse
</span><span class="code-line">    <span class="token keyword">case</span> <span class="token function">decodingError</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">case</span> <span class="token function">serverError</span><span class="token punctuation">(</span>statusCode<span class="token punctuation">:</span> <span class="token class-name">Int</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>각 케이스에 대한 error message도 정의합니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">NetworkError</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> errorMessage<span class="token punctuation">:</span> <span class="token class-name">String</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">switch</span> <span class="token keyword">self</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">case</span> <span class="token punctuation">.</span>invalidUrl<span class="token punctuation">:</span>
</span><span class="code-line">            <span class="token keyword">return</span> <span class="token class-name">Constants</span><span class="token punctuation">.</span><span class="token class-name">Error</span><span class="token punctuation">.</span>url
</span><span class="code-line">        <span class="token keyword">case</span> <span class="token punctuation">.</span>invalidResponse<span class="token punctuation">:</span>
</span><span class="code-line">            <span class="token keyword">return</span> <span class="token class-name">Constants</span><span class="token punctuation">.</span><span class="token class-name">Error</span><span class="token punctuation">.</span>response
</span><span class="code-line">        <span class="token keyword">case</span> <span class="token punctuation">.</span><span class="token function">decodingError</span><span class="token punctuation">(</span><span class="token keyword">let</span> description<span class="token punctuation">)</span><span class="token punctuation">:</span>
</span><span class="code-line">            <span class="token keyword">return</span> <span class="token class-name">Constants</span><span class="token punctuation">.</span><span class="token class-name">Error</span><span class="token punctuation">.</span>decoding <span class="token operator">+</span> description
</span><span class="code-line">        <span class="token keyword">case</span> <span class="token punctuation">.</span><span class="token function">serverError</span><span class="token punctuation">(</span><span class="token keyword">let</span> statusCode<span class="token punctuation">)</span><span class="token punctuation">:</span>
</span><span class="code-line">            <span class="token keyword">return</span> <span class="token class-name">Constants</span><span class="token punctuation">.</span><span class="token class-name">Error</span><span class="token punctuation">.</span>server <span class="token operator">+</span> <span class="token class-name">String</span><span class="token punctuation">(</span>statusCode<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">private</span> <span class="token keyword">extension</span> <span class="token class-name">Constants</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">struct</span> <span class="token class-name">Error</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">static</span> <span class="token keyword">let</span> url <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"유효하지 않은 URL입니다"</span></span>
</span><span class="code-line">        <span class="token keyword">static</span> <span class="token keyword">let</span> response <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"유효하지 않은 응답입니다"</span></span>
</span><span class="code-line">        <span class="token keyword">static</span> <span class="token keyword">let</span> decoding <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"디코딩 에러입니다: "</span></span>
</span><span class="code-line">        <span class="token keyword">static</span> <span class="token keyword">let</span> server <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"서버 에러입니다: "</span></span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>정의한 에러 타입으로 에러 핸들을 추가합니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">private</span> <span class="token keyword">func</span> <span class="token function-definition function">fetchStation</span><span class="token punctuation">(</span>tmX<span class="token punctuation">:</span> <span class="token class-name">Double</span><span class="token punctuation">,</span> tmY<span class="token punctuation">:</span> <span class="token class-name">Double</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token operator">-></span> <span class="token punctuation">[</span><span class="token class-name">MunziModel</span><span class="token punctuation">.</span><span class="token class-name">StationModel</span><span class="token punctuation">.</span><span class="token class-name">Item</span><span class="token punctuation">]</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">do</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">let</span> station<span class="token punctuation">:</span> <span class="token class-name">MunziModel</span><span class="token punctuation">.</span><span class="token class-name">StationModel</span> <span class="token operator">=</span> <span class="token keyword">try</span> <span class="token keyword">await</span> <span class="token class-name">NetworkService</span><span class="token punctuation">.</span>shared<span class="token punctuation">.</span><span class="token function">request</span><span class="token punctuation">(</span>endpoint<span class="token punctuation">:</span> <span class="token class-name">APIEndpoint</span><span class="token punctuation">.</span><span class="token function">station</span><span class="token punctuation">(</span>x<span class="token punctuation">:</span> tmX<span class="token punctuation">,</span> y<span class="token punctuation">:</span> tmY<span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token keyword">let</span> result <span class="token operator">=</span> station<span class="token punctuation">.</span>response<span class="token punctuation">.</span>body<span class="token punctuation">.</span>items
</span><span class="code-line">        <span class="token keyword">return</span> result
</span><span class="code-line">    <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token keyword">let</span> error <span class="token keyword">as</span> <span class="token class-name">NetworkError</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token function">print</span><span class="token punctuation">(</span>error<span class="token punctuation">.</span>errorMessage<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
</span><span class="code-line">    <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token function">print</span><span class="token punctuation">(</span>error<span class="token punctuation">.</span>localizedDescription<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token keyword">return</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="caching">Caching</h2>
<ul>
<li><code>URLCache</code>로 캐싱하기 위해 <code>NetworkService</code>에서 설정합니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">static</span> <span class="token keyword">let</span> shared<span class="token punctuation">:</span> <span class="token class-name">NetworkService</span> <span class="token operator">=</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> memoryCapacity <span class="token operator">=</span> <span class="token number">50</span> <span class="token operator">*</span> <span class="token number">1024</span> <span class="token operator">*</span> <span class="token number">1024</span> <span class="token comment">// 50 MB</span>
</span><span class="code-line">    <span class="token keyword">let</span> diskCapacity <span class="token operator">=</span> <span class="token number">100</span> <span class="token operator">*</span> <span class="token number">1024</span> <span class="token operator">*</span> <span class="token number">1024</span> <span class="token comment">// 100 MB</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">let</span> diskUrl <span class="token operator">=</span> <span class="token class-name">FileManager</span><span class="token punctuation">.</span><span class="token keyword">default</span><span class="token punctuation">.</span><span class="token function">urls</span><span class="token punctuation">(</span><span class="token keyword">for</span><span class="token punctuation">:</span> <span class="token punctuation">.</span>cachesDirectory<span class="token punctuation">,</span> <span class="token keyword">in</span><span class="token punctuation">:</span> <span class="token punctuation">.</span>userDomainMask<span class="token punctuation">)</span><span class="token punctuation">.</span>first<span class="token operator">?</span><span class="token punctuation">.</span><span class="token function">appendingPathComponent</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"cache"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">let</span> cache <span class="token operator">=</span> <span class="token class-name">DurationService</span><span class="token punctuation">(</span>memoryCapacity<span class="token punctuation">:</span> memoryCapacity<span class="token punctuation">,</span> diskCapacity<span class="token punctuation">:</span> diskCapacity<span class="token punctuation">,</span> directory<span class="token punctuation">:</span> diskUrl<span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">let</span> config <span class="token operator">=</span> <span class="token class-name">URLSessionConfiguration</span><span class="token punctuation">.</span><span class="token keyword">default</span>
</span><span class="code-line">    config<span class="token punctuation">.</span>timeoutIntervalForRequest <span class="token operator">=</span> <span class="token number">10</span>
</span><span class="code-line">    config<span class="token punctuation">.</span>timeoutIntervalForResource <span class="token operator">=</span> <span class="token number">60</span>
</span><span class="code-line">    config<span class="token punctuation">.</span>urlCache <span class="token operator">=</span> cache
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">let</span> session <span class="token operator">=</span> <span class="token class-name">URLSession</span><span class="token punctuation">(</span>configuration<span class="token punctuation">:</span> config<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">return</span> <span class="token class-name">NetworkService</span><span class="token punctuation">(</span>session<span class="token punctuation">:</span> session<span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>수동으로 캐시를 사용할수도 있습니다.</li>
<li>request 함수내에 캐시를 수동으로 저장합니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">let</span> cachedData <span class="token operator">=</span> <span class="token class-name">CachedURLResponse</span><span class="token punctuation">(</span>response<span class="token punctuation">:</span> response<span class="token punctuation">,</span> data<span class="token punctuation">:</span> data<span class="token punctuation">)</span>
</span><span class="code-line"><span class="token class-name">URLCache</span><span class="token punctuation">.</span>shared<span class="token punctuation">.</span><span class="token function">storeCachedResponse</span><span class="token punctuation">(</span>cachedData<span class="token punctuation">,</span> <span class="token keyword">for</span><span class="token punctuation">:</span> urlRequest<span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>캐시를 수동으로 사용하기 위해서는 다음과 같이합니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">if</span> <span class="token keyword">let</span> cachedResponse <span class="token operator">=</span> <span class="token class-name">URLCache</span><span class="token punctuation">.</span>shared<span class="token punctuation">.</span><span class="token function">cachedResponse</span><span class="token punctuation">(</span><span class="token keyword">for</span><span class="token punctuation">:</span> request<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> data <span class="token operator">=</span> cachedResponse<span class="token punctuation">.</span>data
</span><span class="code-line"><span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token comment">// Network 통해서 데이터 가져오기</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>캐시를 삭제해야 할때 사용하는 코드입니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">URLCache</span><span class="token punctuation">.</span>shared<span class="token punctuation">.</span><span class="token function">removeAllCachedResponses</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token class-name">URLCache</span><span class="token punctuation">.</span>shared<span class="token punctuation">.</span><span class="token function">removeCachedResponse</span><span class="token punctuation">(</span><span class="token keyword">for</span><span class="token punctuation">:</span> request<span class="token punctuation">)</span>
</span></code></pre>
<h2 id="combine-방식">Combine 방식</h2>
<ul>
<li>Async/await 대신 Combine을 선호한다면, 이렇게도 사용할수 있습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">import</span> <span class="token class-name">Combine</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">protocol</span> <span class="token class-name">NetworkService</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">request</span><span class="token operator">&#x3C;</span><span class="token class-name">T</span><span class="token punctuation">:</span> <span class="token class-name">Decodable</span><span class="token operator">></span><span class="token punctuation">(</span>endpoint<span class="token punctuation">:</span> <span class="token class-name">Endpoint</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">AnyPublisher</span><span class="token operator">&#x3C;</span><span class="token class-name">T</span><span class="token punctuation">,</span> <span class="token class-name">Error</span><span class="token operator">></span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">APINetworkService</span><span class="token punctuation">:</span> <span class="token class-name">NetworkService</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">request</span><span class="token operator">&#x3C;</span><span class="token class-name">T</span><span class="token operator">></span><span class="token punctuation">(</span>endpoint<span class="token punctuation">:</span> <span class="token class-name">Endpoint</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">AnyPublisher</span><span class="token operator">&#x3C;</span><span class="token class-name">T</span><span class="token punctuation">,</span> <span class="token class-name">Error</span><span class="token operator">></span> <span class="token keyword">where</span> <span class="token class-name">T</span><span class="token punctuation">:</span> <span class="token class-name">Decodable</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">let</span> urlRequest <span class="token operator">=</span> <span class="token keyword">try</span><span class="token operator">!</span> <span class="token function">buildURLRequest</span><span class="token punctuation">(</span><span class="token keyword">for</span><span class="token punctuation">:</span> endpoint<span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">        <span class="token keyword">return</span> <span class="token class-name">URLSession</span><span class="token punctuation">.</span>shared<span class="token punctuation">.</span><span class="token function">dataTaskPublisher</span><span class="token punctuation">(</span><span class="token keyword">for</span><span class="token punctuation">:</span> urlRequest<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">\</span><span class="token punctuation">.</span>data<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">decode</span><span class="token punctuation">(</span>type<span class="token punctuation">:</span> <span class="token class-name">T</span><span class="token punctuation">.</span><span class="token keyword">self</span><span class="token punctuation">,</span> decoder<span class="token punctuation">:</span> <span class="token class-name">JSONDecoder</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">receive</span><span class="token punctuation">(</span>on<span class="token punctuation">:</span> <span class="token class-name">DispatchQueue</span><span class="token punctuation">.</span>main<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">eraseToAnyPublisher</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="unit-test">Unit Test</h2>
<ul>
<li><code>NetworkProtocol</code>을 준수하는 <code>NetworkService</code>의 mock 버전을 생성합니다.</li>
<li>이 <code>MockService</code>는 실제 네트워크 요청을 하지 않고 사전에 정의된 응답을 반환합니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">MockNetworkService</span><span class="token punctuation">:</span> <span class="token class-name">NetworkProtocol</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> mockData<span class="token punctuation">:</span> <span class="token class-name">Data</span><span class="token operator">?</span>
</span><span class="code-line">    <span class="token keyword">var</span> mockError<span class="token punctuation">:</span> <span class="token class-name">Error</span><span class="token operator">?</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">request</span><span class="token operator">&#x3C;</span><span class="token class-name">T</span><span class="token operator">></span><span class="token punctuation">(</span>endpoint<span class="token punctuation">:</span> <span class="token class-name">Endpoint</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token keyword">throws</span> <span class="token operator">-></span> <span class="token class-name">T</span> <span class="token keyword">where</span> <span class="token class-name">T</span><span class="token punctuation">:</span> <span class="token class-name">Decodable</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">if</span> <span class="token keyword">let</span> error <span class="token operator">=</span> mockError <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">throw</span> error
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">guard</span> <span class="token keyword">let</span> data <span class="token operator">=</span> mockData <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">throw</span> <span class="token class-name">NetworkError</span><span class="token punctuation">.</span>noData
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">return</span> <span class="token keyword">try</span> <span class="token class-name">JSONDecoder</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">decode</span><span class="token punctuation">(</span><span class="token class-name">T</span><span class="token punctuation">.</span><span class="token keyword">self</span><span class="token punctuation">,</span> from<span class="token punctuation">:</span> data<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>XCTest를 사용하여 이러한 시나리오에 대한 테스트를 작성합니다.</li>
<li>성공적으로 데이터를 가져오는 테스트와 네트워크 문제에 대한 테스트 케이스입니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token attribute atrule">@testable</span> <span class="token keyword">import</span> <span class="token class-name">AppName</span>
</span><span class="code-line"><span class="token keyword">import</span> <span class="token class-name">XCTest</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">NetworkServiceTests</span><span class="token punctuation">:</span> <span class="token class-name">XCTestCase</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> mockNetworkService<span class="token punctuation">:</span> <span class="token class-name">MockNetworkService</span><span class="token operator">!</span>
</span><span class="code-line">    <span class="token keyword">var</span> dataToReturn<span class="token punctuation">:</span> <span class="token class-name">Data</span><span class="token operator">!</span>
</span><span class="code-line">    <span class="token keyword">var</span> errorToReturn<span class="token punctuation">:</span> <span class="token class-name">Error</span><span class="token operator">!</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">override</span> <span class="token keyword">func</span> <span class="token function-definition function">setUp</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token function">setUp</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        mockNetworkService <span class="token operator">=</span> <span class="token class-name">MockNetworkService</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">override</span> <span class="token keyword">func</span> <span class="token function-definition function">tearDown</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        mockNetworkService <span class="token operator">=</span> <span class="token nil constant">nil</span>
</span><span class="code-line">        <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token function">tearDown</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">testFetchPostsSuccess</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">let</span> posts <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token class-name">Post</span><span class="token punctuation">(</span>id<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span> title<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Test Post"</span></span><span class="token punctuation">,</span> body<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"This is a test"</span></span><span class="token punctuation">)</span><span class="token punctuation">]</span>
</span><span class="code-line">        dataToReturn <span class="token operator">=</span> <span class="token keyword">try</span><span class="token operator">!</span> <span class="token class-name">JSONEncoder</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">encode</span><span class="token punctuation">(</span>posts<span class="token punctuation">)</span>
</span><span class="code-line">        mockNetworkService<span class="token punctuation">.</span>mockData <span class="token operator">=</span> dataToReturn
</span><span class="code-line">
</span><span class="code-line">        <span class="token keyword">do</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">let</span> fetchedPosts<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">Post</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">try</span> <span class="token keyword">await</span> mockNetworkService<span class="token punctuation">.</span><span class="token function">request</span><span class="token punctuation">(</span>endpoint<span class="token punctuation">:</span> <span class="token class-name">APIEndpoint</span><span class="token punctuation">.</span>fetchPosts<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token class-name">XCTAssertEqual</span><span class="token punctuation">(</span>fetchedPosts<span class="token punctuation">.</span>count<span class="token punctuation">,</span> posts<span class="token punctuation">.</span>count<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token class-name">XCTAssertEqual</span><span class="token punctuation">(</span>fetchedPosts<span class="token punctuation">.</span>first<span class="token operator">?</span><span class="token punctuation">.</span>id<span class="token punctuation">,</span> posts<span class="token punctuation">.</span>first<span class="token operator">?</span><span class="token punctuation">.</span>id<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token class-name">XCTFail</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Expected successful fetch, received error"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">testFetchPostsWithConnectivityError</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token punctuation">{</span>
</span><span class="code-line">        errorToReturn <span class="token operator">=</span> <span class="token class-name">NetworkError</span><span class="token punctuation">.</span>connectivityError
</span><span class="code-line">        mockNetworkService<span class="token punctuation">.</span>mockError <span class="token operator">=</span> errorToReturn
</span><span class="code-line">
</span><span class="code-line">        <span class="token keyword">do</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">let</span> <span class="token omit keyword">_</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">Post</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">try</span> <span class="token keyword">await</span> mockNetworkService<span class="token punctuation">.</span><span class="token function">request</span><span class="token punctuation">(</span>endpoint<span class="token punctuation">:</span> <span class="token class-name">APIEndpoint</span><span class="token punctuation">.</span>fetchPosts<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token class-name">XCTFail</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Expected connectivity error, received successful fetch"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token class-name">XCTFail</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Expected connectivity error, received different error"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/combine-to-async-await</guid>
      <title>Combine에서 Swift Concurrency로</title>
      <description>비동기 처리를 위한 Combine을 Swift Concurrency로 변경하기</description>
      <link>https://www.hohyeonmoon.com/blog/combine-to-async-await</link>
      <pubDate>Thu, 11 Jan 2024 10:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>Swift 5.5에 Swift Concurrency가 등장하면서, 많은 것을 대체하게 되었는데요.</li>
<li>그 중 대표적인 것이 비동기 프로그래밍을 도와주던 Closure와 Combine입니다.</li>
</ul>
<h2 id="asyncawait">async/await</h2>
<ul>
<li><a href="https://developer.apple.com/documentation/combine/using-combine-for-your-app-s-asynchronous-code">공식 문서</a>를 보면, 다음과 같은 팁이 적혀있습니다.</li>
<li>대략, <code>async/await</code>가 <code>completion</code> 클로저와 <code>Combine Future</code>의 필요성을 없앤다고 합니다.</li>
</ul>
<blockquote>
<p>You don’t need closure-based asychronicity patterns if you’re using the async-await features in Swift 5.5 and later. Instead, your code can await an asynchronous call, and then execute the code that would have been in the closure. This eliminates the need for both conventional completion handlers and Combine futures. For more information, see Concurrency in The Swift Programming Language.</p>
</blockquote>
<h2 id="example">Example</h2>
<ul>
<li>다음과 같이 Combine으로 구현 된 3가지 예시 파일 API, Service, ViewModel이 있습니다.</li>
<li>각각의 함수 선언부와 리턴부만 표기해보겠습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token comment">// API.swift</span>
</span><span class="code-line"><span class="token keyword">class</span> <span class="token constant">API</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">func</span> <span class="token function-definition function">perform</span><span class="token operator">&#x3C;</span><span class="token class-name">T</span><span class="token punctuation">:</span> <span class="token class-name">Decodable</span><span class="token operator">></span><span class="token punctuation">(</span>method<span class="token punctuation">:</span> <span class="token class-name">HTTPMethod</span><span class="token punctuation">,</span> url<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token operator">?</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">AnyPublisher</span><span class="token operator">&#x3C;</span><span class="token class-name">HTTPResponse</span><span class="token operator">&#x3C;</span><span class="token class-name">T</span><span class="token operator">></span><span class="token punctuation">,</span> <span class="token class-name">Error</span><span class="token operator">></span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token operator">...</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">return</span> <span class="token class-name">URLSession</span><span class="token punctuation">.</span>shared<span class="token punctuation">.</span><span class="token function">dataTaskPublisher</span><span class="token punctuation">(</span><span class="token keyword">for</span><span class="token punctuation">:</span> request<span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">.</span>tryMap <span class="token punctuation">{</span> result <span class="token operator">-></span> <span class="token class-name">HTTPResponse</span><span class="token operator">&#x3C;</span><span class="token class-name">T</span><span class="token operator">></span> <span class="token keyword">in</span>
</span><span class="code-line">        <span class="token keyword">let</span> value <span class="token operator">=</span> <span class="token keyword">try</span> <span class="token keyword">self</span><span class="token punctuation">.</span>decoder<span class="token punctuation">.</span><span class="token function">decode</span><span class="token punctuation">(</span><span class="token class-name">T</span><span class="token punctuation">.</span><span class="token keyword">self</span><span class="token punctuation">,</span> from<span class="token punctuation">:</span> result<span class="token punctuation">.</span>data<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token keyword">return</span> <span class="token class-name">HTTPResponse</span><span class="token punctuation">(</span>value<span class="token punctuation">:</span> value<span class="token punctuation">,</span> response<span class="token punctuation">:</span> result<span class="token punctuation">.</span>response<span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">}</span>
</span><span class="code-line">      <span class="token punctuation">.</span><span class="token function">receive</span><span class="token punctuation">(</span>on<span class="token punctuation">:</span> <span class="token class-name">DispatchQueue</span><span class="token punctuation">.</span>main<span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">.</span><span class="token function">eraseToAnyPublisher</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token comment">// Service.swift</span>
</span><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">Service</span><span class="token punctuation">:</span> <span class="token class-name">ServiceType</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token operator">...</span>
</span><span class="code-line">
</span><span class="code-line">  <span class="token keyword">func</span> <span class="token function-definition function">request</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">AnyPublisher</span><span class="token operator">&#x3C;</span><span class="token punctuation">[</span><span class="token class-name">SomeType</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token class-name">Error</span><span class="token operator">></span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token operator">...</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">return</span> <span class="token constant">API</span><span class="token punctuation">.</span>shared<span class="token punctuation">.</span><span class="token function">perform</span><span class="token punctuation">(</span>method<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token keyword">get</span><span class="token punctuation">,</span> url<span class="token punctuation">:</span> component<span class="token operator">?</span><span class="token punctuation">.</span>string<span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">\</span><span class="token punctuation">.</span>value<span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">.</span><span class="token function">eraseToAnyPublisher</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token comment">// ViewModel.swift</span>
</span><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">requestSomething</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">self</span><span class="token punctuation">.</span>service<span class="token punctuation">.</span><span class="token function">request</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">.</span>sink <span class="token punctuation">{</span> <span class="token omit keyword">_</span> <span class="token keyword">in</span>
</span><span class="code-line">      <span class="token operator">...</span>
</span><span class="code-line">    <span class="token punctuation">}</span> receiveValue<span class="token punctuation">:</span> <span class="token punctuation">{</span> response <span class="token keyword">in</span>
</span><span class="code-line">      <span class="token keyword">self</span><span class="token punctuation">.</span>response <span class="token operator">=</span> response
</span><span class="code-line">    <span class="token punctuation">}</span><span class="token punctuation">.</span><span class="token function">store</span><span class="token punctuation">(</span><span class="token keyword">in</span><span class="token punctuation">:</span> <span class="token operator">&#x26;</span><span class="token keyword">self</span><span class="token punctuation">.</span>cancellable<span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="apiswift">API.swift</h2>
<ul>
<li><code>API.swift</code> 변경점 입니다.</li>
<li>우선 함수 선언부에서 AnyPublisher를 제거하고 async throws를 추가했습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token comment">// Combine</span>
</span><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">perform</span><span class="token operator">&#x3C;</span><span class="token class-name">T</span><span class="token punctuation">:</span> <span class="token class-name">Decodable</span><span class="token operator">></span><span class="token punctuation">(</span>method<span class="token punctuation">:</span> <span class="token class-name">HTTPMethod</span><span class="token punctuation">,</span> url<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token operator">?</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">AnyPublisher</span><span class="token operator">&#x3C;</span><span class="token class-name">HTTPResponse</span><span class="token operator">&#x3C;</span><span class="token class-name">T</span><span class="token operator">></span><span class="token punctuation">,</span> <span class="token class-name">Error</span><span class="token operator">></span>
</span><span class="code-line">
</span><span class="code-line"><span class="token comment">// async/await</span>
</span><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">perform</span><span class="token operator">&#x3C;</span><span class="token class-name">T</span><span class="token punctuation">:</span> <span class="token class-name">Decodable</span><span class="token operator">></span><span class="token punctuation">(</span>method<span class="token punctuation">:</span> <span class="token class-name">HTTPMethod</span><span class="token punctuation">,</span> url<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token operator">?</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token keyword">throws</span> <span class="token operator">-></span> <span class="token class-name">HTTPResponse</span><span class="token operator">&#x3C;</span><span class="token class-name">T</span><span class="token operator">></span>
</span></code></pre>
<ul>
<li>그에 맞게 return 타입도 변경해줍니다.</li>
<li>dataTaskPublisher 대신 async 메소드인 data(from:)을 사용합니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token comment">// Combine</span>
</span><span class="code-line"><span class="token keyword">return</span> <span class="token class-name">URLSession</span><span class="token punctuation">.</span>shared<span class="token punctuation">.</span><span class="token function">dataTaskPublisher</span><span class="token punctuation">(</span><span class="token keyword">for</span><span class="token punctuation">:</span> request<span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">.</span>tryMap <span class="token punctuation">{</span> result <span class="token operator">-></span> <span class="token class-name">HTTPResponse</span><span class="token operator">&#x3C;</span><span class="token class-name">T</span><span class="token operator">></span> <span class="token keyword">in</span>
</span><span class="code-line">      <span class="token keyword">let</span> value <span class="token operator">=</span> <span class="token keyword">try</span> <span class="token keyword">self</span><span class="token punctuation">.</span>decoder<span class="token punctuation">.</span><span class="token function">decode</span><span class="token punctuation">(</span><span class="token class-name">T</span><span class="token punctuation">.</span><span class="token keyword">self</span><span class="token punctuation">,</span> from<span class="token punctuation">:</span> result<span class="token punctuation">.</span>data<span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token keyword">return</span> <span class="token class-name">HTTPResponse</span><span class="token punctuation">(</span>value<span class="token punctuation">:</span> value<span class="token punctuation">,</span> response<span class="token punctuation">:</span> result<span class="token punctuation">.</span>response<span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">.</span><span class="token function">receive</span><span class="token punctuation">(</span>on<span class="token punctuation">:</span> <span class="token class-name">DispatchQueue</span><span class="token punctuation">.</span>main<span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">.</span><span class="token function">eraseToAnyPublisher</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token comment">// async/await</span>
</span><span class="code-line"><span class="token keyword">let</span> <span class="token punctuation">(</span>data<span class="token punctuation">,</span> urlResponse<span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token keyword">try</span> <span class="token keyword">await</span> <span class="token class-name">URLSession</span><span class="token punctuation">.</span>shared<span class="token punctuation">.</span><span class="token function">data</span><span class="token punctuation">(</span>from<span class="token punctuation">:</span> url<span class="token punctuation">)</span>
</span><span class="code-line"><span class="token keyword">let</span> response <span class="token operator">=</span> <span class="token keyword">try</span> decoder<span class="token punctuation">.</span><span class="token function">decode</span><span class="token punctuation">(</span><span class="token class-name">T</span><span class="token punctuation">.</span><span class="token keyword">self</span><span class="token punctuation">,</span> from<span class="token punctuation">:</span> data<span class="token punctuation">)</span>
</span><span class="code-line"><span class="token keyword">return</span> <span class="token class-name">HTTPResponse</span><span class="token punctuation">(</span>value<span class="token punctuation">:</span> response<span class="token punctuation">,</span> response<span class="token punctuation">:</span> urlResponse<span class="token punctuation">)</span>
</span></code></pre>
<h2 id="serviceswift">Service.swift</h2>
<ul>
<li><code>Service.swift</code> 변경점 입니다.</li>
<li>똑같이 AnyPublisher를 제거하고 async throws를 추가했습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token comment">// Combine</span>
</span><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">request</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">AnyPublisher</span><span class="token operator">&#x3C;</span><span class="token punctuation">[</span><span class="token class-name">SomeType</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token class-name">Error</span><span class="token operator">></span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token comment">// async/await</span>
</span><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">request</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token keyword">throws</span> <span class="token operator">-></span> <span class="token punctuation">[</span><span class="token class-name">SomeType</span><span class="token punctuation">]</span>
</span></code></pre>
<ul>
<li>역시나 그에 맞게, return을 수정해줍니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token comment">// Combine</span>
</span><span class="code-line"><span class="token keyword">return</span> <span class="token constant">API</span><span class="token punctuation">.</span>shared<span class="token punctuation">.</span><span class="token function">perform</span><span class="token punctuation">(</span>method<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token keyword">get</span><span class="token punctuation">,</span> url<span class="token punctuation">:</span> component<span class="token operator">?</span><span class="token punctuation">.</span>string<span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">\</span><span class="token punctuation">.</span>value<span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">.</span><span class="token function">eraseToAnyPublisher</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token comment">// async/await</span>
</span><span class="code-line"><span class="token keyword">return</span> <span class="token keyword">try</span> <span class="token keyword">await</span> <span class="token constant">API</span><span class="token punctuation">.</span>shared<span class="token punctuation">.</span><span class="token function">perform</span><span class="token punctuation">(</span>method<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token keyword">get</span><span class="token punctuation">,</span> url<span class="token punctuation">:</span> component<span class="token operator">?</span><span class="token punctuation">.</span>string<span class="token punctuation">)</span><span class="token punctuation">.</span>value
</span></code></pre>
<h2 id="viewmodelswift">ViewModel.swift</h2>
<ul>
<li><code>ViewModel.swift</code> 변경점 입니다.</li>
<li>sink로 값을 받아오던 것과는 다르게 Task로 값을 받아옵니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token comment">// Combine</span>
</span><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">requestSomething</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">self</span><span class="token punctuation">.</span>service<span class="token punctuation">.</span><span class="token function">request</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">.</span>sink <span class="token punctuation">{</span> <span class="token omit keyword">_</span> <span class="token keyword">in</span>
</span><span class="code-line">      <span class="token operator">...</span>
</span><span class="code-line">    <span class="token punctuation">}</span> receiveValue<span class="token punctuation">:</span> <span class="token punctuation">{</span> response <span class="token keyword">in</span>
</span><span class="code-line">      <span class="token keyword">self</span><span class="token punctuation">.</span>response <span class="token operator">=</span> response
</span><span class="code-line">    <span class="token punctuation">}</span><span class="token punctuation">.</span><span class="token function">store</span><span class="token punctuation">(</span><span class="token keyword">in</span><span class="token punctuation">:</span> <span class="token operator">&#x26;</span><span class="token keyword">self</span><span class="token punctuation">.</span>cancellable<span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token comment">// async/await</span>
</span><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">requestSomething</span><span class="token punctuation">(</span><span class="token punctuation">)</span>  <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token class-name">Task</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">self</span><span class="token punctuation">.</span>response <span class="token operator">=</span> <span class="token keyword">try</span> <span class="token keyword">await</span> <span class="token keyword">self</span><span class="token punctuation">.</span>service<span class="token punctuation">.</span><span class="token function">request</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>다음과 같은 방식으로 호출하면 되겠습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">View</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">.</span>onAppear <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">self</span><span class="token punctuation">.</span>viewModel<span class="token punctuation">.</span><span class="token function">requestSomething</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span></code></pre>
<h2 id="결과물">결과물</h2>
<ul>
<li>Combine 대신 Swift Concurrency를 사용해서 구현해본 3가지 파일의 결과물입니다.</li>
<li>개인적으로는 훨씬 직관적이고 간단해졌다고 생각합니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token comment">// API.swift</span>
</span><span class="code-line"><span class="token keyword">class</span> <span class="token constant">API</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">func</span> <span class="token function-definition function">perform</span><span class="token operator">&#x3C;</span><span class="token class-name">T</span><span class="token punctuation">:</span> <span class="token class-name">Decodable</span><span class="token operator">></span><span class="token punctuation">(</span>method<span class="token punctuation">:</span> <span class="token class-name">HTTPMethod</span><span class="token punctuation">,</span> url<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token operator">?</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token keyword">throws</span> <span class="token operator">-></span> <span class="token class-name">HTTPResponse</span><span class="token operator">&#x3C;</span><span class="token class-name">T</span><span class="token operator">></span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token operator">...</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">let</span> <span class="token punctuation">(</span>data<span class="token punctuation">,</span> urlResponse<span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token keyword">try</span> <span class="token keyword">await</span> <span class="token class-name">URLSession</span><span class="token punctuation">.</span>shared<span class="token punctuation">.</span><span class="token function">data</span><span class="token punctuation">(</span>from<span class="token punctuation">:</span> url<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">let</span> response <span class="token operator">=</span> <span class="token keyword">try</span> decoder<span class="token punctuation">.</span><span class="token function">decode</span><span class="token punctuation">(</span><span class="token class-name">T</span><span class="token punctuation">.</span><span class="token keyword">self</span><span class="token punctuation">,</span> from<span class="token punctuation">:</span> data<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">return</span> <span class="token class-name">HTTPResponse</span><span class="token punctuation">(</span>value<span class="token punctuation">:</span> response<span class="token punctuation">,</span> response<span class="token punctuation">:</span> urlResponse<span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token comment">// Service.swift</span>
</span><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">Service</span><span class="token punctuation">:</span> <span class="token class-name">ServiceType</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token operator">...</span>
</span><span class="code-line">
</span><span class="code-line">  <span class="token keyword">func</span> <span class="token function-definition function">request</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token keyword">throws</span> <span class="token operator">-></span> <span class="token punctuation">[</span><span class="token class-name">SomeType</span><span class="token punctuation">]</span>
</span><span class="code-line">    <span class="token operator">...</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">return</span> <span class="token keyword">try</span> <span class="token keyword">await</span> <span class="token constant">API</span><span class="token punctuation">.</span>shared<span class="token punctuation">.</span><span class="token function">perform</span><span class="token punctuation">(</span>method<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token keyword">get</span><span class="token punctuation">,</span> url<span class="token punctuation">:</span> component<span class="token operator">?</span><span class="token punctuation">.</span>string<span class="token punctuation">)</span><span class="token punctuation">.</span>value
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token comment">// ViewModel.swift</span>
</span><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">requestSomething</span><span class="token punctuation">(</span><span class="token punctuation">)</span>  <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token class-name">Task</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">self</span><span class="token punctuation">.</span>response <span class="token operator">=</span> <span class="token keyword">try</span> <span class="token keyword">await</span> <span class="token keyword">self</span><span class="token punctuation">.</span>service<span class="token punctuation">.</span><span class="token function">request</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="참고">참고</h2>
<ul>
<li><a href="https://developer.apple.com/documentation/combine/using-combine-for-your-app-s-asynchronous-code">Apple 공식 문서</a></li>
<li><a href="https://zeddios.tistory.com/1335">Zeddios 티스토리 블로그</a></li>
</ul>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/ios-openai-gpt-api</guid>
      <title>iOS에서 OpenAI API 사용하기</title>
      <description>SwiftUI에서 OpenAI SPM을 이용해 GPT를 비롯한 OpenAI API를 사용하는 방법</description>
      <link>https://www.hohyeonmoon.com/blog/ios-openai-gpt-api</link>
      <pubDate>Sun, 10 Dec 2023 18:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>iOS에서 SwiftUI 예시를 통해 OpenAI API를 사용하는 방법에 대해 알아보겠습니다.</li>
<li>예시에서는 OpenAI GPT 모델을 통해 Chat 기능을 구현하지만, 다른 API도 비슷하게 사용하면됩니다.</li>
<li>MacPaw의 OpenAI SPM을 통해 보다 쉽게 구현 할 수 있었습니다.</li>
</ul>
<h2 id="openai-spm-설치">OpenAI SPM 설치</h2>
<ul>
<li><a href="https://github.com/MacPaw/OpenAI">MacPaw의 OpenAI SPM</a>을 프로젝트에 설치합니다.</li>
</ul>
<p><img src="/images/ios-openai-gpt-api-1.png" alt="ios-openai-gpt-api"></p>
<h2 id="openai-api-키-설정">OpenAI API 키 설정</h2>
<ul>
<li><a href="https://platform.openai.com/api-keys">OpenAI의 API 페이지</a>에서 Key를 발급 받습니다.</li>
</ul>
<p><img src="/images/ios-openai-gpt-api-2.png" alt="ios-openai-gpt-api"></p>
<ul>
<li>별도 plist 파일을 생성해 해당 Key를 넣어줍니다.</li>
</ul>
<pre><code class="language-plist code-highlight"><span class="code-line">// Keys.plist
</span><span class="code-line">&#x3C;?xml version="1.0" encoding="UTF-8"?>
</span><span class="code-line">&#x3C;!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
</span><span class="code-line">&#x3C;plist version="1.0">
</span><span class="code-line">&#x3C;dict>
</span><span class="code-line">    &#x3C;key>openai&#x3C;/key>
</span><span class="code-line">    &#x3C;string>APIKEY&#x3C;/string>
</span><span class="code-line">&#x3C;/dict>
</span><span class="code-line">&#x3C;/plist>
</span></code></pre>
<ul>
<li>민감한 정보이기에 gitignore에 추가해 git에 포함되지 않도록 합니다.</li>
</ul>
<pre class="language-git"><code class="language-git code-highlight"><span class="code-line">// .gitignore
</span><span class="code-line">Keys.plist
</span></code></pre>
<h2 id="gpt로-chat-구현">GPT로 Chat 구현</h2>
<ul>
<li>키값 디코딩을 위해 간단하게 모델을 만들어줍니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">AiModel</span><span class="token punctuation">:</span> <span class="token class-name">Decodable</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> openai<span class="token punctuation">:</span> <span class="token class-name">String</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>ViewModel의 init에서 OpenAI API Key를 다음과 같이 plist에서 불러오고, OpenAI 객체를 만듭니다.</li>
<li>OpenAI 객체로 GPT에 Request를 보내는 함수도 추가합니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token attribute atrule">@Observable</span> <span class="token keyword">class</span> <span class="token class-name">AiViewModel</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> openAI<span class="token punctuation">:</span> <span class="token class-name">OpenAI</span><span class="token operator">?</span>
</span><span class="code-line">    <span class="token keyword">var</span> respond <span class="token operator">=</span> <span class="token string-literal"><span class="token string">""</span></span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">guard</span> <span class="token keyword">let</span> url <span class="token operator">=</span> <span class="token class-name">Bundle</span><span class="token punctuation">.</span>main<span class="token punctuation">.</span><span class="token function">url</span><span class="token punctuation">(</span>forResource<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Keys"</span></span><span class="token punctuation">,</span> withExtension<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"plist"</span></span><span class="token punctuation">)</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">}</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">do</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">let</span> data <span class="token operator">=</span> <span class="token keyword">try</span> <span class="token class-name">Data</span><span class="token punctuation">(</span>contentsOf<span class="token punctuation">:</span> url<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token keyword">let</span> keys <span class="token operator">=</span> <span class="token keyword">try</span> <span class="token class-name">PropertyListDecoder</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">decode</span><span class="token punctuation">(</span><span class="token class-name">AiModel</span><span class="token punctuation">.</span><span class="token keyword">self</span><span class="token punctuation">,</span> from<span class="token punctuation">:</span> data<span class="token punctuation">)</span>
</span><span class="code-line">            openAI <span class="token operator">=</span> <span class="token class-name">OpenAI</span><span class="token punctuation">(</span>apiToken<span class="token punctuation">:</span> keys<span class="token punctuation">.</span>openai<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token string-literal"><span class="token string">"Decoding error: </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">error</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">.</span><span class="token function">debug</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">request</span><span class="token punctuation">(</span>prompt<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">let</span> query <span class="token operator">=</span> <span class="token class-name">ChatQuery</span><span class="token punctuation">(</span>model<span class="token punctuation">:</span> <span class="token punctuation">.</span>gpt3_5Turbo_16k<span class="token punctuation">,</span> messages<span class="token punctuation">:</span> <span class="token punctuation">[</span>
</span><span class="code-line">            <span class="token class-name">Chat</span><span class="token punctuation">(</span>role<span class="token punctuation">:</span> <span class="token punctuation">.</span>system<span class="token punctuation">,</span> content<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"사용자를 응원해줘"</span></span><span class="token punctuation">)</span><span class="token punctuation">,</span>
</span><span class="code-line">            <span class="token class-name">Chat</span><span class="token punctuation">(</span>role<span class="token punctuation">:</span> <span class="token punctuation">.</span>user<span class="token punctuation">,</span> content<span class="token punctuation">:</span> prompt<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">]</span><span class="token punctuation">)</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">do</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">let</span> result <span class="token operator">=</span> <span class="token keyword">try</span> <span class="token keyword">await</span> openAI<span class="token operator">?</span><span class="token punctuation">.</span><span class="token function">chats</span><span class="token punctuation">(</span>query<span class="token punctuation">:</span> query<span class="token punctuation">)</span>
</span><span class="code-line">            respond <span class="token operator">=</span> result<span class="token operator">?</span><span class="token punctuation">.</span>choices<span class="token punctuation">.</span>first<span class="token operator">?</span><span class="token punctuation">.</span>message<span class="token punctuation">.</span>content <span class="token operator">??</span> <span class="token string-literal"><span class="token string">""</span></span>
</span><span class="code-line">        <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"AI error: </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">error</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>이제 View에서 ViewModel을 통해 OpenAI API를 사용합니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">AiView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token attribute atrule">@State</span> <span class="token keyword">private</span> <span class="token keyword">var</span> aiViewModel <span class="token operator">=</span> <span class="token class-name">AiViewModel</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">Text</span><span class="token punctuation">(</span>aiViewModel<span class="token punctuation">.</span>respond<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">.</span>task <span class="token punctuation">{</span>
</span><span class="code-line">                aiViewModel<span class="token punctuation">.</span><span class="token function">request</span><span class="token punctuation">(</span>prompt<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"OpenAI API 사용하는 방법을 설명해줘"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="openai-패키지">OpenAI 패키지</h2>
<ul>
<li>MacPaw의 OpenAI 패키지는 Chat 기능 사용을 위해 다음과 같은 구조를 갖고 있습니다.</li>
<li>더 자세한 내용과 다른 API 사용을 위해서는 <a href="https://platform.openai.com/docs/introduction">OpenAI API 도큐먼트</a>와 <a href="https://github.com/MacPaw/OpenAI#usage">MacPaw OpenAI 레포지토리</a>를 방문해보세요.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"> <span class="token keyword">struct</span> <span class="token class-name">ChatQuery</span><span class="token punctuation">:</span> <span class="token class-name">Codable</span> <span class="token punctuation">{</span>
</span><span class="code-line">     <span class="token keyword">public</span> <span class="token keyword">let</span> model<span class="token punctuation">:</span> <span class="token class-name">Model</span>
</span><span class="code-line">     <span class="token keyword">public</span> <span class="token keyword">let</span> messages<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">Chat</span><span class="token punctuation">]</span>
</span><span class="code-line">     <span class="token keyword">public</span> <span class="token keyword">let</span> functions<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">ChatFunctionDeclaration</span><span class="token punctuation">]</span><span class="token operator">?</span>
</span><span class="code-line">     <span class="token keyword">public</span> <span class="token keyword">let</span> temperature<span class="token punctuation">:</span> <span class="token class-name">Double</span><span class="token operator">?</span>
</span><span class="code-line">     <span class="token keyword">public</span> <span class="token keyword">let</span> topP<span class="token punctuation">:</span> <span class="token class-name">Double</span><span class="token operator">?</span>
</span><span class="code-line">     <span class="token keyword">public</span> <span class="token keyword">let</span> n<span class="token punctuation">:</span> <span class="token class-name">Int</span><span class="token operator">?</span>
</span><span class="code-line">     <span class="token keyword">public</span> <span class="token keyword">let</span> stop<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">String</span><span class="token punctuation">]</span><span class="token operator">?</span>
</span><span class="code-line">     <span class="token keyword">public</span> <span class="token keyword">let</span> maxTokens<span class="token punctuation">:</span> <span class="token class-name">Int</span><span class="token operator">?</span>
</span><span class="code-line">     <span class="token keyword">public</span> <span class="token keyword">let</span> presencePenalty<span class="token punctuation">:</span> <span class="token class-name">Double</span><span class="token operator">?</span>
</span><span class="code-line">     <span class="token keyword">public</span> <span class="token keyword">let</span> frequencyPenalty<span class="token punctuation">:</span> <span class="token class-name">Double</span><span class="token operator">?</span>
</span><span class="code-line">     <span class="token keyword">public</span> <span class="token keyword">let</span> logitBias<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">String</span><span class="token punctuation">:</span><span class="token class-name">Int</span><span class="token punctuation">]</span><span class="token operator">?</span>
</span><span class="code-line">     <span class="token keyword">public</span> <span class="token keyword">let</span> user<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token operator">?</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ChatResult</span><span class="token punctuation">:</span> <span class="token class-name">Codable</span><span class="token punctuation">,</span> <span class="token class-name">Equatable</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">public</span> <span class="token keyword">struct</span> <span class="token class-name">Choice</span><span class="token punctuation">:</span> <span class="token class-name">Codable</span><span class="token punctuation">,</span> <span class="token class-name">Equatable</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">public</span> <span class="token keyword">let</span> index<span class="token punctuation">:</span> <span class="token class-name">Int</span>
</span><span class="code-line">        <span class="token keyword">public</span> <span class="token keyword">let</span> message<span class="token punctuation">:</span> <span class="token class-name">Chat</span>
</span><span class="code-line">        <span class="token keyword">public</span> <span class="token keyword">let</span> finishReason<span class="token punctuation">:</span> <span class="token class-name">String</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">public</span> <span class="token keyword">struct</span> <span class="token class-name">Usage</span><span class="token punctuation">:</span> <span class="token class-name">Codable</span><span class="token punctuation">,</span> <span class="token class-name">Equatable</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">public</span> <span class="token keyword">let</span> promptTokens<span class="token punctuation">:</span> <span class="token class-name">Int</span>
</span><span class="code-line">        <span class="token keyword">public</span> <span class="token keyword">let</span> completionTokens<span class="token punctuation">:</span> <span class="token class-name">Int</span>
</span><span class="code-line">        <span class="token keyword">public</span> <span class="token keyword">let</span> totalTokens<span class="token punctuation">:</span> <span class="token class-name">Int</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">public</span> <span class="token keyword">let</span> id<span class="token punctuation">:</span> <span class="token class-name">String</span>
</span><span class="code-line">    <span class="token keyword">public</span> <span class="token keyword">let</span> object<span class="token punctuation">:</span> <span class="token class-name">String</span>
</span><span class="code-line">    <span class="token keyword">public</span> <span class="token keyword">let</span> created<span class="token punctuation">:</span> <span class="token class-name">TimeInterval</span>
</span><span class="code-line">    <span class="token keyword">public</span> <span class="token keyword">let</span> model<span class="token punctuation">:</span> <span class="token class-name">Model</span>
</span><span class="code-line">    <span class="token keyword">public</span> <span class="token keyword">let</span> choices<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">Choice</span><span class="token punctuation">]</span>
</span><span class="code-line">    <span class="token keyword">public</span> <span class="token keyword">let</span> usage<span class="token punctuation">:</span> <span class="token class-name">Usage</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swiftui-custom-context-menu</guid>
      <title>SwiftUI Custom Context Menu</title>
      <description>SwiftUI로 iMessage의 리액션 같은 Custom Context Menu를 만들어봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/swiftui-custom-context-menu</link>
      <pubDate>Sat, 02 Dec 2023 10:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>애플의 Messages 앱에는 각 메세지 버블을 누르고 있으면 리액션을 남기는 기능이 있습니다.</li>
<li>SwiftUI로 이와 같은 커스텀 Context Menu를 만들어 보겠습니다.</li>
</ul>
<h2 id="viewmodifier-만들기">ViewModifier 만들기</h2>
<ul>
<li>어떤 View에서든 사용할수 있도록 <code>customContextMenu</code>를 modifier로 만들어봤습니다.</li>
<li>이 함수는 <code>CustomContextMenuModifier</code>를 modifier로 넘겨주는 역할을 합니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">customContextMenu</span><span class="token operator">&#x3C;</span><span class="token class-name">CustomView</span><span class="token punctuation">:</span> <span class="token class-name">View</span><span class="token operator">></span><span class="token punctuation">(</span>
</span><span class="code-line">        customView<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">CustomView</span><span class="token punctuation">,</span>
</span><span class="code-line">        menu<span class="token punctuation">:</span> <span class="token attribute atrule">@escaping</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">UIMenu</span><span class="token punctuation">,</span>
</span><span class="code-line">        tapped<span class="token punctuation">:</span> <span class="token attribute atrule">@escaping</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">modifier</span><span class="token punctuation">(</span>
</span><span class="code-line">            <span class="token class-name">CustomContextMenuModifier</span><span class="token punctuation">(</span>
</span><span class="code-line">                customView<span class="token punctuation">:</span> <span class="token function">customView</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
</span><span class="code-line">                menu<span class="token punctuation">:</span> <span class="token function">menu</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
</span><span class="code-line">                tapped<span class="token punctuation">:</span> tapped
</span><span class="code-line">            <span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>실직적인 ViewModifier를 준수하는 <code>CustomContextMenuModifier</code>는 다음과 같습니다.</li>
<li>여기에는 <code>ContextMenuHelper</code>와 <code>readSize</code> 같은 코드가 포함되어 있는데, 이어서 알아보도록 하겠습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">CustomContextMenuModifier</span><span class="token operator">&#x3C;</span><span class="token class-name">CustomView</span><span class="token punctuation">:</span> <span class="token class-name">View</span><span class="token operator">></span><span class="token punctuation">:</span> <span class="token class-name">ViewModifier</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token attribute atrule">@State</span> <span class="token keyword">var</span> customSize <span class="token operator">=</span> <span class="token class-name">CGSize</span><span class="token punctuation">.</span>zero
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">var</span> customView<span class="token punctuation">:</span> <span class="token class-name">CustomView</span><span class="token operator">?</span>
</span><span class="code-line">    <span class="token keyword">var</span> menu<span class="token punctuation">:</span> <span class="token class-name">UIMenu</span>
</span><span class="code-line">    <span class="token keyword">var</span> tapped<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">body</span><span class="token punctuation">(</span>content<span class="token punctuation">:</span> <span class="token class-name">Content</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        content
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">hidden</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">overlay</span><span class="token punctuation">(</span>
</span><span class="code-line">                <span class="token class-name">ContextMenuHelper</span><span class="token punctuation">(</span>
</span><span class="code-line">                    customSize<span class="token punctuation">:</span> $customSize<span class="token punctuation">,</span>
</span><span class="code-line">                    content<span class="token punctuation">:</span> content<span class="token punctuation">,</span>
</span><span class="code-line">                    customView<span class="token punctuation">:</span> customView<span class="token punctuation">,</span>
</span><span class="code-line">                    menu<span class="token punctuation">:</span> menu<span class="token punctuation">,</span>
</span><span class="code-line">                    tapped<span class="token punctuation">:</span> tapped
</span><span class="code-line">                <span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">overlay</span><span class="token punctuation">(</span>
</span><span class="code-line">                customView<span class="token operator">?</span>
</span><span class="code-line">                    <span class="token punctuation">.</span><span class="token function">hidden</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">                    <span class="token punctuation">.</span>readSize <span class="token punctuation">{</span> customSize <span class="token operator">=</span> <span class="token short-argument">$0</span> <span class="token punctuation">}</span>
</span><span class="code-line">            <span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="uikit-활용하기">UIKit 활용하기</h2>
<ul>
<li>다음은 <code>ContextMenuHelper</code> 구현 부분으로 UIKit의 Context Menu 관련 코드를 활용합니다.</li>
<li>SwiftUI에서 받아온 View, Menu, 그리고 로직을 Context Menu에 실질적으로 녹여내는 부분입니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContextMenuHelper</span><span class="token operator">&#x3C;</span><span class="token class-name">Content</span><span class="token punctuation">:</span> <span class="token class-name">View</span><span class="token punctuation">,</span> <span class="token class-name">CustomView</span><span class="token punctuation">:</span> <span class="token class-name">View</span><span class="token operator">></span><span class="token punctuation">:</span> <span class="token class-name">UIViewRepresentable</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token attribute atrule">@Binding</span> <span class="token keyword">var</span> customSize<span class="token punctuation">:</span> <span class="token class-name">CGSize</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">var</span> content<span class="token punctuation">:</span> <span class="token class-name">Content</span>
</span><span class="code-line">    <span class="token keyword">var</span> customView<span class="token punctuation">:</span> <span class="token class-name">CustomView</span>
</span><span class="code-line">    <span class="token keyword">var</span> menu<span class="token punctuation">:</span> <span class="token class-name">UIMenu</span>
</span><span class="code-line">    <span class="token keyword">var</span> tapped<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">makeCoordinator</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Coordinator</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">return</span> <span class="token class-name">Coordinator</span><span class="token punctuation">(</span>parent<span class="token punctuation">:</span> <span class="token keyword">self</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">makeUIView</span><span class="token punctuation">(</span>context<span class="token punctuation">:</span> <span class="token class-name">Context</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">UIView</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">let</span> view <span class="token operator">=</span> <span class="token class-name">UIView</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        view<span class="token punctuation">.</span>backgroundColor <span class="token operator">=</span> <span class="token punctuation">.</span>clear
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">let</span> hostView <span class="token operator">=</span> <span class="token class-name">UIHostingController</span><span class="token punctuation">(</span>rootView<span class="token punctuation">:</span> content<span class="token punctuation">)</span>
</span><span class="code-line">        hostView<span class="token punctuation">.</span>view<span class="token punctuation">.</span>translatesAutoresizingMaskIntoConstraints <span class="token operator">=</span> <span class="token boolean">false</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">let</span> constraints <span class="token operator">=</span> <span class="token punctuation">[</span>
</span><span class="code-line">            hostView<span class="token punctuation">.</span>view<span class="token punctuation">.</span>topAnchor<span class="token punctuation">.</span><span class="token function">constraint</span><span class="token punctuation">(</span>equalTo<span class="token punctuation">:</span> view<span class="token punctuation">.</span>topAnchor<span class="token punctuation">)</span><span class="token punctuation">,</span>
</span><span class="code-line">            hostView<span class="token punctuation">.</span>view<span class="token punctuation">.</span>leadingAnchor<span class="token punctuation">.</span><span class="token function">constraint</span><span class="token punctuation">(</span>equalTo<span class="token punctuation">:</span> view<span class="token punctuation">.</span>leadingAnchor<span class="token punctuation">)</span><span class="token punctuation">,</span>
</span><span class="code-line">            hostView<span class="token punctuation">.</span>view<span class="token punctuation">.</span>trailingAnchor<span class="token punctuation">.</span><span class="token function">constraint</span><span class="token punctuation">(</span>equalTo<span class="token punctuation">:</span> view<span class="token punctuation">.</span>trailingAnchor<span class="token punctuation">)</span><span class="token punctuation">,</span>
</span><span class="code-line">            hostView<span class="token punctuation">.</span>view<span class="token punctuation">.</span>bottomAnchor<span class="token punctuation">.</span><span class="token function">constraint</span><span class="token punctuation">(</span>equalTo<span class="token punctuation">:</span> view<span class="token punctuation">.</span>bottomAnchor<span class="token punctuation">)</span><span class="token punctuation">,</span>
</span><span class="code-line">            
</span><span class="code-line">            hostView<span class="token punctuation">.</span>view<span class="token punctuation">.</span>widthAnchor<span class="token punctuation">.</span><span class="token function">constraint</span><span class="token punctuation">(</span>equalTo<span class="token punctuation">:</span> view<span class="token punctuation">.</span>widthAnchor<span class="token punctuation">)</span><span class="token punctuation">,</span>
</span><span class="code-line">            hostView<span class="token punctuation">.</span>view<span class="token punctuation">.</span>heightAnchor<span class="token punctuation">.</span><span class="token function">constraint</span><span class="token punctuation">(</span>equalTo<span class="token punctuation">:</span> view<span class="token punctuation">.</span>heightAnchor<span class="token punctuation">)</span><span class="token punctuation">,</span>
</span><span class="code-line">        <span class="token punctuation">]</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">let</span> interaction <span class="token operator">=</span> <span class="token class-name">UIContextMenuInteraction</span><span class="token punctuation">(</span>delegate<span class="token punctuation">:</span> context<span class="token punctuation">.</span>coordinator<span class="token punctuation">)</span>
</span><span class="code-line">        view<span class="token punctuation">.</span><span class="token function">addSubview</span><span class="token punctuation">(</span>hostView<span class="token punctuation">.</span>view<span class="token punctuation">)</span>
</span><span class="code-line">        view<span class="token punctuation">.</span><span class="token function">addConstraints</span><span class="token punctuation">(</span>constraints<span class="token punctuation">)</span>
</span><span class="code-line">        view<span class="token punctuation">.</span><span class="token function">addInteraction</span><span class="token punctuation">(</span>interaction<span class="token punctuation">)</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">return</span> view
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">updateUIView</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> uiView<span class="token punctuation">:</span> <span class="token class-name">UIView</span><span class="token punctuation">,</span> context<span class="token punctuation">:</span> <span class="token class-name">Context</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">class</span> <span class="token class-name">Coordinator</span><span class="token punctuation">:</span> <span class="token class-name">NSObject</span><span class="token punctuation">,</span> <span class="token class-name">UIContextMenuInteractionDelegate</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">var</span> parent<span class="token punctuation">:</span> <span class="token class-name">ContextMenuHelper</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">init</span><span class="token punctuation">(</span>parent<span class="token punctuation">:</span> <span class="token class-name">ContextMenuHelper</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">self</span><span class="token punctuation">.</span>parent <span class="token operator">=</span> parent
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">                
</span><span class="code-line">        <span class="token keyword">func</span> <span class="token function-definition function">contextMenuInteraction</span><span class="token punctuation">(</span>
</span><span class="code-line">            <span class="token omit keyword">_</span> interaction<span class="token punctuation">:</span> <span class="token class-name">UIContextMenuInteraction</span><span class="token punctuation">,</span>
</span><span class="code-line">            configurationForMenuAtLocation location<span class="token punctuation">:</span> <span class="token class-name">CGPoint</span>
</span><span class="code-line">        <span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">UIContextMenuConfiguration</span><span class="token operator">?</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token class-name">UIContextMenuConfiguration</span><span class="token punctuation">(</span>identifier<span class="token punctuation">:</span> <span class="token nil constant">nil</span><span class="token punctuation">,</span> previewProvider<span class="token punctuation">:</span> <span class="token nil constant">nil</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> items <span class="token keyword">in</span>
</span><span class="code-line">                <span class="token keyword">return</span> <span class="token keyword">self</span><span class="token punctuation">.</span>parent<span class="token punctuation">.</span>menu
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">func</span> <span class="token function-definition function">contextMenuInteraction</span><span class="token punctuation">(</span>
</span><span class="code-line">            <span class="token omit keyword">_</span> interaction<span class="token punctuation">:</span> <span class="token class-name">UIContextMenuInteraction</span><span class="token punctuation">,</span>
</span><span class="code-line">            willPerformPreviewActionForMenuWith configuration<span class="token punctuation">:</span> <span class="token class-name">UIContextMenuConfiguration</span><span class="token punctuation">,</span>
</span><span class="code-line">            animator<span class="token punctuation">:</span> <span class="token class-name">UIContextMenuInteractionCommitAnimating</span>
</span><span class="code-line">        <span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">self</span><span class="token punctuation">.</span>parent<span class="token punctuation">.</span><span class="token function">tapped</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">func</span> <span class="token function-definition function">contextMenuInteraction</span><span class="token punctuation">(</span>
</span><span class="code-line">            <span class="token omit keyword">_</span> interaction<span class="token punctuation">:</span> <span class="token class-name">UIContextMenuInteraction</span><span class="token punctuation">,</span>
</span><span class="code-line">            configuration<span class="token punctuation">:</span> <span class="token class-name">UIContextMenuConfiguration</span><span class="token punctuation">,</span>
</span><span class="code-line">            highlightPreviewForItemWithIdentifier identifier<span class="token punctuation">:</span> <span class="token class-name">NSCopying</span>
</span><span class="code-line">        <span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">UITargetedPreview</span><span class="token operator">?</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">guard</span> <span class="token keyword">let</span> interactionView <span class="token operator">=</span> interaction<span class="token punctuation">.</span>view <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token nil constant">nil</span> <span class="token punctuation">}</span>
</span><span class="code-line">            <span class="token keyword">guard</span> <span class="token keyword">let</span> snapshotView <span class="token operator">=</span> interactionView<span class="token punctuation">.</span><span class="token function">snapshotView</span><span class="token punctuation">(</span>afterScreenUpdates<span class="token punctuation">:</span> <span class="token boolean">false</span><span class="token punctuation">)</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token nil constant">nil</span> <span class="token punctuation">}</span>
</span><span class="code-line">            
</span><span class="code-line">            <span class="token keyword">let</span> padding<span class="token punctuation">:</span> <span class="token class-name">CGFloat</span> <span class="token operator">=</span> <span class="token number">16</span>
</span><span class="code-line">            
</span><span class="code-line">            <span class="token keyword">let</span> customView <span class="token operator">=</span> <span class="token class-name">UIHostingController</span><span class="token punctuation">(</span>rootView<span class="token punctuation">:</span> parent<span class="token punctuation">.</span>customView<span class="token punctuation">)</span><span class="token punctuation">.</span>view<span class="token operator">!</span>
</span><span class="code-line">            customView<span class="token punctuation">.</span>frame <span class="token operator">=</span> <span class="token class-name">CGRect</span><span class="token punctuation">(</span>origin<span class="token punctuation">:</span> <span class="token class-name">CGPoint</span><span class="token punctuation">(</span>x<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span> y<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">,</span> size<span class="token punctuation">:</span> parent<span class="token punctuation">.</span>customSize<span class="token punctuation">)</span>
</span><span class="code-line">            customView<span class="token punctuation">.</span>backgroundColor <span class="token operator">=</span> <span class="token punctuation">.</span>clear
</span><span class="code-line">            customView<span class="token punctuation">.</span>layer<span class="token punctuation">.</span>cornerRadius <span class="token operator">=</span> <span class="token number">15</span>
</span><span class="code-line">            customView<span class="token punctuation">.</span>layer<span class="token punctuation">.</span>masksToBounds <span class="token operator">=</span> <span class="token boolean">true</span>
</span><span class="code-line">            customView<span class="token punctuation">.</span>translatesAutoresizingMaskIntoConstraints <span class="token operator">=</span> <span class="token boolean">false</span>
</span><span class="code-line">            customView<span class="token punctuation">.</span>transform <span class="token operator">=</span> <span class="token class-name">CGAffineTransform</span><span class="token punctuation">(</span>translationX<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span> y<span class="token punctuation">:</span> <span class="token class-name">UIScreen</span><span class="token punctuation">.</span>main<span class="token punctuation">.</span>bounds<span class="token punctuation">.</span>height<span class="token punctuation">)</span>
</span><span class="code-line">            
</span><span class="code-line">            <span class="token class-name">UIView</span><span class="token punctuation">.</span><span class="token function">animate</span><span class="token punctuation">(</span>
</span><span class="code-line">                withDuration<span class="token punctuation">:</span> <span class="token number">0.5</span><span class="token punctuation">,</span>
</span><span class="code-line">                delay<span class="token punctuation">:</span> <span class="token number">0.5</span><span class="token punctuation">,</span>
</span><span class="code-line">                usingSpringWithDamping<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span>
</span><span class="code-line">                initialSpringVelocity<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span>
</span><span class="code-line">                options<span class="token punctuation">:</span> <span class="token punctuation">.</span>curveEaseOut<span class="token punctuation">,</span>
</span><span class="code-line">                animations<span class="token punctuation">:</span> <span class="token punctuation">{</span>
</span><span class="code-line">                    customView<span class="token punctuation">.</span>transform <span class="token operator">=</span> <span class="token punctuation">.</span>identity
</span><span class="code-line">                    customView<span class="token punctuation">.</span>alpha <span class="token operator">=</span> <span class="token number">1</span>
</span><span class="code-line">                <span class="token punctuation">}</span><span class="token punctuation">,</span>
</span><span class="code-line">                completion<span class="token punctuation">:</span> <span class="token nil constant">nil</span>
</span><span class="code-line">            <span class="token punctuation">)</span>
</span><span class="code-line">            
</span><span class="code-line">            snapshotView<span class="token punctuation">.</span>layer<span class="token punctuation">.</span>cornerRadius <span class="token operator">=</span> <span class="token number">20</span>
</span><span class="code-line">            snapshotView<span class="token punctuation">.</span>layer<span class="token punctuation">.</span>masksToBounds <span class="token operator">=</span> <span class="token boolean">true</span>
</span><span class="code-line">            snapshotView<span class="token punctuation">.</span>translatesAutoresizingMaskIntoConstraints <span class="token operator">=</span> <span class="token boolean">false</span>
</span><span class="code-line">            
</span><span class="code-line">            <span class="token keyword">let</span> containerWidth <span class="token operator">=</span> <span class="token function">max</span><span class="token punctuation">(</span>parent<span class="token punctuation">.</span>customSize<span class="token punctuation">.</span>width<span class="token punctuation">,</span> snapshotView<span class="token punctuation">.</span>frame<span class="token punctuation">.</span>width<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token keyword">let</span> containerHeight <span class="token operator">=</span> parent<span class="token punctuation">.</span>customSize<span class="token punctuation">.</span>height <span class="token operator">+</span> snapshotView<span class="token punctuation">.</span>frame<span class="token punctuation">.</span>height <span class="token operator">+</span> padding
</span><span class="code-line">            <span class="token keyword">let</span> containerSize <span class="token operator">=</span> <span class="token class-name">CGSize</span><span class="token punctuation">(</span>width<span class="token punctuation">:</span> containerWidth<span class="token punctuation">,</span> height<span class="token punctuation">:</span> containerHeight<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token keyword">let</span> container <span class="token operator">=</span> <span class="token class-name">UIView</span><span class="token punctuation">(</span>frame<span class="token punctuation">:</span> <span class="token class-name">CGRect</span><span class="token punctuation">(</span>origin<span class="token punctuation">:</span> <span class="token punctuation">.</span>zero<span class="token punctuation">,</span> size<span class="token punctuation">:</span> containerSize<span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">            
</span><span class="code-line">            container<span class="token punctuation">.</span>backgroundColor <span class="token operator">=</span> <span class="token punctuation">.</span>clear
</span><span class="code-line">            container<span class="token punctuation">.</span><span class="token function">addSubview</span><span class="token punctuation">(</span>customView<span class="token punctuation">)</span>
</span><span class="code-line">            container<span class="token punctuation">.</span><span class="token function">addSubview</span><span class="token punctuation">(</span>snapshotView<span class="token punctuation">)</span>
</span><span class="code-line">            
</span><span class="code-line">            customView<span class="token punctuation">.</span>leadingAnchor<span class="token punctuation">.</span><span class="token function">constraint</span><span class="token punctuation">(</span>equalTo<span class="token punctuation">:</span> container<span class="token punctuation">.</span>leadingAnchor<span class="token punctuation">)</span><span class="token punctuation">.</span>isActive <span class="token operator">=</span> <span class="token boolean">true</span>
</span><span class="code-line">            customView<span class="token punctuation">.</span>topAnchor<span class="token punctuation">.</span><span class="token function">constraint</span><span class="token punctuation">(</span>equalTo<span class="token punctuation">:</span> container<span class="token punctuation">.</span>topAnchor<span class="token punctuation">)</span><span class="token punctuation">.</span>isActive <span class="token operator">=</span> <span class="token boolean">true</span>
</span><span class="code-line">            customView<span class="token punctuation">.</span>widthAnchor<span class="token punctuation">.</span><span class="token function">constraint</span><span class="token punctuation">(</span>equalToConstant<span class="token punctuation">:</span> parent<span class="token punctuation">.</span>customSize<span class="token punctuation">.</span>width<span class="token punctuation">)</span><span class="token punctuation">.</span>isActive <span class="token operator">=</span> <span class="token boolean">true</span>
</span><span class="code-line">            customView<span class="token punctuation">.</span>heightAnchor<span class="token punctuation">.</span><span class="token function">constraint</span><span class="token punctuation">(</span>equalToConstant<span class="token punctuation">:</span> parent<span class="token punctuation">.</span>customSize<span class="token punctuation">.</span>height<span class="token punctuation">)</span><span class="token punctuation">.</span>isActive <span class="token operator">=</span> <span class="token boolean">true</span>
</span><span class="code-line">            
</span><span class="code-line">            snapshotView<span class="token punctuation">.</span>widthAnchor<span class="token punctuation">.</span><span class="token function">constraint</span><span class="token punctuation">(</span>equalToConstant<span class="token punctuation">:</span> interactionView<span class="token punctuation">.</span>frame<span class="token punctuation">.</span>width<span class="token punctuation">)</span><span class="token punctuation">.</span>isActive <span class="token operator">=</span> <span class="token boolean">true</span>
</span><span class="code-line">            snapshotView<span class="token punctuation">.</span>centerXAnchor<span class="token punctuation">.</span><span class="token function">constraint</span><span class="token punctuation">(</span>equalTo<span class="token punctuation">:</span> container<span class="token punctuation">.</span>centerXAnchor<span class="token punctuation">)</span><span class="token punctuation">.</span>isActive <span class="token operator">=</span> <span class="token boolean">true</span>
</span><span class="code-line">            snapshotView<span class="token punctuation">.</span>bottomAnchor<span class="token punctuation">.</span><span class="token function">constraint</span><span class="token punctuation">(</span>equalTo<span class="token punctuation">:</span> container<span class="token punctuation">.</span>bottomAnchor<span class="token punctuation">)</span><span class="token punctuation">.</span>isActive <span class="token operator">=</span> <span class="token boolean">true</span>
</span><span class="code-line">            snapshotView<span class="token punctuation">.</span>topAnchor<span class="token punctuation">.</span><span class="token function">constraint</span><span class="token punctuation">(</span>equalTo<span class="token punctuation">:</span> customView<span class="token punctuation">.</span>bottomAnchor<span class="token punctuation">,</span> constant<span class="token punctuation">:</span> padding<span class="token punctuation">)</span><span class="token punctuation">.</span>isActive <span class="token operator">=</span> <span class="token boolean">true</span>
</span><span class="code-line">            
</span><span class="code-line">            <span class="token keyword">let</span> centerPoint <span class="token operator">=</span> <span class="token class-name">CGPoint</span><span class="token punctuation">(</span>
</span><span class="code-line">                x<span class="token punctuation">:</span> interactionView<span class="token punctuation">.</span>center<span class="token punctuation">.</span>x<span class="token punctuation">,</span>
</span><span class="code-line">                y<span class="token punctuation">:</span> interactionView<span class="token punctuation">.</span>center<span class="token punctuation">.</span>y <span class="token operator">-</span> <span class="token punctuation">(</span>customView<span class="token punctuation">.</span>bounds<span class="token punctuation">.</span>height <span class="token operator">+</span> padding<span class="token punctuation">)</span> <span class="token operator">/</span> <span class="token number">2</span>
</span><span class="code-line">            <span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token keyword">let</span> previewTarget <span class="token operator">=</span> <span class="token class-name">UIPreviewTarget</span><span class="token punctuation">(</span>container<span class="token punctuation">:</span> interactionView<span class="token punctuation">,</span> center<span class="token punctuation">:</span> centerPoint<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token keyword">let</span> previewParams <span class="token operator">=</span> <span class="token class-name">UIPreviewParameters</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">            previewParams<span class="token punctuation">.</span>backgroundColor <span class="token operator">=</span> <span class="token punctuation">.</span>clear
</span><span class="code-line">            previewParams<span class="token punctuation">.</span>shadowPath <span class="token operator">=</span> <span class="token class-name">UIBezierPath</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">            
</span><span class="code-line">            <span class="token keyword">return</span> <span class="token class-name">UITargetedPreview</span><span class="token punctuation">(</span>view<span class="token punctuation">:</span> container<span class="token punctuation">,</span> parameters<span class="token punctuation">:</span> previewParams<span class="token punctuation">,</span> target<span class="token punctuation">:</span> previewTarget<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="유틸성-코드">유틸성 코드</h2>
<ul>
<li>다른 코드에서 사용된 유틸성 코드입니다.</li>
<li><code>readSize</code>는 해당 View의 사이즈를 읽어옵니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">readSize</span><span class="token punctuation">(</span>onChange<span class="token punctuation">:</span> <span class="token attribute atrule">@escaping</span> <span class="token punctuation">(</span><span class="token class-name">CGSize</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Void</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token function">background</span><span class="token punctuation">(</span>
</span><span class="code-line">            <span class="token class-name">GeometryReader</span> <span class="token punctuation">{</span> proxy <span class="token keyword">in</span>
</span><span class="code-line">                <span class="token class-name">Color</span><span class="token punctuation">.</span>clear
</span><span class="code-line">                    <span class="token punctuation">.</span><span class="token function">preference</span><span class="token punctuation">(</span>key<span class="token punctuation">:</span> <span class="token class-name">SizePreferenceKey</span><span class="token punctuation">.</span><span class="token keyword">self</span><span class="token punctuation">,</span> value<span class="token punctuation">:</span> proxy<span class="token punctuation">.</span>size<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">onPreferenceChange</span><span class="token punctuation">(</span><span class="token class-name">SizePreferenceKey</span><span class="token punctuation">.</span><span class="token keyword">self</span><span class="token punctuation">,</span> perform<span class="token punctuation">:</span> onChange<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">SizePreferenceKey</span><span class="token punctuation">:</span> <span class="token class-name">PreferenceKey</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">static</span> <span class="token keyword">var</span> defaultValue<span class="token punctuation">:</span> <span class="token class-name">CGSize</span> <span class="token operator">=</span> <span class="token punctuation">.</span>zero
</span><span class="code-line">    <span class="token keyword">static</span> <span class="token keyword">func</span> <span class="token function-definition function">reduce</span><span class="token punctuation">(</span>value<span class="token punctuation">:</span> <span class="token keyword">inout</span> <span class="token class-name">CGSize</span><span class="token punctuation">,</span> nextValue<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">CGSize</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>Context Menu를 닫기 위해 사용되는 <code>dismissTopViewController</code> 코드입니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">dismissTopViewController</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">let</span> windowScene <span class="token operator">=</span> <span class="token class-name">UIApplication</span><span class="token punctuation">.</span>shared<span class="token punctuation">.</span>connectedScenes<span class="token punctuation">.</span>first <span class="token keyword">as</span><span class="token operator">?</span> <span class="token class-name">UIWindowScene</span>
</span><span class="code-line">        <span class="token keyword">let</span> window <span class="token operator">=</span> windowScene<span class="token operator">?</span><span class="token punctuation">.</span>windows<span class="token punctuation">.</span>first
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">if</span> <span class="token keyword">var</span> topController <span class="token operator">=</span> window<span class="token operator">?</span><span class="token punctuation">.</span>rootViewController <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">while</span> <span class="token keyword">let</span> presentedViewController <span class="token operator">=</span> topController<span class="token punctuation">.</span>presentedViewController <span class="token punctuation">{</span>
</span><span class="code-line">                topController <span class="token operator">=</span> presentedViewController
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">            topController<span class="token punctuation">.</span><span class="token function">dismiss</span><span class="token punctuation">(</span>animated<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="customcontextmenu-사용법">customContextMenu 사용법</h2>
<ul>
<li>이렇게 완성된 <code>customContextMenu</code>를 사용한 예시 코드입니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">CustomContextView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token attribute atrule">@State</span> <span class="token keyword">var</span> items <span class="token operator">=</span> <span class="token class-name">Array</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token operator">..&#x3C;</span><span class="token number">30</span><span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">List</span><span class="token punctuation">(</span>items<span class="token punctuation">,</span> id<span class="token punctuation">:</span> <span class="token punctuation">\</span><span class="token punctuation">.</span><span class="token keyword">self</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Message bubble </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation"><span class="token short-argument">$0</span></span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token punctuation">.</span><span class="token function">foregroundColor</span><span class="token punctuation">(</span><span class="token punctuation">.</span>white<span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token punctuation">.</span><span class="token function">padding</span><span class="token punctuation">(</span><span class="token punctuation">.</span>vertical<span class="token punctuation">,</span> <span class="token number">12</span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token punctuation">.</span><span class="token function">padding</span><span class="token punctuation">(</span><span class="token punctuation">.</span>horizontal<span class="token punctuation">,</span> <span class="token number">20</span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token punctuation">.</span><span class="token function">background</span><span class="token punctuation">(</span><span class="token punctuation">.</span>gray<span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token punctuation">.</span><span class="token function">cornerRadius</span><span class="token punctuation">(</span><span class="token number">20</span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token punctuation">.</span>customContextMenu <span class="token punctuation">{</span>
</span><span class="code-line">                    <span class="token class-name">HStack</span> <span class="token punctuation">{</span>
</span><span class="code-line">                        <span class="token class-name">Button</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"😀"</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">                            <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"smile"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">                            <span class="token function">dismissTopViewController</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">                        <span class="token punctuation">}</span>
</span><span class="code-line">                        <span class="token class-name">Button</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"🥹"</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">                            <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"oh"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">                            <span class="token function">dismissTopViewController</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">                        <span class="token punctuation">}</span>
</span><span class="code-line">                        <span class="token class-name">Button</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"😂"</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">                            <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"cry"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">                            <span class="token function">dismissTopViewController</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">                        <span class="token punctuation">}</span>
</span><span class="code-line">                    <span class="token punctuation">}</span>
</span><span class="code-line">                    <span class="token punctuation">.</span><span class="token function">buttonStyle</span><span class="token punctuation">(</span><span class="token punctuation">.</span>borderless<span class="token punctuation">)</span>
</span><span class="code-line">                    <span class="token punctuation">.</span><span class="token function">frame</span><span class="token punctuation">(</span>width<span class="token punctuation">:</span> <span class="token number">150</span><span class="token punctuation">,</span> height<span class="token punctuation">:</span> <span class="token number">50</span><span class="token punctuation">)</span>
</span><span class="code-line">                    <span class="token punctuation">.</span><span class="token function">background</span><span class="token punctuation">(</span><span class="token punctuation">.</span>thinMaterial<span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token punctuation">}</span> menu<span class="token punctuation">:</span> <span class="token punctuation">{</span>
</span><span class="code-line">                    <span class="token class-name">UIMenu</span><span class="token punctuation">(</span>title<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">""</span></span><span class="token punctuation">,</span> children<span class="token punctuation">:</span> <span class="token punctuation">[</span>
</span><span class="code-line">                        <span class="token class-name">UIAction</span><span class="token punctuation">(</span>title<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Like"</span></span><span class="token punctuation">,</span> image<span class="token punctuation">:</span> <span class="token class-name">UIImage</span><span class="token punctuation">(</span>systemName<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"circle"</span></span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token omit keyword">_</span> <span class="token keyword">in</span> <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"like"</span></span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
</span><span class="code-line">                        <span class="token class-name">UIAction</span><span class="token punctuation">(</span>title<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Share"</span></span><span class="token punctuation">,</span> image<span class="token punctuation">:</span> <span class="token class-name">UIImage</span><span class="token punctuation">(</span>systemName<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"circle"</span></span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token omit keyword">_</span> <span class="token keyword">in</span> <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"share"</span></span><span class="token punctuation">)</span> <span class="token punctuation">}</span>
</span><span class="code-line">                    <span class="token punctuation">]</span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token punctuation">}</span> tapped<span class="token punctuation">:</span> <span class="token punctuation">{</span>
</span><span class="code-line">                    <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"tapped"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token punctuation">}</span>
</span><span class="code-line">                <span class="token punctuation">.</span><span class="token function">listRowInsets</span><span class="token punctuation">(</span><span class="token class-name">EdgeInsets</span><span class="token punctuation">(</span>top<span class="token punctuation">:</span> <span class="token number">4</span><span class="token punctuation">,</span> leading<span class="token punctuation">:</span> <span class="token number">12</span><span class="token punctuation">,</span> bottom<span class="token punctuation">:</span> <span class="token number">4</span><span class="token punctuation">,</span> trailing<span class="token punctuation">:</span> <span class="token number">12</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token punctuation">.</span><span class="token function">listRowSeparator</span><span class="token punctuation">(</span><span class="token punctuation">.</span>hidden<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">listStyle</span><span class="token punctuation">(</span><span class="token punctuation">.</span>plain<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="결과물">결과물</h2>
<ul>
<li>위의 예시 코드를 실행한 모습입니다.</li>
</ul>
<p><img src="/images/swiftui-custom-context-menu-1.gif" alt="swiftui-custom-context-menu"></p>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swiftui-custom-ptr</guid>
      <title>SwiftUI Custom PTR</title>
      <description>SwiftUI로 Meta의 Threads 앱 같은 커스텀 Pull To Refresh 인디케이터 만들어봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/swiftui-custom-ptr</link>
      <pubDate>Sat, 25 Nov 2023 10:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>Meta의 Threads 앱 홈 화면 상단에는 로고가 있고, 새로고침을 하면 미려하게 움직입니다.</li>
<li>SwiftUI로 이와 같은 커스텀 Pull To Refresh 인디케이터를 만들어 보겠습니다.</li>
</ul>
<h2 id="threads-앱">Threads 앱</h2>
<ul>
<li>Threads 앱의 PTR(Pull-to-refresh) 인디케이터는 다음과 같습니다.</li>
</ul>
<p><img src="/images/swiftui-custom-ptr-1.gif" alt="swiftui-custom-ptr"></p>
<h2 id="커스텀-ptr-만들기">커스텀 PTR 만들기</h2>
<ul>
<li>테스트에 사용한 완성된 코드는 다음과 같습니다.</li>
<li>아래에서 하나씩 살펴보겠습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token attribute atrule">@Environment</span><span class="token punctuation">(</span><span class="token punctuation">\</span><span class="token punctuation">.</span>safeAreaInsets<span class="token punctuation">)</span> <span class="token keyword">private</span> <span class="token keyword">var</span> safeAreaInsets
</span><span class="code-line">    
</span><span class="code-line">    <span class="token attribute atrule">@State</span> <span class="token keyword">private</span> <span class="token keyword">var</span> elements <span class="token operator">=</span> <span class="token class-name">Array</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token operator">..&#x3C;</span><span class="token number">30</span><span class="token punctuation">)</span><span class="token punctuation">.</span>map <span class="token punctuation">{</span> <span class="token class-name">String</span><span class="token punctuation">(</span><span class="token short-argument">$0</span><span class="token punctuation">)</span> <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token attribute atrule">@State</span> <span class="token keyword">private</span> <span class="token keyword">var</span> yOffset<span class="token punctuation">:</span> <span class="token class-name">CGFloat</span> <span class="token operator">=</span> <span class="token number">0</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">let</span> config <span class="token operator">=</span> <span class="token class-name">RefreshConfig</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        
</span><span class="code-line">    <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">List</span><span class="token punctuation">(</span><span class="token class-name">Array</span><span class="token punctuation">(</span>elements<span class="token punctuation">.</span><span class="token function">enumerated</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span> id<span class="token punctuation">:</span> <span class="token punctuation">\</span><span class="token punctuation">.</span>element<span class="token punctuation">)</span> <span class="token punctuation">{</span> index<span class="token punctuation">,</span> item <span class="token keyword">in</span>
</span><span class="code-line">            <span class="token class-name">Text</span><span class="token punctuation">(</span>item<span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token punctuation">.</span><span class="token function">frame</span><span class="token punctuation">(</span>height<span class="token punctuation">:</span> <span class="token number">100</span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token punctuation">.</span><span class="token function">listRowInsets</span><span class="token punctuation">(</span><span class="token punctuation">.</span>zero<span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token punctuation">.</span><span class="token function">padding</span><span class="token punctuation">(</span><span class="token punctuation">.</span>horizontal<span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token punctuation">.</span><span class="token keyword">if</span> <span class="token punctuation">(</span>index <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">                    <span class="token short-argument">$0</span><span class="token punctuation">.</span>onChangeOffsetY <span class="token punctuation">{</span> <span class="token keyword">self</span><span class="token punctuation">.</span>yOffset <span class="token operator">=</span> <span class="token short-argument">$0</span> <span class="token punctuation">}</span>
</span><span class="code-line">                <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">safeAreaInset</span><span class="token punctuation">(</span>edge<span class="token punctuation">:</span> <span class="token punctuation">.</span>top<span class="token punctuation">,</span> spacing<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token class-name">RefreshIconView</span><span class="token punctuation">(</span>
</span><span class="code-line">                yOffset<span class="token punctuation">:</span> $yOffset<span class="token punctuation">,</span>
</span><span class="code-line">                config<span class="token punctuation">:</span> config<span class="token punctuation">,</span>
</span><span class="code-line">                headerInset<span class="token punctuation">:</span> safeAreaInsets<span class="token punctuation">.</span>top <span class="token operator">+</span> config<span class="token punctuation">.</span>headerHeight                
</span><span class="code-line">            <span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">                <span class="token keyword">try</span><span class="token operator">?</span> <span class="token keyword">await</span> <span class="token class-name">Task</span><span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span><span class="token keyword">for</span><span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">seconds</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">}</span> refreshView<span class="token punctuation">:</span> <span class="token punctuation">{</span> state <span class="token keyword">in</span>
</span><span class="code-line">                <span class="token class-name">IconView</span><span class="token punctuation">(</span>state<span class="token punctuation">:</span> state<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">listStyle</span><span class="token punctuation">(</span><span class="token punctuation">.</span>plain<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="유틸성-구현">유틸성 구현</h2>
<ul>
<li>테스트 코드에 사용된 <code>if</code> modifier 입니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token attribute atrule">@ViewBuilder</span>
</span><span class="code-line">    <span class="token keyword">func</span> `<span class="token keyword">if</span>`<span class="token operator">&#x3C;</span><span class="token class-name">Content</span><span class="token punctuation">:</span> <span class="token class-name">View</span><span class="token operator">></span><span class="token punctuation">(</span><span class="token omit keyword">_</span> condition<span class="token punctuation">:</span> <span class="token class-name">Bool</span><span class="token punctuation">,</span> transform<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token keyword">Self</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Content</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">if</span> condition <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token function">transform</span><span class="token punctuation">(</span><span class="token keyword">self</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">self</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>View의 y offset 변화 감지를 트래킹 하기 위한 <code>onChangeOffsetY</code> modifier 입니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">onChangeOffsetY</span><span class="token punctuation">(</span>coordinateSpace<span class="token punctuation">:</span> <span class="token class-name">CoordinateSpace</span> <span class="token operator">=</span> <span class="token punctuation">.</span>global<span class="token punctuation">,</span> onChange<span class="token punctuation">:</span> <span class="token attribute atrule">@escaping</span> <span class="token punctuation">(</span><span class="token class-name">CGFloat</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Void</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">self</span><span class="token punctuation">.</span>overlay <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token class-name">GeometryReader</span> <span class="token punctuation">{</span> proxy <span class="token keyword">in</span>
</span><span class="code-line">                <span class="token class-name">Color</span><span class="token punctuation">.</span>clear
</span><span class="code-line">                    <span class="token punctuation">.</span><span class="token function">preference</span><span class="token punctuation">(</span>key<span class="token punctuation">:</span> <span class="token class-name">OffsetYPreferenceKey</span><span class="token punctuation">.</span><span class="token keyword">self</span><span class="token punctuation">,</span> value<span class="token punctuation">:</span> proxy<span class="token punctuation">.</span><span class="token function">frame</span><span class="token punctuation">(</span><span class="token keyword">in</span><span class="token punctuation">:</span> coordinateSpace<span class="token punctuation">)</span><span class="token punctuation">.</span>minY<span class="token punctuation">)</span>
</span><span class="code-line">                    <span class="token punctuation">.</span><span class="token function">onPreferenceChange</span><span class="token punctuation">(</span><span class="token class-name">OffsetYPreferenceKey</span><span class="token punctuation">.</span><span class="token keyword">self</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> value <span class="token keyword">in</span>
</span><span class="code-line">                        <span class="token function">onChange</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span>
</span><span class="code-line">                    <span class="token punctuation">}</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">OffsetYPreferenceKey</span><span class="token punctuation">:</span> <span class="token class-name">PreferenceKey</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">static</span> <span class="token keyword">var</span> defaultValue<span class="token punctuation">:</span> <span class="token class-name">CGFloat</span> <span class="token operator">=</span> <span class="token number">0</span>
</span><span class="code-line">    <span class="token keyword">static</span> <span class="token keyword">func</span> <span class="token function-definition function">reduce</span><span class="token punctuation">(</span>value<span class="token punctuation">:</span> <span class="token keyword">inout</span> <span class="token class-name">CGFloat</span><span class="token punctuation">,</span> nextValue<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">CGFloat</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        value <span class="token operator">=</span> <span class="token function">nextValue</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>Safe area를 쉽게 가져오기 위한 environment value 구현입니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">EnvironmentValues</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> safeAreaInsets<span class="token punctuation">:</span> <span class="token class-name">EdgeInsets</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">self</span><span class="token punctuation">[</span><span class="token class-name">SafeAreaInsetsKey</span><span class="token punctuation">.</span><span class="token keyword">self</span><span class="token punctuation">]</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">SafeAreaInsetsKey</span><span class="token punctuation">:</span> <span class="token class-name">EnvironmentKey</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">static</span> <span class="token keyword">var</span> defaultValue<span class="token punctuation">:</span> <span class="token class-name">EdgeInsets</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">let</span> windowScene <span class="token operator">=</span> <span class="token class-name">UIApplication</span><span class="token punctuation">.</span>shared<span class="token punctuation">.</span>connectedScenes<span class="token punctuation">.</span>first <span class="token keyword">as</span><span class="token operator">?</span> <span class="token class-name">UIWindowScene</span>
</span><span class="code-line">        <span class="token keyword">let</span> window <span class="token operator">=</span> windowScene<span class="token operator">?</span><span class="token punctuation">.</span>windows<span class="token punctuation">.</span>first
</span><span class="code-line">        <span class="token keyword">return</span> window<span class="token operator">?</span><span class="token punctuation">.</span>safeAreaInsets<span class="token punctuation">.</span>swiftUiInsets <span class="token operator">??</span> <span class="token class-name">EdgeInsets</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">UIEdgeInsets</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> swiftUiInsets<span class="token punctuation">:</span> <span class="token class-name">EdgeInsets</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">EdgeInsets</span><span class="token punctuation">(</span>top<span class="token punctuation">:</span> top<span class="token punctuation">,</span> leading<span class="token punctuation">:</span> <span class="token keyword">left</span><span class="token punctuation">,</span> bottom<span class="token punctuation">:</span> bottom<span class="token punctuation">,</span> trailing<span class="token punctuation">:</span> <span class="token keyword">right</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>기본 zero inset을 위한 확장 구현입니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">EdgeInsets</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">static</span> <span class="token keyword">var</span> zero<span class="token punctuation">:</span> <span class="token class-name">EdgeInsets</span> <span class="token punctuation">{</span> <span class="token punctuation">.</span><span class="token keyword">init</span><span class="token punctuation">(</span>top<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span> leading<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span> bottom<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span> trailing<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="ptr-본격-구현">PTR 본격 구현</h2>
<ul>
<li>본격적인 세팅으로, PTR을 구현하기 위한 정의 부분입니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">typealias</span> <span class="token class-name">RefreshAction</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token operator">-></span> <span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">enum</span> <span class="token class-name">RefreshMode</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">case</span> notRefreshing
</span><span class="code-line">    <span class="token keyword">case</span> pulling
</span><span class="code-line">    <span class="token keyword">case</span> refreshing
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">RefreshState</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> mode<span class="token punctuation">:</span> <span class="token class-name">RefreshMode</span> <span class="token operator">=</span> <span class="token punctuation">.</span>notRefreshing
</span><span class="code-line">    <span class="token keyword">var</span> dragPosition<span class="token punctuation">:</span> <span class="token class-name">CGFloat</span> <span class="token operator">=</span> <span class="token number">0</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">RefreshConfig</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> refreshAt<span class="token punctuation">:</span> <span class="token class-name">CGFloat</span> <span class="token operator">=</span> <span class="token number">100</span>
</span><span class="code-line">    <span class="token keyword">var</span> headerHeight<span class="token punctuation">:</span> <span class="token class-name">CGFloat</span> <span class="token operator">=</span> <span class="token number">80</span>
</span><span class="code-line">    <span class="token keyword">var</span> resetPoint<span class="token punctuation">:</span> <span class="token class-name">CGFloat</span> <span class="token operator">=</span> <span class="token number">5</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span></code></pre>
<ul>
<li>List 화면 최상단에 위치했던 RefreshIconView 구현입니다.</li>
<li>실질적인 refreshAction과 refreshView를 연결해주는 부분입니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">RefreshIconView</span><span class="token operator">&#x3C;</span><span class="token class-name">RefreshView</span><span class="token punctuation">:</span> <span class="token class-name">View</span><span class="token operator">></span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token attribute atrule">@Binding</span> <span class="token keyword">var</span> yOffset<span class="token punctuation">:</span> <span class="token class-name">CGFloat</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">let</span> config<span class="token punctuation">:</span> <span class="token class-name">Config</span>
</span><span class="code-line">    <span class="token keyword">let</span> headerInset<span class="token punctuation">:</span> <span class="token class-name">CGFloat</span>
</span><span class="code-line">    <span class="token keyword">let</span> refreshAction<span class="token punctuation">:</span> <span class="token class-name">RefreshAction</span>
</span><span class="code-line">    <span class="token keyword">let</span> refreshView<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token class-name">Binding</span><span class="token operator">&#x3C;</span><span class="token class-name">RefreshState</span><span class="token operator">></span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">RefreshView</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token attribute atrule">@State</span> <span class="token keyword">private</span> <span class="token keyword">var</span> state <span class="token operator">=</span> <span class="token class-name">RefreshState</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token attribute atrule">@State</span> <span class="token keyword">private</span> <span class="token keyword">var</span> distance<span class="token punctuation">:</span> <span class="token class-name">CGFloat</span> <span class="token operator">=</span> <span class="token number">0</span>
</span><span class="code-line">    <span class="token attribute atrule">@State</span> <span class="token keyword">private</span> <span class="token keyword">var</span> canRefresh <span class="token operator">=</span> <span class="token boolean">true</span>
</span><span class="code-line">    <span class="token attribute atrule">@State</span> <span class="token keyword">private</span> <span class="token keyword">var</span> pastYOffset<span class="token punctuation">:</span> <span class="token class-name">CGFloat</span> <span class="token operator">=</span> <span class="token number">0</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">var</span> iconOffset<span class="token punctuation">:</span> <span class="token class-name">CGFloat</span> <span class="token punctuation">{</span>
</span><span class="code-line">        config<span class="token punctuation">.</span>headerHeight <span class="token operator">*</span> state<span class="token punctuation">.</span>dragPosition
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token function">refreshView</span><span class="token punctuation">(</span>$state<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">opacity</span><span class="token punctuation">(</span>canRefresh <span class="token operator">?</span> <span class="token number">1</span> <span class="token punctuation">:</span> <span class="token number">0.6</span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">frame</span><span class="token punctuation">(</span>height<span class="token punctuation">:</span> config<span class="token punctuation">.</span>headerHeight<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">offset</span><span class="token punctuation">(</span>y<span class="token punctuation">:</span> iconOffset<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">onChange</span><span class="token punctuation">(</span>of<span class="token punctuation">:</span> yOffset<span class="token punctuation">)</span> <span class="token punctuation">{</span> value <span class="token keyword">in</span>
</span><span class="code-line">                <span class="token function">offsetChanged</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span>
</span><span class="code-line">                pastYOffset <span class="token operator">=</span> value
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">func</span> <span class="token function-definition function">offsetChanged</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> val<span class="token punctuation">:</span> <span class="token class-name">CGFloat</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        distance <span class="token operator">=</span> val <span class="token operator">-</span> headerInset
</span><span class="code-line">        state<span class="token punctuation">.</span>dragPosition <span class="token operator">=</span> <span class="token function">normalize</span><span class="token punctuation">(</span>from<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span> to<span class="token punctuation">:</span> config<span class="token punctuation">.</span>refreshAt<span class="token punctuation">,</span> by<span class="token punctuation">:</span> distance<span class="token punctuation">)</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">guard</span> canRefresh <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">            canRefresh <span class="token operator">=</span> <span class="token punctuation">(</span>distance <span class="token operator">&#x3C;=</span> config<span class="token punctuation">.</span>resetPoint<span class="token punctuation">)</span> <span class="token operator">&#x26;&#x26;</span> <span class="token punctuation">(</span>state<span class="token punctuation">.</span>mode <span class="token operator">==</span> <span class="token punctuation">.</span>notRefreshing<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token keyword">return</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">guard</span> distance <span class="token operator">></span> <span class="token number">0</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">            state<span class="token punctuation">.</span>mode <span class="token operator">=</span> <span class="token punctuation">.</span>notRefreshing
</span><span class="code-line">            <span class="token keyword">return</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">                
</span><span class="code-line">        <span class="token keyword">if</span> distance <span class="token operator">>=</span> config<span class="token punctuation">.</span>refreshAt <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token class-name">UIImpactFeedbackGenerator</span><span class="token punctuation">(</span>style<span class="token punctuation">:</span> <span class="token punctuation">.</span>medium<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">impactOccurred</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">            state<span class="token punctuation">.</span>mode <span class="token operator">=</span> <span class="token punctuation">.</span>refreshing
</span><span class="code-line">            withAnimation <span class="token punctuation">{</span> canRefresh <span class="token operator">=</span> <span class="token boolean">false</span> <span class="token punctuation">}</span>
</span><span class="code-line">            
</span><span class="code-line">            <span class="token class-name">Task</span> <span class="token punctuation">{</span>
</span><span class="code-line">                <span class="token keyword">await</span> <span class="token function">refreshAction</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">                withAnimation <span class="token punctuation">{</span> canRefresh <span class="token operator">=</span> <span class="token boolean">true</span> <span class="token punctuation">}</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> distance <span class="token operator">></span> <span class="token number">0</span> <span class="token operator">&#x26;&#x26;</span> val <span class="token operator">></span> pastYOffset <span class="token punctuation">{</span>
</span><span class="code-line">            state<span class="token punctuation">.</span>mode <span class="token operator">=</span> <span class="token punctuation">.</span>pulling
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>Refresh Icon의 실질적인 UI 부분입니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">IconView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token attribute atrule">@State</span> <span class="token keyword">private</span> <span class="token keyword">var</span> scaling <span class="token operator">=</span> <span class="token boolean">false</span>
</span><span class="code-line">    <span class="token attribute atrule">@Binding</span> <span class="token keyword">var</span> state<span class="token punctuation">:</span> <span class="token class-name">RefreshState</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">VStack</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">switch</span> state<span class="token punctuation">.</span>mode <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">case</span> <span class="token punctuation">.</span>notRefreshing<span class="token punctuation">:</span>
</span><span class="code-line">                <span class="token class-name">Image</span><span class="token punctuation">(</span><span class="token punctuation">.</span>hohyeon<span class="token punctuation">)</span>
</span><span class="code-line">                    <span class="token punctuation">.</span><span class="token function">resizable</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">                    <span class="token punctuation">.</span><span class="token function">frame</span><span class="token punctuation">(</span>width<span class="token punctuation">:</span> <span class="token number">50</span><span class="token punctuation">,</span> height<span class="token punctuation">:</span> <span class="token number">50</span><span class="token punctuation">)</span>
</span><span class="code-line">                    <span class="token punctuation">.</span>onAppear <span class="token punctuation">{</span>
</span><span class="code-line">                        withAnimation <span class="token punctuation">{</span>
</span><span class="code-line">                            scaling <span class="token operator">=</span> <span class="token boolean">false</span>
</span><span class="code-line">                        <span class="token punctuation">}</span>
</span><span class="code-line">                    <span class="token punctuation">}</span>
</span><span class="code-line">            <span class="token keyword">case</span> <span class="token punctuation">.</span>pulling<span class="token punctuation">:</span>
</span><span class="code-line">                <span class="token class-name">Image</span><span class="token punctuation">(</span><span class="token punctuation">.</span>hohyeon<span class="token punctuation">)</span>
</span><span class="code-line">                    <span class="token punctuation">.</span><span class="token function">resizable</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">                    <span class="token punctuation">.</span><span class="token function">frame</span><span class="token punctuation">(</span>width<span class="token punctuation">:</span> <span class="token number">50</span><span class="token punctuation">,</span> height<span class="token punctuation">:</span> <span class="token number">50</span><span class="token punctuation">)</span>
</span><span class="code-line">                    <span class="token punctuation">.</span><span class="token function">rotationEffect</span><span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token function">degrees</span><span class="token punctuation">(</span><span class="token number">360</span> <span class="token operator">*</span> state<span class="token punctuation">.</span>dragPosition<span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token keyword">case</span> <span class="token punctuation">.</span>refreshing<span class="token punctuation">:</span>
</span><span class="code-line">                <span class="token class-name">Image</span><span class="token punctuation">(</span><span class="token punctuation">.</span>hohyeon<span class="token punctuation">)</span>
</span><span class="code-line">                    <span class="token punctuation">.</span><span class="token function">resizable</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">                    <span class="token punctuation">.</span><span class="token function">frame</span><span class="token punctuation">(</span>width<span class="token punctuation">:</span> <span class="token number">50</span><span class="token punctuation">,</span> height<span class="token punctuation">:</span> <span class="token number">50</span><span class="token punctuation">)</span>
</span><span class="code-line">                    <span class="token punctuation">.</span><span class="token function">scaleEffect</span><span class="token punctuation">(</span>scaling <span class="token operator">?</span> <span class="token number">2</span> <span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">)</span>
</span><span class="code-line">                    <span class="token punctuation">.</span>task <span class="token punctuation">{</span>
</span><span class="code-line">                        withAnimation <span class="token punctuation">{</span>
</span><span class="code-line">                            scaling <span class="token operator">=</span> <span class="token boolean">true</span>
</span><span class="code-line">                        <span class="token punctuation">}</span>
</span><span class="code-line">                        <span class="token keyword">try</span><span class="token operator">?</span> <span class="token keyword">await</span> <span class="token class-name">Task</span><span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span><span class="token keyword">for</span><span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">seconds</span><span class="token punctuation">(</span><span class="token number">0.2</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">                        withAnimation <span class="token punctuation">{</span>
</span><span class="code-line">                            scaling <span class="token operator">=</span> <span class="token boolean">false</span>
</span><span class="code-line">                        <span class="token punctuation">}</span>
</span><span class="code-line">                    <span class="token punctuation">}</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="결과물">결과물</h2>
<p><img src="/images/swiftui-custom-ptr-2.gif" alt="swiftui-custom-ptr"></p>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/zappy-ai-sns</guid>
      <title>AI 기반 SNS, Zappy</title>
      <description>제가 iOS 앱 개발에 참여한 Zappy를 소개합니다</description>
      <link>https://www.hohyeonmoon.com/blog/zappy-ai-sns</link>
      <pubDate>Sat, 28 Oct 2023 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<h2 id="zappy-출시">Zappy 출시</h2>
<p><img src="/images/zappy-ai-sns-1.png" alt="zappy-ai-sns"></p>
<ul>
<li>근무 중인 스타트업에서 Zappy(재피)라는 AI 기반 SNS를 출시했습니다!</li>
<li>저는 iOS 엔지니어로 참여하여, 앱의 핵심 기능을 구현했습니다.</li>
</ul>
<p><img src="/images/zappy-ai-sns-2.png" alt="zappy-ai-sns">
<img src="/images/zappy-ai-sns-3.png" alt="zappy-ai-sns"></p>
<ul>
<li>마케팅도 곳곳에서 열심히 진행되고 있습니다.</li>
</ul>
<h2 id="링크">링크</h2>
<p><strong><a href="https://a.zpy.kr/465w/2">Zappy 앱 다운로드</a></strong></p>
<ul>
<li>현재는 iOS 앱만 출시된 상태지만, Android 앱도 출시될 예정입니다.</li>
<li>(이제 Android 앱도 출시했습니다) 관심 있으신 분은 앱을 이용해주세요!</li>
</ul>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/ios-limit-capture</guid>
      <title>UIKit에서 화면 캡쳐 방지하기</title>
      <description>iOS UIKit에서 스크린샷과 화면 녹화를 방지하는 방법에 대해 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/ios-limit-capture</link>
      <pubDate>Sat, 17 Jun 2023 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<h2 id="화면-캡쳐-방지">화면 캡쳐 방지</h2>
<ul>
<li>iOS 앱에서 콘텐츠 보호를 위해 화면 캡쳐를 방지해야 하는 경우가 있습니다.</li>
<li><strong>스크린샷</strong>(이미지)과 <strong>화면 녹화</strong>(영상)를 통틀어 화면 캡쳐라고 표현을 해봤는데요.</li>
<li>애플의 <code>isSecureTextEntry</code>를 활용한 트릭을 사용해 화면 캡쳐 방지를 구현해보겠습니다.</li>
<li>더불어, <strong>스크린샷</strong>과 <strong>화면 녹화</strong>를 구분해 방지하는 방법도 알아보겠습니다.</li>
</ul>
<h2 id="issecuretextentry-트릭">isSecureTextEntry 트릭</h2>
<ul>
<li><code>UITextField</code>의 <code>isSecureTextEntry</code> 속성이 <code>true</code>면, 해당 <code>TextField</code>의 내용은 캡쳐했을때 가려집니다.</li>
<li>이는 원래 비밀번호 등 민감한 정보를 캡쳐하는 것을 방지하기 위한 것으로 알려져있는데요.</li>
<li>이를 활용해 화면 캡쳐를 방지하고 싶은 <code>View</code>에 <code>TextField</code>를 추가하면 캡쳐를 막을 수 있습니다.</li>
</ul>
<h2 id="uiview-확장">UIView 확장</h2>
<ul>
<li>Swift 파일을 추가해 아래와 같이 UIView를 확장합니다.</li>
<li>코드에 대한 설명은 코드내 주석으로 추가했습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">import</span> <span class="token class-name">UIKit</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">private</span> <span class="token keyword">var</span> <span class="token class-name">AssociatedObjectHandle</span> <span class="token operator">=</span> <span class="token number">0</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">UIView</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token comment">// 트릭을 위한 임의의 UITextField</span>
</span><span class="code-line">  <span class="token keyword">private</span> <span class="token keyword">var</span> secureTextField<span class="token punctuation">:</span> <span class="token class-name">UITextField</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">if</span> <span class="token keyword">let</span> textField <span class="token operator">=</span> <span class="token function">objc_getAssociatedObject</span><span class="token punctuation">(</span><span class="token keyword">self</span><span class="token punctuation">,</span> <span class="token operator">&#x26;</span><span class="token class-name">AssociatedObjectHandle</span><span class="token punctuation">)</span> <span class="token keyword">as</span><span class="token operator">?</span> <span class="token class-name">UITextField</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token comment">// 추가된 TextField가 있다면 해당 객체 반환</span>
</span><span class="code-line">      <span class="token keyword">return</span> textField
</span><span class="code-line">    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token comment">// 추가된 TextField가 없다면 생성해서</span>
</span><span class="code-line">      <span class="token keyword">let</span> textField <span class="token operator">=</span> <span class="token class-name">UITextField</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token comment">// 캡쳐하려는 UIView에 추가하고</span>
</span><span class="code-line">      <span class="token function">addSubview</span><span class="token punctuation">(</span>textField<span class="token punctuation">)</span>
</span><span class="code-line">      textField<span class="token punctuation">.</span>centerYAnchor<span class="token punctuation">.</span><span class="token function">constraint</span><span class="token punctuation">(</span>equalTo<span class="token punctuation">:</span> centerYAnchor<span class="token punctuation">)</span><span class="token punctuation">.</span>isActive <span class="token operator">=</span> <span class="token boolean">true</span>
</span><span class="code-line">      textField<span class="token punctuation">.</span>centerXAnchor<span class="token punctuation">.</span><span class="token function">constraint</span><span class="token punctuation">(</span>equalTo<span class="token punctuation">:</span> centerXAnchor<span class="token punctuation">)</span><span class="token punctuation">.</span>isActive <span class="token operator">=</span> <span class="token boolean">true</span>
</span><span class="code-line">      textField<span class="token punctuation">.</span>layer<span class="token punctuation">.</span><span class="token function">removeFromSuperlayer</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token comment">// 캡쳐하려는 UIView의 Layer를 TextField의 Layer 사이에 끼워 넣고</span>
</span><span class="code-line">      layer<span class="token punctuation">.</span>superlayer<span class="token operator">?</span><span class="token punctuation">.</span><span class="token function">insertSublayer</span><span class="token punctuation">(</span>textField<span class="token punctuation">.</span>layer<span class="token punctuation">,</span> at<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">)</span>
</span><span class="code-line">      textField<span class="token punctuation">.</span>layer<span class="token punctuation">.</span>sublayers<span class="token operator">?</span><span class="token punctuation">.</span>last<span class="token operator">?</span><span class="token punctuation">.</span><span class="token function">addSublayer</span><span class="token punctuation">(</span>layer<span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token comment">// 마지막으로 set 해서 return</span>
</span><span class="code-line">      <span class="token function">objc_setAssociatedObject</span><span class="token punctuation">(</span><span class="token keyword">self</span><span class="token punctuation">,</span> <span class="token operator">&#x26;</span><span class="token class-name">AssociatedObjectHandle</span><span class="token punctuation">,</span> textField<span class="token punctuation">,</span> objc_AssociationPolicy<span class="token punctuation">.</span><span class="token constant">OBJC_ASSOCIATION_RETAIN_NONATOMIC</span><span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token keyword">return</span> textField
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">  <span class="token comment">// 트릭의 활성화를 제어하는 메소드</span>
</span><span class="code-line">  <span class="token keyword">func</span> <span class="token function-definition function">secureMode</span><span class="token punctuation">(</span>enable<span class="token punctuation">:</span> <span class="token class-name">Bool</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    secureTextField<span class="token punctuation">.</span>isSecureTextEntry <span class="token operator">=</span> enable
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="사용-방법">사용 방법</h2>
<blockquote>
<p>조금 더 유연한 화면 캡쳐 대응을 위해 <strong>스크린샷</strong>과 <strong>화면 녹화</strong>를 구분하는 방법도 추가해봤습니다. 해당 코드는 스크린샷은 허용하고 화면 녹화는 방지하도록 작성했습니다.</p>
</blockquote>
<ul>
<li>구현한 Extension을 실제 <code>View</code>와 <code>ViewController</code>에서 사용해보겠습니다.</li>
<li>코드에 대한 설명은 코드내 주석으로 추가했습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">import</span> <span class="token class-name">UIKit</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">ViewController</span><span class="token punctuation">:</span> <span class="token class-name">UIViewController</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token comment">// 예시 콘텐츠</span>
</span><span class="code-line">  <span class="token keyword">private</span> <span class="token keyword">lazy</span> <span class="token keyword">var</span> label <span class="token operator">=</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> label <span class="token operator">=</span> <span class="token class-name">UILabel</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    label<span class="token punctuation">.</span>text <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"캡쳐 보호가 필요한 콘텐츠"</span></span>
</span><span class="code-line">    <span class="token keyword">return</span> label
</span><span class="code-line">  <span class="token punctuation">}</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">  <span class="token keyword">override</span> <span class="token keyword">func</span> <span class="token function-definition function">viewDidLoad</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token function">viewDidLoad</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token comment">// 캡쳐 감지용 노티피케이션 센터 추가</span>
</span><span class="code-line">    <span class="token class-name">NotificationCenter</span><span class="token punctuation">.</span><span class="token keyword">default</span><span class="token punctuation">.</span><span class="token function">addObserver</span><span class="token punctuation">(</span>
</span><span class="code-line">      <span class="token keyword">self</span><span class="token punctuation">,</span>
</span><span class="code-line">      selector<span class="token punctuation">:</span> <span class="token other-directive property">#selector</span><span class="token punctuation">(</span>captureAction<span class="token punctuation">)</span><span class="token punctuation">,</span>
</span><span class="code-line">      name<span class="token punctuation">:</span> <span class="token class-name">UIScreen</span><span class="token punctuation">.</span>capturedDidChangeNotification<span class="token punctuation">,</span>
</span><span class="code-line">      object<span class="token punctuation">:</span> <span class="token nil constant">nil</span>
</span><span class="code-line">    <span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token comment">// 예시 콘텐츠 추가</span>
</span><span class="code-line">    view<span class="token punctuation">.</span><span class="token function">addSubview</span><span class="token punctuation">(</span>label<span class="token punctuation">)</span>
</span><span class="code-line">    label<span class="token punctuation">.</span>translatesAutoresizingMaskIntoConstraints <span class="token operator">=</span> <span class="token boolean">false</span>
</span><span class="code-line">    label<span class="token punctuation">.</span>centerXAnchor<span class="token punctuation">.</span><span class="token function">constraint</span><span class="token punctuation">(</span>equalTo<span class="token punctuation">:</span> view<span class="token punctuation">.</span>centerXAnchor<span class="token punctuation">)</span><span class="token punctuation">.</span>isActive <span class="token operator">=</span> <span class="token boolean">true</span>
</span><span class="code-line">    label<span class="token punctuation">.</span>centerYAnchor<span class="token punctuation">.</span><span class="token function">constraint</span><span class="token punctuation">(</span>equalTo<span class="token punctuation">:</span> view<span class="token punctuation">.</span>centerYAnchor<span class="token punctuation">)</span><span class="token punctuation">.</span>isActive <span class="token operator">=</span> <span class="token boolean">true</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">  <span class="token comment">// 캡쳐시 실행되는 액션 메소드</span>
</span><span class="code-line">  <span class="token attribute atrule">@objc</span> <span class="token keyword">private</span> <span class="token keyword">func</span> <span class="token function-definition function">captureAction</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">if</span> <span class="token class-name">UIScreen</span><span class="token punctuation">.</span>main<span class="token punctuation">.</span>isCaptured <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token comment">// 캡쳐 중이면 = 화면 녹화 중이면</span>
</span><span class="code-line">      view<span class="token punctuation">.</span><span class="token function">secureMode</span><span class="token punctuation">(</span>enable<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token comment">// 캡쳐 중이 아니면 = 화면 녹화가 끝났으면</span>
</span><span class="code-line">      view<span class="token punctuation">.</span><span class="token function">secureMode</span><span class="token punctuation">(</span>enable<span class="token punctuation">:</span> <span class="token boolean">false</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>핵심적인 사용 코드는 결국 아래 부분입니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">if</span> <span class="token class-name">UIScreen</span><span class="token punctuation">.</span>main<span class="token punctuation">.</span>isCaptured <span class="token punctuation">{</span>
</span><span class="code-line">  view<span class="token punctuation">.</span><span class="token function">secureMode</span><span class="token punctuation">(</span>enable<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">  view<span class="token punctuation">.</span><span class="token function">secureMode</span><span class="token punctuation">(</span>enable<span class="token punctuation">:</span> <span class="token boolean">false</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="적용한-결과">적용한 결과</h2>
<ul>
<li>스크린샷</li>
</ul>
<p><img src="/images/ios-limit-capture-1.png" alt="ios-limit-capture"></p>
<ul>
<li>화면 녹화</li>
</ul>
<p><img src="/images/ios-limit-capture-2.png" alt="ios-limit-capture"></p>
<h2 id="주의사항">주의사항</h2>
<ul>
<li>스크린샷과 화면 녹화와 같은 화면 캡쳐는 실기기에서만 정상적으로 테스트가 가능합니다.</li>
</ul>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/custom-alert-builder-pattern</guid>
      <title>빌더 패턴으로 UIKit Custom Alert 만들기</title>
      <description>iOS UIKit에서 빌더 패턴으로 사용하기 편한 Custom Alert을 만들어봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/custom-alert-builder-pattern</link>
      <pubDate>Fri, 14 Apr 2023 20:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<h2 id="왜-빌더-패턴">왜 빌더 패턴</h2>
<ul>
<li>빌더 패턴은 생성 패턴으로 코드의 결합도를 줄이고 재사용성을 높인다는 장점이 있습니다.</li>
<li>빌더 패턴은 사용하는 부분에서 파라미터를 모두 채워주지 않아도 필요한 값으로 생성이 가능합니다.</li>
<li>사용하는 곳에서 파라미터 값을 모두 채워주지 않아도 되어 코드가 간결해집니다.</li>
<li>한마디로 정리하면, Custom Alert을 편하게 사용(호출)하기 위해 빌더 패턴을 사용했습니다.</li>
</ul>
<h2 id="alertbuilder">AlertBuilder</h2>
<ul>
<li>Custom Alert을 구현하기 위해 우선 AlertBuilder 클래스를 만듭니다.</li>
<li>AlertBuilder에는 Custom Alert을 띄울 baseViewController와 포함하고 있는 alertViewController가 필요합니다.</li>
<li>alertTitle, message, addActionConfirm과 같은 Alert의 요소들도 필요합니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">AlertBuilder</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">private</span> <span class="token keyword">let</span> baseViewController<span class="token punctuation">:</span> <span class="token class-name">UIViewController</span>
</span><span class="code-line">  <span class="token keyword">private</span> <span class="token keyword">let</span> alertViewController <span class="token operator">=</span> <span class="token class-name">CustomAlertViewController</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">  <span class="token keyword">private</span> <span class="token keyword">var</span> alertTitle<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token operator">?</span>
</span><span class="code-line">  <span class="token keyword">private</span> <span class="token keyword">var</span> message<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token operator">?</span>
</span><span class="code-line">  <span class="token keyword">private</span> <span class="token keyword">var</span> addActionConfirm<span class="token punctuation">:</span> <span class="token class-name">AddAction</span><span class="token operator">?</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>그 다음에는 AlertBuilder의 init과 함수들을 구현했습니다.</li>
<li>init에는 baseViewController 정도를 넣어줍니다.</li>
<li>setTitle, setMessage, addActionConfirm은 각 프로퍼티에 값을 넣어주는 역할을 합니다.</li>
<li>특이점으로는 return으로 self를 리턴해서 Builder을 사용할때 이어서 호출 할 수 있게합니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">AlertBuilder</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token operator">...</span>
</span><span class="code-line">
</span><span class="code-line">  <span class="token keyword">init</span><span class="token punctuation">(</span>viewController<span class="token punctuation">:</span> <span class="token class-name">UIViewController</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    baseViewController <span class="token operator">=</span> viewController
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">  <span class="token keyword">func</span> <span class="token function-definition function">setTitle</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> text<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">AlertBuilder</span> <span class="token punctuation">{</span>
</span><span class="code-line">    alertTitle <span class="token operator">=</span> text
</span><span class="code-line">    <span class="token keyword">return</span> <span class="token keyword">self</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">  <span class="token keyword">func</span> <span class="token function-definition function">setMessage</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> text<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">AlertBuilder</span> <span class="token punctuation">{</span>
</span><span class="code-line">    message <span class="token operator">=</span> text
</span><span class="code-line">    <span class="token keyword">return</span> <span class="token keyword">self</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">  <span class="token keyword">func</span> <span class="token function-definition function">addActionConfirm</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> text<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">,</span> action<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Void</span><span class="token punctuation">)</span><span class="token operator">?</span> <span class="token operator">=</span> <span class="token nil constant">nil</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">AlertBuilder</span> <span class="token punctuation">{</span>
</span><span class="code-line">    addActionConfirm <span class="token operator">=</span> <span class="token class-name">AddAction</span><span class="token punctuation">(</span>text<span class="token punctuation">:</span> text<span class="token punctuation">,</span> action<span class="token punctuation">:</span> action<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">return</span> <span class="token keyword">self</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>AddAction은 구조체로 text와 action 프로퍼티를 갖고 있습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">AddAction</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">var</span> text<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token operator">?</span>
</span><span class="code-line">  <span class="token keyword">var</span> action<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Void</span><span class="token punctuation">)</span><span class="token operator">?</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>AlertBuilder의 마지막으로는 show 함수를 구현합니다.</li>
<li>Alert 형태를 갖추도록 modalPresentationStyle과 modalTransitionStyle을 지정합니다.</li>
<li>alertViewController에 프로퍼티 값을 전달하고, baseViewController 위에 alertViewController를 띄웁니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">AlertBuilder</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token operator">...</span>
</span><span class="code-line">
</span><span class="code-line">  <span class="token attribute atrule">@discardableResult</span>
</span><span class="code-line">  <span class="token keyword">func</span> <span class="token function-definition function">show</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token keyword">Self</span> <span class="token punctuation">{</span>
</span><span class="code-line">    alertViewController<span class="token punctuation">.</span>modalPresentationStyle <span class="token operator">=</span> <span class="token punctuation">.</span>overFullScreen
</span><span class="code-line">    alertViewController<span class="token punctuation">.</span>modalTransitionStyle <span class="token operator">=</span> <span class="token punctuation">.</span>crossDissolve
</span><span class="code-line">
</span><span class="code-line">    alertViewController<span class="token punctuation">.</span>alertTitle <span class="token operator">=</span> alertTitle
</span><span class="code-line">    alertViewController<span class="token punctuation">.</span>message <span class="token operator">=</span> message
</span><span class="code-line">    alertViewController<span class="token punctuation">.</span>addActionConfirm <span class="token operator">=</span> addActionConfirm
</span><span class="code-line">
</span><span class="code-line">    baseViewController<span class="token punctuation">.</span><span class="token function">present</span><span class="token punctuation">(</span>alertViewController<span class="token punctuation">,</span> animated<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">return</span> <span class="token keyword">self</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="customalertviewcontroller">CustomAlertViewController</h2>
<ul>
<li>CustomAlertViewController를 구현할 차례입니다.</li>
<li>기본적인 프로퍼티 alertTitle, message, addActionConfirm을 선언합니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">CustomAlertViewController</span><span class="token punctuation">:</span> <span class="token class-name">UIViewController</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">var</span> alertTitle<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token operator">?</span>
</span><span class="code-line">  <span class="token keyword">var</span> message<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token operator">?</span>
</span><span class="code-line">  <span class="token keyword">var</span> addActionConfirm<span class="token punctuation">:</span> <span class="token class-name">AddAction</span><span class="token operator">?</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>그리고 UI 요소들을 생성합니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">CustomAlertViewController</span><span class="token punctuation">:</span> <span class="token class-name">UIViewController</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token operator">...</span>
</span><span class="code-line">
</span><span class="code-line">  <span class="token keyword">private</span> <span class="token keyword">lazy</span> <span class="token keyword">var</span> alertView <span class="token operator">=</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> view <span class="token operator">=</span> <span class="token class-name">UIView</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    view<span class="token punctuation">.</span>layer<span class="token punctuation">.</span>cornerRadius <span class="token operator">=</span> <span class="token number">16</span>
</span><span class="code-line">    view<span class="token punctuation">.</span>backgroundColor <span class="token operator">=</span> <span class="token punctuation">.</span>secondarySystemBackground
</span><span class="code-line">    <span class="token keyword">return</span> view
</span><span class="code-line">  <span class="token punctuation">}</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">  <span class="token keyword">private</span> <span class="token keyword">lazy</span> <span class="token keyword">var</span> titleLabel <span class="token operator">=</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> label <span class="token operator">=</span> <span class="token class-name">UILabel</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    label<span class="token punctuation">.</span>font <span class="token operator">=</span> <span class="token class-name">UIFont</span><span class="token punctuation">.</span><span class="token function">systemFont</span><span class="token punctuation">(</span>ofSize<span class="token punctuation">:</span> <span class="token number">16</span><span class="token punctuation">,</span> weight<span class="token punctuation">:</span> <span class="token punctuation">.</span>bold<span class="token punctuation">)</span>
</span><span class="code-line">    label<span class="token punctuation">.</span>textAlignment <span class="token operator">=</span> <span class="token punctuation">.</span>center
</span><span class="code-line">    label<span class="token punctuation">.</span>text <span class="token operator">=</span> alertTitle
</span><span class="code-line">    <span class="token keyword">return</span> label
</span><span class="code-line">  <span class="token punctuation">}</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">  <span class="token keyword">private</span> <span class="token keyword">lazy</span> <span class="token keyword">var</span> messageLabel <span class="token operator">=</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> label <span class="token operator">=</span> <span class="token class-name">UILabel</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    label<span class="token punctuation">.</span>font <span class="token operator">=</span> <span class="token class-name">UIFont</span><span class="token punctuation">.</span><span class="token function">systemFont</span><span class="token punctuation">(</span>ofSize<span class="token punctuation">:</span> <span class="token number">13</span><span class="token punctuation">)</span>
</span><span class="code-line">    label<span class="token punctuation">.</span>textAlignment <span class="token operator">=</span> <span class="token punctuation">.</span>center
</span><span class="code-line">    label<span class="token punctuation">.</span>text <span class="token operator">=</span> message
</span><span class="code-line">    <span class="token keyword">return</span> label
</span><span class="code-line">  <span class="token punctuation">}</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">  <span class="token keyword">private</span> <span class="token keyword">lazy</span> <span class="token keyword">var</span> horizontalDividerView <span class="token operator">=</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> view <span class="token operator">=</span> <span class="token class-name">UIView</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    view<span class="token punctuation">.</span>backgroundColor <span class="token operator">=</span> <span class="token punctuation">.</span>lightGray
</span><span class="code-line">    <span class="token keyword">return</span> view
</span><span class="code-line">  <span class="token punctuation">}</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">  <span class="token keyword">private</span> <span class="token keyword">lazy</span> <span class="token keyword">var</span> confirmButton <span class="token operator">=</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> button <span class="token operator">=</span> <span class="token class-name">UIButton</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    button<span class="token punctuation">.</span><span class="token function">setTitleColor</span><span class="token punctuation">(</span><span class="token punctuation">.</span>label<span class="token punctuation">,</span> <span class="token keyword">for</span><span class="token punctuation">:</span> <span class="token punctuation">.</span>normal<span class="token punctuation">)</span>
</span><span class="code-line">    button<span class="token punctuation">.</span>titleLabel<span class="token operator">?</span><span class="token punctuation">.</span>font <span class="token operator">=</span> <span class="token class-name">UIFont</span><span class="token punctuation">.</span><span class="token function">systemFont</span><span class="token punctuation">(</span>ofSize<span class="token punctuation">:</span> <span class="token number">14</span><span class="token punctuation">,</span> weight<span class="token punctuation">:</span> <span class="token punctuation">.</span>bold<span class="token punctuation">)</span>
</span><span class="code-line">    button<span class="token punctuation">.</span><span class="token function">setTitle</span><span class="token punctuation">(</span>addActionConfirm<span class="token operator">?</span><span class="token punctuation">.</span>text<span class="token punctuation">,</span> <span class="token keyword">for</span><span class="token punctuation">:</span> <span class="token punctuation">.</span>normal<span class="token punctuation">)</span>
</span><span class="code-line">    button<span class="token punctuation">.</span><span class="token function">addTarget</span><span class="token punctuation">(</span><span class="token keyword">self</span><span class="token punctuation">,</span> action<span class="token punctuation">:</span> <span class="token other-directive property">#selector</span><span class="token punctuation">(</span>pressed<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token keyword">for</span><span class="token punctuation">:</span> <span class="token punctuation">.</span>touchUpInside<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">return</span> button
</span><span class="code-line">  <span class="token punctuation">}</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">  <span class="token attribute atrule">@objc</span> <span class="token keyword">func</span> <span class="token function-definition function">pressed</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    addActionConfirm<span class="token operator">?</span><span class="token punctuation">.</span>action<span class="token operator">?</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token function">dismiss</span><span class="token punctuation">(</span>animated<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>마지막으로, UI 요소들의 위치를 적절히 잡습니다.</li>
<li>레이아웃을 잡기 위해서는 많이 사용하는 SnapKit 라이브러리를 사용했습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">CustomAlertViewController</span><span class="token punctuation">:</span> <span class="token class-name">UIViewController</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token operator">...</span>
</span><span class="code-line">
</span><span class="code-line">  <span class="token keyword">override</span> <span class="token keyword">func</span> <span class="token function-definition function">viewDidLoad</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token function">viewDidLoad</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token function">setViews</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">  <span class="token keyword">private</span> <span class="token keyword">func</span> <span class="token function-definition function">setViews</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    view<span class="token punctuation">.</span>backgroundColor <span class="token operator">=</span> <span class="token punctuation">.</span>systemBackground<span class="token punctuation">.</span><span class="token function">withAlphaComponent</span><span class="token punctuation">(</span><span class="token number">0.5</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">    view<span class="token punctuation">.</span><span class="token function">addSubview</span><span class="token punctuation">(</span>alertView<span class="token punctuation">)</span>
</span><span class="code-line">    alertView<span class="token punctuation">.</span>snp<span class="token punctuation">.</span>makeConstraints <span class="token punctuation">{</span> make <span class="token keyword">in</span>
</span><span class="code-line">      make<span class="token punctuation">.</span>width<span class="token punctuation">.</span><span class="token function">equalTo</span><span class="token punctuation">(</span><span class="token number">300</span><span class="token punctuation">)</span>
</span><span class="code-line">      make<span class="token punctuation">.</span>center<span class="token punctuation">.</span><span class="token function">equalToSuperview</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">    alertView<span class="token punctuation">.</span><span class="token function">addSubview</span><span class="token punctuation">(</span>titleLabel<span class="token punctuation">)</span>
</span><span class="code-line">    titleLabel<span class="token punctuation">.</span>snp<span class="token punctuation">.</span>makeConstraints <span class="token punctuation">{</span> make <span class="token keyword">in</span>
</span><span class="code-line">      make<span class="token punctuation">.</span>width<span class="token punctuation">.</span><span class="token function">equalTo</span><span class="token punctuation">(</span><span class="token number">260</span><span class="token punctuation">)</span>
</span><span class="code-line">      make<span class="token punctuation">.</span>centerX<span class="token punctuation">.</span><span class="token function">equalToSuperview</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">      make<span class="token punctuation">.</span>top<span class="token punctuation">.</span><span class="token function">equalToSuperview</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">offset</span><span class="token punctuation">(</span><span class="token number">30</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">    alertView<span class="token punctuation">.</span><span class="token function">addSubview</span><span class="token punctuation">(</span>messageLabel<span class="token punctuation">)</span>
</span><span class="code-line">    messageLabel<span class="token punctuation">.</span>snp<span class="token punctuation">.</span>makeConstraints <span class="token punctuation">{</span> make <span class="token keyword">in</span>
</span><span class="code-line">      make<span class="token punctuation">.</span>width<span class="token punctuation">.</span><span class="token function">equalTo</span><span class="token punctuation">(</span><span class="token number">260</span><span class="token punctuation">)</span>
</span><span class="code-line">      make<span class="token punctuation">.</span>centerX<span class="token punctuation">.</span><span class="token function">equalToSuperview</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">      make<span class="token punctuation">.</span>top<span class="token punctuation">.</span><span class="token function">equalTo</span><span class="token punctuation">(</span>titleLabel<span class="token punctuation">.</span>snp<span class="token punctuation">.</span>bottom<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">offset</span><span class="token punctuation">(</span><span class="token number">20</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">    alertView<span class="token punctuation">.</span><span class="token function">addSubview</span><span class="token punctuation">(</span>horizontalDividerView<span class="token punctuation">)</span>
</span><span class="code-line">    horizontalDividerView<span class="token punctuation">.</span>snp<span class="token punctuation">.</span>makeConstraints <span class="token punctuation">{</span> make <span class="token keyword">in</span>
</span><span class="code-line">      make<span class="token punctuation">.</span>width<span class="token punctuation">.</span>centerX<span class="token punctuation">.</span><span class="token function">equalToSuperview</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">      make<span class="token punctuation">.</span>height<span class="token punctuation">.</span><span class="token function">equalTo</span><span class="token punctuation">(</span><span class="token number">0.5</span><span class="token punctuation">)</span>
</span><span class="code-line">      make<span class="token punctuation">.</span>top<span class="token punctuation">.</span><span class="token function">equalTo</span><span class="token punctuation">(</span>messageLabel<span class="token punctuation">.</span>snp<span class="token punctuation">.</span>bottom<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">offset</span><span class="token punctuation">(</span><span class="token number">30</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">    alertView<span class="token punctuation">.</span><span class="token function">addSubview</span><span class="token punctuation">(</span>confirmButton<span class="token punctuation">)</span>
</span><span class="code-line">    confirmButton<span class="token punctuation">.</span>snp<span class="token punctuation">.</span>makeConstraints <span class="token punctuation">{</span> make <span class="token keyword">in</span>
</span><span class="code-line">      make<span class="token punctuation">.</span>width<span class="token punctuation">.</span><span class="token function">equalTo</span><span class="token punctuation">(</span><span class="token number">300</span><span class="token punctuation">)</span>
</span><span class="code-line">      make<span class="token punctuation">.</span>centerX<span class="token punctuation">.</span><span class="token function">equalToSuperview</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">      make<span class="token punctuation">.</span>height<span class="token punctuation">.</span><span class="token function">equalTo</span><span class="token punctuation">(</span><span class="token number">50</span><span class="token punctuation">)</span>
</span><span class="code-line">      make<span class="token punctuation">.</span>top<span class="token punctuation">.</span><span class="token function">equalTo</span><span class="token punctuation">(</span>horizontalDividerView<span class="token punctuation">.</span>snp<span class="token punctuation">.</span>bottom<span class="token punctuation">)</span>
</span><span class="code-line">      make<span class="token punctuation">.</span>bottom<span class="token punctuation">.</span><span class="token function">equalToSuperview</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="custom-alert-사용">Custom Alert 사용</h2>
<ul>
<li>Custom Alert은 원하는 ViewController에서 다음과 같이 호출 할 수 있습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">AlertBuilder</span><span class="token punctuation">(</span>viewController<span class="token punctuation">:</span> <span class="token keyword">self</span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">.</span><span class="token function">setTitle</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"알럿창"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">.</span><span class="token function">setMessage</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"알럿창의 메시지입니다"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">.</span><span class="token function">addActionConfirm</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"확인"</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"확인을 눌렀습니다."</span></span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">.</span><span class="token function">show</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span></code></pre>
<h2 id="결과물">결과물</h2>
<ul>
<li>이대로 실행해보면 다음과 같은 Custom Alert 창을 볼 수 있습니다.</li>
</ul>
<p><img src="/images/custom-alert-builder-pattern-1.png" alt="custom-alert-builder-pattern"></p>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/rich-push-notification</guid>
      <title>iOS Rich Push Notification</title>
      <description>iOS에서 이미지가 포함된 Rich Push Notification을 세팅, 구현, 그리고 테스트 해봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/rich-push-notification</link>
      <pubDate>Fri, 17 Mar 2023 18:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<h2 id="push-세팅">Push 세팅</h2>
<ul>
<li>Xcode에 Apple 계정 로그인을 합니다.</li>
</ul>
<p><img src="/images/rich-push-notification-1.png" alt="rich-push-notification"></p>
<ul>
<li>그리고 <code>Signing</code>과 <code>App Group</code> 설정하고, Capabilities에서 <code>Push Notifications</code>를 추가합니다.</li>
</ul>
<p><img src="/images/rich-push-notification-2.png" alt="rich-push-notification"></p>
<ul>
<li><a href="https://developer.apple.com/account/resources/authkeys/list">Apple Developer 사이트</a>에서 새로운 Key를 생성하고 APNs를 활성화합니다.</li>
</ul>
<p><img src="/images/rich-push-notification-3.png" alt="rich-push-notification"></p>
<ul>
<li>Key가 생성되면 반드시 잘 보관하고, <code>Key ID</code>도 기록해둡니다.</li>
</ul>
<p><img src="/images/rich-push-notification-4.png" alt="rich-push-notification"></p>
<h2 id="코드-구현">코드 구현</h2>
<ul>
<li>다음과 같이 Notification을 받기 위한 권한을 받습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">import</span> <span class="token class-name">UIKit</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token attribute atrule">@main</span>
</span><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">AppDelegate</span><span class="token punctuation">:</span> <span class="token class-name">UIResponder</span><span class="token punctuation">,</span> <span class="token class-name">UIApplicationDelegate</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">func</span> <span class="token function-definition function">application</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> application<span class="token punctuation">:</span> <span class="token class-name">UIApplication</span><span class="token punctuation">,</span> didFinishLaunchingWithOptions launchOptions<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">UIApplication</span><span class="token punctuation">.</span><span class="token class-name">LaunchOptionsKey</span><span class="token punctuation">:</span> <span class="token keyword">Any</span><span class="token punctuation">]</span><span class="token operator">?</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Bool</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">UNUserNotificationCenter</span><span class="token punctuation">.</span><span class="token function">current</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">requestAuthorization</span><span class="token punctuation">(</span>options<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token punctuation">.</span>alert<span class="token punctuation">,</span> <span class="token punctuation">.</span>sound<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> granted<span class="token punctuation">,</span> <span class="token omit keyword">_</span> <span class="token keyword">in</span>
</span><span class="code-line">      <span class="token keyword">if</span> granted <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">DispatchQueue</span><span class="token punctuation">.</span>main<span class="token punctuation">.</span><span class="token keyword">async</span> <span class="token punctuation">{</span>
</span><span class="code-line">          <span class="token class-name">UIApplication</span><span class="token punctuation">.</span>shared<span class="token punctuation">.</span><span class="token function">registerForRemoteNotifications</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">      <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token keyword">return</span> <span class="token boolean">true</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>권한을 받았으면, delegate 함수를 통해 push에 필요한 token 값을 처리합니다.</li>
<li>테스트를 위해 임의로 콘솔에 print 합니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">application</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> application<span class="token punctuation">:</span> <span class="token class-name">UIApplication</span><span class="token punctuation">,</span> didRegisterForRemoteNotificationsWithDeviceToken deviceToken<span class="token punctuation">:</span> <span class="token class-name">Data</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> deviceToken<span class="token punctuation">:</span> <span class="token class-name">String</span> <span class="token operator">=</span> deviceToken<span class="token punctuation">.</span>map <span class="token punctuation">{</span> <span class="token class-name">String</span><span class="token punctuation">(</span>format<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"%02.2hhx"</span></span><span class="token punctuation">,</span> <span class="token short-argument">$0</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">.</span><span class="token function">joined</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Device token is: </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">deviceToken</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>Push Notification 수신 처리에 대한 구현을 합니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">AppDelegate</span><span class="token punctuation">:</span> <span class="token class-name">UNUserNotificationCenterDelegate</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token comment">// 앱이 포그라운드 상태일 때 푸시 수신</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">userNotificationCenter</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> center<span class="token punctuation">:</span> <span class="token class-name">UNUserNotificationCenter</span><span class="token punctuation">,</span> willPresent notification<span class="token punctuation">:</span> <span class="token class-name">UNNotification</span><span class="token punctuation">,</span> withCompletionHandler completionHandler<span class="token punctuation">:</span> <span class="token attribute atrule">@escaping</span> <span class="token punctuation">(</span><span class="token class-name">UNNotificationPresentationOptions</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Void</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">let</span> userInfo <span class="token operator">=</span> notification<span class="token punctuation">.</span>request<span class="token punctuation">.</span>content<span class="token punctuation">.</span>userInfo
</span><span class="code-line">        
</span><span class="code-line">        <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"수신된 푸시 데이터: </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">userInfo</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token comment">// 포그라운드에서 알림 표시 옵션 설정</span>
</span><span class="code-line">        <span class="token function">completionHandler</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">.</span>banner<span class="token punctuation">,</span> <span class="token punctuation">.</span>badge<span class="token punctuation">,</span> <span class="token punctuation">.</span>sound<span class="token punctuation">]</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token comment">// 사용자가 알림을 탭했을 때 처리</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">userNotificationCenter</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> center<span class="token punctuation">:</span> <span class="token class-name">UNUserNotificationCenter</span><span class="token punctuation">,</span> didReceive response<span class="token punctuation">:</span> <span class="token class-name">UNNotificationResponse</span><span class="token punctuation">,</span> withCompletionHandler completionHandler<span class="token punctuation">:</span> <span class="token attribute atrule">@escaping</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Void</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">let</span> userInfo <span class="token operator">=</span> response<span class="token punctuation">.</span>notification<span class="token punctuation">.</span>request<span class="token punctuation">.</span>content<span class="token punctuation">.</span>userInfo
</span><span class="code-line">        
</span><span class="code-line">        <span class="token comment">// 알림 탭 처리 로직 구현</span>
</span><span class="code-line">        <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"사용자가 탭한 알림 데이터: </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">userInfo</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token function">completionHandler</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>Rich Push Notification을 위한 구현을 시작합니다.</li>
<li>File → New → Target을 통해 Notification Service Extension을 추가합니다.</li>
</ul>
<p><img src="/images/rich-push-notification-5.png" alt="rich-push-notification"></p>
<ul>
<li>이 Target을 통해 Push Notification에 이미지를 띄우는 작업을 하면됩니다.</li>
<li>아래와 같이 NotificationService을 구현하면 이제 아이폰에서도 이미지 Push Notification을 띄울수 있게됩니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">import</span> <span class="token class-name">UserNotifications</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">NotificationService</span><span class="token punctuation">:</span> <span class="token class-name">UNNotificationServiceExtension</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">var</span> contentHandler<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token class-name">UNNotificationContent</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Void</span><span class="token punctuation">)</span><span class="token operator">?</span>
</span><span class="code-line">  <span class="token keyword">var</span> bestAttemptContent<span class="token punctuation">:</span> <span class="token class-name">UNMutableNotificationContent</span><span class="token operator">?</span>
</span><span class="code-line">
</span><span class="code-line">  <span class="token keyword">override</span> <span class="token keyword">func</span> <span class="token function-definition function">didReceive</span><span class="token punctuation">(</span>
</span><span class="code-line">    <span class="token omit keyword">_</span> request<span class="token punctuation">:</span> <span class="token class-name">UNNotificationRequest</span><span class="token punctuation">,</span>
</span><span class="code-line">    withContentHandler contentHandler<span class="token punctuation">:</span> <span class="token attribute atrule">@escaping</span> <span class="token punctuation">(</span><span class="token class-name">UNNotificationContent</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Void</span>
</span><span class="code-line">  <span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">self</span><span class="token punctuation">.</span>contentHandler <span class="token operator">=</span> contentHandler
</span><span class="code-line">    bestAttemptContent <span class="token operator">=</span> <span class="token punctuation">(</span>request<span class="token punctuation">.</span>content<span class="token punctuation">.</span><span class="token function">mutableCopy</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">as</span><span class="token operator">?</span> <span class="token class-name">UNMutableNotificationContent</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">defer</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token function">contentHandler</span><span class="token punctuation">(</span>bestAttemptContent <span class="token operator">??</span> request<span class="token punctuation">.</span>content<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">guard</span> <span class="token keyword">let</span> attachment <span class="token operator">=</span> request<span class="token punctuation">.</span>attachment <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">    bestAttemptContent<span class="token operator">?</span><span class="token punctuation">.</span>attachments <span class="token operator">=</span> <span class="token punctuation">[</span>attachment<span class="token punctuation">]</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">  <span class="token keyword">override</span> <span class="token keyword">func</span> <span class="token function-definition function">serviceExtensionTimeWillExpire</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">if</span> <span class="token keyword">let</span> contentHandler <span class="token operator">=</span> contentHandler<span class="token punctuation">,</span>
</span><span class="code-line">       <span class="token keyword">let</span> bestAttemptContent <span class="token operator">=</span>  bestAttemptContent <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token function">contentHandler</span><span class="token punctuation">(</span>bestAttemptContent<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">UNNotificationRequest</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">var</span> attachment<span class="token punctuation">:</span> <span class="token class-name">UNNotificationAttachment</span><span class="token operator">?</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">guard</span> <span class="token keyword">let</span> attachmentURL <span class="token operator">=</span> content<span class="token punctuation">.</span>userInfo<span class="token punctuation">[</span><span class="token string-literal"><span class="token string">"image"</span></span><span class="token punctuation">]</span> <span class="token keyword">as</span><span class="token operator">?</span> <span class="token class-name">String</span><span class="token punctuation">,</span>
</span><span class="code-line">          <span class="token keyword">let</span> imageData <span class="token operator">=</span> <span class="token keyword">try</span><span class="token operator">?</span> <span class="token class-name">Data</span><span class="token punctuation">(</span>contentsOf<span class="token punctuation">:</span> <span class="token function">URL</span><span class="token punctuation">(</span>string<span class="token punctuation">:</span> attachmentURL<span class="token punctuation">)</span><span class="token operator">!</span><span class="token punctuation">)</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token keyword">return</span> <span class="token nil constant">nil</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token keyword">return</span> <span class="token keyword">try</span><span class="token operator">?</span> <span class="token class-name">UNNotificationAttachment</span><span class="token punctuation">(</span>data<span class="token punctuation">:</span> imageData<span class="token punctuation">,</span> options<span class="token punctuation">:</span> <span class="token nil constant">nil</span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">UNNotificationAttachment</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">convenience</span> <span class="token keyword">init</span><span class="token punctuation">(</span>data<span class="token punctuation">:</span> <span class="token class-name">Data</span><span class="token punctuation">,</span> options<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">NSObject</span><span class="token punctuation">:</span> <span class="token class-name">AnyObject</span><span class="token punctuation">]</span><span class="token operator">?</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> fileManager <span class="token operator">=</span> <span class="token class-name">FileManager</span><span class="token punctuation">.</span><span class="token keyword">default</span>
</span><span class="code-line">    <span class="token keyword">let</span> temporaryFolderName <span class="token operator">=</span> <span class="token class-name">ProcessInfo</span><span class="token punctuation">.</span>processInfo<span class="token punctuation">.</span>globallyUniqueString
</span><span class="code-line">    <span class="token keyword">let</span> temporaryFolderURL <span class="token operator">=</span> <span class="token function">URL</span><span class="token punctuation">(</span>fileURLWithPath<span class="token punctuation">:</span> <span class="token class-name">NSTemporaryDirectory</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">appendingPathComponent</span><span class="token punctuation">(</span>temporaryFolderName<span class="token punctuation">,</span> isDirectory<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">try</span> fileManager<span class="token punctuation">.</span><span class="token function">createDirectory</span><span class="token punctuation">(</span>at<span class="token punctuation">:</span> temporaryFolderURL<span class="token punctuation">,</span> withIntermediateDirectories<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> attributes<span class="token punctuation">:</span> <span class="token nil constant">nil</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">let</span> imageFileIdentifier <span class="token operator">=</span> <span class="token function">UUID</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>uuidString <span class="token operator">+</span> <span class="token string-literal"><span class="token string">".png"</span></span>
</span><span class="code-line">    <span class="token keyword">let</span> fileURL <span class="token operator">=</span> temporaryFolderURL<span class="token punctuation">.</span><span class="token function">appendingPathComponent</span><span class="token punctuation">(</span>imageFileIdentifier<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">try</span> data<span class="token punctuation">.</span><span class="token function">write</span><span class="token punctuation">(</span>to<span class="token punctuation">:</span> fileURL<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">try</span> <span class="token keyword">self</span><span class="token punctuation">.</span><span class="token keyword">init</span><span class="token punctuation">(</span>identifier<span class="token punctuation">:</span> imageFileIdentifier<span class="token punctuation">,</span> url<span class="token punctuation">:</span> fileURL<span class="token punctuation">,</span> options<span class="token punctuation">:</span> options<span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="push-테스트">Push 테스트</h2>
<ul>
<li>Notification Service Extension은 실기기에서만 작동합니다.</li>
<li>그래서 앱을 실기기에서 빌드하고 <a href="https://github.com/onmyway133/PushNotifications/releases">Push Notification Test</a>를 다운로드 받아 실행합니다.</li>
</ul>
<p><img src="/images/rich-push-notification-6.png" alt="rich-push-notification"></p>
<p>다음 정보들을 입력해 테스트 Push를 Send 하면 실기기에 Push 노티가 뜹니다.</p>
<ul>
<li>Authentication: Token</li>
<li>P8 파일: Apple Developer 사이트에서 다운 받은 P8 파일 선택</li>
<li>Key ID: Apple Developer 사이트에서 받은 Key ID</li>
<li>Team ID: Apple Developer 사이트 우측 상단의 팀 ID</li>
<li>Bundle ID: com.hohyeonmoon.Pushy</li>
<li>Device Token: Xcode 콘솔에 프린트 된 토큰</li>
<li>Environment: Sandbox</li>
<li>Message:</li>
</ul>
<pre class="language-json"><code class="language-json code-highlight"><span class="code-line"><span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token property">"Simulator Target Bundle"</span><span class="token operator">:</span> <span class="token string">"com.hohyeonmoon.Pushy"</span><span class="token punctuation">,</span>
</span><span class="code-line">  <span class="token property">"aps"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token property">"alert"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token property">"title"</span><span class="token operator">:</span> <span class="token string">"Hi"</span><span class="token punctuation">,</span>
</span><span class="code-line">      <span class="token property">"subtitle"</span><span class="token operator">:</span> <span class="token string">"It's me"</span><span class="token punctuation">,</span>
</span><span class="code-line">      <span class="token property">"body"</span><span class="token operator">:</span> <span class="token string">"Hi. It's me, Hohyeon Moon."</span>
</span><span class="code-line">    <span class="token punctuation">}</span><span class="token punctuation">,</span>
</span><span class="code-line">    <span class="token property">"mutable-content"</span><span class="token operator">:</span> <span class="token number">1</span>
</span><span class="code-line">  <span class="token punctuation">}</span><span class="token punctuation">,</span>
</span><span class="code-line">  <span class="token property">"image"</span><span class="token operator">:</span> <span class="token string">"https://www.hohyeonmoon.com/images/icon-logo-light.png"</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><img src="/images/rich-push-notification-7.png" alt="rich-push-notification"></p>
<ul>
<li>앱을 빌드한 실기기에 위와 같이 이미지가 포함된 Push Notification이 나타납니다.</li>
</ul>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swift-lint-swift-format</guid>
      <title>SwiftLint와 SwiftFormat 적용</title>
      <description>SwiftLint와 SwiftFormat를 설정해 Swift 코드 스타일링을 편하게 해봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/swift-lint-swift-format</link>
      <pubDate>Thu, 12 Jan 2023 18:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<h2 id="swiftlint와-swiftformat이란">SwiftLint와 SwiftFormat이란?</h2>
<ul>
<li><a href="https://github.com/realm/SwiftLint">SwiftLint</a>와 <a href="https://github.com/nicklockwood/SwiftFormat">SwiftFormat</a>은 둘 다 Swift 코드 스타일을 좋게 유지하기 위해 도와주는 툴입니다.</li>
<li>다만, SwiftLint는 linting에 SwiftFormat은 formatting에 조금 더 초점을 맞췄습니다.</li>
<li>Linting은 코드 스타일의 정해진 규칙을 어길시 warning 혹은 error를 띄워줍니다.</li>
<li>Formatting은 warning과 error 대신 코드를 수정합니다.</li>
</ul>
<h2 id="homebrew로-설치">Homebrew로 설치</h2>
<ul>
<li>SwiftLint와 SwiftFormat 둘 다, 사용하기 위해서는 맥에 설치를 해야합니다.</li>
<li>둘 다 Homebrew를 지원하므로 다음 명령어를 터미널에서 실행해 설치합니다.</li>
</ul>
<pre class="language-bash"><code class="language-bash code-highlight"><span class="code-line">brew <span class="token function">install</span> swiftlint
</span><span class="code-line">brew <span class="token function">install</span> swiftformat
</span></code></pre>
<ul>
<li>다음 명령어를 통해 잘 설치 되었는지 확인하고 넘어갑니다.</li>
</ul>
<pre class="language-bash"><code class="language-bash code-highlight"><span class="code-line">brew list
</span></code></pre>
<h2 id="swiftlint-설정">SwiftLint 설정</h2>
<ul>
<li>이제 Xcode에서 설정을 진행해야 합니다.</li>
<li>Target 프로젝트의 Build Phase로 이동하여 New Run Script Phase를 눌러 추가합니다.</li>
</ul>
<p><img src="/images/swift-lint-swift-format-1.png" alt="swift-lint-swift-format"></p>
<ul>
<li>추가된 Script 이름을 <code>SwiftLint</code>로 변경해주고 다른 설정은 그대로 나두고 script를 작성해줍니다.</li>
</ul>
<p><img src="/images/swift-lint-swift-format-2.png" alt="swift-lint-swift-format"></p>
<ul>
<li>다음과 같이 작성해주면 되는데, 해당 <code>PATH</code>는 Apple Silicon 맥 기준입니다.</li>
</ul>
<pre class="language-bash"><code class="language-bash code-highlight"><span class="code-line"><span class="token comment"># Type a script or drag a script file from your workspace to insert its path.</span>
</span><span class="code-line"><span class="token builtin class-name">export</span> <span class="token assign-left variable"><span class="token environment constant">PATH</span></span><span class="token operator">=</span><span class="token string">"<span class="token environment constant">$PATH</span>:/opt/homebrew/bin"</span>
</span><span class="code-line"><span class="token keyword">if</span> <span class="token function">which</span> swiftlint <span class="token operator">></span> /dev/null<span class="token punctuation">;</span> <span class="token keyword">then</span>
</span><span class="code-line">  swiftlint
</span><span class="code-line"><span class="token keyword">else</span>
</span><span class="code-line">  <span class="token builtin class-name">echo</span> <span class="token string">"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint"</span>
</span><span class="code-line"><span class="token keyword">fi</span>
</span></code></pre>
<ul>
<li>프로젝트의 디렉토리에 <code>.swiftlint.yml</code> 파일을 생성해서 여기에 커스텀 룰을 설정합니다.</li>
<li>룰에 대한 자세한 설명은 <a href="https://github.com/realm/SwiftLint/blob/main/Rules.md">SwiftLint 레포의 Rules</a>에 있습니다.</li>
</ul>
<p><img src="/images/swift-lint-swift-format-3.png" alt="swift-lint-swift-format"></p>
<h2 id="swiftformat-설정">SwiftFormat 설정</h2>
<ul>
<li>SwiftLint를 설정했듯이 New Run Script Phase를 추가해 script를 작성합니다.</li>
</ul>
<p><img src="/images/swift-lint-swift-format-4.png" alt="swift-lint-swift-format"></p>
<ul>
<li>다음과 같이 script를 작성하면 되고, 이 역시 Apple Silicon 맥 기준입니다.</li>
</ul>
<pre class="language-bash"><code class="language-bash code-highlight"><span class="code-line"><span class="token comment"># Type a script or drag a script file from your workspace to insert its path.</span>
</span><span class="code-line"><span class="token builtin class-name">export</span> <span class="token assign-left variable"><span class="token environment constant">PATH</span></span><span class="token operator">=</span><span class="token string">"<span class="token environment constant">$PATH</span>:/opt/homebrew/bin"</span>
</span><span class="code-line"><span class="token keyword">if</span> <span class="token function">which</span> swiftformat <span class="token operator">></span> /dev/null<span class="token punctuation">;</span> <span class="token keyword">then</span>
</span><span class="code-line">  swiftformat <span class="token builtin class-name">.</span>
</span><span class="code-line"><span class="token keyword">else</span>
</span><span class="code-line">  <span class="token builtin class-name">echo</span> <span class="token string">"warning: SwiftFormat not installed, download from https://github.com/nicklockwood/SwiftFormat"</span>
</span><span class="code-line"><span class="token keyword">fi</span>
</span></code></pre>
<ul>
<li>프로젝트의 디렉토리에 <code>.swiftformat</code> 파일을 생성해서 여기에 커스텀 룰을 설정합니다.</li>
<li>룰에 대한 자세한 설명은 <a href="https://github.com/nicklockwood/SwiftFormat/blob/master/Rules.md">SwiftFormat 레포의 Rules</a>에 있습니다.</li>
</ul>
<p><img src="/images/swift-lint-swift-format-3.png" alt="swift-lint-swift-format"></p>
<h2 id="build-하기">Build 하기</h2>
<ul>
<li>Build Phase를 최종적으로 다음과 같이 정렬합니다.</li>
</ul>
<p><img src="/images/swift-lint-swift-format-5.png" alt="swift-lint-swift-format"></p>
<ul>
<li>그리고 빌드해보면 formatting과 linting이 컴파일 전에 진행됩니다.</li>
</ul>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/launch-screen-animation</guid>
      <title>iOS Launch Screen에 Animation 적용하기</title>
      <description>iOS UIKit의 Launch Screen 혹은 Splash Screen을 Lottie Animation으로 구현해봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/launch-screen-animation</link>
      <pubDate>Wed, 04 Jan 2023 00:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<h2 id="lottie-패키지-추가">Lottie 패키지 추가</h2>
<p><img src="/images/launch-screen-animation-1.png" alt="launch-screen-animation"></p>
<ul>
<li>Swift Package Manager 혹은 CocoaPods을 통해 <a href="https://github.com/airbnb/lottie-ios">Lottie iOS 패키지</a>를 프로젝트에 추가합니다.</li>
</ul>
<h2 id="lottie-애니메이션-파일-추가">Lottie 애니메이션 파일 추가</h2>
<p><img src="/images/launch-screen-animation-2.png" alt="launch-screen-animation"></p>
<ul>
<li>원하는 애니메이션 파일을 JSON 포맷으로 구해서 프로젝트에 추가합니다.</li>
<li>Lottie에서 직접 운영하는 <a href="https://lottiefiles.com">LottieFiles</a>에서 파일을 쉽게 구할 수 있습니다.</li>
</ul>
<h2 id="launch-screen-구현하기">Launch Screen 구현하기</h2>
<p><img src="/images/launch-screen-animation-3.png" alt="launch-screen-animation"></p>
<ul>
<li><code>LaunchScreen.storyboard</code>의 화면을 애니메이션 파일의 첫 화면과 일치하게 만듭니다.</li>
<li>메인 <code>ViewController</code>에 Lottie를 import 합니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">import</span> <span class="token class-name">Lottie</span>
</span></code></pre>
<ul>
<li><code>animationView</code>를 다음과 같이 생성합니다.</li>
<li>애니메이션 파일을 <code>LottieAnimationView</code>로 불러오는 작업입니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">private</span> <span class="token keyword">let</span> animationView<span class="token punctuation">:</span> <span class="token class-name">LottieAnimationView</span> <span class="token operator">=</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">let</span> lottieAnimationView <span class="token operator">=</span> <span class="token class-name">LottieAnimationView</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"2023"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">  lottieAnimationView<span class="token punctuation">.</span>backgroundColor <span class="token operator">=</span> <span class="token class-name">UIColor</span><span class="token punctuation">(</span>red<span class="token punctuation">:</span> <span class="token number">52</span><span class="token operator">/</span><span class="token number">255</span><span class="token punctuation">,</span> green<span class="token punctuation">:</span> <span class="token number">144</span><span class="token operator">/</span><span class="token number">255</span><span class="token punctuation">,</span> blue<span class="token punctuation">:</span> <span class="token number">220</span><span class="token operator">/</span><span class="token number">255</span><span class="token punctuation">,</span> alpha<span class="token punctuation">:</span> <span class="token number">1.0</span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token keyword">return</span> lottieAnimationView
</span><span class="code-line"><span class="token punctuation">}</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>마지막으로 <code>viewDidLoad</code>에 다음과 같이 구현합니다.</li>
<li>1번은 실제 LauchScreen 종료 후 가상 LaunchScreen인 <code>animationView</code>를 띄워주는 작업입니다.</li>
<li>2번은 <code>animationView</code>의 크기와 위치를 지정해주는 작업입니다.</li>
<li>3번은 <code>animationView</code>의 애니메이션을 실행하고 완료 되었을때 <code>animationView</code>를 지우는 작업입니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">override</span> <span class="token keyword">func</span> <span class="token function-definition function">viewDidLoad</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token function">viewDidLoad</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">  <span class="token comment">// 1</span>
</span><span class="code-line">  view<span class="token punctuation">.</span><span class="token function">addSubview</span><span class="token punctuation">(</span>animationView<span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">  <span class="token comment">// 2</span>
</span><span class="code-line">  animationView<span class="token punctuation">.</span>frame <span class="token operator">=</span> view<span class="token punctuation">.</span>bounds
</span><span class="code-line">  animationView<span class="token punctuation">.</span>center <span class="token operator">=</span> view<span class="token punctuation">.</span>center
</span><span class="code-line">  animationView<span class="token punctuation">.</span>alpha <span class="token operator">=</span> <span class="token number">1</span>
</span><span class="code-line">
</span><span class="code-line">  <span class="token comment">// 3</span>
</span><span class="code-line">  animationView<span class="token punctuation">.</span>play <span class="token punctuation">{</span> <span class="token omit keyword">_</span> <span class="token keyword">in</span>
</span><span class="code-line">    <span class="token class-name">UIView</span><span class="token punctuation">.</span><span class="token function">animate</span><span class="token punctuation">(</span>withDuration<span class="token punctuation">:</span> <span class="token number">0.3</span><span class="token punctuation">,</span> animations<span class="token punctuation">:</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token keyword">self</span><span class="token punctuation">.</span>animationView<span class="token punctuation">.</span>alpha <span class="token operator">=</span> <span class="token number">0</span>
</span><span class="code-line">    <span class="token punctuation">}</span><span class="token punctuation">,</span> completion<span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token omit keyword">_</span> <span class="token keyword">in</span>
</span><span class="code-line">      <span class="token keyword">self</span><span class="token punctuation">.</span>animationView<span class="token punctuation">.</span>isHidden <span class="token operator">=</span> <span class="token boolean">true</span>
</span><span class="code-line">      <span class="token keyword">self</span><span class="token punctuation">.</span>animationView<span class="token punctuation">.</span><span class="token function">removeFromSuperview</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="결과물">결과물</h2>
<p><img src="/images/launch-screen-animation-4.gif" alt="launch-screen-animation"></p>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swiftui-sheet-inside-foreach</guid>
      <title>SwiftUI ForEach 내부의 Sheet에 대하여</title>
      <description>SwiftUI에서 ForEach와 List 같은 Loop 내부에서 Sheet를 사용하는 것에 대해 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/swiftui-sheet-inside-foreach</link>
      <pubDate>Wed, 28 Dec 2022 16:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<h2 id="sheet와-foreach">Sheet와 ForEach</h2>
<p>Sheet는 뷰를 Modal하게 띄우기 위한 modifier이고, ForEach는 뷰를 반복적으로 렌더링하기 위한 SwiftUI의 View입니다. 그래서 기본적으로 다음과 같이 다른 뷰를 Modal하게 띄워주는 List 형태의 화면을 구성할수 있습니다.</p>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">import</span> <span class="token class-name">SwiftUI</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">Todo</span><span class="token punctuation">:</span> <span class="token class-name">Identifiable</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">let</span> id <span class="token operator">=</span> <span class="token function">UUID</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token keyword">var</span> text<span class="token punctuation">:</span> <span class="token class-name">String</span>
</span><span class="code-line">  <span class="token keyword">var</span> due<span class="token punctuation">:</span> <span class="token class-name">String</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">SwiftUIView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">private</span> <span class="token keyword">var</span> todos <span class="token operator">=</span> <span class="token punctuation">[</span>
</span><span class="code-line">    <span class="token class-name">Todo</span><span class="token punctuation">(</span>text<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Task 1"</span></span><span class="token punctuation">,</span> due<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Mon"</span></span><span class="token punctuation">)</span><span class="token punctuation">,</span>
</span><span class="code-line">    <span class="token class-name">Todo</span><span class="token punctuation">(</span>text<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Task 2"</span></span><span class="token punctuation">,</span> due<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Wed"</span></span><span class="token punctuation">)</span><span class="token punctuation">,</span>
</span><span class="code-line">    <span class="token class-name">Todo</span><span class="token punctuation">(</span>text<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Task 3"</span></span><span class="token punctuation">,</span> due<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Fri"</span></span><span class="token punctuation">)</span><span class="token punctuation">,</span>
</span><span class="code-line">    <span class="token class-name">Todo</span><span class="token punctuation">(</span>text<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Task 4"</span></span><span class="token punctuation">,</span> due<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Sat"</span></span><span class="token punctuation">)</span><span class="token punctuation">,</span>
</span><span class="code-line">    <span class="token class-name">Todo</span><span class="token punctuation">(</span>text<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Task 5"</span></span><span class="token punctuation">,</span> due<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Sun"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">]</span>
</span><span class="code-line">
</span><span class="code-line">  <span class="token attribute atrule">@State</span> <span class="token keyword">private</span> <span class="token keyword">var</span> sheetTodo<span class="token punctuation">:</span> <span class="token class-name">Todo</span><span class="token operator">?</span>
</span><span class="code-line">
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">List</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token class-name">ForEach</span><span class="token punctuation">(</span>todos<span class="token punctuation">)</span> <span class="token punctuation">{</span> todo <span class="token keyword">in</span>
</span><span class="code-line">        <span class="token class-name">HStack</span> <span class="token punctuation">{</span>
</span><span class="code-line">          <span class="token class-name">Text</span><span class="token punctuation">(</span>todo<span class="token punctuation">.</span>text<span class="token punctuation">)</span>
</span><span class="code-line">          <span class="token class-name">Spacer</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">          <span class="token class-name">Button</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Detail"</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            sheetTodo <span class="token operator">=</span> todo
</span><span class="code-line">          <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">      <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">.</span><span class="token function">sheet</span><span class="token punctuation">(</span>item<span class="token punctuation">:</span> $sheetTodo<span class="token punctuation">)</span> <span class="token punctuation">{</span> todo <span class="token keyword">in</span>
</span><span class="code-line">      <span class="token class-name">VStack</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"My Sheet View"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Task: </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">todo<span class="token punctuation">.</span>text</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Due: </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">todo<span class="token punctuation">.</span>due</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p>이 코드를 간단하게 알아보겠습니다.</p>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">Todo</span><span class="token punctuation">:</span> <span class="token class-name">Identifiable</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">let</span> id <span class="token operator">=</span> <span class="token function">UUID</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token keyword">var</span> text<span class="token punctuation">:</span> <span class="token class-name">String</span>
</span><span class="code-line">  <span class="token keyword">var</span> due<span class="token punctuation">:</span> <span class="token class-name">String</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p>이 부분은 Model이라고도 할 수 있는 부분으로 Todo의 구조체를 만들어놓은 것입니다.</p>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">private</span> <span class="token keyword">var</span> todos <span class="token operator">=</span> <span class="token punctuation">[</span>
</span><span class="code-line">  <span class="token class-name">Todo</span><span class="token punctuation">(</span>text<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Task 1"</span></span><span class="token punctuation">,</span> due<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Mon"</span></span><span class="token punctuation">)</span><span class="token punctuation">,</span>
</span><span class="code-line">  <span class="token class-name">Todo</span><span class="token punctuation">(</span>text<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Task 2"</span></span><span class="token punctuation">,</span> due<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Wed"</span></span><span class="token punctuation">)</span><span class="token punctuation">,</span>
</span><span class="code-line">  <span class="token class-name">Todo</span><span class="token punctuation">(</span>text<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Task 3"</span></span><span class="token punctuation">,</span> due<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Fri"</span></span><span class="token punctuation">)</span><span class="token punctuation">,</span>
</span><span class="code-line">  <span class="token class-name">Todo</span><span class="token punctuation">(</span>text<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Task 4"</span></span><span class="token punctuation">,</span> due<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Sat"</span></span><span class="token punctuation">)</span><span class="token punctuation">,</span>
</span><span class="code-line">  <span class="token class-name">Todo</span><span class="token punctuation">(</span>text<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Task 5"</span></span><span class="token punctuation">,</span> due<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Sun"</span></span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">]</span>
</span></code></pre>
<p>이 부분은 todos 배열을 선언하고 초기화 한 부분입니다.</p>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token class-name">List</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">ForEach</span><span class="token punctuation">(</span>todos<span class="token punctuation">)</span> <span class="token punctuation">{</span> todo <span class="token keyword">in</span>
</span><span class="code-line">      <span class="token class-name">HStack</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">Text</span><span class="token punctuation">(</span>todo<span class="token punctuation">.</span>text<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token class-name">Spacer</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token class-name">Button</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Detail"</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">          sheetTodo <span class="token operator">=</span> todo
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">      <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">.</span><span class="token function">sheet</span><span class="token punctuation">(</span>item<span class="token punctuation">:</span> $sheetTodo<span class="token punctuation">)</span> <span class="token punctuation">{</span> todo <span class="token keyword">in</span>
</span><span class="code-line">    <span class="token class-name">VStack</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"My Sheet View"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Task: </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">todo<span class="token punctuation">.</span>text</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Due: </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">todo<span class="token punctuation">.</span>due</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p>이 부분은 실제 View의 UI를 구성하는 부분입니다. 이 코드를 실행보면 다음과 같이 UI가 구성되고, Detail을 누르면 그에 해당하는 View가 Modal하게 띄워집니다.</p>
<p><img src="/images/swiftui-sheet-inside-foreach-1.png" alt="swiftui-sheet-inside-foreach"></p>
<h2 id="실수하는-부분">실수하는 부분</h2>
<p>ForEach 혹은 List와 같은 루프와 Sheet를 같이 사용할 때 많이 범하는 실수가 있습니다. 루프안에 Sheet를 사용하는 것인데요. 다음 코드가 그 실수를 대변하는 하나의 예시입니다.</p>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">import</span> <span class="token class-name">SwiftUI</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">Todo</span><span class="token punctuation">:</span> <span class="token class-name">Identifiable</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">let</span> id <span class="token operator">=</span> <span class="token function">UUID</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token keyword">var</span> text<span class="token punctuation">:</span> <span class="token class-name">String</span>
</span><span class="code-line">  <span class="token keyword">var</span> due<span class="token punctuation">:</span> <span class="token class-name">String</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">SwiftUIView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">private</span> <span class="token keyword">var</span> todos <span class="token operator">=</span> <span class="token punctuation">[</span>
</span><span class="code-line">    <span class="token class-name">Todo</span><span class="token punctuation">(</span>text<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Task 1"</span></span><span class="token punctuation">,</span> due<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Mon"</span></span><span class="token punctuation">)</span><span class="token punctuation">,</span>
</span><span class="code-line">    <span class="token class-name">Todo</span><span class="token punctuation">(</span>text<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Task 2"</span></span><span class="token punctuation">,</span> due<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Wed"</span></span><span class="token punctuation">)</span><span class="token punctuation">,</span>
</span><span class="code-line">    <span class="token class-name">Todo</span><span class="token punctuation">(</span>text<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Task 3"</span></span><span class="token punctuation">,</span> due<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Fri"</span></span><span class="token punctuation">)</span><span class="token punctuation">,</span>
</span><span class="code-line">    <span class="token class-name">Todo</span><span class="token punctuation">(</span>text<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Task 4"</span></span><span class="token punctuation">,</span> due<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Sat"</span></span><span class="token punctuation">)</span><span class="token punctuation">,</span>
</span><span class="code-line">    <span class="token class-name">Todo</span><span class="token punctuation">(</span>text<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Task 5"</span></span><span class="token punctuation">,</span> due<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Sun"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">]</span>
</span><span class="code-line">
</span><span class="code-line">  <span class="token attribute atrule">@State</span> <span class="token keyword">private</span> <span class="token keyword">var</span> showTodo <span class="token operator">=</span> <span class="token boolean">false</span>
</span><span class="code-line">  <span class="token attribute atrule">@State</span> <span class="token keyword">private</span> <span class="token keyword">var</span> sheetTodo<span class="token punctuation">:</span> <span class="token class-name">Todo</span><span class="token operator">?</span>
</span><span class="code-line">
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">List</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token class-name">ForEach</span><span class="token punctuation">(</span>todos<span class="token punctuation">)</span> <span class="token punctuation">{</span> todo <span class="token keyword">in</span>
</span><span class="code-line">        <span class="token class-name">HStack</span> <span class="token punctuation">{</span>
</span><span class="code-line">          <span class="token class-name">Text</span><span class="token punctuation">(</span>todo<span class="token punctuation">.</span>text<span class="token punctuation">)</span>
</span><span class="code-line">          <span class="token class-name">Spacer</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">          <span class="token class-name">Button</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Detail"</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            showTodo<span class="token punctuation">.</span><span class="token function">toggle</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">          <span class="token punctuation">}</span>
</span><span class="code-line">          <span class="token punctuation">.</span><span class="token function">sheet</span><span class="token punctuation">(</span>isPresented<span class="token punctuation">:</span> $showTodo<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token class-name">VStack</span> <span class="token punctuation">{</span>
</span><span class="code-line">              <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"My Sheet View"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">              <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Task: </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">todo<span class="token punctuation">.</span>text</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">              <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Due: </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">todo<span class="token punctuation">.</span>due</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">          <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">      <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p>이렇게 코드를 작성하고 실행해보면, 어떤 Detail을 눌러도 마지막 Detail에 대한 View가 Modal 하게 띄워집니다. 그 이유는 Sheet가 ForEach 루프안에 있고, 그에 따라 각 Detail 버튼마다 Sheet이 생성되어 showTodo 변수가 toggle 될 때 모든 버튼의 Sheet이 활성화 되어서 그런 것입니다.</p>
<p>그렇기 때문에 이를 주의하고, Sheet는 루프 밖에서 만드는 것이 대체로 좋습니다.</p>
<h2 id="데이터-binding">데이터 Binding</h2>
<p>때로는 루프안에서 사용되는 데이터와 Sheet로 넘겨주는 데이터를 Binding 시켜줄 필요가 있습니다. 예를들어, Sheet로 띄우는 View에 TextField를 사용하는 경우가 있습니다. 그럴때는 다음과 같이 코드를 작성하면됩니다.</p>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">import</span> <span class="token class-name">SwiftUI</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">Todo</span><span class="token punctuation">:</span> <span class="token class-name">Identifiable</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">let</span> id <span class="token operator">=</span> <span class="token function">UUID</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token keyword">var</span> text<span class="token punctuation">:</span> <span class="token class-name">String</span>
</span><span class="code-line">  <span class="token keyword">var</span> due<span class="token punctuation">:</span> <span class="token class-name">String</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">SwiftUIView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token attribute atrule">@State</span> <span class="token keyword">private</span> <span class="token keyword">var</span> todos <span class="token operator">=</span> <span class="token punctuation">[</span>
</span><span class="code-line">    <span class="token class-name">Todo</span><span class="token punctuation">(</span>text<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Task 1"</span></span><span class="token punctuation">,</span> due<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Mon"</span></span><span class="token punctuation">)</span><span class="token punctuation">,</span>
</span><span class="code-line">    <span class="token class-name">Todo</span><span class="token punctuation">(</span>text<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Task 2"</span></span><span class="token punctuation">,</span> due<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Wed"</span></span><span class="token punctuation">)</span><span class="token punctuation">,</span>
</span><span class="code-line">    <span class="token class-name">Todo</span><span class="token punctuation">(</span>text<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Task 3"</span></span><span class="token punctuation">,</span> due<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Fri"</span></span><span class="token punctuation">)</span><span class="token punctuation">,</span>
</span><span class="code-line">    <span class="token class-name">Todo</span><span class="token punctuation">(</span>text<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Task 4"</span></span><span class="token punctuation">,</span> due<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Sat"</span></span><span class="token punctuation">)</span><span class="token punctuation">,</span>
</span><span class="code-line">    <span class="token class-name">Todo</span><span class="token punctuation">(</span>text<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Task 5"</span></span><span class="token punctuation">,</span> due<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Sun"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">]</span>
</span><span class="code-line">
</span><span class="code-line">  <span class="token attribute atrule">@State</span> <span class="token keyword">private</span> <span class="token keyword">var</span> showTodo <span class="token operator">=</span> <span class="token boolean">false</span>
</span><span class="code-line">  <span class="token attribute atrule">@State</span> <span class="token keyword">private</span> <span class="token keyword">var</span> sheetTodo<span class="token punctuation">:</span> <span class="token class-name">Todo</span><span class="token operator">?</span>
</span><span class="code-line">
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">List</span><span class="token punctuation">(</span>todos<span class="token punctuation">)</span> <span class="token punctuation">{</span> todo <span class="token keyword">in</span>
</span><span class="code-line">      <span class="token class-name">HStack</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">Text</span><span class="token punctuation">(</span>todo<span class="token punctuation">.</span>text<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token class-name">Spacer</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token class-name">Button</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Detail"</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">          sheetTodo <span class="token operator">=</span> todo
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">      <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">.</span><span class="token function">sheet</span><span class="token punctuation">(</span>item<span class="token punctuation">:</span> $sheetTodo<span class="token punctuation">)</span> <span class="token punctuation">{</span> todo <span class="token keyword">in</span>
</span><span class="code-line">      <span class="token class-name">VStack</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"My Sheet View"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token class-name">TextField</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Task: "</span></span><span class="token punctuation">,</span> text<span class="token punctuation">:</span> $todos<span class="token punctuation">.</span>first <span class="token punctuation">{</span> <span class="token short-argument">$0</span><span class="token punctuation">.</span>id <span class="token operator">==</span> todo<span class="token punctuation">.</span>id <span class="token punctuation">}</span><span class="token operator">!</span><span class="token punctuation">.</span>text<span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p>다른 부분은 대부분 똑같고, 아래 부분만 살짝 다릅니다.</p>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token punctuation">.</span><span class="token function">sheet</span><span class="token punctuation">(</span>item<span class="token punctuation">:</span> $sheetTodo<span class="token punctuation">)</span> <span class="token punctuation">{</span> todo <span class="token keyword">in</span>
</span><span class="code-line">  <span class="token class-name">VStack</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"My Sheet View"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token class-name">TextField</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Task: "</span></span><span class="token punctuation">,</span> text<span class="token punctuation">:</span> $todos<span class="token punctuation">.</span>first <span class="token punctuation">{</span> <span class="token short-argument">$0</span><span class="token punctuation">.</span>id <span class="token operator">==</span> todo<span class="token punctuation">.</span>id <span class="token punctuation">}</span><span class="token operator">!</span><span class="token punctuation">.</span>text<span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p>우선, Sheet의 파라미터가 isPresented가 아닌 item으로 item안에 들어가는 값이 변경될때 sheet가 발동됩니다. 그리고 TextField와 같이 데이터와 Binding 된 값이 필요한 경우, todos 내에서 id 값을 비교해 해당 element를 받아와 사용하면됩니다.</p>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/chatgpt-swiftui</guid>
      <title>SwiftUI도 꽤 능숙한 ChatGPT</title>
      <description>ChatGPT는 SwiftUI도 꽤 능숙하지만 이것은 과연 좋은 소식일까요?</description>
      <link>https://www.hohyeonmoon.com/blog/chatgpt-swiftui</link>
      <pubDate>Mon, 05 Dec 2022 18:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p><img src="/images/chatgpt-swiftui-1.png" alt="chatgpt-swiftui"></p>
<p><a href="https://openai.com/blog/chatgpt/">ChatGPT</a>는 인간과 상호 작용하면서 많은 일을 할 수 있는 OpenAI의 프로젝트입니다. ChatGPT가 SwiftUI 코드를 얼마나 잘 구현하는지 살펴보겠습니다.</p>
<h2 id="chat-시작">Chat 시작</h2>
<p><img src="/images/chatgpt-swiftui-2.png" alt="chatgpt-swiftui"></p>
<p><strong>Me:</strong></p>
<p>Hey, can you make a SwiftUI calculator?</p>
<p><strong>ChatGPT:</strong></p>
<p>Sure, here is a simple SwiftUI calculator that you can use as a starting point. It can perform basic arithmetic operations like addition, subtraction, multiplication, and division. You can customize it to add more functionality as needed.</p>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">import</span> <span class="token class-name">SwiftUI</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">CalculatorView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token attribute atrule">@State</span> <span class="token keyword">private</span> <span class="token keyword">var</span> firstNumber <span class="token operator">=</span> <span class="token string-literal"><span class="token string">""</span></span>
</span><span class="code-line">    <span class="token attribute atrule">@State</span> <span class="token keyword">private</span> <span class="token keyword">var</span> secondNumber <span class="token operator">=</span> <span class="token string-literal"><span class="token string">""</span></span>
</span><span class="code-line">    <span class="token attribute atrule">@State</span> <span class="token keyword">private</span> <span class="token keyword">var</span> operation <span class="token operator">=</span> <span class="token string-literal"><span class="token string">""</span></span>
</span><span class="code-line">    <span class="token attribute atrule">@State</span> <span class="token keyword">private</span> <span class="token keyword">var</span> result <span class="token operator">=</span> <span class="token string-literal"><span class="token string">""</span></span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">VStack</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token class-name">HStack</span> <span class="token punctuation">{</span>
</span><span class="code-line">                <span class="token class-name">TextField</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Enter first number"</span></span><span class="token punctuation">,</span> text<span class="token punctuation">:</span> $firstNumber<span class="token punctuation">)</span>
</span><span class="code-line">                    <span class="token punctuation">.</span><span class="token function">keyboardType</span><span class="token punctuation">(</span><span class="token punctuation">.</span>decimalPad<span class="token punctuation">)</span>
</span><span class="code-line">                    <span class="token punctuation">.</span><span class="token function">textFieldStyle</span><span class="token punctuation">(</span><span class="token class-name">RoundedBorderTextFieldStyle</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">                <span class="token class-name">TextField</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Enter second number"</span></span><span class="token punctuation">,</span> text<span class="token punctuation">:</span> $secondNumber<span class="token punctuation">)</span>
</span><span class="code-line">                    <span class="token punctuation">.</span><span class="token function">keyboardType</span><span class="token punctuation">(</span><span class="token punctuation">.</span>decimalPad<span class="token punctuation">)</span>
</span><span class="code-line">                    <span class="token punctuation">.</span><span class="token function">textFieldStyle</span><span class="token punctuation">(</span><span class="token class-name">RoundedBorderTextFieldStyle</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">            <span class="token class-name">HStack</span> <span class="token punctuation">{</span>
</span><span class="code-line">                <span class="token class-name">Button</span><span class="token punctuation">(</span>action<span class="token punctuation">:</span> <span class="token punctuation">{</span>
</span><span class="code-line">                    <span class="token keyword">self</span><span class="token punctuation">.</span>operation <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"+"</span></span>
</span><span class="code-line">                    <span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">calculate</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">                    <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"+"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token punctuation">}</span>
</span><span class="code-line">                <span class="token punctuation">.</span><span class="token function">buttonStyle</span><span class="token punctuation">(</span><span class="token class-name">RoundedButtonStyle</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">                <span class="token class-name">Button</span><span class="token punctuation">(</span>action<span class="token punctuation">:</span> <span class="token punctuation">{</span>
</span><span class="code-line">                    <span class="token keyword">self</span><span class="token punctuation">.</span>operation <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"-"</span></span>
</span><span class="code-line">                    <span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">calculate</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">                    <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"-"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token punctuation">}</span>
</span><span class="code-line">                <span class="token punctuation">.</span><span class="token function">buttonStyle</span><span class="token punctuation">(</span><span class="token class-name">RoundedButtonStyle</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">                <span class="token class-name">Button</span><span class="token punctuation">(</span>action<span class="token punctuation">:</span> <span class="token punctuation">{</span>
</span><span class="code-line">                    <span class="token keyword">self</span><span class="token punctuation">.</span>operation <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"*"</span></span>
</span><span class="code-line">                    <span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">calculate</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">                    <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"*"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token punctuation">}</span>
</span><span class="code-line">                <span class="token punctuation">.</span><span class="token function">buttonStyle</span><span class="token punctuation">(</span><span class="token class-name">RoundedButtonStyle</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">                <span class="token class-name">Button</span><span class="token punctuation">(</span>action<span class="token punctuation">:</span> <span class="token punctuation">{</span>
</span><span class="code-line">                    <span class="token keyword">self</span><span class="token punctuation">.</span>operation <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"/"</span></span>
</span><span class="code-line">                    <span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">calculate</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">                    <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"/"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token punctuation">}</span>
</span><span class="code-line">                <span class="token punctuation">.</span><span class="token function">buttonStyle</span><span class="token punctuation">(</span><span class="token class-name">RoundedButtonStyle</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">            <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Result: </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">result</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">func</span> <span class="token function-definition function">calculate</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">guard</span> <span class="token keyword">let</span> first <span class="token operator">=</span> <span class="token class-name">Double</span><span class="token punctuation">(</span>firstNumber<span class="token punctuation">)</span><span class="token punctuation">,</span>
</span><span class="code-line">            <span class="token keyword">let</span> second <span class="token operator">=</span> <span class="token class-name">Double</span><span class="token punctuation">(</span>secondNumber<span class="token punctuation">)</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">                result <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"Invalid input"</span></span>
</span><span class="code-line">                <span class="token keyword">return</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">        <span class="token keyword">switch</span> operation <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">case</span> <span class="token string-literal"><span class="token string">"+"</span></span><span class="token punctuation">:</span>
</span><span class="code-line">            result <span class="token operator">=</span> <span class="token class-name">String</span><span class="token punctuation">(</span>first <span class="token operator">+</span> second<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token keyword">case</span> <span class="token string-literal"><span class="token string">"-"</span></span><span class="token punctuation">:</span>
</span><span class="code-line">            result <span class="token operator">=</span> <span class="token class-name">String</span><span class="token punctuation">(</span>first <span class="token operator">-</span> second<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token keyword">case</span> <span class="token string-literal"><span class="token string">"*"</span></span><span class="token punctuation">:</span>
</span><span class="code-line">            result <span class="token operator">=</span> <span class="token class-name">String</span><span class="token punctuation">(</span>first <span class="token operator">*</span> second<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token keyword">case</span> <span class="token string-literal"><span class="token string">"/"</span></span><span class="token punctuation">:</span>
</span><span class="code-line">            result <span class="token operator">=</span> <span class="token class-name">String</span><span class="token punctuation">(</span>first <span class="token operator">/</span> second<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token keyword">default</span><span class="token punctuation">:</span>
</span><span class="code-line">            result <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"Invalid input"</span></span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">RoundedButtonStyle</span><span class="token punctuation">:</span> <span class="token class-name">ButtonStyle</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">makeBody</span><span class="token punctuation">(</span>configuration<span class="token punctuation">:</span> <span class="token class-name">Configuration</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        configuration<span class="token punctuation">.</span>label
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">padding</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">foregroundColor</span><span class="token punctuation">(</span><span class="token punctuation">.</span>white<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">background</span><span class="token punctuation">(</span><span class="token class-name">Color</span><span class="token punctuation">.</span>blue<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">cornerRadius</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p>To use this calculator in your SwiftUI app, simply create an instance of the <code>CalculatorView</code> struct and add it to your app's hierarchy. For example:</p>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">CalculatorView</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><strong>Me:</strong></p>
<p>Can you separate business logic to view model?</p>
<p><strong>ChatGPT:</strong></p>
<p>Sure, here is an updated version of the calculator that uses a view model to separate the business logic from the user interface code. This makes the code more modular and easier to maintain.</p>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">import</span> <span class="token class-name">SwiftUI</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">CalculatorView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token attribute atrule">@ObservedObject</span> <span class="token keyword">var</span> viewModel <span class="token operator">=</span> <span class="token class-name">CalculatorViewModel</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">VStack</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token class-name">HStack</span> <span class="token punctuation">{</span>
</span><span class="code-line">                <span class="token class-name">TextField</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Enter first number"</span></span><span class="token punctuation">,</span> text<span class="token punctuation">:</span> $viewModel<span class="token punctuation">.</span>firstNumber<span class="token punctuation">)</span>
</span><span class="code-line">                    <span class="token punctuation">.</span><span class="token function">keyboardType</span><span class="token punctuation">(</span><span class="token punctuation">.</span>decimalPad<span class="token punctuation">)</span>
</span><span class="code-line">                    <span class="token punctuation">.</span><span class="token function">textFieldStyle</span><span class="token punctuation">(</span><span class="token class-name">RoundedBorderTextFieldStyle</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">                <span class="token class-name">TextField</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Enter second number"</span></span><span class="token punctuation">,</span> text<span class="token punctuation">:</span> $viewModel<span class="token punctuation">.</span>secondNumber<span class="token punctuation">)</span>
</span><span class="code-line">                    <span class="token punctuation">.</span><span class="token function">keyboardType</span><span class="token punctuation">(</span><span class="token punctuation">.</span>decimalPad<span class="token punctuation">)</span>
</span><span class="code-line">                    <span class="token punctuation">.</span><span class="token function">textFieldStyle</span><span class="token punctuation">(</span><span class="token class-name">RoundedBorderTextFieldStyle</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">            <span class="token class-name">HStack</span> <span class="token punctuation">{</span>
</span><span class="code-line">                <span class="token class-name">Button</span><span class="token punctuation">(</span>action<span class="token punctuation">:</span> <span class="token punctuation">{</span>
</span><span class="code-line">                    <span class="token keyword">self</span><span class="token punctuation">.</span>viewModel<span class="token punctuation">.</span>operation <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"+"</span></span>
</span><span class="code-line">                    <span class="token keyword">self</span><span class="token punctuation">.</span>viewModel<span class="token punctuation">.</span><span class="token function">calculate</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">                    <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"+"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token punctuation">}</span>
</span><span class="code-line">                <span class="token punctuation">.</span><span class="token function">buttonStyle</span><span class="token punctuation">(</span><span class="token class-name">RoundedButtonStyle</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">                <span class="token class-name">Button</span><span class="token punctuation">(</span>action<span class="token punctuation">:</span> <span class="token punctuation">{</span>
</span><span class="code-line">                    <span class="token keyword">self</span><span class="token punctuation">.</span>viewModel<span class="token punctuation">.</span>operation <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"-"</span></span>
</span><span class="code-line">                    <span class="token keyword">self</span><span class="token punctuation">.</span>viewModel<span class="token punctuation">.</span><span class="token function">calculate</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">                    <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"-"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token punctuation">}</span>
</span><span class="code-line">                <span class="token punctuation">.</span><span class="token function">buttonStyle</span><span class="token punctuation">(</span><span class="token class-name">RoundedButtonStyle</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">                <span class="token class-name">Button</span><span class="token punctuation">(</span>action<span class="token punctuation">:</span> <span class="token punctuation">{</span>
</span><span class="code-line">                    <span class="token keyword">self</span><span class="token punctuation">.</span>viewModel<span class="token punctuation">.</span>operation <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"*"</span></span>
</span><span class="code-line">                    <span class="token keyword">self</span><span class="token punctuation">.</span>viewModel<span class="token punctuation">.</span><span class="token function">calculate</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">                    <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"*"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token punctuation">}</span>
</span><span class="code-line">                <span class="token punctuation">.</span><span class="token function">buttonStyle</span><span class="token punctuation">(</span><span class="token class-name">RoundedButtonStyle</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">                <span class="token class-name">Button</span><span class="token punctuation">(</span>action<span class="token punctuation">:</span> <span class="token punctuation">{</span>
</span><span class="code-line">                    <span class="token keyword">self</span><span class="token punctuation">.</span>viewModel<span class="token punctuation">.</span>operation <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"/"</span></span>
</span><span class="code-line">                    <span class="token keyword">self</span><span class="token punctuation">.</span>viewModel<span class="token punctuation">.</span><span class="token function">calculate</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">                    <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"/"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token punctuation">}</span>
</span><span class="code-line">                <span class="token punctuation">.</span><span class="token function">buttonStyle</span><span class="token punctuation">(</span><span class="token class-name">RoundedButtonStyle</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">            <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Result: </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">viewModel<span class="token punctuation">.</span>result</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">RoundedButtonStyle</span><span class="token punctuation">:</span> <span class="token class-name">ButtonStyle</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">makeBody</span><span class="token punctuation">(</span>configuration<span class="token punctuation">:</span> <span class="token class-name">Configuration</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        configuration<span class="token punctuation">.</span>label
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">padding</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">foregroundColor</span><span class="token punctuation">(</span><span class="token punctuation">.</span>white<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">background</span><span class="token punctuation">(</span><span class="token class-name">Color</span><span class="token punctuation">.</span>blue<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">cornerRadius</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">CalculatorViewModel</span><span class="token punctuation">:</span> <span class="token class-name">ObservableObject</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token attribute atrule">@Published</span> <span class="token keyword">var</span> firstNumber <span class="token operator">=</span> <span class="token string-literal"><span class="token string">""</span></span>
</span><span class="code-line">    <span class="token attribute atrule">@Published</span> <span class="token keyword">var</span> secondNumber <span class="token operator">=</span> <span class="token string-literal"><span class="token string">""</span></span>
</span><span class="code-line">    <span class="token attribute atrule">@Published</span> <span class="token keyword">var</span> operation <span class="token operator">=</span> <span class="token string-literal"><span class="token string">""</span></span>
</span><span class="code-line">    <span class="token attribute atrule">@Published</span> <span class="token keyword">var</span> result <span class="token operator">=</span> <span class="token string-literal"><span class="token string">""</span></span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">calculate</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">guard</span> <span class="token keyword">let</span> first <span class="token operator">=</span> <span class="token class-name">Double</span><span class="token punctuation">(</span>firstNumber<span class="token punctuation">)</span><span class="token punctuation">,</span>
</span><span class="code-line">            <span class="token keyword">let</span> second <span class="token operator">=</span> <span class="token class-name">Double</span><span class="token punctuation">(</span>secondNumber<span class="token punctuation">)</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">                result <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"Invalid input"</span></span>
</span><span class="code-line">                <span class="token keyword">return</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">        <span class="token keyword">switch</span> operation <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">case</span> <span class="token string-literal"><span class="token string">"+"</span></span><span class="token punctuation">:</span>
</span><span class="code-line">            result <span class="token operator">=</span> <span class="token class-name">String</span><span class="token punctuation">(</span>first <span class="token operator">+</span> second<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token keyword">case</span> <span class="token string-literal"><span class="token string">"-"</span></span><span class="token punctuation">:</span>
</span><span class="code-line">            result <span class="token operator">=</span> <span class="token class-name">String</span><span class="token punctuation">(</span>first <span class="token operator">-</span> second<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token keyword">case</span> <span class="token string-literal"><span class="token string">"*"</span></span><span class="token punctuation">:</span>
</span><span class="code-line">            result <span class="token operator">=</span> <span class="token class-name">String</span><span class="token punctuation">(</span>first <span class="token operator">*</span> second<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token keyword">case</span> <span class="token string-literal"><span class="token string">"/"</span></span><span class="token punctuation">:</span>
</span><span class="code-line">            result <span class="token operator">=</span> <span class="token class-name">String</span><span class="token punctuation">(</span>first <span class="token operator">/</span> second<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token keyword">default</span><span class="token punctuation">:</span>
</span><span class="code-line">            result <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"Invalid input"</span></span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><img src="/images/chatgpt-swiftui-3.png" alt="chatgpt-swiftui"></p>
<p><strong>Me:</strong></p>
<p>Can you make it prettier but in a shorter code?</p>
<p><strong>ChatGPT:</strong></p>
<p>Sure, here is a more concise version of the SwiftUI calculator that uses custom styles to make it look more attractive. This version also includes a clear button that resets the calculator to its initial state.</p>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">import</span> <span class="token class-name">SwiftUI</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">CalculatorView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token attribute atrule">@ObservedObject</span> <span class="token keyword">var</span> viewModel <span class="token operator">=</span> <span class="token class-name">CalculatorViewModel</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">VStack</span><span class="token punctuation">(</span>spacing<span class="token punctuation">:</span> <span class="token number">20</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Result: </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">viewModel<span class="token punctuation">.</span>result</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token punctuation">.</span><span class="token function">font</span><span class="token punctuation">(</span><span class="token punctuation">.</span>title<span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">            <span class="token class-name">HStack</span><span class="token punctuation">(</span>spacing<span class="token punctuation">:</span> <span class="token number">20</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">                <span class="token class-name">CalculatorButton</span><span class="token punctuation">(</span>label<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"1"</span></span><span class="token punctuation">,</span> action<span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token keyword">self</span><span class="token punctuation">.</span>viewModel<span class="token punctuation">.</span><span class="token function">addNumber</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"1"</span></span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token class-name">CalculatorButton</span><span class="token punctuation">(</span>label<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"2"</span></span><span class="token punctuation">,</span> action<span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token keyword">self</span><span class="token punctuation">.</span>viewModel<span class="token punctuation">.</span><span class="token function">addNumber</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"2"</span></span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token class-name">CalculatorButton</span><span class="token punctuation">(</span>label<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"3"</span></span><span class="token punctuation">,</span> action<span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token keyword">self</span><span class="token punctuation">.</span>viewModel<span class="token punctuation">.</span><span class="token function">addNumber</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"3"</span></span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token class-name">CalculatorButton</span><span class="token punctuation">(</span>label<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"+"</span></span><span class="token punctuation">,</span> action<span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token keyword">self</span><span class="token punctuation">.</span>viewModel<span class="token punctuation">.</span><span class="token function">addOperation</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"+"</span></span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">            <span class="token class-name">HStack</span><span class="token punctuation">(</span>spacing<span class="token punctuation">:</span> <span class="token number">20</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">                <span class="token class-name">CalculatorButton</span><span class="token punctuation">(</span>label<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"4"</span></span><span class="token punctuation">,</span> action<span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token keyword">self</span><span class="token punctuation">.</span>viewModel<span class="token punctuation">.</span><span class="token function">addNumber</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"4"</span></span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token class-name">CalculatorButton</span><span class="token punctuation">(</span>label<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"5"</span></span><span class="token punctuation">,</span> action<span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token keyword">self</span><span class="token punctuation">.</span>viewModel<span class="token punctuation">.</span><span class="token function">addNumber</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"5"</span></span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token class-name">CalculatorButton</span><span class="token punctuation">(</span>label<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"6"</span></span><span class="token punctuation">,</span> action<span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token keyword">self</span><span class="token punctuation">.</span>viewModel<span class="token punctuation">.</span><span class="token function">addNumber</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"6"</span></span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token class-name">CalculatorButton</span><span class="token punctuation">(</span>label<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"-"</span></span><span class="token punctuation">,</span> action<span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token keyword">self</span><span class="token punctuation">.</span>viewModel<span class="token punctuation">.</span><span class="token function">addOperation</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"-"</span></span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">            <span class="token class-name">HStack</span><span class="token punctuation">(</span>spacing<span class="token punctuation">:</span> <span class="token number">20</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">                <span class="token class-name">CalculatorButton</span><span class="token punctuation">(</span>label<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"7"</span></span><span class="token punctuation">,</span> action<span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token keyword">self</span><span class="token punctuation">.</span>viewModel<span class="token punctuation">.</span><span class="token function">addNumber</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"7"</span></span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token class-name">CalculatorButton</span><span class="token punctuation">(</span>label<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"8"</span></span><span class="token punctuation">,</span> action<span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token keyword">self</span><span class="token punctuation">.</span>viewModel<span class="token punctuation">.</span><span class="token function">addNumber</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"8"</span></span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token class-name">CalculatorButton</span><span class="token punctuation">(</span>label<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"9"</span></span><span class="token punctuation">,</span> action<span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token keyword">self</span><span class="token punctuation">.</span>viewModel<span class="token punctuation">.</span><span class="token function">addNumber</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"9"</span></span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token class-name">CalculatorButton</span><span class="token punctuation">(</span>label<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"*"</span></span><span class="token punctuation">,</span> action<span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token keyword">self</span><span class="token punctuation">.</span>viewModel<span class="token punctuation">.</span><span class="token function">addOperation</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"*"</span></span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">            <span class="token class-name">HStack</span><span class="token punctuation">(</span>spacing<span class="token punctuation">:</span> <span class="token number">20</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">                <span class="token class-name">CalculatorButton</span><span class="token punctuation">(</span>label<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"C"</span></span><span class="token punctuation">,</span> action<span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token keyword">self</span><span class="token punctuation">.</span>viewModel<span class="token punctuation">.</span><span class="token function">clear</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token class-name">CalculatorButton</span><span class="token punctuation">(</span>label<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"0"</span></span><span class="token punctuation">,</span> action<span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token keyword">self</span><span class="token punctuation">.</span>viewModel<span class="token punctuation">.</span><span class="token function">addNumber</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"0"</span></span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token class-name">CalculatorButton</span><span class="token punctuation">(</span>label<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"="</span></span><span class="token punctuation">,</span> action<span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token keyword">self</span><span class="token punctuation">.</span>viewModel<span class="token punctuation">.</span><span class="token function">calculate</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token class-name">CalculatorButton</span><span class="token punctuation">(</span>label<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"/"</span></span><span class="token punctuation">,</span> action<span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token keyword">self</span><span class="token punctuation">.</span>viewModel<span class="token punctuation">.</span><span class="token function">addOperation</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"/"</span></span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">padding</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">CalculatorButton</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> label<span class="token punctuation">:</span> <span class="token class-name">String</span>
</span><span class="code-line">    <span class="token keyword">let</span> action<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Void</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">Button</span><span class="token punctuation">(</span>action<span class="token punctuation">:</span> action<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token class-name">Text</span><span class="token punctuation">(</span>label<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">buttonStyle</span><span class="token punctuation">(</span><span class="token class-name">CalculatorButtonStyle</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">CalculatorButtonStyle</span><span class="token punctuation">:</span> <span class="token class-name">ButtonStyle</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">makeBody</span><span class="token punctuation">(</span>configuration<span class="token punctuation">:</span> <span class="token class-name">Configuration</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        configuration<span class="token punctuation">.</span>label
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">font</span><span class="token punctuation">(</span><span class="token punctuation">.</span>title<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">frame</span><span class="token punctuation">(</span>minWidth<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span> maxWidth<span class="token punctuation">:</span> <span class="token punctuation">.</span>infinity<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">padding</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">foregroundColor</span><span class="token punctuation">(</span><span class="token punctuation">.</span>white<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">background</span><span class="token punctuation">(</span><span class="token class-name">Color</span><span class="token punctuation">.</span>blue<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">cornerRadius</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">CalculatorViewModel</span><span class="token punctuation">:</span> <span class="token class-name">ObservableObject</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token attribute atrule">@Published</span> <span class="token keyword">var</span> result <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"0"</span></span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">var</span> currentNumber <span class="token operator">=</span> <span class="token string-literal"><span class="token string">""</span></span>
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">var</span> previousNumber <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"0"</span></span>
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">var</span> currentOperation <span class="token operator">=</span> <span class="token string-literal"><span class="token string">""</span></span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">add</span>
</span></code></pre>
<p><strong>Me:</strong></p>
<p>(ChatGPT가 제한된 코드 라인에서 응답하지 못한 것 같습니다. 그래서!) Make the code little shorter.</p>
<p><strong>ChatGPT:</strong></p>
<p>Sure, here is an even more concise version of the SwiftUI calculator that uses a single <code>CalculatorButton</code> struct to display all the buttons in the calculator. This version also includes a clear button that resets the calculator to its initial state.</p>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">import</span> <span class="token class-name">SwiftUI</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">CalculatorView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token attribute atrule">@ObservedObject</span> <span class="token keyword">var</span> viewModel <span class="token operator">=</span> <span class="token class-name">CalculatorViewModel</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">VStack</span><span class="token punctuation">(</span>spacing<span class="token punctuation">:</span> <span class="token number">20</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Result: </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">viewModel<span class="token punctuation">.</span>result</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token punctuation">.</span><span class="token function">font</span><span class="token punctuation">(</span><span class="token punctuation">.</span>title<span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">            <span class="token class-name">ForEach</span><span class="token punctuation">(</span><span class="token number">0</span> <span class="token operator">..&#x3C;</span> <span class="token number">4</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> row <span class="token keyword">in</span>
</span><span class="code-line">                <span class="token class-name">HStack</span><span class="token punctuation">(</span>spacing<span class="token punctuation">:</span> <span class="token number">20</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">                    <span class="token class-name">ForEach</span><span class="token punctuation">(</span><span class="token number">0</span> <span class="token operator">..&#x3C;</span> <span class="token number">4</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> column <span class="token keyword">in</span>
</span><span class="code-line">                        <span class="token class-name">CalculatorButton</span><span class="token punctuation">(</span>label<span class="token punctuation">:</span> <span class="token keyword">self</span><span class="token punctuation">.</span>viewModel<span class="token punctuation">.</span><span class="token function">buttonLabel</span><span class="token punctuation">(</span><span class="token keyword">for</span><span class="token punctuation">:</span> row<span class="token punctuation">,</span> column<span class="token punctuation">)</span><span class="token punctuation">,</span>
</span><span class="code-line">                                         action<span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token keyword">self</span><span class="token punctuation">.</span>viewModel<span class="token punctuation">.</span><span class="token function">buttonTapped</span><span class="token punctuation">(</span><span class="token keyword">for</span><span class="token punctuation">:</span> row<span class="token punctuation">,</span> column<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
</span><span class="code-line">                    <span class="token punctuation">}</span>
</span><span class="code-line">                <span class="token punctuation">}</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">padding</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">CalculatorButton</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> label<span class="token punctuation">:</span> <span class="token class-name">String</span>
</span><span class="code-line">    <span class="token keyword">let</span> action<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Void</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">Button</span><span class="token punctuation">(</span>action<span class="token punctuation">:</span> action<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token class-name">Text</span><span class="token punctuation">(</span>label<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">buttonStyle</span><span class="token punctuation">(</span><span class="token class-name">CalculatorButtonStyle</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">CalculatorButtonStyle</span><span class="token punctuation">:</span> <span class="token class-name">ButtonStyle</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">makeBody</span><span class="token punctuation">(</span>configuration<span class="token punctuation">:</span> <span class="token class-name">Configuration</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        configuration<span class="token punctuation">.</span>label
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">font</span><span class="token punctuation">(</span><span class="token punctuation">.</span>title<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">frame</span><span class="token punctuation">(</span>minWidth<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span> maxWidth<span class="token punctuation">:</span> <span class="token punctuation">.</span>infinity<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">padding</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">foregroundColor</span><span class="token punctuation">(</span><span class="token punctuation">.</span>white<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">background</span><span class="token punctuation">(</span><span class="token class-name">Color</span><span class="token punctuation">.</span>blue<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">cornerRadius</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">CalculatorViewModel</span><span class="token punctuation">:</span> <span class="token class-name">ObservableObject</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token attribute atrule">@Published</span> <span class="token keyword">var</span> result <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"0"</span></span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">var</span> currentNumber <span class="token operator">=</span> <span class="token string-literal"><span class="token string">""</span></span>
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">var</span> previousNumber <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"0"</span></span>
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">var</span> currentOperation <span class="token operator">=</span> <span class="token string-literal"><span class="token string">""</span></span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">buttonLabel</span><span class="token punctuation">(</span><span class="token keyword">for</span> row<span class="token punctuation">:</span> <span class="token class-name">Int</span><span class="token punctuation">,</span> <span class="token omit keyword">_</span> column<span class="token punctuation">:</span> <span class="token class-name">Int</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">String</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">let</span> buttonTitles <span class="token operator">=</span> <span class="token punctuation">[</span>
</span><span class="code-line">            <span class="token punctuation">[</span><span class="token string-literal"><span class="token string">"1"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"2"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"3"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"+"</span></span><span class="token punctuation">]</span><span class="token punctuation">,</span>
</span><span class="code-line">            <span class="token punctuation">[</span><span class="token string-literal"><span class="token string">"4"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"5"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"6"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"-"</span></span><span class="token punctuation">]</span><span class="token punctuation">,</span>
</span><span class="code-line">            <span class="token punctuation">[</span><span class="token string-literal"><span class="token string">"7"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"8"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"9"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"*"</span></span><span class="token punctuation">]</span><span class="token punctuation">,</span>
</span><span class="code-line">            <span class="token punctuation">[</span><span class="token string-literal"><span class="token string">"C"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"0"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"="</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"/"</span></span><span class="token punctuation">]</span>
</span><span class="code-line">        <span class="token punctuation">]</span>
</span><span class="code-line">        <span class="token keyword">return</span> buttonTitles<span class="token punctuation">[</span>row<span class="token punctuation">]</span><span class="token punctuation">[</span>column<span class="token punctuation">]</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">buttonTapped</span><span class="token punctuation">(</span><span class="token keyword">for</span> row<span class="token punctuation">:</span> <span class="token class-name">Int</span><span class="token punctuation">,</span> <span class="token omit keyword">_</span> column<span class="token punctuation">:</span> <span class="token class-name">Int</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">let</span> buttonActions <span class="token operator">=</span> <span class="token punctuation">[</span>
</span><span class="code-line">            <span class="token punctuation">[</span>addNumber<span class="token punctuation">,</span> addNumber<span class="token punctuation">,</span> addNumber<span class="token punctuation">,</span> addOperation<span class="token punctuation">]</span><span class="token punctuation">,</span>
</span><span class="code-line">            <span class="token punctuation">[</span>addNumber<span class="token punctuation">,</span> addNumber<span class="token punctuation">,</span> addNumber<span class="token punctuation">,</span> addOperation<span class="token punctuation">]</span><span class="token punctuation">,</span>
</span><span class="code-line">            <span class="token punctuation">[</span>addNumber<span class="token punctuation">,</span> addNumber<span class="token punctuation">,</span> addNumber<span class="token punctuation">,</span> addOperation<span class="token punctuation">]</span><span class="token punctuation">,</span>
</span><span class="code-line">            <span class="token punctuation">[</span>clear<span class="token punctuation">,</span> addNumber<span class="token punctuation">,</span> calculate<span class="token punctuation">,</span> addOperation<span class="token punctuation">]</span>
</span><span class="code-line">        <span class="token punctuation">]</span>
</span><span class="code-line">        <span class="token keyword">let</span> action <span class="token operator">=</span> buttonActions<span class="token punctuation">[</span>row<span class="token punctuation">]</span><span class="token punctuation">[</span>column<span class="token punctuation">]</span>
</span><span class="code-line">        <span class="token function">action</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">addNumber</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        currentNumber <span class="token operator">+=</span> <span class="token string-literal"><span class="token string">"1"</span></span>
</span><span class="code-line">        result <span class="token operator">=</span> currentNumber
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">addOperation</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        previousNumber <span class="token operator">=</span> result
</span><span class="code-line">        currentOperation <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"+"</span></span>
</span><span class="code-line">        currentNumber <span class="token operator">=</span> <span class="token string-literal"><span class="token string">""</span></span>
</span><span class="code-line">        result <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"0"</span></span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">calculate</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">let</span> result <span class="token operator">=</span> <span class="token number">0</span>
</span><span class="code-line">        <span class="token keyword">self</span><span class="token punctuation">.</span>result <span class="token operator">=</span> <span class="token class-name">String</span><span class="token punctuation">(</span>result<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">clear</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        currentNumber <span class="token operator">=</span> <span class="token string-literal"><span class="token string">""</span></span>
</span><span class="code-line">        previousNumber <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"0"</span></span>
</span><span class="code-line">        currentOperation <span class="token operator">=</span> <span class="token string-literal"><span class="token string">""</span></span>
</span><span class="code-line">        result <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"0"</span></span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><img src="/images/chatgpt-swiftui-4.png" alt="chatgpt-swiftui"></p>
<p><strong>Me:</strong></p>
<p>Make it look and feel modern.</p>
<p><strong>ChatGPT:</strong></p>
<p>Here is the most concise version of the SwiftUI calculator that I can come up with. This version uses a single <code>CalculatorButton</code> struct to display all the buttons in the calculator, and it includes a clear button that resets the calculator to its initial state.</p>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">import</span> <span class="token class-name">SwiftUI</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">CalculatorView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token attribute atrule">@ObservedObject</span> <span class="token keyword">var</span> viewModel <span class="token operator">=</span> <span class="token class-name">CalculatorViewModel</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">VStack</span><span class="token punctuation">(</span>spacing<span class="token punctuation">:</span> <span class="token number">20</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token class-name">HStack</span> <span class="token punctuation">{</span>
</span><span class="code-line">                <span class="token class-name">Spacer</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Result: </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">viewModel<span class="token punctuation">.</span>result</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">                    <span class="token punctuation">.</span><span class="token function">font</span><span class="token punctuation">(</span><span class="token punctuation">.</span>title<span class="token punctuation">)</span>
</span><span class="code-line">                    <span class="token punctuation">.</span><span class="token function">foregroundColor</span><span class="token punctuation">(</span><span class="token punctuation">.</span>secondary<span class="token punctuation">)</span>
</span><span class="code-line">                    <span class="token punctuation">.</span><span class="token function">padding</span><span class="token punctuation">(</span><span class="token punctuation">.</span>trailing<span class="token punctuation">,</span> <span class="token number">20</span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">            <span class="token class-name">ForEach</span><span class="token punctuation">(</span><span class="token number">0</span> <span class="token operator">..&#x3C;</span> <span class="token number">4</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> row <span class="token keyword">in</span>
</span><span class="code-line">                <span class="token class-name">HStack</span><span class="token punctuation">(</span>spacing<span class="token punctuation">:</span> <span class="token number">20</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">                    <span class="token class-name">ForEach</span><span class="token punctuation">(</span><span class="token number">0</span> <span class="token operator">..&#x3C;</span> <span class="token number">4</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> column <span class="token keyword">in</span>
</span><span class="code-line">                        <span class="token class-name">CalculatorButton</span><span class="token punctuation">(</span>label<span class="token punctuation">:</span> <span class="token keyword">self</span><span class="token punctuation">.</span>viewModel<span class="token punctuation">.</span><span class="token function">buttonLabel</span><span class="token punctuation">(</span><span class="token keyword">for</span><span class="token punctuation">:</span> row<span class="token punctuation">,</span> column<span class="token punctuation">)</span><span class="token punctuation">,</span>
</span><span class="code-line">                                         action<span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token keyword">self</span><span class="token punctuation">.</span>viewModel<span class="token punctuation">.</span><span class="token function">buttonTapped</span><span class="token punctuation">(</span><span class="token keyword">for</span><span class="token punctuation">:</span> row<span class="token punctuation">,</span> column<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
</span><span class="code-line">                    <span class="token punctuation">}</span>
</span><span class="code-line">                <span class="token punctuation">}</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">padding</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">background</span><span class="token punctuation">(</span><span class="token class-name">Color</span><span class="token punctuation">(</span><span class="token punctuation">.</span>systemGray6<span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">cornerRadius</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">CalculatorButton</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> label<span class="token punctuation">:</span> <span class="token class-name">String</span>
</span><span class="code-line">    <span class="token keyword">let</span> action<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Void</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">Button</span><span class="token punctuation">(</span>action<span class="token punctuation">:</span> action<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token class-name">Text</span><span class="token punctuation">(</span>label<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">buttonStyle</span><span class="token punctuation">(</span><span class="token class-name">CalculatorButtonStyle</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">CalculatorButtonStyle</span><span class="token punctuation">:</span> <span class="token class-name">ButtonStyle</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">makeBody</span><span class="token punctuation">(</span>configuration<span class="token punctuation">:</span> <span class="token class-name">Configuration</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        configuration<span class="token punctuation">.</span>label
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">font</span><span class="token punctuation">(</span><span class="token punctuation">.</span>title<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">frame</span><span class="token punctuation">(</span>minWidth<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span> maxWidth<span class="token punctuation">:</span> <span class="token punctuation">.</span>infinity<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">padding</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">foregroundColor</span><span class="token punctuation">(</span><span class="token punctuation">.</span>white<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">background</span><span class="token punctuation">(</span><span class="token class-name">Color</span><span class="token punctuation">.</span>blue<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">cornerRadius</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">CalculatorViewModel</span><span class="token punctuation">:</span> <span class="token class-name">ObservableObject</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token attribute atrule">@Published</span> <span class="token keyword">var</span> result <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"0"</span></span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">var</span> currentNumber <span class="token operator">=</span> <span class="token string-literal"><span class="token string">""</span></span>
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">var</span> previousNumber <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"0"</span></span>
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">var</span> currentOperation <span class="token operator">=</span> <span class="token string-literal"><span class="token string">""</span></span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">buttonLabel</span><span class="token punctuation">(</span><span class="token keyword">for</span> row<span class="token punctuation">:</span> <span class="token class-name">Int</span><span class="token punctuation">,</span> <span class="token omit keyword">_</span> column<span class="token punctuation">:</span> <span class="token class-name">Int</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">String</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">let</span> buttonTitles <span class="token operator">=</span> <span class="token punctuation">[</span>            <span class="token punctuation">[</span><span class="token string-literal"><span class="token string">"1"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"2"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"3"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"+"</span></span><span class="token punctuation">]</span><span class="token punctuation">,</span>
</span><span class="code-line">            <span class="token punctuation">[</span><span class="token string-literal"><span class="token string">"4"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"5"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"6"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"-"</span></span><span class="token punctuation">]</span><span class="token punctuation">,</span>
</span><span class="code-line">            <span class="token punctuation">[</span><span class="token string-literal"><span class="token string">"7"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"8"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"9"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"*"</span></span><span class="token punctuation">]</span><span class="token punctuation">,</span>
</span><span class="code-line">            <span class="token punctuation">[</span><span class="token string-literal"><span class="token string">"C"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"0"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"="</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"/"</span></span><span class="token punctuation">]</span>
</span><span class="code-line">        <span class="token punctuation">]</span>
</span><span class="code-line">        <span class="token keyword">return</span> buttonTitles<span class="token punctuation">[</span>row<span class="token punctuation">]</span><span class="token punctuation">[</span>column<span class="token punctuation">]</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">buttonTapped</span><span class="token punctuation">(</span><span class="token keyword">for</span> row<span class="token punctuation">:</span> <span class="token class-name">Int</span><span class="token punctuation">,</span> <span class="token omit keyword">_</span> column<span class="token punctuation">:</span> <span class="token class-name">Int</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">let</span> buttonActions <span class="token operator">=</span> <span class="token punctuation">[</span>            <span class="token punctuation">[</span>addNumber<span class="token punctuation">,</span> addNumber<span class="token punctuation">,</span> addNumber<span class="token punctuation">,</span> addOperation<span class="token punctuation">]</span><span class="token punctuation">,</span>
</span><span class="code-line">            <span class="token punctuation">[</span>addNumber<span class="token punctuation">,</span> addNumber<span class="token punctuation">,</span> addNumber<span class="token punctuation">,</span> addOperation<span class="token punctuation">]</span><span class="token punctuation">,</span>
</span><span class="code-line">            <span class="token punctuation">[</span>addNumber<span class="token punctuation">,</span> addNumber<span class="token punctuation">,</span> addNumber<span class="token punctuation">,</span> addOperation<span class="token punctuation">]</span><span class="token punctuation">,</span>
</span><span class="code-line">            <span class="token punctuation">[</span>clear<span class="token punctuation">,</span> addNumber<span class="token punctuation">,</span> calculate<span class="token punctuation">,</span> addOperation<span class="token punctuation">]</span>
</span><span class="code-line">        <span class="token punctuation">]</span>
</span><span class="code-line">        <span class="token keyword">let</span> action <span class="token operator">=</span> buttonActions<span class="token punctuation">[</span>row<span class="token punctuation">]</span><span class="token punctuation">[</span>column<span class="token punctuation">]</span>
</span><span class="code-line">        <span class="token function">action</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">addNumber</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        currentNumber <span class="token operator">+=</span> <span class="token string-literal"><span class="token string">"1"</span></span>
</span><span class="code-line">        result <span class="token operator">=</span> currentNumber
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">addOperation</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        previousNumber <span class="token operator">=</span> result
</span><span class="code-line">        currentOperation <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"+"</span></span>
</span><span class="code-line">        currentNumber <span class="token operator">=</span> <span class="token string-literal"><span class="token string">""</span></span>
</span><span class="code-line">        result <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"0"</span></span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">calculate</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">let</span> result <span class="token operator">=</span> <span class="token number">0</span>
</span><span class="code-line">        <span class="token keyword">self</span><span class="token punctuation">.</span>result <span class="token operator">=</span> <span class="token class-name">String</span><span class="token punctuation">(</span>result<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">clear</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">      currentNumber <span class="token operator">=</span> <span class="token string-literal"><span class="token string">""</span></span>
</span><span class="code-line">      previousNumber <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"0"</span></span>
</span><span class="code-line">      currentOperation <span class="token operator">=</span> <span class="token string-literal"><span class="token string">""</span></span>
</span><span class="code-line">      result <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"0"</span></span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><img src="/images/chatgpt-swiftui-5.png" alt="chatgpt-swiftui"></p>
<h2 id="chat-ends">Chat ends</h2>
<p>ChatGPT가 한글로도 대화가 가능하지만 영어가 조금 더 잘 되는거 같아 영어로 진행했습니다.</p>
<p>ChatGPT는 소프트웨어 엔지니어인 저에게 놀라운 경험이었습니다. GPT가 우리의 삶을 어떻게 변화시킬지 이미 관심 반, 걱정 반이지만 흥미로운건 맞는것 같습니다.</p>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/migrate-cloudkit-firebase</guid>
      <title>CloudKit을 Firebase로 마이그레이션 하기</title>
      <description>CloudKit과 CoreData 조합을 Firebase의 Firestore로 마이그레이션 하는 방법입니다</description>
      <link>https://www.hohyeonmoon.com/blog/migrate-cloudkit-firebase</link>
      <pubDate>Thu, 01 Dec 2022 22:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<h2 id="마이그레이션-배경">마이그레이션 배경</h2>
<p><img src="/images/migrate-cloudkit-firebase-1.png" alt="migrate-cloukit-firebase"></p>
<p>서비스가 애플 기기만 지원한다면 CloudKit과 CoreData를 사용해 DB 동기화를 진행하면 편합니다. 하지만 웹과 안드로이드를 지원해야 한다면 상황이 달라집니다.</p>
<p>CloudKit JS를 통해 웹과 안드로이드에서도 iCloud DB에 접근할 수 있기는 합니다. 하지만 다른 솔루션보다 비교적 구현이 까다롭고, 사용자 입장에서 애플 계정이 반드시 필요하다는 단점이 있습니다.</p>
<p>미래에라도 웹과 안드로이드를 지원할 계획이 있다면, CloudKit은 조금 아쉬운 솔루션이 될 수 있습니다. 제가 운영하고 있는 서비스 또한 미래에 웹과 안드로이드를 지원할 계획이 생기면서 기존에 사용하던 CloudKit을 걷어내고 Firebase를 사용하기 시작했습니다.</p>
<h2 id="firebase-장점">Firebase 장점</h2>
<p><img src="/images/migrate-cloudkit-firebase-2.png" alt="migrate-cloukit-firebase"></p>
<p>Firebase에는 여러 장점이 있지만, 그 중에서도 가장 마음에 들었던 장점에 대해 소개해보고자 합니다.</p>
<p>우선, 사용자가 다양한 방식으로 로그인해서 DB에 접근 할 수 있도록 지원합니다. 이메일과 전화번호 로그인은 당연하고, 구글 로그인이나 애플 로그인과 같은 소셜 로그인을 비롯해 SAML 로그인 방식까지 제공합니다.</p>
<p>서비스 초기에는 Firebase로 충분하고도 넘치겠지만, 서비스가 커지면 조금 더 유연한 기능과 가격 정책의 솔루션이 필요할 수 있습니다. 그럴 때 개발 인력이 충분하기만 하다면, 언제든 GCP(구글 클라우드 플랫폼)로 확장할 수 있어 이 또한 큰 장점입니다.</p>
<p>Firebase에는 이미 수많은 기능이 구현되어 있고, 이를 사용하기만 하면 서비스에 바로 적용할수 있기 때문에 비교적 손쉬운 구현 방법과 인터넷상에 존재하는 방대한 양의 리소스 역시 장점이라고 생각합니다.</p>
<p>마지막으로, Firestore는 Firebase의 DB 서비스인데요. Firestore가 오프라인 모드를 지원하기 때문에 Core Data와 같이 별도의 로컬 데이터베이스가 필요하지 않았고 이 또한 모바일에 개발 할 때 매우 편리했습니다.</p>
<h2 id="마이그레이션-방법">마이그레이션 방법</h2>
<p>마이그레이션을 위해서 가장 좋은 시나리오는 CloudKit의 iCloud 데이터베이스에서 데이터를 추출해서 Firebase의 Firestore로 옮기는 것입니다. 하지만, iCloud는 데이터 추출을 지원하지 않고 있고 그렇기에 이런 방식으로는 마이그레이션 할 수 없었습니다.</p>
<p>그래서 약간의 우회적인 방법을 사용했습니다. CloudKit에서 사용자의 로컬 DB인 Core Data에 데이터가 들어오면, 그 데이터를 갖고 Firebase로 마이그레이션을 진행하는 것입니다. 즉, CloudKit에서 Core Data로, 그리고 Core Data에서 Firebase로 데이터를 옮기는 것입니다.</p>
<h2 id="마이그레이션-진행">마이그레이션 진행</h2>
<p>앱이 Firebase 마이그레이션 버전을 최초로 실행 할 때 실행할 마이그레이션 함수를 구현해보겠습니다. 우선 제 서비스의 데이터는 사진과 같이 크게 Facials와 Tasks로 나뉘어 있습니다.</p>
<p><img src="/images/migrate-cloudkit-firebase-3.png" alt="migrate-cloukit-firebase"></p>
<p>그렇기 때문에 Firestore에 Facials와 Tasks 컬렉션을 만들어줍니다.</p>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">let</span> database <span class="token operator">=</span> <span class="token class-name">Firestore</span><span class="token punctuation">.</span><span class="token function">firestore</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">collection</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Users"</span></span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">document</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"</span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">user<span class="token punctuation">.</span>id</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">let</span> facialsRef <span class="token operator">=</span> database<span class="token punctuation">.</span><span class="token function">collection</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Facials"</span></span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token keyword">let</span> tasksRef <span class="token operator">=</span> database<span class="token punctuation">.</span><span class="token function">collection</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Tasks"</span></span><span class="token punctuation">)</span>
</span></code></pre>
<p>이제 <code>migrateCloudKit</code>이라는 마이그레이션 함수를 구현해보겠습니다. 우선, parameter로 CoreData 데이터를 각각 받아와 <code>migrateFacials</code>와 <code>migrateTasks</code>에 각각 넣어줍니다.</p>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">migrateCloudKit</span><span class="token punctuation">(</span>coreFacials<span class="token punctuation">:</span> <span class="token class-name">FetchedResults</span><span class="token operator">&#x3C;</span><span class="token class-name">Facials</span><span class="token operator">></span><span class="token punctuation">,</span> coreTasks<span class="token punctuation">:</span> <span class="token class-name">FetchedResults</span><span class="token operator">&#x3C;</span><span class="token class-name">Tasks</span><span class="token operator">></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token function">migrateFacials</span><span class="token punctuation">(</span>coreFacials<span class="token punctuation">:</span> coreFacials<span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token function">migrateTasks</span><span class="token punctuation">(</span>coreTasks<span class="token punctuation">:</span> coreTasks<span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><code>migrateFacials</code>는 이렇게 생겼습니다. CoreData의 모든 Facials 데이터를 돌면서 Firestore에 자료형에 맞게 setData 합니다.</p>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">migrateFacials</span><span class="token punctuation">(</span>coreFacials<span class="token punctuation">:</span> <span class="token class-name">FetchedResults</span><span class="token operator">&#x3C;</span><span class="token class-name">Facials</span><span class="token operator">></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">  coreFacials<span class="token punctuation">.</span>forEach <span class="token punctuation">{</span> coreFacial <span class="token keyword">in</span>
</span><span class="code-line">    <span class="token keyword">let</span> facial <span class="token operator">=</span> facialsRef<span class="token punctuation">.</span><span class="token function">document</span><span class="token punctuation">(</span><span class="token function">UUID</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>uuidString<span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line">    facial<span class="token punctuation">.</span><span class="token function">setData</span><span class="token punctuation">(</span><span class="token punctuation">[</span>
</span><span class="code-line">      <span class="token string-literal"><span class="token string">"value"</span></span><span class="token punctuation">:</span> coreFacial<span class="token punctuation">.</span>value <span class="token comment">// Example</span>
</span><span class="code-line">    <span class="token punctuation">]</span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><code>migrateTasks</code> 역시 비슷한 방식으로 migrate 합니다. 다만, 여기서는 setData가 완료되고 마이그레이션이 끝나면 migrated 키 값을 가진 UserDefaults를 true로 설정합니다. 이렇게 하면, 앱이 다음 번에 실행 될 때 마이그레이션이 일어나지 않습니다.</p>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">migrateTasks</span><span class="token punctuation">(</span>coreTasks<span class="token punctuation">:</span> <span class="token class-name">FetchedResults</span><span class="token operator">&#x3C;</span><span class="token class-name">Tasks</span><span class="token operator">></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">  coreTasks<span class="token punctuation">.</span>forEach <span class="token punctuation">{</span> coreTask <span class="token keyword">in</span>
</span><span class="code-line">    <span class="token keyword">if</span> <span class="token keyword">let</span> uuid <span class="token operator">=</span> coreTask<span class="token punctuation">.</span>id<span class="token operator">?</span><span class="token punctuation">.</span>uuidString <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token keyword">let</span> task <span class="token operator">=</span> tasksRef<span class="token punctuation">.</span><span class="token function">document</span><span class="token punctuation">(</span>uuid<span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">      task<span class="token punctuation">.</span><span class="token function">setData</span><span class="token punctuation">(</span><span class="token punctuation">[</span>
</span><span class="code-line">        <span class="token string-literal"><span class="token string">"due"</span></span><span class="token punctuation">:</span> coreTask<span class="token punctuation">.</span>due <span class="token operator">??</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token comment">// Example</span>
</span><span class="code-line">        <span class="token string-literal"><span class="token string">"text"</span></span><span class="token punctuation">:</span> coreTask<span class="token punctuation">.</span>text <span class="token operator">??</span> <span class="token string-literal"><span class="token string">""</span></span> <span class="token comment">// Example</span>
</span><span class="code-line">      <span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token omit keyword">_</span> <span class="token keyword">in</span>
</span><span class="code-line">        <span class="token comment">// Set migrated to true</span>
</span><span class="code-line">        <span class="token class-name">UserDefaults</span><span class="token punctuation">.</span>standard<span class="token punctuation">.</span><span class="token keyword">set</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">,</span> forKey<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"migrated"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p>SwiftUI 라이프사이클 onAppear에서 마이그레이션 여부에 따라, <code>migrateCloudKit</code>를 실행합니다.</p>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token punctuation">.</span>onAppear <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">if</span> <span class="token operator">!</span><span class="token class-name">UserDefaults</span><span class="token punctuation">.</span>standard<span class="token punctuation">.</span><span class="token function">bool</span><span class="token punctuation">(</span>forKey<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"migrated"</span></span><span class="token punctuation">)</span>  <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token function">migrateCloudKit</span><span class="token punctuation">(</span>coreFacials<span class="token punctuation">:</span> facials<span class="token punctuation">,</span> coreTasks<span class="token punctuation">:</span> tasks<span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p>이렇게 마이그레이션 과정이 끝나면, 기존의 데이터는 모두 Firebase의 Firestore로 이동됩니다. 이제 기존의 CoreData 코드를 Firebase에 맞게 수정해주면 Firebase로의 마이그레이션이 모두 끝납니다.</p>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swiftui-task-modifier</guid>
      <title>SwiftUI task에서 비동기 작업하기</title>
      <description>SwiftUI의 새로운 modifier인 task를 onAppear 대신 사용해 비동기 작업을 실행해봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/swiftui-task-modifier</link>
      <pubDate>Thu, 28 Jul 2022 03:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>이번에는 iOS 15에서 새로 생긴 SwiftUI의 새로운 modifier인 <code>task</code>에 대해서 알아보겠습니다.</li>
<li><code>task</code>는 <code>onAppear</code>에 비교적 적합하지 않았던 비동기 작업을 더 적절하게 실행할수 있게 해줍니다.</li>
</ul>
<h2 id="소개">소개</h2>
<ul>
<li>SwiftUI에서는 네트워크 요청이 필요할때 대부분 View가 생성되는 시점인 <code>onAppear</code>에서 진행했는데요.</li>
<li>이제 네트워크 요청 같이 비동기 작업이 필요한 작업은 <code>onAppear</code>보다 <code>task</code>에서 진행하면 될 것 같습니다.</li>
<li>하지만 <code>task</code>는 iOS 15에서 소개 된 만큼, iOS 15 미만의 버전에서 사용이 불가합니다.</li>
</ul>
<h2 id="정의">정의</h2>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token comment">// Adds a task to perform before this view appears or when a specified value changes.</span>
</span><span class="code-line"><span class="token function">task</span><span class="token punctuation">(</span>id<span class="token punctuation">:</span>priority<span class="token punctuation">:</span><span class="token omit keyword">_</span><span class="token punctuation">:</span><span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li><code>task</code>의 형태와 정의는 다음과 같은데요.</li>
<li>쉽게 말해, <code>task</code>는 view가 나타기 전에 혹은 특정한 값이 변경 될 때 수행할 비동기 작업을 추가합니다.</li>
<li>여기서 특정한 값이란 id에 들어가는 값을 의미합니다.</li>
</ul>
<h2 id="선언부와-리턴-값">선언부와 리턴 값</h2>
<ul>
<li><code>task</code>의 선언부와 리턴 값은 다음과 같은데요.</li>
<li>parameter로 id, priority, 그리고 action이 선택적으로 들어갑니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">task</span><span class="token operator">&#x3C;</span><span class="token class-name">T</span><span class="token operator">></span><span class="token punctuation">(</span>
</span><span class="code-line">    id value<span class="token punctuation">:</span> <span class="token class-name">T</span><span class="token punctuation">,</span>
</span><span class="code-line">    priority<span class="token punctuation">:</span> <span class="token class-name">TaskPriority</span> <span class="token operator">=</span> <span class="token punctuation">.</span>userInitiated<span class="token punctuation">,</span>
</span><span class="code-line">    <span class="token omit keyword">_</span> action<span class="token punctuation">:</span> <span class="token attribute atrule">@escaping</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token operator">-></span> <span class="token class-name">Void</span>
</span><span class="code-line"><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token keyword">where</span> <span class="token class-name">T</span> <span class="token punctuation">:</span> <span class="token class-name">Equatable</span>
</span></code></pre>
<ul>
<li>여기서 id는 <code>Equatable</code>을 준수하는 타입의 값이고 priority는 <code>TaskPriority</code> 타입 값입니다.</li>
<li>action에는 <code>onAppear</code>에서 처럼 실행할 코드를 넣으면 되지만, 비동기 작업을 하는 코드라는 것이 핵심입니다.</li>
<li>return 값으로는 view가 나타나기 전에 비동기 action을 실행하거나 id 값이 변경될때 task를 재시작하는 view가 리턴됩니다.</li>
</ul>
<h2 id="장점">장점</h2>
<ul>
<li><code>task</code>가 <code>onAppear</code>이 있음에도 필요한 이유는 좋은 점이 있기 때문이죠.</li>
<li><code>task</code>의 좋은점은 task가 modifier로 추가된 view의 수명과 일치하는 수명을 갖기 때문입니다.</li>
<li>즉, <code>task</code>에 넣은 작업이 완료되기 전에 View가 사라지면 SwiftUI가 task에 있던 작업을 취소하거나 재실행 해줍니다.</li>
</ul>
<h2 id="예시">예시</h2>
<ul>
<li><code>task</code>를 사용하는 예시를 들어보겠습니다.</li>
<li>우선 Message라는 구조체가 다음과 같이 있습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">Message</span><span class="token punctuation">:</span> <span class="token class-name">Decodable</span><span class="token punctuation">,</span> <span class="token class-name">Identifiable</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> id<span class="token punctuation">:</span> <span class="token class-name">Int</span>
</span><span class="code-line">    <span class="token keyword">let</span> text<span class="token punctuation">:</span> <span class="token class-name">String</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>그리고 다음과 같이 메시지들을 불러오는 비동기 작업을 하는 <code>loadMessages</code>라는 함수가 있습니다.</li>
<li><code>loadMessages</code>와 같은 함수를 실행할때 <code>task</code>에서 실행하면 훨씬 적절한 타이밍에 실행할수 있습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token attribute atrule">@State</span> <span class="token keyword">private</span> <span class="token keyword">var</span> messages <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token class-name">Message</span><span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">          <span class="token class-name">List</span><span class="token punctuation">(</span>messages<span class="token punctuation">)</span> <span class="token punctuation">{</span> message <span class="token keyword">in</span>
</span><span class="code-line">              <span class="token class-name">VStack</span> <span class="token punctuation">{</span>
</span><span class="code-line">                  <span class="token class-name">Text</span><span class="token punctuation">(</span>message<span class="token punctuation">.</span>text<span class="token punctuation">)</span>
</span><span class="code-line">              <span class="token punctuation">}</span>
</span><span class="code-line">          <span class="token punctuation">}</span>
</span><span class="code-line">          <span class="token punctuation">.</span>task <span class="token punctuation">{</span>
</span><span class="code-line">              <span class="token keyword">await</span> <span class="token function">loadMessages</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">          <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">loadMessages</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">do</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">let</span> url <span class="token operator">=</span> <span class="token function">URL</span><span class="token punctuation">(</span>string<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"https://example.com/messages.json"</span></span><span class="token punctuation">)</span><span class="token operator">!</span>
</span><span class="code-line">            <span class="token keyword">let</span> <span class="token punctuation">(</span>data<span class="token punctuation">,</span> <span class="token omit keyword">_</span><span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token keyword">try</span> <span class="token keyword">await</span> <span class="token class-name">URLSession</span><span class="token punctuation">.</span>shared<span class="token punctuation">.</span><span class="token function">data</span><span class="token punctuation">(</span>from<span class="token punctuation">:</span> url<span class="token punctuation">)</span>
</span><span class="code-line">            messages <span class="token operator">=</span> <span class="token keyword">try</span> <span class="token class-name">JSONDecoder</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">decode</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token class-name">Message</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token keyword">self</span><span class="token punctuation">,</span> from<span class="token punctuation">:</span> data<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">{</span>
</span><span class="code-line">            messages <span class="token operator">=</span> <span class="token punctuation">[</span>
</span><span class="code-line">                <span class="token class-name">Message</span><span class="token punctuation">(</span>id<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span> text<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Please try again later."</span></span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">]</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="추가-기능">추가 기능</h2>
<ul>
<li><code>task</code>를 사용하는 효과가 더욱 부각되는 것은 id 값을 활용할 때 입니다.</li>
<li><code>task</code>에 <code>Equatable</code>을 준수하는 id 값을 넣는다고 생각해봅시다.</li>
<li>이 때, id 값이 변경되면 SwiftUI는 자동으로 이전의 작업을 취소하고 새로운 값으로 새 작업을 생성합니다.</li>
<li>예를들어, 다시 한번 다음과 같이 <code>Message</code> 구조체가 있다고 생각해봅시다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">Message</span><span class="token punctuation">:</span> <span class="token class-name">Decodable</span><span class="token punctuation">,</span> <span class="token class-name">Identifiable</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> id<span class="token punctuation">:</span> <span class="token class-name">Int</span>
</span><span class="code-line">    <span class="token keyword">let</span> text<span class="token punctuation">:</span> <span class="token class-name">String</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>이전의 예시와는 다르게, <code>selectedBox</code>라는 변수가 추가 되었습니다.</li>
<li>이는 <code>.task(id: selectedBox)</code>에서 사용되고 있는데요.</li>
<li><code>selectedBox</code>의 값에 따라 다른 url에서 data를 fetch 해오고 작업이 재실행 되는 것을 볼 수 있습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token attribute atrule">@State</span> <span class="token keyword">private</span> <span class="token keyword">var</span> messages <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token class-name">Message</span><span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token attribute atrule">@State</span> <span class="token keyword">private</span> <span class="token keyword">var</span> selectedBox <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"Inbox"</span></span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">let</span> messageBoxes <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string-literal"><span class="token string">"Inbox"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"Sent"</span></span><span class="token punctuation">]</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">NavigationView</span> <span class="token punctuation">{</span>
</span><span class="code-line">          <span class="token class-name">List</span><span class="token punctuation">(</span>messages<span class="token punctuation">)</span> <span class="token punctuation">{</span> message <span class="token keyword">in</span>
</span><span class="code-line">              <span class="token class-name">VStack</span> <span class="token punctuation">{</span>
</span><span class="code-line">                  <span class="token class-name">Text</span><span class="token punctuation">(</span>message<span class="token punctuation">.</span>text<span class="token punctuation">)</span>
</span><span class="code-line">              <span class="token punctuation">}</span>
</span><span class="code-line">          <span class="token punctuation">}</span>                    
</span><span class="code-line">          <span class="token punctuation">.</span><span class="token function">task</span><span class="token punctuation">(</span>id<span class="token punctuation">:</span> selectedBox<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">              <span class="token keyword">await</span> <span class="token function">fetchData</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">          <span class="token punctuation">}</span>
</span><span class="code-line">            
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">fetchData</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">do</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">let</span> url <span class="token operator">=</span> <span class="token function">URL</span><span class="token punctuation">(</span>string<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"https://example.com/</span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">selectedBox<span class="token punctuation">.</span><span class="token function">lowercased</span><span class="token punctuation">(</span><span class="token punctuation">)</span></span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">.json"</span></span><span class="token punctuation">)</span><span class="token operator">!</span>
</span><span class="code-line">            <span class="token keyword">let</span> <span class="token punctuation">(</span>data<span class="token punctuation">,</span> <span class="token omit keyword">_</span><span class="token punctuation">)</span> <span class="token operator">=</span> <span class="token keyword">try</span> <span class="token keyword">await</span> <span class="token class-name">URLSession</span><span class="token punctuation">.</span>shared<span class="token punctuation">.</span><span class="token function">data</span><span class="token punctuation">(</span>from<span class="token punctuation">:</span> url<span class="token punctuation">)</span>
</span><span class="code-line">            messages <span class="token operator">=</span> <span class="token keyword">try</span> <span class="token class-name">JSONDecoder</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">decode</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token class-name">Message</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token keyword">self</span><span class="token punctuation">,</span> from<span class="token punctuation">:</span> data<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">{</span>
</span><span class="code-line">            messages <span class="token operator">=</span> <span class="token punctuation">[</span>
</span><span class="code-line">                <span class="token class-name">Message</span><span class="token punctuation">(</span>id<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span> text<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Please try again later."</span></span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">]</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>추가적으로, <code>task</code> modifier는 priority 파라미터도 존재해서 task의 우선순위도 정해줄수 있습니다.</li>
<li>예를들어, <code>.task(priority: .low)</code>는 낮은 우선 순위의 작업을 생성 할 것입니다.</li>
</ul>
<h2 id="참고">참고</h2>
<ul>
<li><a href="https://developer.apple.com/documentation/swiftui/view/task(id:priority:_:)">애플 공식 문서</a></li>
<li><a href="https://www.hackingwithswift.com/quick-start/concurrency/how-to-run-tasks-using-swiftuis-task-modifier">Hacking with Swift</a></li>
</ul>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swift-generics</guid>
      <title>Swift Generics와 타입 시스템</title>
      <description>Swift의 Generics와 Type system에 대해 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/swift-generics</link>
      <pubDate>Sat, 16 Jul 2022 20:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>이번에는 Swift에서의 Generics에 대해 알아보겠습니다.</li>
<li>Generics는 Swift가 타입 시스템이기에 더욱 필요한데요.</li>
</ul>
<h2 id="swift-타입-시스템">Swift 타입 시스템</h2>
<ul>
<li>Swift는 타입 시스템을 가진 프로그래밍 언어입니다.</li>
<li>그래서 아래와 같은 코드는 빌드 에러를 리턴합니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">sum</span><span class="token punctuation">(</span>a<span class="token punctuation">:</span> <span class="token class-name">Int</span><span class="token punctuation">,</span> b<span class="token punctuation">:</span> <span class="token class-name">Int</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">return</span> a <span class="token operator">+</span> b
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token function">sum</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">)</span> <span class="token comment">// return 3</span>
</span><span class="code-line"><span class="token function">sum</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"1"</span></span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span> <span class="token comment">// build error</span>
</span><span class="code-line"><span class="token number">1</span> <span class="token operator">==</span> <span class="token string-literal"><span class="token string">"1"</span></span>  <span class="token comment">// build error</span>
</span></code></pre>
<h2 id="타입-시스템의-장단점">타입 시스템의 장단점</h2>
<ul>
<li>타입 시스템을 가진 언어는 더 안전하고, 버그가 없는 프로그램을 만들 수 있게 해줍니다.</li>
<li>하지만, 다양한 케이스를 일일히 다뤄줘야 한다는 단점도 있는데요.</li>
<li>아래와 같이 두 숫자를 더하는 함수만 봐도 그렇습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">sum</span><span class="token punctuation">(</span>a<span class="token punctuation">:</span> <span class="token class-name">Int</span><span class="token punctuation">,</span> b<span class="token punctuation">:</span> <span class="token class-name">Int</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Int</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">return</span> a <span class="token operator">+</span> b 
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">sum</span><span class="token punctuation">(</span>a<span class="token punctuation">:</span> <span class="token class-name">Double</span><span class="token punctuation">,</span> b<span class="token punctuation">:</span> <span class="token class-name">Double</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Double</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">return</span> a <span class="token operator">+</span> b
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">sum</span><span class="token punctuation">(</span>a<span class="token punctuation">:</span> <span class="token class-name">CGFloat</span><span class="token punctuation">,</span> b<span class="token punctuation">:</span> <span class="token class-name">CGFloat</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">CGFloat</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">return</span> a <span class="token operator">+</span> b
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="generic-function">Generic Function</h2>
<ul>
<li>이러한 타입 시스템의 단점을 보완하기 위해 Generics가 존재합니다.</li>
<li>Generics를 사용해 만든, 두 숫자를 더하는 아래의 함수를 봅시다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">sum</span><span class="token operator">&#x3C;</span><span class="token class-name">T</span><span class="token punctuation">:</span> <span class="token class-name">Summable</span><span class="token operator">></span><span class="token punctuation">(</span>a<span class="token punctuation">:</span> <span class="token class-name">T</span><span class="token punctuation">,</span> b<span class="token punctuation">:</span> <span class="token class-name">T</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">T</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">return</span> a <span class="token operator">+</span> b
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>이러한 함수를 "Generic Function"이라고 부릅니다.</li>
</ul>
<h2 id="swift-generics">Swift Generics</h2>
<ul>
<li>Generic Type이라는 것도 있는데요.</li>
<li>애플의 Foundation에서 쓰이는 많은 클래스들도 Generic Type 입니다.</li>
<li>Stack 자료 구조로 예를 들어보겠습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">Stack</span><span class="token operator">&#x3C;</span><span class="token class-name">Element</span><span class="token operator">></span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">var</span> list<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">Element</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
</span><span class="code-line">  
</span><span class="code-line">  <span class="token keyword">func</span> <span class="token function-definition function">push</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> element<span class="token punctuation">:</span> <span class="token class-name">Element</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    list<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>element<span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">  <span class="token keyword">func</span> <span class="token function-definition function">pop</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Element</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">return</span> list<span class="token punctuation">.</span><span class="token function">popLast</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">}</span> 
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>이런식으로, 초기화 할 때 지정해주는 타입을 Generic Type이라고 하고 Array, Dictionary 등도 이에 속합니다.</li>
</ul>
<h2 id="type-constraint">Type Constraint</h2>
<ul>
<li>Generic의 Type을 제약(Constraint)하기 위해서는 어떤 클래스나 프로토콜을 콜론과 함께 위치시키면 됩니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">someFunction</span><span class="token operator">&#x3C;</span><span class="token class-name">T</span><span class="token punctuation">:</span> <span class="token class-name">SomeClass</span><span class="token punctuation">,</span> <span class="token class-name">U</span><span class="token punctuation">:</span> <span class="token class-name">SomeProtocol</span><span class="token operator">></span><span class="token punctuation">(</span>someT<span class="token punctuation">:</span> <span class="token class-name">T</span><span class="token punctuation">,</span> someU<span class="token punctuation">:</span> <span class="token class-name">U</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token comment">// 함수 본문 코드</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="associated-type">Associated Type</h2>
<ul>
<li>이 부분은 지난 글 <a href="/blog/swift-associated-type/">Swift의 Associated Type</a>을 참고해주세요!</li>
</ul>
<h2 id="generic-where-절">Generic Where 절</h2>
<ul>
<li>Generic Where 절(clause)로는 연관 타입이 특정 조건을 준수하도록 할 수 있습니다.</li>
<li>다음 예시에서는 두 컨테이너가 동일한 타입의 컨테이너일 필요는 없지만, 동일한 타입의 아이템들을 가지고 있어야 합니다.</li>
<li>이 조건은 Type Constraint와 Generic Where 절의 조합으로 표현이 가능합니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">allItemsMatch</span><span class="token operator">&#x3C;</span>C1<span class="token punctuation">:</span> <span class="token class-name">Container</span><span class="token punctuation">,</span> C2<span class="token punctuation">:</span> <span class="token class-name">Container</span><span class="token operator">></span>
</span><span class="code-line"><span class="token punctuation">(</span><span class="token omit keyword">_</span> someContainer<span class="token punctuation">:</span> C1<span class="token punctuation">,</span> <span class="token omit keyword">_</span> anotherContainer<span class="token punctuation">:</span> C2<span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Bool</span>
</span><span class="code-line"><span class="token keyword">where</span> C1<span class="token punctuation">.</span><span class="token class-name">Item</span> <span class="token operator">==</span> C2<span class="token punctuation">.</span><span class="token class-name">Item</span><span class="token punctuation">,</span> C1<span class="token punctuation">.</span><span class="token class-name">Item</span><span class="token punctuation">:</span> <span class="token class-name">Equatable</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token comment">// 함수 본문 코드</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="참고">참고</h2>
<ul>
<li><a href="https://docs.swift.org/swift-book/LanguageGuide/Generics.html">Swift 공식 사이트</a></li>
</ul>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swift-various-property</guid>
      <title>Swift의 다양한 Property</title>
      <description>Swift의 저장 프로퍼티, 연산 프로퍼티, 타입 프로퍼티 등 다양한 프로퍼티에 대해 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/swift-various-property</link>
      <pubDate>Thu, 14 Jul 2022 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>Property는 변수의 다른 이름입니다.</li>
<li>클래스, 구조체, 열거 등 전체적으로 사용되는 변수를 프로퍼티라고 부릅니다.</li>
<li>Property의 종류에는 저장 프로퍼티, 연산 프로퍼티, 타입 프로퍼티가 있습니다.</li>
<li>순서대로 하나씩 알아보겠습니다.</li>
</ul>
<h2 id="저장-프로퍼티">저장 프로퍼티</h2>
<ul>
<li>저장 프로퍼티는 가장 일반적인 프로퍼티로써, 값을 저장하는 용도로 사용됩니다.</li>
<li>초기값을 설정 할 수 있고, 클래스 구조체에서는 인스턴스와 연관된 값을 저장합니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">let</span> name <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"Hohyeon Moon"</span></span>
</span><span class="code-line"><span class="token keyword">var</span> age <span class="token operator">=</span> <span class="token number">25</span>
</span></code></pre>
<h2 id="지연-저장-프로퍼티">지연 저장 프로퍼티</h2>
<ul>
<li>지연 저장 프로퍼티는 프로퍼티가 처음으로 사용되기 전까지 초기값이 계산되지 않는 특성을 갖고 있습니다.</li>
<li>lazy 키워드를 선언 앞에 작성해서 사용할 수 있고, let은 지연 저장 프로퍼티로 사용할 수 없습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">Position</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">lazy</span> <span class="token keyword">var</span> point<span class="token punctuation">:</span> <span class="token class-name">CoordinatePoint</span> <span class="token operator">=</span> <span class="token class-name">CoordinatePoint</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="연산-프로퍼티">연산 프로퍼티</h2>
<ul>
<li>실제로 값을 저장하지는 않고, get과 set 키워드로 값을 간접적으로 설정하거나 받는 프로퍼티입니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">var</span> wallet<span class="token punctuation">:</span> <span class="token class-name">Int</span> <span class="token operator">=</span> <span class="token number">10000</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">var</span> counter<span class="token punctuation">:</span> <span class="token class-name">Int</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">get</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">return</span> wallet
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">set</span><span class="token punctuation">(</span>money<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        wallet <span class="token operator">+=</span> money
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="타입-프로퍼티">타입 프로퍼티</h2>
<ul>
<li>타입 프로퍼티로는 인스턴스의 속성이 아닌, 타입에 따른 속성을 정의할 수 있습니다.</li>
<li>static 키워드를 사용해서 값 타입에서 타입 프로퍼티를 설정할 수 있고,</li>
<li>class 키워드를 사용해서 클래스 타입에서 타입 프로퍼티를 설정할 수 있습니다.</li>
<li>값을 가져올때는 클래스의 이름을 통해서 가져올 수 있습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">AudioChannel</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">static</span> <span class="token keyword">let</span> level <span class="token operator">=</span> <span class="token number">10</span>
</span><span class="code-line">    <span class="token keyword">static</span> <span class="token keyword">var</span> maxLevel <span class="token operator">=</span> <span class="token number">0</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token function">print</span><span class="token punctuation">(</span><span class="token class-name">AudioChannel</span><span class="token punctuation">.</span>level<span class="token punctuation">)</span> 
</span><span class="code-line"><span class="token function">print</span><span class="token punctuation">(</span><span class="token class-name">AudioChannel</span><span class="token punctuation">.</span>maxLevel<span class="token punctuation">)</span>
</span></code></pre>
<h2 id="프로퍼티-옵저버">프로퍼티 옵저버</h2>
<ul>
<li>Property Observers는 프로퍼티의 값이 변경 될 때 지정된 코드를 실행해줍니다.</li>
<li>Lazy 프로퍼티에는 사용 될 수 없고, 저장 프로티에서만 사용이 가능합니다.</li>
<li>Property의 값이 변경되기 직전에 willSet이 호출되고, 변경된 직후에는 didSet이 호출됩니다.</li>
<li>willSet에서는 newValue가, didSet에서는 oldValue가 자동으로 전달됩니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">Account</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> credit<span class="token punctuation">:</span> <span class="token class-name">Int</span> <span class="token operator">=</span> <span class="token number">0</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">willSet</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"잔액이 </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">credit</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">에서 </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">newValue</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">원으로 변경될 예정입니다."</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">didSet</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"잔액이 </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">oldValue</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">에서 </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">credit</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">으로 변경되었습니다."</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">let</span> myAccount <span class="token operator">=</span> <span class="token class-name">Account</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">myAccount<span class="token punctuation">.</span>credit <span class="token operator">=</span> <span class="token number">1000</span>
</span></code></pre>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swift-async-await</guid>
      <title>Swift 5.5의 async/await</title>
      <description>Swift 5.5에서 공개되어 비동기 프로그래밍을 도와주는 async/await를 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/swift-async-await</link>
      <pubDate>Wed, 13 Jul 2022 18:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>Swift 5.5에서 추가적인 비동기 프로그래밍 방법인 <code>async/await</code>가 등장했습니다.</li>
<li>이는 Swift에서 비동기 프로그래밍을 할 때 있었던 몇 가지 문제를 해결했습니다.</li>
</ul>
<h2 id="기존-문제점">기존 문제점</h2>
<p>Swift에서 비동기 프로그래밍을 할 때는 다음과 같은 문제점이 있었습니다.</p>
<ul>
<li>Nested closures로 코드가 복잡해집니다.</li>
<li>에러 핸들링 코드가 장황해집니다.</li>
<li>코드를 이해하기 어려워 실수하기 쉽습니다.</li>
</ul>
<h2 id="해결">해결</h2>
<ul>
<li><code>async/await</code>로 이러한 문제를 해결하고 간편하게 코드를 작성할수 있게되었습니다.</li>
<li>다음과 같이 <code>fetchWeatherHistory</code> 이후에 <code>upload</code>가 되어야 하는 경우에도 <code>async/await</code>로 해결 할 수 있습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">fetchWeatherHistory</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token operator">-></span> <span class="token punctuation">[</span><span class="token class-name">Double</span><span class="token punctuation">]</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
</span><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">upload</span><span class="token punctuation">(</span>result<span class="token punctuation">:</span> <span class="token class-name">Double</span><span class="token punctuation">)</span> <span class="token keyword">async</span> <span class="token operator">-></span> <span class="token class-name">String</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">processWeather</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">let</span> records <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">fetchWeatherHistory</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token keyword">let</span> response <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">upload</span><span class="token punctuation">(</span>result<span class="token punctuation">:</span> average<span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>더 구체적인 사용 예시는 <a href="/blog/combine-to-async-await">Combine에서 async/await로 변경하기</a>를 확인해주세요.</li>
</ul>
<h2 id="호환성">호환성</h2>
<ul>
<li>Xcode 13.2부터 async/await의 backward compatibility를 지원합니다.</li>
<li>iOS 13, macOS 10.15, watchOS 6, tvOS 13부터 async/await 사용이 가능합니다.</li>
</ul>
<h2 id="참고">참고</h2>
<ul>
<li><a href="https://zeddios.tistory.com/1230">Zeddios Tistory</a></li>
<li><a href="https://swiftbysundell.com/special/swift-concurrency-backward-compatibility/">Swift by Sundell</a></li>
<li><a href="https://www.hackingwithswift.com/swift/5.5/async-await">Hacking with Swift</a></li>
</ul>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swift-associated-type</guid>
      <title>Swift의 Associated Type</title>
      <description>Swift의 Protocol에서 사용되는 Associated Type에 대해 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/swift-associated-type</link>
      <pubDate>Tue, 12 Jul 2022 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>Swift의 Associated Type에 대해 알기 위해서는 기본적으로 Protocol을 알고 있어야합니다.</li>
<li>Associated Type은 Protocol을 Generic 하게 사용할수 있게 도와주는데요.</li>
<li>Protocol에서 사용되는 타입을 위한 플레이스홀더 역할을 합니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">protocol</span> <span class="token class-name">ItemStoring</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">associatedtype</span> <span class="token class-name">DataType</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">var</span> items<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">DataType</span><span class="token punctuation">]</span> <span class="token punctuation">{</span> <span class="token keyword">get</span> <span class="token keyword">set</span> <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token keyword">mutating</span> <span class="token keyword">func</span> <span class="token function-definition function">add</span><span class="token punctuation">(</span>item<span class="token punctuation">:</span> <span class="token class-name">DataType</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>ItemStoring 프로토콜을 예시로 시작해봅시다.</li>
<li>여기서 DataType이 Associated Type입니다.</li>
<li>이를 items와 add 함수가 사용하고 있는데요.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">ItemStoring</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">mutating</span> <span class="token keyword">func</span> <span class="token function-definition function">add</span><span class="token punctuation">(</span>item<span class="token punctuation">:</span> <span class="token class-name">DataType</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        items<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>item<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>DataType을 사용해 extension에서 add 함수 기본 구현을 할 수도 있습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">NameDatabase</span><span class="token punctuation">:</span> <span class="token class-name">ItemStoring</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> items <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token class-name">String</span><span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>Associated Type의 장점을 이제 볼 수 있는데요.</li>
<li>ItemStoring 프로토콜을 준수하는 struct를 만들어봤습니다.</li>
<li>다음과 같이만 작성해도 DataType이 String임을 Swift는 알고, 이에 맞게 코드가 작동합니다.</li>
</ul>
<h2 id="참고">참고</h2>
<ul>
<li><a href="https://www.hackingwithswift.com/example-code/language/what-is-a-protocol-associated-type">Hacking with Swift</a></li>
<li><a href="https://docs.swift.org/swift-book/LanguageGuide/Protocols.html">Swift.org Docs</a></li>
</ul>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swift-swiftui</guid>
      <title>SwiftUI를 위한 Swift 5.1 기능</title>
      <description>SwiftUI를 위해서 추가된 Swift의 기능들에 대해 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/swift-swiftui</link>
      <pubDate>Wed, 15 Jun 2022 18:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<h2 id="opaque-리턴-타입">Opaque 리턴 타입</h2>
<ul>
<li>SwiftUI에서 <code>some</code>이라는 키워드가 눈에 띄었다.</li>
<li><code>some</code>은 opaque 리턴 타입을 선언할 수 있게 해준다.</li>
<li>즉, <code>some</code>을 통해 generic한 protocol도 리턴 타입으로 사용될 수 있다.</li>
<li>가장 대표적으로, <code>some</code>은 SwiftUI의 body에서 사용된다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Hello, world!"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li><code>some</code>이 없었다면, 아래와 같이 특정 View 타입을 지정해주거나</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token class-name">Text</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Hello, world!"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>AnyView를 사용해 타입을 지워야한다.</li>
<li>그러면 리턴할때마다 타입을 다음과 같이 지워야한다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token class-name">AnyView</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">AnyView</span><span class="token punctuation">(</span><span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Hello, world!"</span></span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="return-생략">return 생략</h2>
<ul>
<li>단일 표현 함수는 return 키워드를 생략할 수 있다.</li>
<li>아래의 두 코드는 동일하게 작동한다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">return</span> <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Hello, world!"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Hello, world!"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="function-builders">Function builders</h2>
<blockquote>
<p>23년 10월 기준 Function Builder는 ResultBuilder로 대체 됨.</p>
</blockquote>
<ul>
<li><code>some</code> 키워드나 return 키워드 생략은 View에 대해 이해가 가능하게 해준다.</li>
<li>하지만 여전히 <code>VStack</code>, <code>HStack</code>, <code>Group</code>에 대한 이해는 불가능하다.</li>
<li>아래와 같은 코드가 return이나 추가 문법 없이 어떻게 하나로 묶이는지 설명이 안된다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">HeaderView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> image<span class="token punctuation">:</span> <span class="token class-name">UIImage</span>
</span><span class="code-line">    <span class="token keyword">let</span> title<span class="token punctuation">:</span> <span class="token class-name">String</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">VStack</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token class-name">Image</span><span class="token punctuation">(</span>uiImage<span class="token punctuation">:</span> image<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token class-name">Text</span><span class="token punctuation">(</span>title<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>function builder(현재는 @resultBuilder)가 이를 설명해준다.</li>
<li>이에 대한 자세한 설명은, <a href="https://developer.apple.com/documentation/swiftui/viewbuilder">애플 공식 문서</a>를 참고하자.</li>
</ul>
<h2 id="property-wrappers">Property wrappers</h2>
<ul>
<li>property wrapper는 말그대로 property 값이 자동으로 wrap되는 기능이다.</li>
<li>SwiftUI에서는 이를 통해, bindable property들을 쉽게 정의할수 있게 도와준다.</li>
<li><code>@State</code>가 하나의 예시가 될 수 있다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">Setting</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token attribute atrule">@State</span> <span class="token keyword">var</span> save<span class="token punctuation">:</span> <span class="token class-name">Bool</span>
</span><span class="code-line">    <span class="token attribute atrule">@State</span> <span class="token keyword">var</span> enable<span class="token punctuation">:</span> <span class="token class-name">Bool</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">return</span> <span class="token class-name">VStack</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token class-name">Toggle</span><span class="token punctuation">(</span>isOn<span class="token punctuation">:</span> $save<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">                <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Save"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">            <span class="token class-name">Toggle</span><span class="token punctuation">(</span>isOn<span class="token punctuation">:</span> $enable<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">                <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Enable"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>위 예시와 같이 <code>@State</code>는 property의 값을 State 타입으로 wrap 해준다.</li>
<li>여기서 property wrapper이 없었다면 아래와 같이 작성해야 할 것이다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">Setting</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> save<span class="token punctuation">:</span> <span class="token class-name">State</span><span class="token operator">&#x3C;</span><span class="token class-name">Bool</span><span class="token operator">></span>
</span><span class="code-line">    <span class="token keyword">var</span> enable<span class="token punctuation">:</span> <span class="token class-name">State</span><span class="token operator">&#x3C;</span><span class="token class-name">Bool</span><span class="token operator">></span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">return</span> <span class="token class-name">VStack</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token class-name">Toggle</span><span class="token punctuation">(</span>isOn<span class="token punctuation">:</span> save<span class="token punctuation">.</span>binding<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">                <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Save"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">            <span class="token class-name">Toggle</span><span class="token punctuation">(</span>isOn<span class="token punctuation">:</span> enable<span class="token punctuation">.</span>binding<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">                <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Enable"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>SwiftUI의 State 구조체는 다음과 같이 단순화 시킬 수 있기 때문이다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token attribute atrule">@propertyWrapper</span>
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">State</span><span class="token operator">&#x3C;</span><span class="token class-name">Value</span><span class="token operator">></span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">init</span><span class="token punctuation">(</span>initialValue<span class="token punctuation">:</span> <span class="token class-name">Value</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token operator">...</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">var</span> wrappedValue<span class="token punctuation">:</span> <span class="token class-name">Value</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">get</span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token keyword">set</span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swiftui-tutorial-preview</guid>
      <title>SwiftUI Preview 사용하기</title>
      <description>다양한 디바이스에서 SwiftUI를 Preview 하는 방법에 대해 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/swiftui-tutorial-preview</link>
      <pubDate>Tue, 07 Jun 2022 18:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>이번에는 다양한 디바이스에서 SwiftUI를 Preview 하는 방법에 대해 알아보겠습니다.</li>
</ul>
<h2 id="macro-preview">Macro Preview</h2>
<blockquote>
<p>Xcode 15와 Swift 5.9 이후, Swift의 Macro를 통해 더 쉽게 Preview를 할 수 있게 되었습니다.</p>
</blockquote>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token other-directive property">#Preview</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">ContentView</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token other-directive property">#Preview</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Hello World!"</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">ContentView</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="swiftui-preview">SwiftUI Preview</h2>
<ul>
<li>기본적으로 SwiftUI의 Preview는 각 SwiftUI 파일 하단에 작성되어 있습니다.</li>
<li>Xcode에서 처음 SwiftUI 파일을 생성하면 다음과 같은 코드가 하단에 있을 것입니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView_Previews</span><span class="token punctuation">:</span> <span class="token class-name">PreviewProvider</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">static</span> <span class="token keyword">var</span> previews<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">ContentView</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="다양한-기기에서-preview-하기">다양한 기기에서 Preview 하기</h2>
<ul>
<li>설정에 따라 다르겠지만, Preview 하면 기본적으로 보여주는 기기가 각자 있을 것입니다.</li>
<li>다른 기기에서 Preview 하기 위해서는 다음과 같이 코드를 변경하면 됩니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">ContentView</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">.</span><span class="token function">previewDevice</span><span class="token punctuation">(</span><span class="token class-name">PreviewDevice</span><span class="token punctuation">(</span>rawValue<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"iPhone SE"</span></span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span></code></pre>
<h2 id="한-번에-여러기기에서-preview-하기">한 번에 여러기기에서 Preview 하기</h2>
<ul>
<li>여러기기의 Preview를 한 화면에 한 번에 볼 수도 있습니다.</li>
<li>다음과 같이 여러개의 ContentView를 Group으로 감싸주면 됩니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView_Previews</span><span class="token punctuation">:</span> <span class="token class-name">PreviewProvider</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">static</span> <span class="token keyword">var</span> previews<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">Group</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token class-name">ContentViewOne</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token class-name">ContentViewTwo</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>코드를 실행해보면 다음과 같이 됩니다.</li>
</ul>
<p><img src="/images/swiftui-tutorial-preview-1.gif" alt="swiftui-tutorial-preview"></p>
<h2 id="preview-dark-mode">Preview Dark Mode</h2>
<ul>
<li>기기의 상태가 Dark Mode 환경일 때를 Preview 할 수도 있습니다.</li>
<li>다음과 같이 Preview 코드를 작성하면 됩니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView_Previews</span><span class="token punctuation">:</span> <span class="token class-name">PreviewProvider</span> <span class="token punctuation">{</span>
</span><span class="code-line"> <span class="token keyword">static</span> <span class="token keyword">var</span> previews<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token class-name">Group</span> <span class="token punctuation">{</span>
</span><span class="code-line">   <span class="token class-name">ContentViewOne</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">.</span><span class="token function">environment</span><span class="token punctuation">(</span><span class="token punctuation">\</span><span class="token punctuation">.</span>colorScheme<span class="token punctuation">,</span> <span class="token punctuation">.</span>light<span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">   <span class="token class-name">ContentViewTwo</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">.</span><span class="token function">environment</span><span class="token punctuation">(</span><span class="token punctuation">\</span><span class="token punctuation">.</span>colorScheme<span class="token punctuation">,</span> <span class="token punctuation">.</span>dark<span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"> <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><img src="/images/swiftui-tutorial-preview-2.gif" alt="swiftui-tutorial-preview"></p>
<h2 id="마무리">마무리</h2>
<ul>
<li>이렇게 해서 다양한 디바이스에서 SwiftUI를 Preview 하는 방법에 대해 알아봤습니다.</li>
</ul>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swiftui-tutorial-uikit</guid>
      <title>SwiftUI와 UIKit 같이 사용하기</title>
      <description>SwiftUI와 UIKit을 같이 사용하는 방법에 대해 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/swiftui-tutorial-uikit</link>
      <pubDate>Sun, 29 May 2022 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>SwiftUI와 UIKit은 같이 사용될 수 있습니다.</li>
<li>SwiftUI는 ViewController에 embed 될 수 있는데요.</li>
<li>반대로 UIKit View 역시 SwiftUI에서 사용되도록 개조될 수 있습니다.</li>
</ul>
<h2 id="swiftui-to-uikit">SwiftUI to UIKit</h2>
<ul>
<li>SwiftUI View는 다음과 같이 쉽게 UIKit에서 사용할 수 있습니다.</li>
<li>기본적으로, UIHostingController로 SwiftUI를 감싸서 사용하면 됩니다.</li>
</ul>
<h3 id="uiviewcontroller로-사용하기">UIViewController로 사용하기</h3>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">let</span> vc <span class="token operator">=</span> <span class="token class-name">UIHostingController</span><span class="token punctuation">(</span>rootView<span class="token punctuation">:</span> <span class="token class-name">MyView</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>UIHostingController는 UIViewController를 상속합니다.</li>
<li>그래서 UIHostingController를 UIViewController로 바로 사용하면 됩니다.</li>
</ul>
<h3 id="uiview로-사용하기">UIView로 사용하기</h3>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">let</span> childView <span class="token operator">=</span> <span class="token class-name">UIHostingController</span><span class="token punctuation">(</span>rootView<span class="token punctuation">:</span> <span class="token class-name">MyView</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token function">addChild</span><span class="token punctuation">(</span>childView<span class="token punctuation">)</span>
</span><span class="code-line">childView<span class="token punctuation">.</span>view<span class="token punctuation">.</span>frame <span class="token operator">=</span> frame
</span><span class="code-line">view<span class="token punctuation">.</span><span class="token function">addSubview</span><span class="token punctuation">(</span>childView<span class="token punctuation">.</span>view<span class="token punctuation">)</span>
</span><span class="code-line">childView<span class="token punctuation">.</span><span class="token function">didMove</span><span class="token punctuation">(</span>toParent<span class="token punctuation">:</span> <span class="token keyword">self</span><span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>SwiftUI View를 UIView로 사용할수도 있습니다.</li>
<li>Interface Builder의 Container View를 사용하거나, 위와 같이 programmatically 사용합니다.</li>
</ul>
<h2 id="uikit-to-swiftui">UIKit to SwiftUI</h2>
<ul>
<li>반대로, UIKit도 다음과 같이 SwiftUI에서 사용할 수 있습니다.</li>
<li>기존 UI 타입에 따라 해당하는 프로토콜을 준수해 사용할수 있습니다.</li>
</ul>
<p><img src="/images/swiftui-tutorial-uikit-1.png" alt="swiftui-tutorial-uikit"></p>
<h3 id="uiview-예시">UIView 예시</h3>
<ul>
<li>UIView를 예시로 SwiftUI에서 사용해보겠습니다.</li>
<li>UIViewRepresentable를 conform하는 wrapper를 만들면 여타 SwiftUI view와 같이 작동하게 됩니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">MySwiftUIView</span><span class="token punctuation">:</span> <span class="token class-name">UIViewRepresentable</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">func</span> <span class="token function-definition function">makeUIView</span><span class="token punctuation">(</span>context<span class="token punctuation">:</span> <span class="token class-name">Context</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">UIView</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token comment">// View를 원하는대로 생성하는 곳</span>
</span><span class="code-line">    <span class="token keyword">let</span> view <span class="token operator">=</span> <span class="token class-name">UIView</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">return</span> view
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line">  
</span><span class="code-line">  <span class="token keyword">func</span> <span class="token function-definition function">updateUIView</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> view<span class="token punctuation">:</span> <span class="token class-name">UIView</span><span class="token punctuation">,</span> context<span class="token punctuation">:</span> <span class="token class-name">Context</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token comment">// View를 원하는대로 수정하는 곳</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h3 id="coordinator-사용하기">Coordinator 사용하기</h3>
<ul>
<li>Coordinator로 더 심화된 작업도 할 수 있습니다.</li>
<li>예를들어, UIKit의 DataSource나 Delegate을 사용할수 있습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">MySwiftUIView</span><span class="token punctuation">:</span> <span class="token class-name">UIViewControllerRepresentable</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">func</span> <span class="token function-definition function">makeCoordinator</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Coordinator</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token class-name">Coordinator</span><span class="token punctuation">(</span><span class="token keyword">self</span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">  <span class="token keyword">func</span> <span class="token function-definition function">makeUIViewController</span><span class="token punctuation">(</span>context<span class="token punctuation">:</span> <span class="token class-name">Context</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">UIViewController</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> viewController <span class="token operator">=</span> <span class="token class-name">UIViewController</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">return</span> viewController
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">  <span class="token keyword">func</span> <span class="token function-definition function">updateUIViewController</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> uiViewController<span class="token punctuation">:</span> <span class="token class-name">UIViewController</span><span class="token punctuation">,</span> context<span class="token punctuation">:</span> <span class="token class-name">Context</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token comment">// ViewController를 원하는대로 수정하는 곳</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line">  
</span><span class="code-line">  <span class="token keyword">class</span> <span class="token class-name">Coordinator</span><span class="token punctuation">:</span> <span class="token class-name">NSObject</span><span class="token punctuation">,</span> <span class="token class-name">UITableViewDataSource</span><span class="token punctuation">,</span> <span class="token class-name">UITableViewDelegate</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> parent<span class="token punctuation">:</span> <span class="token class-name">UIViewController</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">init</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> viewController<span class="token punctuation">:</span> <span class="token class-name">UIViewController</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">self</span><span class="token punctuation">.</span>parent <span class="token operator">=</span> viewController
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token comment">// TableView DataSource, Delegate</span>
</span><span class="code-line">  <span class="token punctuation">}</span>  
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h3 id="myswiftuiview-사용하기">MySwiftUIView 사용하기</h3>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">MyView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">MySwiftUIView</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h3 id="라이프사이클">라이프사이클</h3>
<ul>
<li>Initialization: <code>makeCoordinator()</code> → <code>makeXXX()</code> → <code>updateXXX()</code></li>
<li>Update: <code>updateXXX()</code></li>
<li>Deinitialization: <code>dismantleXXX()</code></li>
</ul>
<h2 id="마무리">마무리</h2>
<ul>
<li>이렇게 해서 SwiftUI와 UIKit을 같이 사용하는 방법에 대해 알아봤습니다.</li>
</ul>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swiftui-data-flow</guid>
      <title>SwiftUI의 데이터 흐름</title>
      <description>Property Wrapper를 이용한 SwiftUI에서의 데이터 흐름에 대하여</description>
      <link>https://www.hohyeonmoon.com/blog/swiftui-data-flow</link>
      <pubDate>Sat, 28 May 2022 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>SwiftUI에서의 데이터 흐름과 라이프사이클을 알아보고자 합니다.</li>
<li>SwiftUI 데이터 흐름에 대해서는 애플의 <a href="https://developer.apple.com/videos/play/wwdc2019/226/">WWDC19</a>와 <a href="https://developer.apple.com/videos/play/wwdc2020/10040/">WWDC20</a> 영상이 있습니다.</li>
<li>WWDC23 이후 완전히 개편된 간편해진 데이터 사용 방법에 <a href="https://developer.apple.com/documentation/swiftui/migrating-from-the-observable-object-protocol-to-the-observable-macro">공식 문서</a>도 있습니다.</li>
</ul>
<h2 id="swiftui-라이프사이클">SwiftUI 라이프사이클</h2>
<ul>
<li>SwiftUI에는 View의 상태를 나타내는 라이프사이클이 아래와 같이 단 두가지 밖에 없습니다.</li>
<li>대신 상태를 나타내는 다양한 Property Wrapper가 존재해 Data 흐름에 대한 여러 상태에 대응할 수 있습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token punctuation">.</span>onAppear <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"View appeared"</span></span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token punctuation">.</span>onDisappear <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"View disappeared"</span></span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="wwdc-23-이후">WWDC 23 이후</h2>
<blockquote>
<p>Xcode 15와 Swift 5.9 이후, <a href="https://developer.apple.com/documentation/observation">Observation</a>의 Observable Macro를 통해 더 쉽게 SwiftUI를 다룰 수 있게 되었습니다</p>
</blockquote>
<ul>
<li><code>Observable</code> 프로토콜을 준수하는 대신, <code>@Observable</code> Macro를 표시합니다.</li>
<li>이로 인해, <code>@Published</code> 프로퍼티 래퍼도 이제 필요하지 않게 되었습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token comment">// BEFORE</span>
</span><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">Library</span><span class="token punctuation">:</span> <span class="token class-name">ObservableObject</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token attribute atrule">@Published</span> <span class="token keyword">var</span> books<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">Book</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token class-name">Book</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token class-name">Book</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token class-name">Book</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">]</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token comment">// AFTER</span>
</span><span class="code-line"><span class="token attribute atrule">@Observable</span> <span class="token keyword">class</span> <span class="token class-name">Library</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> books<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">Book</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token class-name">Book</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token class-name">Book</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token class-name">Book</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">]</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li><code>@State</code>, <code>@Binding</code>, <code>@StateObject</code>, <code>@ObservedObject</code>, <code>@EnvironmentObject</code>와 같은 프로퍼티 래퍼들이 있었습니다.</li>
<li>그러나 이제는 훨씬 간단하게, 값 타입과 참조 타입 모두 <code>@State</code> 프로퍼티 래퍼만을 사용하면 됩니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token comment">// BEFORE</span>
</span><span class="code-line"><span class="token attribute atrule">@main</span>
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">BookReaderApp</span><span class="token punctuation">:</span> <span class="token class-name">App</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token attribute atrule">@StateObject</span> <span class="token keyword">private</span> <span class="token keyword">var</span> library <span class="token operator">=</span> <span class="token class-name">Library</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">Scene</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">WindowGroup</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token class-name">LibraryView</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token punctuation">.</span><span class="token function">environmentObject</span><span class="token punctuation">(</span>library<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token comment">// AFTER</span>
</span><span class="code-line"><span class="token attribute atrule">@main</span>
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">BookReaderApp</span><span class="token punctuation">:</span> <span class="token class-name">App</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token attribute atrule">@State</span> <span class="token keyword">private</span> <span class="token keyword">var</span> library <span class="token operator">=</span> <span class="token class-name">Library</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">Scene</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">WindowGroup</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token class-name">LibraryView</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token punctuation">.</span><span class="token function">environment</span><span class="token punctuation">(</span>library<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li><code>@EnvironmentObject</code> 역시, <code>@Environment</code>로 통일할수 있게 되었습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token comment">// BEFORE</span>
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">LibraryView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token attribute atrule">@EnvironmentObject</span> <span class="token keyword">var</span> library<span class="token punctuation">:</span> <span class="token class-name">Library</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">List</span><span class="token punctuation">(</span>library<span class="token punctuation">.</span>books<span class="token punctuation">)</span> <span class="token punctuation">{</span> book <span class="token keyword">in</span>
</span><span class="code-line">            <span class="token class-name">BookView</span><span class="token punctuation">(</span>book<span class="token punctuation">:</span> book<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token comment">// AFTER</span>
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">LibraryView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token attribute atrule">@Environment</span><span class="token punctuation">(</span><span class="token class-name">Library</span><span class="token punctuation">.</span><span class="token keyword">self</span><span class="token punctuation">)</span> <span class="token keyword">private</span> <span class="token keyword">var</span> library
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">List</span><span class="token punctuation">(</span>library<span class="token punctuation">.</span>books<span class="token punctuation">)</span> <span class="token punctuation">{</span> book <span class="token keyword">in</span>
</span><span class="code-line">            <span class="token class-name">BookView</span><span class="token punctuation">(</span>book<span class="token punctuation">:</span> book<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li><code>@ObservedObject</code> 역시, 필요가 없어졌습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token comment">// BEFORE</span>
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">BookView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token attribute atrule">@ObservedObject</span> <span class="token keyword">var</span> book<span class="token punctuation">:</span> <span class="token class-name">Book</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">Text</span><span class="token punctuation">(</span>book<span class="token punctuation">.</span>title<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token comment">// AFTER</span>
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">BookView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> book<span class="token punctuation">:</span> <span class="token class-name">Book</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">Text</span><span class="token punctuation">(</span>book<span class="token punctuation">.</span>title<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li><code>Observable</code>을 준수하는 오브젝트에 대해 <code>@Binding</code>이 필요한 경우에만 <code>@Bindable</code>을 사용하면 됩니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token comment">// BEFORE</span>
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">BookEditView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token attribute atrule">@ObservedObject</span> <span class="token keyword">var</span> book<span class="token punctuation">:</span> <span class="token class-name">Book</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">TextField</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Title"</span></span><span class="token punctuation">,</span> text<span class="token punctuation">:</span> $book<span class="token punctuation">.</span>title<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token comment">// AFTER</span>
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">BookEditView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token attribute atrule">@Bindable</span> <span class="token keyword">var</span> book<span class="token punctuation">:</span> <span class="token class-name">Book</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">TextField</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Title"</span></span><span class="token punctuation">,</span> text<span class="token punctuation">:</span> $book<span class="token punctuation">.</span>title<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="wwdc-23-이전">WWDC 23 이전</h2>
<h3 id="state">@State</h3>
<ul>
<li>
<p><a href="https://developer.apple.com/documentation/swiftui/state">State</a> 프로퍼티 래퍼는 크게 2가지 역할을 합니다.</p>
</li>
<li>
<p>View를 준수하는 struct 변수의 값을 변경할수 있게합니다.</p>
</li>
<li>
<p>변수의 값이 변경되면 View의 body가 다시 계산될수 있게합니다.</p>
</li>
<li>
<p>State 변수는 주로 Source of Truth 역할을 하기에 private으로 선언됩니다.</p>
</li>
<li>
<p>다른 view와 이를 공유하고 싶다면, 아래에서 소개될 <code>@Binding</code>이나 <code>@ObservedObject</code>를 사용합니다.</p>
</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token attribute atrule">@State</span> <span class="token keyword">private</span> <span class="token keyword">var</span> number <span class="token operator">=</span> <span class="token number">0</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h3 id="binding">@Binding</h3>
<ul>
<li><a href="https://developer.apple.com/documentation/swiftui/binding">Binding</a> 프로퍼티 래퍼는 부모 view의 State 변수와 같은 값을 양방향으로 연결되도록 합니다.</li>
<li>아래 코드에서 <code>isPresented</code>는 <code>showAddView</code>를 바인딩 시켜줘서 값을 변경합니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token attribute atrule">@State</span> <span class="token keyword">private</span> <span class="token keyword">var</span> showAddView <span class="token operator">=</span> <span class="token boolean">false</span>
</span><span class="code-line">
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">VStack</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token class-name">Button</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Trigger"</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        showAddView <span class="token operator">=</span> <span class="token boolean">true</span>
</span><span class="code-line">      <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">.</span><span class="token function">sheet</span><span class="token punctuation">(</span>isPresented<span class="token punctuation">:</span> $showAddView<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token class-name">AddView</span><span class="token punctuation">(</span>isPresented<span class="token punctuation">:</span> <span class="token keyword">self</span><span class="token punctuation">.</span>$showAddView<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">AddView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token attribute atrule">@Binding</span> <span class="token keyword">var</span> isPresented<span class="token punctuation">:</span> <span class="token class-name">Bool</span>
</span><span class="code-line">
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">Button</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Dismiss"</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token keyword">self</span><span class="token punctuation">.</span>isPresented <span class="token operator">=</span> <span class="token boolean">false</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h3 id="observableobject">ObservableObject</h3>
<ul>
<li><a href="https://developer.apple.com/documentation/combine/observableobject">ObservableObject</a> Protocol은 Combine 프레임워크의 일부로, 객체를 옵저빙 할 수 있게 도와줍니다.</li>
<li>클래스가 ObservableObject Protocol을 준수하도록 해주고, Published 프로퍼티 래퍼를 사용하면 됩니다.</li>
<li><a href="https://developer.apple.com/documentation/combine/published">Published</a> 변수를 사용하면 변수의 값이 변경 되었다는 것을 View가 알 수 있게 해줍니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">MyViewModel</span><span class="token punctuation">:</span> <span class="token class-name">ObservableObject</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token attribute atrule">@Published</span> <span class="token keyword">var</span> dataSource<span class="token punctuation">:</span> <span class="token class-name">MyModel</span>
</span><span class="code-line">  
</span><span class="code-line">  <span class="token keyword">init</span><span class="token punctuation">(</span>dataSource<span class="token punctuation">:</span> <span class="token class-name">MyModel</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">self</span><span class="token punctuation">.</span>dataSource <span class="token operator">=</span> dataSource
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h3 id="stateobject">@StateObject</h3>
<ul>
<li><a href="https://developer.apple.com/documentation/swiftui/stateobject">StateObject</a> 프로퍼티 래퍼를 WWDC 2020에서 애플이 추가로 공개했습니다.</li>
<li>ObservedObject 프로퍼티 래퍼와 비슷한 방식으로 작동하지만, View가 다시 랜더링 될 때 릴리즈 되는것을 방지해줍니다.</li>
<li>State와 마찬가지로, 일반적으로 Source of Truth 역할을 하기에 주로 private으로 선언됩니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">User</span><span class="token punctuation">:</span> <span class="token class-name">ObservableObject</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token attribute atrule">@Published</span> <span class="token keyword">var</span> name <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"Hohyeon Moon"</span></span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token attribute atrule">@StateObject</span> <span class="token keyword">private</span> <span class="token keyword">var</span> user <span class="token operator">=</span> <span class="token class-name">User</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h3 id="observedobject">@ObservedObject</h3>
<ul>
<li><a href="https://developer.apple.com/documentation/swiftui/observedobject">ObservedObject</a> 프로퍼티 래퍼는 view가 객체를 옵저빙 할 수 있게합니다.</li>
<li>아래 코드에서 User class는 ObservableObject를 준수하고 <code>@Published</code> 변수를 갖고 있습니다.</li>
<li><code>@ObservedObject</code> user 변수는 이러한 User class 객체를 담고 있습니다.</li>
<li>SwiftUI는 이러한 user 객체의 <code>@Published</code> 변수 값이 변경될 때 view를 refresh합니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token attribute atrule">@StateObject</span> <span class="token keyword">private</span> <span class="token keyword">var</span> user <span class="token operator">=</span> <span class="token class-name">User</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">ChildView</span><span class="token punctuation">(</span>user<span class="token punctuation">:</span> user<span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ChildView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token attribute atrule">@ObservedObject</span> <span class="token keyword">var</span> user<span class="token punctuation">:</span> <span class="token class-name">User</span>
</span><span class="code-line">
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">Text</span><span class="token punctuation">(</span>user<span class="token punctuation">.</span>name<span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h3 id="environmentobject">@EnvironmentObject</h3>
<ul>
<li><code>@EnvironmentObject</code>는 보통 앱 전반에 걸쳐 공유되는 데이터에 사용됩니다.</li>
<li><code>@EnvironmentObject</code>는 <code>.environmentObject()</code>를 통해 값을 전달할 수 있습니다.</li>
<li>전달하는 object는 ObservableObject 프로토콜을 준수해야 합니다.</li>
<li>아래 코드와 같이 root view를 제공하면, 어떠한 view에서도 사용이 가능합니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">Settings</span><span class="token punctuation">:</span> <span class="token class-name">ObservableObject</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token attribute atrule">@Published</span> <span class="token keyword">var</span> version <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"0"</span></span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token attribute atrule">@StateObject</span> <span class="token keyword">var</span> settings <span class="token operator">=</span> <span class="token class-name">Settings</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">MainView</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">.</span><span class="token function">environmentObject</span><span class="token punctuation">(</span>settings<span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">MainView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token attribute atrule">@EnvironmentObject</span> <span class="token keyword">var</span> settings<span class="token punctuation">:</span> <span class="token class-name">Settings</span>
</span><span class="code-line">
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">Text</span><span class="token punctuation">(</span>settings<span class="token punctuation">.</span>version<span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="property-wrapper">Property Wrapper</h2>
<ul>
<li>
<p><a href="https://developer.apple.com/documentation/swiftui/dynamicproperty">DynamicProperty</a>를 준수하면, 값이 변경됐을때 View의 body가 다시 계산됩니다.</p>
</li>
<li>
<p>State, Binding, StateObject, ObservedObject, EnvironmentObject 등은 DynamicProperty를 준수합니다.</p>
</li>
<li>
<p>SwiftUI에는 이와 같이 여러가지 프로퍼티 래퍼가 있고 이를 접근하는 방식이 여러가지 존재합니다.</p>
</li>
<li>
<p>아래와 같이 State 변수 number는 <code>number</code>, <code>_number</code>, <code>$number</code>로 접근 가능합니다.</p>
</li>
</ul>
<pre><code class="code-highlight"><span class="code-line">@State private var number = 0
</span><span class="code-line">
</span><span class="code-line">_number // Binding&#x3C;Int>
</span><span class="code-line">number // Int (= _number.wrappedValue)
</span><span class="code-line">$number // Binding&#x3C;Int>: (= _number.projectedValue)
</span></code></pre>
<h2 id="총-정리">총 정리</h2>
<ul>
<li>이렇게 해서 SwiftUI에서는 라이프사이클과 데이터 흐름을 어떻게 처리하는지 알아봤습니다.</li>
<li><a href="https://swiftuipropertywrappers.com">swiftuipropertywrappers.com</a>의 이미지를 빌려와 총 정리를 해보면 이렇습니다.</li>
</ul>
<p><img src="/images/swiftui-data-flow-1.png" alt="swiftui-data-flow"></p>
<h2 id="참고">참고</h2>
<blockquote>
<p>본문에 링크되어 있는 링크는 제외했습니다</p>
</blockquote>
<ul>
<li><a href="https://stackoverflow.com/questions/56551131/what-does-the-dollar-sign-do-in-swift-swiftui/56567163#56567163">What does the dollar sign do in Swift &#x26; SwiftUI</a></li>
<li><a href="https://stackoverflow.com/a/65209375/6456268">What does the underscore mean before a variable in SwiftUI</a></li>
</ul>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swiftui-tutorial-tab-view</guid>
      <title>SwiftUI TabView 사용하기</title>
      <description>SwiftUI의 TabView에 대해 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/swiftui-tutorial-tab-view</link>
      <pubDate>Fri, 27 May 2022 18:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>이번에는 SwiftUI의 TabView에 대해 알아보겠습니다.</li>
</ul>
<h2 id="tabview-역할">TabView 역할</h2>
<ul>
<li>SwiftUI TabView의 역할은 UIKit의 UITabBarController와 비슷합니다.</li>
<li>하나의 화면에 여러 개의 View를 Tab 방식으로 보여주는 것입니다.</li>
</ul>
<h2 id="tabview-형태">TabView 형태</h2>
<ul>
<li>TabView의 형태는 다음과 같이 TabView 안에 여러 개의 View를 넣는 형태입니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">TabView</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token comment">// Views</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="일반-tabview">일반 TabView</h2>
<ul>
<li>TabView 안에 표시할 View(Text)를 넣어보았습니다.</li>
<li>각 View의 tabItem 속성 값으로는 Image와 Text를 넣었습니다.</li>
<li>Image는 SF Symbols 값을, Text는 String 값을 넣었는데요.</li>
<li>그러면 각 이미지와 텍스트가 탭바에 표시됩니다.</li>
<li>추가적으로, 마지막 tabItem에는 badge를 붙여봤는데요.</li>
<li>badge를 통해 몇 개의 알림이 있는지 등을 표시할수도 있습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span> <span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">TabView</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"The First Tab"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">.</span>tabItem <span class="token punctuation">{</span>
</span><span class="code-line">          <span class="token class-name">Image</span><span class="token punctuation">(</span>systemName<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"1.square.fill"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">          <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"First"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">      <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Another Tab"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">.</span>tabItem <span class="token punctuation">{</span>
</span><span class="code-line">          <span class="token class-name">Image</span><span class="token punctuation">(</span>systemName<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"2.square.fill"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">          <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Second"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">      <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"The Last Tab"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">.</span>tabItem <span class="token punctuation">{</span>
</span><span class="code-line">          <span class="token class-name">Image</span><span class="token punctuation">(</span>systemName<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"3.square.fill"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">          <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Third"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">badge</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">.</span><span class="token function">font</span><span class="token punctuation">(</span><span class="token punctuation">.</span>headline<span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><img src="/images/swiftui-tutorial-tab-view-1.png" alt="swiftui-tutorial-tab-view"></p>
<h2 id="page-방식-tabview">Page 방식 TabView</h2>
<ul>
<li>스와이프로 넘기는 Page 방식으로 TabView 스타일을 변경 할 수도 있습니다.</li>
<li>아래와 같이 <code>tabViewStyle</code>을 추가하면 됩니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">TabView</span> <span class="token punctuation">{</span><span class="token operator">...</span><span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">.</span><span class="token function">tabViewStyle</span><span class="token punctuation">(</span><span class="token punctuation">.</span>page<span class="token punctuation">)</span>
</span></code></pre>
<p><img src="/images/swiftui-tutorial-tab-view-2.png" alt="swiftui-tutorial-tab-view"></p>
<h2 id="마무리">마무리</h2>
<ul>
<li>이렇게 해서 SwiftUI에서는 TabView를 어떻게 사용하는지 알아봤습니다.</li>
</ul>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swiftui-tutorial-navigation</guid>
      <title>SwiftUI NavigationView와 NavigationStack</title>
      <description>SwiftUI의 NavigationView와 NavigationStack에 대해 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/swiftui-tutorial-navigation</link>
      <pubDate>Fri, 27 May 2022 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>이번에는 SwiftUI의 NavigationView와 NavigationStack에 대해 알아보겠습니다.</li>
</ul>
<h2 id="deprecated">Deprecated</h2>
<p><img src="/images/swiftui-tutorial-navigation-8.png" alt="swiftui-tutorial-navigation"></p>
<ul>
<li><code>NavigationView</code>는 WWDC 22를 진행하며 deprecated 되었습니다.</li>
<li>대신 <code>NavigationStack</code>이 생겼는데요.</li>
<li>이는 애플이 조금 더 데이터 기반에 가까운 네비게이션 API를 제공하기 위함으로 보여집니다.</li>
</ul>
<h2 id="navigationstack">NavigationStack</h2>
<ul>
<li>기존의 <code>NavigationView</code> 대신 <code>NavigationStack</code>을 가장 높은 계층에 위치하게 해줍니다.</li>
<li>그리고 기존의 <code>NavigationLink</code>를 사용해도 여전히 잘 작동합니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">MainView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> products<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">Product</span><span class="token punctuation">]</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">NavigationStack</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token class-name">List</span><span class="token punctuation">(</span>products<span class="token punctuation">)</span> <span class="token punctuation">{</span> product <span class="token keyword">in</span>
</span><span class="code-line">                <span class="token class-name">NavigationLink</span><span class="token punctuation">(</span>product<span class="token punctuation">.</span>title<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">                    <span class="token class-name">DetailView</span><span class="token punctuation">(</span>product<span class="token punctuation">:</span> product<span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token punctuation">}</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">navigationTitle</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Products"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">DetailView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> product<span class="token punctuation">:</span> <span class="token class-name">Product</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">Text</span><span class="token punctuation">(</span>product<span class="token punctuation">.</span>detail<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">navigationTitle</span><span class="token punctuation">(</span>product<span class="token punctuation">.</span>title<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="새로운-navigationlink">새로운 NavigationLink</h2>
<ul>
<li>여전히 작동은 잘하지만, 조금 더 데이터 기반의 코드를 작성해봅시다.</li>
<li>새로운 <code>NavigationLink</code> initializer는 데이터 값에 따른 링크 연결을 생성해줍니다.</li>
<li><code>navigationDestination</code>이라는 view modifier로 도착지 view를 특정 값에 따라 정의해줍니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">MainView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> products<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">Product</span><span class="token punctuation">]</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">NavigationStack</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token class-name">List</span><span class="token punctuation">(</span>products<span class="token punctuation">)</span> <span class="token punctuation">{</span> product <span class="token keyword">in</span>
</span><span class="code-line">                <span class="token class-name">NavigationLink</span><span class="token punctuation">(</span>product<span class="token punctuation">.</span>title<span class="token punctuation">,</span> value<span class="token punctuation">:</span> product<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">navigationTitle</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Products"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">navigationDestination</span><span class="token punctuation">(</span><span class="token keyword">for</span><span class="token punctuation">:</span> <span class="token class-name">Product</span><span class="token punctuation">.</span><span class="token keyword">self</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> product <span class="token keyword">in</span>
</span><span class="code-line">                <span class="token class-name">DetailView</span><span class="token punctuation">(</span>product<span class="token punctuation">:</span> product<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="navigationview">NavigationView</h2>
<blockquote>
<p>WWDC 22에서 NavigationView가 deprecated 되고 NavigationStack이 생겼습니다.</p>
</blockquote>
<ul>
<li>NavigationView는 다음과 같이 만들 수 있습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">NavigationView</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token comment">// Views</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>NavigationView와 NavigationLink를 만들어봅시다.</li>
<li>NavigationLink는 NavigationView의 다음 View로 넘어갈 수 있게 해주는 일종의 버튼입니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span> <span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">NavigationView</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token class-name">NavigationLink</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Navigate"</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"안녕하세요"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><img src="/images/swiftui-tutorial-navigation-1.png" alt="swiftui-tutorial-navigation">
<img src="/images/swiftui-tutorial-navigation-2.png" alt="swiftui-tutorial-navigation"></p>
<h2 id="detailview">DetailView</h2>
<ul>
<li>이제 Navigation 링크를 통해 이동할 Detail 뷰를 별도로 만들어봅시다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">DetailView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">List</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token class-name">ForEach</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token operator">...</span><span class="token number">9</span><span class="token punctuation">,</span> id<span class="token punctuation">:</span> <span class="token punctuation">\</span><span class="token punctuation">.</span><span class="token keyword">self</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Happy </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation"><span class="token short-argument">$0</span></span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">.</span><span class="token function">navigationBarTitle</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Detail"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>그리고 다음과 같이 NavigationLink의 destination 파라미터에 DetailView를 넣어줍니다.</li>
<li>이제 NavigationLink를 터치해보면, DetailView로 넘어갑니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span> <span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">NavigationView</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token class-name">NavigationLink</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Navigate"</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">DetailView</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">}</span>
</span><span class="code-line">      <span class="token punctuation">.</span><span class="token function">navigationBarTitle</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Navigation"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><img src="/images/swiftui-tutorial-navigation-3.png" alt="swiftui-tutorial-navigation">
<img src="/images/swiftui-tutorial-navigation-4.png" alt="swiftui-tutorial-navigation"></p>
<h2 id="navigation-bar">Navigation Bar</h2>
<ul>
<li>앱을 사용할때 흔히 볼 수 있는 Navigation bar title도 다음과 같이 만들 수 있습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span> <span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">NavigationView</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Hi"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">navigationBarTitle</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Navigation"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><img src="/images/swiftui-tutorial-navigation-5.png" alt="swiftui-tutorial-navigation"></p>
<ul>
<li>그리고 Navigation bar button도 다음과 같이 만들 수 있습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span> <span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">NavigationView</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Hi"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">navigationBarTitle</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Navigation"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">.</span>toolbar <span class="token punctuation">{</span>
</span><span class="code-line">          <span class="token class-name">ToolbarItem</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token class-name">Button</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"One"</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
</span><span class="code-line">          <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><img src="/images/swiftui-tutorial-navigation-6.png" alt="swiftui-tutorial-navigation"></p>
<ul>
<li>여러개의 Navigation bar button을 만들 수도 있습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span> <span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">NavigationView</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Hi"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">navigationBarTitle</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Navigation"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">.</span>toolbar <span class="token punctuation">{</span>
</span><span class="code-line">          <span class="token class-name">ToolbarItem</span><span class="token punctuation">(</span>placement<span class="token punctuation">:</span> <span class="token punctuation">.</span>navigationBarTrailing<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token class-name">Button</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"One"</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
</span><span class="code-line">          <span class="token punctuation">}</span>
</span><span class="code-line">          <span class="token class-name">ToolbarItem</span><span class="token punctuation">(</span>placement<span class="token punctuation">:</span> <span class="token punctuation">.</span>navigationBarTrailing<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token class-name">Button</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Two"</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
</span><span class="code-line">          <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><img src="/images/swiftui-tutorial-navigation-7.png" alt="swiftui-tutorial-navigation"></p>
<h2 id="마무리">마무리</h2>
<ul>
<li>이렇게 해서 SwiftUI에서는 NavigationView를 어떻게 만드는지에 대해 알아봤습니다.</li>
</ul>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swiftui-tutorial-scrollview</guid>
      <title>SwiftUI ScrollView 사용하기</title>
      <description>SwiftUI에서 ScrollView를 어떻게 사용하는지 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/swiftui-tutorial-scrollview</link>
      <pubDate>Thu, 26 May 2022 18:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>이번에는 SwiftUI에서 ScrollView를 어떻게 사용하는지 알아보겠습니다.</li>
</ul>
<h2 id="scrollview-구현">ScrollView 구현</h2>
<ul>
<li>SwiftUI에서의 스크롤 뷰는 매우 간단합니다.</li>
<li>그저 <code>ScrollView {...}</code> 안에, 추가할 다른 view를 넣으면 됩니다.</li>
<li>다음과 같이 ScrollView 안에 Image와 텍스트를 넣어봤습니다.</li>
<li>실행해보면, 이미지와 텍스트 뷰가 스크롤 되는 것을 볼 수 있습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span> <span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">ScrollView</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token class-name">Image</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"image-name"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Hello Hohyeon"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><img src="/images/swiftui-tutorial-scrollview-1.png" alt="swiftui-tutorial-scrollview"></p>
<ul>
<li>ScrollView의 기본 axes로는 <code>.vertical</code>이 들어가있습니다.</li>
<li>하지만 <code>.horizontal</code>을 넣으면 가로로 스크롤이 되는 스크롤 뷰를 볼 수 있습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span> <span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">ScrollView</span><span class="token punctuation">(</span><span class="token punctuation">.</span>horizontal<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token class-name">Image</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"image-name"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Hello Hohyeon"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>ScrollView의 <code>showsIndicators</code>는 현재 스크롤 위치를 보여주는 인디케이터를 보여주는지에 대한 옵션입니다.</li>
<li>기본으로는 <code>true</code>가 설정되어 있지만, <code>false</code>로 하면 보이지 않습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span> <span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">ScrollView</span><span class="token punctuation">(</span><span class="token punctuation">.</span>horizontal<span class="token punctuation">,</span> showsIndicators<span class="token punctuation">:</span> <span class="token boolean">false</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token class-name">Image</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"image-name"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Hello Hohyeon"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="마무리">마무리</h2>
<ul>
<li>이렇게 해서 SwiftUI에서는 ScrollView를 어떻게 만드는지에 대해 알아봤습니다.</li>
</ul>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swiftui-tutorial-form</guid>
      <title>SwiftUI Form 사용하기</title>
      <description>SwiftUI에서 Form을 어떻게 사용하는지 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/swiftui-tutorial-form</link>
      <pubDate>Thu, 26 May 2022 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>이번에는 SwiftUI에서 Form을 어떻게 사용하는지 알아보겠습니다.</li>
</ul>
<h2 id="form-기본">Form 기본</h2>
<ul>
<li>SwiftUI의 Form은 HStack이나 VStack과 같은 컨테이너와 비슷하게 작동합니다.</li>
<li>즉, Form 안에 여러 뷰를 넣을 수 있다는 것입니다.</li>
<li>단지, 특정 컨트롤 요소에 대해 더 보기 좋고 잘 작동하게 해줍니다.</li>
<li>다음 예시를 보면, 네비게이션 뷰 안에 Form이 있고 그 안에 토글 스위치와 버튼이 있습니다.</li>
<li>실행해보면, 토글 스위치와 버튼이 Form 형태로 차례대로 담기는 것을 볼 수 있습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span> <span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token attribute atrule">@State</span> <span class="token keyword">var</span> toggling <span class="token operator">=</span> <span class="token boolean">false</span>
</span><span class="code-line">  
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">NavigationView</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token class-name">Form</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">Toggle</span><span class="token punctuation">(</span>isOn<span class="token punctuation">:</span> $toggling<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">          <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Toggly"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token class-name">Button</span> <span class="token punctuation">{</span>
</span><span class="code-line">          <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Saved"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span> label<span class="token punctuation">:</span> <span class="token punctuation">{</span>
</span><span class="code-line">          <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Save changes"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">      <span class="token punctuation">}</span><span class="token punctuation">.</span><span class="token function">navigationBarTitle</span><span class="token punctuation">(</span><span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Settings"</span></span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><img src="/images/swiftui-tutorial-form-1.png" alt="swiftui-tutorial-form"></p>
<h2 id="section-나누기">Section 나누기</h2>
<ul>
<li>Form의 섹션을 나누기 위해서는 Form 안에서 Section 별로 구분 지어주면 됩니다.</li>
<li>다음 예시는 Form을 3개의 Section으로 나눴는데요.</li>
<li>하나의 섹션에는 타이틀과 토글 스위치, 다른 섹션에는 여러개의 Text, 그리고 마지막 섹션에는 버튼과 footer가 있습니다.</li>
<li>실행해보면, 섹션이 나뉘어 있는 것을 볼 수 있습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span> <span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token attribute atrule">@State</span> <span class="token keyword">var</span> toggling <span class="token operator">=</span> <span class="token boolean">false</span>
</span><span class="code-line">  
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">NavigationView</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token class-name">Form</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">Section</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Title"</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">          <span class="token class-name">Toggle</span><span class="token punctuation">(</span>isOn<span class="token punctuation">:</span> $toggling<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Toggly"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">          <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token class-name">Section</span> <span class="token punctuation">{</span>
</span><span class="code-line">          <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Texty"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">          <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Texty"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">          <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Texty"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token class-name">Section</span> <span class="token punctuation">{</span>
</span><span class="code-line">          <span class="token class-name">Button</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Save changes"</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Saved"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">          <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">}</span> footer<span class="token punctuation">:</span> <span class="token punctuation">{</span>
</span><span class="code-line">          <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"footer"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">      <span class="token punctuation">}</span><span class="token punctuation">.</span><span class="token function">navigationBarTitle</span><span class="token punctuation">(</span><span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Settings"</span></span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><img src="/images/swiftui-tutorial-form-2.png" alt="swiftui-tutorial-form"></p>
<h2 id="form-활성화-비활성화">Form 활성화 비활성화</h2>
<ul>
<li>Form의 특정 뷰를 활성 또는 비활성 할 수 있는데요.</li>
<li>Toggle 스위치에 따라 toggling 변수에 담기는 bool 값이 변경되고 그 값이 <code>.disabled</code>를 통해 버튼 뷰의 활성화 여부를 결정합니다.</li>
<li>실행해보면, 토글 스위치에 따라 버튼이 활성화 되는 것을 볼 수 있습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span> <span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token attribute atrule">@State</span> <span class="token keyword">var</span> toggling <span class="token operator">=</span> <span class="token boolean">false</span>
</span><span class="code-line">  
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">NavigationView</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token class-name">Form</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">Section</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Title"</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">          <span class="token class-name">Toggle</span><span class="token punctuation">(</span>isOn<span class="token punctuation">:</span> $toggling<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Toggly"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">          <span class="token punctuation">}</span>
</span><span class="code-line">          <span class="token class-name">Button</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Save changes"</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Saved"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">          <span class="token punctuation">}</span><span class="token punctuation">.</span><span class="token function">disabled</span><span class="token punctuation">(</span><span class="token operator">!</span>toggling<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">      <span class="token punctuation">}</span><span class="token punctuation">.</span><span class="token function">navigationBarTitle</span><span class="token punctuation">(</span><span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Settings"</span></span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><img src="/images/swiftui-tutorial-form-3.png" alt="swiftui-tutorial-form">
<img src="/images/swiftui-tutorial-form-4.png" alt="swiftui-tutorial-form"></p>
<h2 id="form-숨기기">Form 숨기기</h2>
<ul>
<li>Form 안의 view를 비활성화 하는 것 뿐만 아니라, 아예 숨길 수도 있습니다.</li>
<li>다음과 같이 토글 스위치 변수의 값에 따라 또 다른 토글 스위치의 보이고 안 보이고를 결정할 수 있는데요.</li>
<li>if 문을 사용하면 됩니다.</li>
<li>실행해보면, 토글 스위치에 따라 다른 토글 스위치가 숨겨집니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span> <span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token attribute atrule">@State</span> <span class="token keyword">var</span> showingAdvancedOptions <span class="token operator">=</span> <span class="token boolean">false</span>
</span><span class="code-line">  <span class="token attribute atrule">@State</span> <span class="token keyword">var</span> toggling <span class="token operator">=</span> <span class="token boolean">false</span>
</span><span class="code-line">  
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">Form</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token class-name">Section</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">Toggle</span><span class="token punctuation">(</span>isOn<span class="token punctuation">:</span> $showingAdvancedOptions<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">          <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Show advanced options"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token keyword">if</span> showingAdvancedOptions <span class="token punctuation">{</span>
</span><span class="code-line">          <span class="token class-name">Toggle</span><span class="token punctuation">(</span>isOn<span class="token punctuation">:</span> $toggling<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Advanced option"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">          <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">      <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><img src="/images/swiftui-tutorial-form-5.png" alt="swiftui-tutorial-form"></p>
<h2 id="마무리">마무리</h2>
<ul>
<li>이렇게 해서 SwiftUI에서는 Form을 어떻게 만드는지에 대해 알아봤습니다.</li>
</ul>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swiftui-tutorial-list</guid>
      <title>SwiftUI List 만들기</title>
      <description>SwiftUI에서 List를 어떻게 만들고 다루는지 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/swiftui-tutorial-list</link>
      <pubDate>Wed, 25 May 2022 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>이번에는 SwiftUI에서 List를 어떻게 만들고 다루는지 알아보겠습니다.</li>
</ul>
<h2 id="list-란">List 란</h2>
<ul>
<li>List는 이름 그대로 목록(List) 인터페이스를 구현하기 위해 존재합니다.</li>
<li>SwiftUI의 리스트는 UIKit의 UITableView와 하는 일이 상당히 비슷합니다.</li>
<li>하지만 구현하기는 훨씬 간편하다고 생각합니다.</li>
</ul>
<h2 id="정적-리스트">정적 리스트</h2>
<ul>
<li>정적 List에 대한 예시를 보여드리겠습니다.</li>
<li>우선 FamilyRow라는 struct가 있습니다.</li>
<li>이 struct는 name 변수와 Text를 리턴하는 body를 갖고 있습니다.</li>
<li>List의 아이템으로 FamilyRow를 넣어주고, 각각의 FamilyRow에 서로 다른 name을 입력해줍니다.</li>
<li>그리고 실행해보면, 각 FamilyRow의 텍스트가 리스트 형태로 표시되는 것을 볼 수 있습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">FamilyRow</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">var</span> name<span class="token punctuation">:</span> <span class="token class-name">String</span>
</span><span class="code-line">  
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Family: </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">name</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">List</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token class-name">FamilyRow</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Hohyeon"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token class-name">FamilyRow</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Moon"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token class-name">FamilyRow</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Jigom"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><img src="/images/swiftui-tutorial-list-1.png" alt="swiftui-tutorial-list"></p>
<h2 id="다이나믹-리스트">다이나믹 리스트</h2>
<ul>
<li>Family라는 Identifiable 프로토콜을 상속 받는 struct가 있습니다.</li>
<li>Identifiable을 상속 받기 위해서는 고유 id 값만 있으면 되는데요.</li>
<li>Family struct에 id와 name 변수를 선언합니다.</li>
<li>FamilyRow는 정적 List를 다룰 때와 비슷한데요.</li>
<li>다이나믹 리스트를 구성하는 것인만큼 정적인 name 변수 대신 family라는 Family 타입 변수를 선언합니다.</li>
<li>ContentView에서는 List에 들어갈 first, second, third 아이템을 만듭니다.</li>
<li>이를 families 배열에 넣어준 뒤, return 값으로 리스트를 반환합니다.</li>
<li>families 배열안에 있는 family element를 각각 반복 실행해서 List에 보여줍니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">Family</span><span class="token punctuation">:</span> <span class="token class-name">Identifiable</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">var</span> id <span class="token operator">=</span> <span class="token function">UUID</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token keyword">var</span> name<span class="token punctuation">:</span> <span class="token class-name">String</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">FamilyRow</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">var</span> family<span class="token punctuation">:</span> <span class="token class-name">Family</span>
</span><span class="code-line">  
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Family: </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">family<span class="token punctuation">.</span>name</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">let</span> first <span class="token operator">=</span> <span class="token class-name">Family</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Hohyeon"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token keyword">let</span> second <span class="token operator">=</span> <span class="token class-name">Family</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Moon"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token keyword">let</span> third <span class="token operator">=</span> <span class="token class-name">Family</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Jigom"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">  
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> families <span class="token operator">=</span> <span class="token punctuation">[</span>first<span class="token punctuation">,</span> second<span class="token punctuation">,</span> third<span class="token punctuation">]</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">return</span> <span class="token class-name">List</span><span class="token punctuation">(</span>families<span class="token punctuation">)</span> <span class="token punctuation">{</span> family <span class="token keyword">in</span>
</span><span class="code-line">      <span class="token class-name">FamilyRow</span><span class="token punctuation">(</span>family<span class="token punctuation">:</span> family<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><img src="/images/swiftui-tutorial-list-1.png" alt="swiftui-tutorial-list"></p>
<h2 id="list-아이템-선택">List 아이템 선택</h2>
<ul>
<li>앞에서와 같이 Family 구조체와 families라는 배열이 있습니다.</li>
<li>여기에 binding 가능한 multiSelection Set 타입 변수가 있습니다.</li>
<li>List에 families와 multiSelection을 넣어주고 네비게이션 바 버튼으로 <code>EditButton</code>을 넣어봅니다.</li>
<li>그러면 <code>EditButton</code>을 눌렀을때 List의 각 row를 선택할수 있게됩니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">struct</span> <span class="token class-name">Family</span><span class="token punctuation">:</span> <span class="token class-name">Identifiable</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> id <span class="token operator">=</span> <span class="token function">UUID</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">var</span> name<span class="token punctuation">:</span> <span class="token class-name">String</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">  <span class="token keyword">private</span> <span class="token keyword">var</span> families <span class="token operator">=</span> <span class="token punctuation">[</span>
</span><span class="code-line">    <span class="token class-name">Family</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Hohyeon"</span></span><span class="token punctuation">)</span><span class="token punctuation">,</span>
</span><span class="code-line">    <span class="token class-name">Family</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Moon"</span></span><span class="token punctuation">)</span><span class="token punctuation">,</span>
</span><span class="code-line">    <span class="token class-name">Family</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Jigom"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">]</span>
</span><span class="code-line">
</span><span class="code-line">  <span class="token attribute atrule">@State</span> <span class="token keyword">private</span> <span class="token keyword">var</span> multiSelection <span class="token operator">=</span> <span class="token class-name">Set</span><span class="token operator">&#x3C;</span><span class="token constant">UUID</span><span class="token operator">></span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">  
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">NavigationView</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token class-name">List</span><span class="token punctuation">(</span>families<span class="token punctuation">,</span> selection<span class="token punctuation">:</span> $multiSelection<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token short-argument">$0</span><span class="token punctuation">.</span>name<span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">}</span>
</span><span class="code-line">      <span class="token punctuation">.</span><span class="token function">navigationTitle</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Family"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">.</span>toolbar <span class="token punctuation">{</span> <span class="token class-name">EditButton</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><img src="/images/swiftui-tutorial-list-2.png" alt="swiftui-tutorial-list"></p>
<h2 id="list-아이템-순서-변경">List 아이템 순서 변경</h2>
<ul>
<li>List의 아이템을 편집하기 위해서는 편집 버튼과 편집 상태에서 작동하는 함수의 정의가 필요한데요.</li>
<li>우선, 네비게이션 바 아이템으로 편집 버튼을 만듭니다.</li>
<li>.onMove(perform: ...)으로 편집 상태에 진입 했을 때 작동할 함수를 부여합니다.</li>
<li>그리고 편집 상태에서 실행할 함수를 정의 해줍니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span> <span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token attribute atrule">@State</span> <span class="token keyword">var</span> users <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string-literal"><span class="token string">"Hohyeon"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"Moon"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"Jigom"</span></span><span class="token punctuation">]</span>
</span><span class="code-line">  
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">NavigationView</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token class-name">List</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">ForEach</span><span class="token punctuation">(</span>users<span class="token punctuation">,</span> id<span class="token punctuation">:</span> <span class="token punctuation">\</span><span class="token punctuation">.</span><span class="token keyword">self</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> user <span class="token keyword">in</span>
</span><span class="code-line">          <span class="token class-name">Text</span><span class="token punctuation">(</span>user<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">onMove</span><span class="token punctuation">(</span>perform<span class="token punctuation">:</span> move<span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">}</span>
</span><span class="code-line">      <span class="token punctuation">.</span><span class="token function">navigationBarItems</span><span class="token punctuation">(</span>trailing<span class="token punctuation">:</span> <span class="token class-name">EditButton</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line">  
</span><span class="code-line">  <span class="token keyword">func</span> <span class="token function-definition function">move</span><span class="token punctuation">(</span>from source<span class="token punctuation">:</span> <span class="token class-name">IndexSet</span><span class="token punctuation">,</span> to destination<span class="token punctuation">:</span> <span class="token class-name">Int</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> reversedSource <span class="token operator">=</span> source<span class="token punctuation">.</span><span class="token function">sorted</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">for</span> index <span class="token keyword">in</span> reversedSource<span class="token punctuation">.</span><span class="token function">reversed</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">      users<span class="token punctuation">.</span><span class="token function">insert</span><span class="token punctuation">(</span>users<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span>at<span class="token punctuation">:</span> index<span class="token punctuation">)</span><span class="token punctuation">,</span> at<span class="token punctuation">:</span> destination<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><img src="/images/swiftui-tutorial-list-3.png" alt="swiftui-tutorial-list"></p>
<h2 id="list-아이템-삭제">List 아이템 삭제</h2>
<ul>
<li>List의 아이템을 삭제하기 위해서는 어려울것 없습니다.</li>
<li>ForEach로 뿌려진 Text 아이템 뒤에 .onDelete(perform: )을 달아줍니다.</li>
<li>그리고 삭제 버튼을 누르면 실행할 함수를 정의 해줍니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span> <span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token attribute atrule">@State</span> <span class="token keyword">var</span> users <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string-literal"><span class="token string">"Hohyeon"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"Moon"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"Jigom"</span></span><span class="token punctuation">]</span>
</span><span class="code-line">  
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">List</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token class-name">ForEach</span><span class="token punctuation">(</span>users<span class="token punctuation">,</span> id<span class="token punctuation">:</span> <span class="token punctuation">\</span><span class="token punctuation">.</span><span class="token keyword">self</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> user <span class="token keyword">in</span>
</span><span class="code-line">        <span class="token class-name">Text</span><span class="token punctuation">(</span>user<span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">}</span>
</span><span class="code-line">      <span class="token punctuation">.</span><span class="token function">onDelete</span><span class="token punctuation">(</span>perform<span class="token punctuation">:</span> delete<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line">  
</span><span class="code-line">  <span class="token keyword">func</span> <span class="token function-definition function">delete</span><span class="token punctuation">(</span>at offsets<span class="token punctuation">:</span> <span class="token class-name">IndexSet</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">if</span> <span class="token keyword">let</span> first <span class="token operator">=</span> offsets<span class="token punctuation">.</span>first <span class="token punctuation">{</span>
</span><span class="code-line">      users<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span>at<span class="token punctuation">:</span> first<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><img src="/images/swiftui-tutorial-list-4.png" alt="swiftui-tutorial-list"></p>
<h2 id="list에-섹션-추가">List에 섹션 추가</h2>
<ul>
<li>List에 섹션을 추가하기 위해서는 리스트안에 Section(header: ...){...}을 넣어줍니다.</li>
<li>그리고 Section 안에 List 아이템을 넣어줍니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">TaskRow</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Task item"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span> <span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">List</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token class-name">Section</span><span class="token punctuation">(</span>header<span class="token punctuation">:</span> <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Important"</span></span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">TaskRow</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token class-name">TaskRow</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token class-name">TaskRow</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">}</span>
</span><span class="code-line">      <span class="token class-name">Section</span><span class="token punctuation">(</span>header<span class="token punctuation">:</span> <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Other"</span></span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">TaskRow</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token class-name">TaskRow</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token class-name">TaskRow</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><img src="/images/swiftui-tutorial-list-5.png" alt="swiftui-tutorial-list"></p>
<h2 id="list-스타일링">List 스타일링</h2>
<ul>
<li>List를 스타일링 하기 위해서는 List 뒤에 .listStyle(...)를 달아줍니다.</li>
<li>listStyle 안에는 ListStyle 타입이 들어가서 예를들어, .grouped가 있습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">GroupedRow</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Task Row"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span> <span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">List</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token class-name">Section</span><span class="token punctuation">(</span>header<span class="token punctuation">:</span> <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Grouped"</span></span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">GroupedRow</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token class-name">GroupedRow</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token class-name">GroupedRow</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">.</span><span class="token function">listStyle</span><span class="token punctuation">(</span><span class="token punctuation">.</span>grouped<span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><img src="/images/swiftui-tutorial-list-6.png" alt="swiftui-tutorial-list"></p>
<h2 id="마무리">마무리</h2>
<ul>
<li>이렇게 해서 SwiftUI에서는 List를 어떻게 만드는지에 대해 알아봤습니다.</li>
</ul>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swiftui-tutorial-grid</guid>
      <title>SwiftUI Grid 사용하기</title>
      <description>SwiftUI에서 Grid를 어떻게 사용하는지에 대해 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/swiftui-tutorial-grid</link>
      <pubDate>Tue, 24 May 2022 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>이번에는 SwiftUI에서 Grid를 어떻게 사용하는지에 대해 알아보겠습니다.</li>
</ul>
<h2 id="griditem">GridItem</h2>
<p><img src="/images/swiftui-tutorial-grid-1.png" alt="swiftui-tutorial-grid"></p>
<ul>
<li><code>GridItem</code>은 이름 그대로 SwiftUI의 Grid를 구성하는 Item 정도로 생각하면됩니다.</li>
<li>다음과 같이 <code>GridItem</code>은 파라미터로 <code>size</code>, <code>spacing</code>, <code>alignment</code>를 받는데요.</li>
<li><code>spacing</code>과 <code>alignment</code>는 여타 컴포넌트들과 마찬가지로 간격과 정렬을 위한 파라미터입니다.</li>
<li>반면, <code>size</code>는 <code>GridItem.Size</code> Enum 타입으로, <code>fixed</code>, <code>flexible</code>, <code>adaptive</code>과 같이 다양한 옵션을 제공합니다.</li>
</ul>
<h3 id="fixed">fixed</h3>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">private</span> <span class="token keyword">var</span> columns<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">GridItem</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span>
</span><span class="code-line">    <span class="token class-name">GridItem</span><span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token function">fixed</span><span class="token punctuation">(</span><span class="token number">50</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
</span><span class="code-line">    <span class="token class-name">GridItem</span><span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token function">fixed</span><span class="token punctuation">(</span><span class="token number">50</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">]</span>
</span></code></pre>
<ul>
<li><code>fixed</code>는 가장 간단한 옵션으로, 정의한 크기 그대로 Item 크기를 설정합니다.</li>
</ul>
<h3 id="flexible">flexible</h3>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">private</span> <span class="token keyword">var</span> columns<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">GridItem</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span>
</span><span class="code-line">    <span class="token class-name">GridItem</span><span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token function">flexible</span><span class="token punctuation">(</span>minimum<span class="token punctuation">:</span> <span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
</span><span class="code-line">    <span class="token class-name">GridItem</span><span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token function">flexible</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">]</span>
</span></code></pre>
<ul>
<li><code>flexible</code> 옵션은 정의한 Item 개수를 유지하기 위해 최선을 다합니다.</li>
<li>하지만 공간이 충분하지 않으면 유연하게 새 row를 만듭니다.</li>
<li><code>flexible</code> 옵션에 대한 minimum 및 maximum 크기도 지정할 수 있는데, 기본으로 10, infinity를 사용합니다.</li>
</ul>
<h3 id="adaptive">adaptive</h3>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">private</span> <span class="token keyword">var</span> columns<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">GridItem</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span>
</span><span class="code-line">    <span class="token class-name">GridItem</span><span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token function">adaptive</span><span class="token punctuation">(</span>minimum<span class="token punctuation">:</span> <span class="token number">50</span><span class="token punctuation">,</span> maximum<span class="token punctuation">:</span> <span class="token number">150</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">]</span>
</span></code></pre>
<ul>
<li><code>adaptive</code> 옵션은 지정한 minimum 크기로 가능한 많은 항목을 채우려고 하고 maximum까지 늘어날수 있습니다.</li>
<li>그렇기에 정의한 Item 개수를 따르지 않습니다.</li>
</ul>
<h2 id="lazyhgrid">LazyHGrid</h2>
<ul>
<li>우선, 가장 간단한 fixed size 옵션의 GridItem row를 통해 LazyHGrid를 구현해보겠습니다.</li>
<li>가로 형태의 ScrollView 안에 LazyHGrid를 위치하게 하고, ForEach 문으로 Grid 안의 요소를 Color로 채워넣어 봤습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">var</span> rows<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">GridItem</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token class-name">Array</span><span class="token punctuation">(</span>repeating<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token keyword">init</span><span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token function">fixed</span><span class="token punctuation">(</span><span class="token number">50</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span> count<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">)</span>
</span><span class="code-line">  
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">ScrollView</span><span class="token punctuation">(</span><span class="token punctuation">.</span>horizontal<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token class-name">LazyHGrid</span><span class="token punctuation">(</span>rows<span class="token punctuation">:</span> rows<span class="token punctuation">,</span> alignment<span class="token punctuation">:</span> <span class="token punctuation">.</span>center<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">ForEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token operator">...</span><span class="token number">19</span><span class="token punctuation">)</span><span class="token punctuation">,</span> id<span class="token punctuation">:</span> <span class="token punctuation">\</span><span class="token punctuation">.</span><span class="token keyword">self</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token omit keyword">_</span> <span class="token keyword">in</span>
</span><span class="code-line">          <span class="token class-name">Color</span><span class="token punctuation">(</span>red<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token keyword">in</span><span class="token punctuation">:</span> <span class="token number">0</span><span class="token operator">...</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">,</span> green<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token keyword">in</span><span class="token punctuation">:</span> <span class="token number">0</span><span class="token operator">...</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">,</span> blue<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token keyword">in</span><span class="token punctuation">:</span> <span class="token number">0</span><span class="token operator">...</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">cornerRadius</span><span class="token punctuation">(</span><span class="token number">15</span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">frame</span><span class="token punctuation">(</span>width<span class="token punctuation">:</span> <span class="token number">50</span><span class="token punctuation">,</span> height<span class="token punctuation">:</span> <span class="token number">50</span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">padding</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">      <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>코드는 다음과 같은 결과를 보여줍니다.</li>
</ul>
<p><img src="/images/swiftui-tutorial-grid-2.png" alt="swiftui-tutorial-grid"></p>
<h2 id="lazyvgrid">LazyVGrid</h2>
<ul>
<li>그 다음은 flexible size 옵션의 GridItem column을 통해 LazyVGrid를 구현해보겠습니다.</li>
<li>세로 형태의 ScrollView 안에 LazyVGrid를 위치하게 하고, ForEach 문으로 Grid 안의 요소를 Color로 채워넣어 봤습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">var</span> columns<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">GridItem</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token class-name">Array</span><span class="token punctuation">(</span>repeating<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token keyword">init</span><span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token function">flexible</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span> count<span class="token punctuation">:</span> <span class="token number">2</span><span class="token punctuation">)</span>
</span><span class="code-line">  
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">ScrollView</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token class-name">LazyVGrid</span><span class="token punctuation">(</span>columns<span class="token punctuation">:</span> columns<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">ForEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token operator">...</span><span class="token number">19</span><span class="token punctuation">)</span><span class="token punctuation">,</span> id<span class="token punctuation">:</span> <span class="token punctuation">\</span><span class="token punctuation">.</span><span class="token keyword">self</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token omit keyword">_</span> <span class="token keyword">in</span>
</span><span class="code-line">          <span class="token class-name">Color</span><span class="token punctuation">(</span>red<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token keyword">in</span><span class="token punctuation">:</span> <span class="token number">0</span><span class="token operator">...</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">,</span> green<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token keyword">in</span><span class="token punctuation">:</span> <span class="token number">0</span><span class="token operator">...</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">,</span> blue<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token keyword">in</span><span class="token punctuation">:</span> <span class="token number">0</span><span class="token operator">...</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">cornerRadius</span><span class="token punctuation">(</span><span class="token number">15</span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">frame</span><span class="token punctuation">(</span>width<span class="token punctuation">:</span> <span class="token number">150</span><span class="token punctuation">,</span> height<span class="token punctuation">:</span> <span class="token number">150</span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">padding</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">      <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>코드는 다음과 같은 결과를 보여줍니다.</li>
</ul>
<p><img src="/images/swiftui-tutorial-grid-3.png" alt="swiftui-tutorial-grid"></p>
<h2 id="grid">Grid</h2>
<ul>
<li>정적인 그리드 표현을 위해, iOS 16 이후부터 일반 Grid도 지원합니다.</li>
<li>아래 코드처럼 <code>Grid</code>와 <code>GridRow</code>를 사용하면 됩니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">Grid</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">GridRow</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Hello"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token class-name">Image</span><span class="token punctuation">(</span>systemName<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"globe"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token class-name">GridRow</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">Image</span><span class="token punctuation">(</span>systemName<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"hand.wave"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"World"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="마무리">마무리</h2>
<ul>
<li>이렇게 해서 SwiftUI에서 어떻게 Grid를 사용하는지에 대해 알아봤습니다.</li>
</ul>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swiftui-tutorial-view</guid>
      <title>SwiftUI View 레이아웃</title>
      <description>SwiftUI에서 View 레이아웃 어떻게 사용하는지에 대해 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/swiftui-tutorial-view</link>
      <pubDate>Mon, 23 May 2022 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>이번에는 SwiftUI에서 View 레이아웃을 어떻게 사용하는지에 대해 알아보겠습니다.</li>
</ul>
<h2 id="hstack-vstack">HStack VStack</h2>
<ul>
<li>두 개 이상의 View를 하나로 감싸기 위해서는 다음과 같이 HStack 혹은 VStack을 감싸면 됩니다.</li>
<li>HStack은 Horizontal Stack, VStack은 Vertical Stack으로 각각 가로와 세로 스택입니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">HStack</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"SwiftUI"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Hohyeon"</span></span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token class-name">VStack</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"SwiftUI"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Hohyeon"</span></span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><img src="/images/swiftui-tutorial-view-1.png" alt="swiftui-tutorial-view">
<img src="/images/swiftui-tutorial-view-2.png" alt="swiftui-tutorial-view"></p>
<h2 id="zstack-사용하기">ZStack 사용하기</h2>
<ul>
<li>ZStack은 또 다른 스택 뷰로, 뷰를 겹칠 때 사용하면 되는데요.</li>
<li>다음 코드는 어떠한 결과를 만들까요?</li>
<li>이미지와 텍스트가 포개지게 됩니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">ZStack</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token class-name">Image</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"image-name"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Hohyeon"</span></span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><img src="/images/swiftui-tutorial-view-3.png" alt="swiftui-tutorial-view"></p>
<h2 id="view-정렬하기">View 정렬하기</h2>
<ul>
<li>스택 안에 있는 뷰들 간에 일정한 간격을 주기 위해서는 <code>spacing</code>을 사용하면 됩니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">VStack</span><span class="token punctuation">(</span>spacing<span class="token punctuation">:</span> <span class="token number">50</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"SwiftUI"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Hohyeon"</span></span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><img src="/images/swiftui-tutorial-view-4.png" alt="swiftui-tutorial-view"></p>
<ul>
<li>Stack 안의 View 사이의 적당한 간격을 주기 위해서는 padding()을 사용하면 되는데요.</li>
<li>padding에 인자 값을 전달하지 않으면 시스템 기본값으로 자동 적용됩니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">VStack</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"SwiftUI"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">.</span><span class="token function">background</span><span class="token punctuation">(</span><span class="token punctuation">.</span>yellow<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">.</span><span class="token function">padding</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">.</span><span class="token function">background</span><span class="token punctuation">(</span><span class="token punctuation">.</span>orange<span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><img src="/images/swiftui-tutorial-view-5.png" alt="swiftui-tutorial-view"></p>
<ul>
<li>그리고 인자 값을 전달하면, 다음과 같이 원하는 위치에 원하는 간격을 줄 수 있습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">VStack</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"SwiftUI"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">.</span><span class="token function">background</span><span class="token punctuation">(</span><span class="token punctuation">.</span>yellow<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">.</span><span class="token function">padding</span><span class="token punctuation">(</span><span class="token punctuation">.</span>vertical<span class="token punctuation">,</span> <span class="token number">25</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">.</span><span class="token function">background</span><span class="token punctuation">(</span><span class="token punctuation">.</span>orange<span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><img src="/images/swiftui-tutorial-view-6.png" alt="swiftui-tutorial-view"></p>
<ul>
<li>스택 안에 있는 View를 정렬하기 위해서는 alignment를 다음과 같이 사용하면 됩니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">VStack</span><span class="token punctuation">(</span>alignment<span class="token punctuation">:</span> <span class="token punctuation">.</span>leading<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"SwiftUI"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Hohyeon Moon"</span></span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><img src="/images/swiftui-tutorial-view-7.png" alt="swiftui-tutorial-view"></p>
<ul>
<li>기본적으로 SwiftUI의 View는 Safe Area 안에 배치됩니다.</li>
<li>Safe Area를 넘고 싶다면, <code>.edgesIgnoringSafeArea</code>를 사용하면 됩니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Hello World"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">.</span><span class="token function">frame</span><span class="token punctuation">(</span>maxWidth<span class="token punctuation">:</span> <span class="token punctuation">.</span>infinity<span class="token punctuation">,</span> maxHeight<span class="token punctuation">:</span> <span class="token punctuation">.</span>infinity<span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">.</span><span class="token function">background</span><span class="token punctuation">(</span><span class="token punctuation">.</span>yellow<span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">.</span><span class="token function">edgesIgnoringSafeArea</span><span class="token punctuation">(</span><span class="token punctuation">.</span>all<span class="token punctuation">)</span>
</span></code></pre>
<p><img src="/images/swiftui-tutorial-view-8.png" alt="swiftui-tutorial-view"></p>
<h2 id="lazy-레이아웃">Lazy 레이아웃</h2>
<ul>
<li>Lazy 키워드가 붙는 레이아웃은 필요한 아이템만큼만 로딩하는 레이아웃인데요.</li>
<li>대표적으로, LazyHStack과 LazyVStack이 있습니다.</li>
<li>즉, 화면에 표시되어 있거나 표시 될 아이템만 로딩해서 앱의 퍼포먼스를 더 좋게해주는 것입니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">ScrollView</span><span class="token punctuation">(</span><span class="token punctuation">.</span>horizontal<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token class-name">LazyHStack</span><span class="token punctuation">(</span>alignment<span class="token punctuation">:</span> <span class="token punctuation">.</span>center<span class="token punctuation">,</span> spacing<span class="token punctuation">:</span> <span class="token number">10</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">ForEach</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token operator">...</span><span class="token number">100</span><span class="token punctuation">,</span> id<span class="token punctuation">:</span> <span class="token punctuation">\</span><span class="token punctuation">.</span><span class="token keyword">self</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Column </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation"><span class="token short-argument">$0</span></span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">padding</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">background</span><span class="token punctuation">(</span><span class="token punctuation">.</span>yellow<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">cornerRadius</span><span class="token punctuation">(</span><span class="token number">15</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">padding</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><img src="/images/swiftui-tutorial-view-9.png" alt="swiftui-tutorial-view"></p>
<h2 id="마무리">마무리</h2>
<ul>
<li>이렇게 해서 SwiftUI에서는 View 레이아웃을 어떻게 이용하는지에 대해 알아봤습니다.</li>
</ul>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swiftui-tutorial-picker</guid>
      <title>SwiftUI Picker 사용하기</title>
      <description>SwiftUI에서 Picker를 어떻게 사용하는지 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/swiftui-tutorial-picker</link>
      <pubDate>Sat, 21 May 2022 18:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>이번에는 SwiftUI에서 Picker를 어떻게 사용하는지 알아보겠습니다.</li>
</ul>
<h2 id="picker-역할">Picker 역할</h2>
<ul>
<li>SwiftUI의 Picker 뷰는 기존 UIPicker의 역할을 담당합니다.</li>
<li>내부적으로는 UIPicker와 UITableView를 동시에 관리한다고 합니다.</li>
</ul>
<h2 id="picker-사용법">Picker 사용법</h2>
<ul>
<li>이렇게 Picker를 임의로 만들어봤는데요, 색상을 선택하는 wheel 스타일의 Picker 예시입니다.</li>
<li>selection에는 $selectedColor를, label에는 안내하는 텍스트 뷰를, content에는 ForEach문으로 텍스트 뷰를 표시해봤습니다.</li>
<li>참고로, Picker의 label은 보이지는 않지만 VoiceOver 등에서 활용됩니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">var</span> colors <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string-literal"><span class="token string">"red"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"green"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"blue"</span></span><span class="token punctuation">]</span>
</span><span class="code-line">  <span class="token attribute atrule">@State</span> <span class="token keyword">var</span> selectedColor <span class="token operator">=</span> <span class="token string-literal"><span class="token string">""</span></span>
</span><span class="code-line">  
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">VStack</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token class-name">Picker</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Choose a color"</span></span><span class="token punctuation">,</span> selection<span class="token punctuation">:</span> $selectedColor<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">ForEach</span><span class="token punctuation">(</span>colors<span class="token punctuation">,</span> id<span class="token punctuation">:</span> <span class="token punctuation">\</span><span class="token punctuation">.</span><span class="token keyword">self</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">          <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token short-argument">$0</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">      <span class="token punctuation">}</span>
</span><span class="code-line">      <span class="token punctuation">.</span><span class="token function">pickerStyle</span><span class="token punctuation">(</span><span class="token punctuation">.</span>wheel<span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">.</span><span class="token function">background</span><span class="token punctuation">(</span><span class="token punctuation">.</span>yellow<span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">.</span><span class="token function">cornerRadius</span><span class="token punctuation">(</span><span class="token number">15</span><span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">.</span><span class="token function">padding</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">      
</span><span class="code-line">      <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"You selected: </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">selectedColor</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><img src="/images/swiftui-tutorial-picker-1.png" alt="swiftui-tutorial-picker"></p>
<ul>
<li>다음은 segment 스타일의 Picker 예시입니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token attribute atrule">@State</span> <span class="token keyword">var</span> selectedColor <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"color"</span></span>
</span><span class="code-line">  <span class="token keyword">var</span> colors <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string-literal"><span class="token string">"red"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"green"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"blue"</span></span><span class="token punctuation">]</span>
</span><span class="code-line">  
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">VStack</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token class-name">Picker</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Choose a color"</span></span><span class="token punctuation">,</span> selection<span class="token punctuation">:</span> $selectedColor<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">ForEach</span><span class="token punctuation">(</span>colors<span class="token punctuation">,</span> id<span class="token punctuation">:</span> <span class="token punctuation">\</span><span class="token punctuation">.</span><span class="token keyword">self</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">          <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token short-argument">$0</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">      <span class="token punctuation">}</span>
</span><span class="code-line">      <span class="token punctuation">.</span><span class="token function">pickerStyle</span><span class="token punctuation">(</span><span class="token punctuation">.</span>segmented<span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">.</span><span class="token function">padding</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">.</span><span class="token function">background</span><span class="token punctuation">(</span><span class="token punctuation">.</span>yellow<span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">.</span><span class="token function">cornerRadius</span><span class="token punctuation">(</span><span class="token number">15</span><span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">.</span><span class="token function">padding</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">      
</span><span class="code-line">      <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"You selected: </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">selectedColor</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><img src="/images/swiftui-tutorial-picker-2.png" alt="swiftui-tutorial-picker"></p>
<ul>
<li>마지막으로 menu 스타일의 Picker 예시입니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token attribute atrule">@State</span> <span class="token keyword">var</span> selectedColor <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"color"</span></span>
</span><span class="code-line">  <span class="token keyword">var</span> colors <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string-literal"><span class="token string">"red"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"green"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"blue"</span></span><span class="token punctuation">]</span>
</span><span class="code-line">  
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">VStack</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"You selected: </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">selectedColor</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">      
</span><span class="code-line">      <span class="token class-name">Picker</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Choose a color"</span></span><span class="token punctuation">,</span> selection<span class="token punctuation">:</span> $selectedColor<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">ForEach</span><span class="token punctuation">(</span>colors<span class="token punctuation">,</span> id<span class="token punctuation">:</span> <span class="token punctuation">\</span><span class="token punctuation">.</span><span class="token keyword">self</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">          <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token short-argument">$0</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">      <span class="token punctuation">}</span>
</span><span class="code-line">      <span class="token punctuation">.</span><span class="token function">pickerStyle</span><span class="token punctuation">(</span><span class="token punctuation">.</span>menu<span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">.</span><span class="token function">padding</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">.</span><span class="token function">background</span><span class="token punctuation">(</span><span class="token punctuation">.</span>yellow<span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">.</span><span class="token function">cornerRadius</span><span class="token punctuation">(</span><span class="token number">15</span><span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">.</span><span class="token function">padding</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><img src="/images/swiftui-tutorial-picker-3.png" alt="swiftui-tutorial-picker"></p>
<h2 id="datepicker">DatePicker</h2>
<ul>
<li>다음으로는 Picker 중 날짜를 선택할수 있는 DatePicker에 대해 알아보겠습니다.</li>
<li><code>DatePicker</code>에 title과 selection으로 각각 <code>String</code>과 <code>Binding&#x3C;Date></code>를 입력합니다.</li>
<li>그리고 <code>displayedComponents</code>에 표기하고 싶은 컴포넌트 타입을 입력합니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token attribute atrule">@State</span> <span class="token keyword">var</span> date <span class="token operator">=</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">  
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">DatePicker</span><span class="token punctuation">(</span>
</span><span class="code-line">      <span class="token string-literal"><span class="token string">"Start Date"</span></span><span class="token punctuation">,</span>
</span><span class="code-line">      selection<span class="token punctuation">:</span> $date<span class="token punctuation">,</span>
</span><span class="code-line">      displayedComponents<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token punctuation">.</span>date<span class="token punctuation">]</span>
</span><span class="code-line">    <span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">.</span><span class="token function">padding</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">.</span><span class="token function">background</span><span class="token punctuation">(</span><span class="token punctuation">.</span>yellow<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">.</span><span class="token function">cornerRadius</span><span class="token punctuation">(</span><span class="token number">15</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">.</span><span class="token function">padding</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>그러면 다음과 같이 날짜를 선택할수 있는 UI가 표시됩니다.</li>
</ul>
<p><img src="/images/swiftui-tutorial-picker-4.png" alt="swiftui-tutorial-picker"></p>
<h2 id="colorpicker">ColorPicker</h2>
<ul>
<li>다음으로는 Picker 중 색상을 선택할 수 있는 ColorPicker에 대해 알아보겠습니다.</li>
<li><code>ColorPicker</code>에 title과 selection으로 각각 <code>String</code>과 <code>Binding&#x3C;Date></code>를 입력합니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token attribute atrule">@State</span> <span class="token keyword">var</span> bgColor <span class="token operator">=</span> <span class="token class-name">Color</span><span class="token punctuation">.</span>yellow
</span><span class="code-line">  
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">ColorPicker</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Color Picker"</span></span><span class="token punctuation">,</span> selection<span class="token punctuation">:</span> $bgColor<span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">.</span><span class="token function">padding</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">.</span><span class="token function">background</span><span class="token punctuation">(</span><span class="token punctuation">.</span>yellow<span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">.</span><span class="token function">cornerRadius</span><span class="token punctuation">(</span><span class="token number">15</span><span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">.</span><span class="token function">padding</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>그러면 다음과 같이 색상을 선택할수 있는 UI가 표시됩니다.</li>
</ul>
<p><img src="/images/swiftui-tutorial-picker-5.png" alt="swiftui-tutorial-picker">
<img src="/images/swiftui-tutorial-picker-6.png" alt="swiftui-tutorial-picker"></p>
<h2 id="마무리">마무리</h2>
<ul>
<li>이렇게 해서 SwiftUI에서 어떻게 Picker을 사용하는지 알아봤습니다.</li>
</ul>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swiftui-tutorial-slider-stepper</guid>
      <title>SwiftUI Slider와 Stepper</title>
      <description>SwiftUI에서 Slider와 Stepper를 어떻게 사용하는지 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/swiftui-tutorial-slider-stepper</link>
      <pubDate>Sat, 21 May 2022 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>이번에는 SwiftUI에서 Slider와 Stepper를 어떻게 사용하는지 알아보겠습니다.</li>
</ul>
<h2 id="slider-역할">Slider 역할</h2>
<ul>
<li>SwiftUI의 <code>Slider</code>는 UIKit의 <code>UISlider</code>와 같은 역할을 합니다.</li>
</ul>
<h2 id="slider-사용법">Slider 사용법</h2>
<ul>
<li>Slider에는 넣을 수 있는 여러 개의 파라미터가 있습니다.</li>
<li>그 중에서 가장 많이 사용하는 파라미터에 대해 알아보겠습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">Slider</span><span class="token punctuation">(</span>value<span class="token punctuation">:</span> <span class="token operator">...</span><span class="token punctuation">,</span> <span class="token keyword">in</span><span class="token punctuation">:</span> <span class="token operator">...</span><span class="token punctuation">,</span> step<span class="token punctuation">:</span> <span class="token operator">...</span><span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>value: Binding 되는 값이 들어갑니다</li>
<li>in: Slider의 범위를 설정해줍니다</li>
<li>step: Slider의 단위를 설정해줍니다</li>
</ul>
<h2 id="slider-전체-코드">Slider 전체 코드</h2>
<ul>
<li>다음과 같은 코드를 실행하면, 다음과 같이 UI가 구성됩니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token attribute atrule">@State</span> <span class="token keyword">private</span> <span class="token keyword">var</span> celsius <span class="token operator">=</span> <span class="token number">0.0</span>
</span><span class="code-line">  
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">VStack</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token class-name">Slider</span><span class="token punctuation">(</span>value<span class="token punctuation">:</span> $celsius<span class="token punctuation">,</span> <span class="token keyword">in</span><span class="token punctuation">:</span> <span class="token operator">-</span><span class="token number">100</span><span class="token operator">...</span><span class="token number">100</span><span class="token punctuation">,</span> step<span class="token punctuation">:</span> <span class="token number">0.1</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">padding</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"</span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">celsius</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string"> Celsius is </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">celsius <span class="token operator">*</span> <span class="token number">9</span> <span class="token operator">/</span> <span class="token number">5</span> <span class="token operator">+</span> <span class="token number">32</span></span><span class="token interpolation-punctuation punctuation">)</span><span class="token string"> Fahrenheit"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><img src="/images/swiftui-tutorial-slider-stepper-1.png" alt="swiftui-tutorial-slider-stepper"></p>
<h2 id="stepper-역할">Stepper 역할</h2>
<ul>
<li>SwiftUI의 <code>Stepper</code>는 UIKit의 <code>UIStepper</code>와 같은 역할을 합니다.</li>
</ul>
<h2 id="stepper-사용법">Stepper 사용법</h2>
<ul>
<li>Stepper에도 넣을 수 있는 여러 개의 파라미터가 있습니다.</li>
<li>그 중에서 가장 많이 사용하는 파라미터에 대해 알아보겠습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">Stepper</span><span class="token punctuation">(</span><span class="token operator">...</span><span class="token punctuation">,</span> value<span class="token punctuation">:</span> <span class="token operator">...</span><span class="token punctuation">,</span> <span class="token keyword">in</span><span class="token punctuation">:</span> <span class="token operator">...</span><span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>title: Stepper의 제목 View가 들어갑니다</li>
<li>value: Binding 되는 값이 들어갑니다</li>
<li>in: Stepper의 범위를 설정해줍니다</li>
</ul>
<h2 id="stepper-전체-코드">Stepper 전체 코드</h2>
<ul>
<li>다음과 같은 코드를 실행하면, 다음과 같이 UI가 구성됩니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token attribute atrule">@State</span> <span class="token keyword">var</span> age <span class="token operator">=</span> <span class="token number">23</span>
</span><span class="code-line">  
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">VStack</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token class-name">Stepper</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Enter your age"</span></span><span class="token punctuation">,</span> value<span class="token punctuation">:</span> $age<span class="token punctuation">,</span> <span class="token keyword">in</span><span class="token punctuation">:</span> <span class="token number">0</span><span class="token operator">...</span><span class="token number">130</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">padding</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">background</span><span class="token punctuation">(</span><span class="token punctuation">.</span>yellow<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">cornerRadius</span><span class="token punctuation">(</span><span class="token number">15</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">padding</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">      
</span><span class="code-line">      <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Your age is </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">age</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><img src="/images/swiftui-tutorial-slider-stepper-2.png" alt="swiftui-tutorial-slider-stepper"></p>
<h2 id="마무리">마무리</h2>
<ul>
<li>이렇게 해서 SwiftUI에서 어떻게 Slider와 Stepper를 사용하는지 알아봤습니다.</li>
</ul>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swiftui-tutorial-buttons</guid>
      <title>SwiftUI 여러 종류의 Button</title>
      <description>SwiftUI에서 여러 종류의 Button를 어떻게 사용하는지에 대해 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/swiftui-tutorial-buttons</link>
      <pubDate>Fri, 20 May 2022 18:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>이번에는 SwiftUI에서 여러 종류의 Button를 어떻게 사용하는지에 대해 알아보겠습니다.</li>
</ul>
<h2 id="일반-button">일반 Button</h2>
<ul>
<li>SwiftUI에서 일반 버튼을 만들기 위해서는 이렇게 하면 됩니다.</li>
<li>Text를 버튼으로 사용하기 위해 텍스트와 Action(실행할 코드)을 입력합니다.</li>
<li>커스텀 뷰를 버튼으로 사용하고 싶다면, Action과 Label을 입력합니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span> <span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token attribute atrule">@State</span> <span class="token keyword">var</span> text<span class="token punctuation">:</span> <span class="token class-name">String</span> <span class="token operator">=</span> <span class="token string-literal"><span class="token string">""</span></span>
</span><span class="code-line">  
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">VStack</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token class-name">Spacer</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">      
</span><span class="code-line">      <span class="token class-name">Button</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"버튼"</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token comment">// 실행할 코드</span>
</span><span class="code-line">      <span class="token punctuation">}</span>
</span><span class="code-line">      
</span><span class="code-line">      <span class="token class-name">Spacer</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">      
</span><span class="code-line">      <span class="token class-name">Button</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token comment">// 실행할 코드</span>
</span><span class="code-line">      <span class="token punctuation">}</span> label<span class="token punctuation">:</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">Image</span><span class="token punctuation">(</span>systemName<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"circle"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">}</span>
</span><span class="code-line">      
</span><span class="code-line">      <span class="token class-name">Spacer</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><img src="/images/swiftui-tutorial-buttons-1.png" alt="swiftui-tutorial-buttons"></p>
<ul>
<li>Button은 예를들어 이렇게 사용될 수 있습니다.</li>
<li>Button을 보면, <code>Text</code>를 레이블로 갖고 있는데요.</li>
<li>이러한 버튼을 누르면 showDetails의 값을 토글하고 디테일 <code>Text</code>를 보여줍니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span> <span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token attribute atrule">@State</span> <span class="token keyword">var</span> showDetails <span class="token operator">=</span> <span class="token boolean">false</span>
</span><span class="code-line">  
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">VStack</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token class-name">Button</span> <span class="token punctuation">{</span>
</span><span class="code-line">        showDetails<span class="token punctuation">.</span><span class="token function">toggle</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">}</span> label<span class="token punctuation">:</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Show details"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">}</span>
</span><span class="code-line">      
</span><span class="code-line">      <span class="token keyword">if</span> showDetails <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Detail description"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">          <span class="token punctuation">.</span><span class="token function">padding</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><img src="/images/swiftui-tutorial-buttons-2.png" alt="swiftui-tutorial-buttons"></p>
<h2 id="여러-종류의-버튼">여러 종류의 버튼</h2>
<ul>
<li>EditButton은 NavigationView의 toolbar과 같은 곳에서 사용 할 수 있는 편집 버튼입니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span> <span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">NavigationView</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Example"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">navigationTitle</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Buttons"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">.</span>toolbar <span class="token punctuation">{</span>
</span><span class="code-line">          <span class="token class-name">EditButton</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><img src="/images/swiftui-tutorial-buttons-3.png" alt="swiftui-tutorial-buttons"></p>
<ul>
<li>Link는 버튼을 누르면 해당 링크로 이동하게 해주는 버튼입니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span> <span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">Link</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"My site"</span></span><span class="token punctuation">,</span> destination<span class="token punctuation">:</span> <span class="token function">URL</span><span class="token punctuation">(</span>string<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"https://www.hohyeonmoon.com"</span></span><span class="token punctuation">)</span><span class="token operator">!</span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><img src="/images/swiftui-tutorial-buttons-4.png" alt="swiftui-tutorial-buttons"></p>
<ul>
<li>Menu 역시 이름 그대로 메뉴 버튼을 만들 수 있게 해줍니다.</li>
<li>Menu 안에 Button을 넣으면 해당 버튼들이 메뉴의 옵션이 됩니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span> <span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">Menu</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Copy"</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token class-name">Button</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Copy Normal"</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Normal"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">}</span>
</span><span class="code-line">      <span class="token class-name">Button</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Copy Formatted"</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Formatted"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><img src="/images/swiftui-tutorial-buttons-5.png" alt="swiftui-tutorial-buttons"></p>
<h2 id="navigationlink">NavigationLink</h2>
<ul>
<li>NavigationView가 있고 이를 다음 페이지로 push 하고 싶다면 NavigationLink를 사용하면 됩니다.</li>
<li>예를 들어, 이렇게 간단한 DetailView가 있다고 해봅시다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">DetailView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Detail"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>그리고 이렇게 ContentView가 있으면 NavigationView를 NavigationLink를 통해 DetailView로 push 할 수 있습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span> <span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">NavigationView</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token class-name">NavigationLink</span><span class="token punctuation">(</span>destination<span class="token punctuation">:</span> <span class="token class-name">DetailView</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">Image</span><span class="token punctuation">(</span>systemName<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"arrowtriangle.right.circle.fill"</span></span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">resizable</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">          <span class="token punctuation">.</span><span class="token function">frame</span><span class="token punctuation">(</span>width<span class="token punctuation">:</span> <span class="token number">50</span><span class="token punctuation">,</span> height<span class="token punctuation">:</span> <span class="token number">50</span><span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">}</span><span class="token punctuation">.</span><span class="token function">navigationBarTitle</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Buttons"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><img src="/images/swiftui-tutorial-buttons-6.png" alt="swiftui-tutorial-buttons">
<img src="/images/swiftui-tutorial-buttons-7.png" alt="swiftui-tutorial-buttons"></p>
<h2 id="toggle-버튼">Toggle 버튼</h2>
<ul>
<li>UIKit의 UISwitch의 역할을 SwiftUI에서는 Toggle이 합니다.</li>
<li>Toggle(..., isOn: ...)을 사용하면 showGreeting의 값은 토글 스위치가 눌릴 때마다 변경됩니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span> <span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token attribute atrule">@State</span> <span class="token keyword">var</span> showGreeting <span class="token operator">=</span> <span class="token boolean">false</span>
</span><span class="code-line">  
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">VStack</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token class-name">Toggle</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Toggle"</span></span><span class="token punctuation">,</span> isOn<span class="token punctuation">:</span> $showGreeting<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">padding</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">background</span><span class="token punctuation">(</span><span class="token punctuation">.</span>orange<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">cornerRadius</span><span class="token punctuation">(</span><span class="token number">15</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">padding</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">      
</span><span class="code-line">      <span class="token keyword">if</span> showGreeting <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Hello."</span></span><span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><img src="/images/swiftui-tutorial-buttons-8.png" alt="swiftui-tutorial-buttons">
<img src="/images/swiftui-tutorial-buttons-9.png" alt="swiftui-tutorial-buttons"></p>
<h2 id="마무리">마무리</h2>
<ul>
<li>이렇게 해서 SwiftUI에서 어떻게 여러 종류의 버튼을 사용하는지에 대해 알아봤습니다.</li>
</ul>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swiftui-tutorial-textfield</guid>
      <title>SwiftUI TextField 사용하기</title>
      <description>SwiftUI에서 TextField를 어떻게 사용하는지에 대해 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/swiftui-tutorial-textfield</link>
      <pubDate>Fri, 20 May 2022 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>이번에는 SwiftUI에서 TextField를 어떻게 사용하는지에 대해 알아보겠습니다.</p>
<h2 id="text-읽어오기">Text 읽어오기</h2>
<ul>
<li>TextField는 Text의 입력을 읽어오기 위한 component 입니다.</li>
<li>우선, TextField를 사용하기 위해서는 <code>TextField</code> 명령어를 사용하면 되는데요.</li>
<li><code>TextField</code>의 인자 값으로 @State로 선언된 변수를 넣어주면, 이 변수에 텍스트가 입력됩니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span> <span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token attribute atrule">@State</span> <span class="token keyword">var</span> name<span class="token punctuation">:</span> <span class="token class-name">String</span> <span class="token operator">=</span> <span class="token string-literal"><span class="token string">""</span></span>
</span><span class="code-line">  
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">VStack</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token class-name">TextField</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Enter your name"</span></span><span class="token punctuation">,</span> text<span class="token punctuation">:</span> $name<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">padding</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">background</span><span class="token punctuation">(</span><span class="token class-name">Color</span><span class="token punctuation">(</span>uiColor<span class="token punctuation">:</span> <span class="token punctuation">.</span>secondarySystemBackground<span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">      
</span><span class="code-line">      <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Hello </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">name</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><img src="/images/swiftui-tutorial-textfield-1.png" alt="swiftui-tutorial-textfield"></p>
<h2 id="textfield-placeholder">TextField placeholder</h2>
<ul>
<li>사실, placeholder은 위에서도 사용 했는데요.</li>
<li>Textfield의 첫 번째 인자 값으로 placeholder 텍스트가 입력됩니다.</li>
<li>예를들어, 이와 같은 코드는 기본으로 Enter your email을 띄워주고, 입력되는 값을 emailAddress 변수에 담아줍니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span> <span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token attribute atrule">@State</span> <span class="token keyword">var</span> emailAddress<span class="token punctuation">:</span> <span class="token class-name">String</span> <span class="token operator">=</span> <span class="token string-literal"><span class="token string">""</span></span>
</span><span class="code-line">  
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">VStack</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token class-name">TextField</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Enter your email"</span></span><span class="token punctuation">,</span> text<span class="token punctuation">:</span> $emailAddress<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">padding</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">background</span><span class="token punctuation">(</span><span class="token class-name">Color</span><span class="token punctuation">(</span>uiColor<span class="token punctuation">:</span> <span class="token punctuation">.</span>secondarySystemBackground<span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">      
</span><span class="code-line">      <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Email </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">emailAddress</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><img src="/images/swiftui-tutorial-textfield-2.png" alt="swiftui-tutorial-textfield"></p>
<h2 id="textfield-스타일">TextField 스타일</h2>
<ul>
<li>TextField의 스타일을 변경하기 위해서는 textFieldStyle을 사용하면 됩니다.</li>
<li>특히, 텍스트필드에 테두리 스타일을 주기 위해서는 roundedBorder을 사용하면 됩니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span> <span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token attribute atrule">@State</span> <span class="token keyword">var</span> emailAddress<span class="token punctuation">:</span> <span class="token class-name">String</span> <span class="token operator">=</span> <span class="token string-literal"><span class="token string">""</span></span>
</span><span class="code-line">  
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">VStack</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token class-name">TextField</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Enter your email"</span></span><span class="token punctuation">,</span> text<span class="token punctuation">:</span> $emailAddress<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">padding</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">background</span><span class="token punctuation">(</span><span class="token class-name">Color</span><span class="token punctuation">(</span>uiColor<span class="token punctuation">:</span> <span class="token punctuation">.</span>secondarySystemBackground<span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">textFieldStyle</span><span class="token punctuation">(</span><span class="token punctuation">.</span>roundedBorder<span class="token punctuation">)</span>
</span><span class="code-line">      
</span><span class="code-line">      <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Email </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">emailAddress</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><img src="/images/swiftui-tutorial-textfield-3.png" alt="swiftui-tutorial-textfield"></p>
<h2 id="secure-textfield">Secure TextField</h2>
<ul>
<li>Secure Textfield는 입력되는 텍스트의 값을 보호해주기 때문에, 암호와 같은 텍스트를 입력 받을 때 사용됩니다.</li>
<li>기본적으로, TextField와 사용 법이 비슷합니다.</li>
<li>SecureField 명령어를 입력하고 첫 인자 값으로 placeholder 텍스트를, 두 번째 입력 값으로 입력 받은 텍스트를 담을 변수를 넣어주면 됩니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span> <span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token attribute atrule">@State</span> <span class="token keyword">var</span> password<span class="token punctuation">:</span> <span class="token class-name">String</span> <span class="token operator">=</span> <span class="token string-literal"><span class="token string">""</span></span>
</span><span class="code-line">  
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">VStack</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token class-name">SecureField</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Enter a password"</span></span><span class="token punctuation">,</span> text<span class="token punctuation">:</span> $password<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">padding</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">background</span><span class="token punctuation">(</span><span class="token class-name">Color</span><span class="token punctuation">(</span>uiColor<span class="token punctuation">:</span> <span class="token punctuation">.</span>secondarySystemBackground<span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">textFieldStyle</span><span class="token punctuation">(</span><span class="token punctuation">.</span>roundedBorder<span class="token punctuation">)</span>
</span><span class="code-line">      
</span><span class="code-line">      <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"You entered: </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">password</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><img src="/images/swiftui-tutorial-textfield-4.png" alt="swiftui-tutorial-textfield"></p>
<h2 id="texteditor">TextEditor</h2>
<ul>
<li>여러 줄의 텍스트를 입력 받기 위해서는 TextEditor을 사용하면 됩니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span> <span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token attribute atrule">@State</span> <span class="token keyword">var</span> text<span class="token punctuation">:</span> <span class="token class-name">String</span> <span class="token operator">=</span> <span class="token string-literal"><span class="token string">""</span></span>
</span><span class="code-line">  
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">TextEditor</span><span class="token punctuation">(</span>text<span class="token punctuation">:</span> $text<span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">.</span><span class="token function">cornerRadius</span><span class="token punctuation">(</span><span class="token number">15</span><span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">.</span><span class="token function">padding</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">.</span><span class="token function">background</span><span class="token punctuation">(</span><span class="token punctuation">.</span>blue<span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><img src="/images/swiftui-tutorial-textfield-5.png" alt="swiftui-tutorial-textfield"></p>
<h2 id="마무리">마무리</h2>
<ul>
<li>이렇게 해서 SwiftUI에서는 TextField를 어떻게 사용하는지 알아봤습니다.</li>
</ul>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swiftui-tutorial-image</guid>
      <title>SwiftUI Image 그리기</title>
      <description>SwiftUI에서 Image를 어떻게 그리는지에 대해 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/swiftui-tutorial-image</link>
      <pubDate>Thu, 19 May 2022 18:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>이번에는 SwiftUI에서 Image를 어떻게 그리는지에 대해 알아보겠습니다.</li>
</ul>
<h2 id="image-그리기">Image 그리기</h2>
<ul>
<li>기본적으로, 이미지 파일을 화면에 띄우기 위해서는 다음과 같이 하면 됩니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">Image</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"image-name"</span></span><span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>iOS 17부터는 이미지 리소스를 <a href="https://developer.apple.com/documentation/swiftui/image/init(_:)">자동으로 static property로 생성합니다</a>.</li>
<li>그래서 이미지 이름을 String으로 넘기지 않고 다음과 같이 부를 수 있습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">Image</span><span class="token punctuation">(</span><span class="token punctuation">.</span>imageName<span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>이번에 새로 내장된 <code>SF Symbols</code> 아이콘을 사용하기 위해서는 다음과 같이 하면 됩니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">Image</span><span class="token punctuation">(</span>systemName<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"circle"</span></span><span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>SwiftUI에서 UIImage를 통해 이미지를 불러오려면, 다음과 같이 하면 됩니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">let</span> image <span class="token operator">=</span> <span class="token class-name">UIImage</span><span class="token punctuation">(</span>named<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"image-name"</span></span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token keyword">return</span> <span class="token class-name">Image</span><span class="token punctuation">(</span>uiImage<span class="token punctuation">:</span> image <span class="token operator">??</span> <span class="token class-name">UIImage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>SwiftUI에서는 다음과 같이 사각형을 그릴 수도 있고, 원을 그릴 수도 있습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">Rectangle</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">.</span><span class="token function">fill</span><span class="token punctuation">(</span><span class="token class-name">Color</span><span class="token punctuation">.</span>blue<span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">.</span><span class="token function">frame</span><span class="token punctuation">(</span>width<span class="token punctuation">:</span> <span class="token number">250</span><span class="token punctuation">,</span> height<span class="token punctuation">:</span> <span class="token number">250</span><span class="token punctuation">)</span>
</span><span class="code-line">  
</span><span class="code-line"><span class="token class-name">Circle</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">.</span><span class="token function">fill</span><span class="token punctuation">(</span><span class="token class-name">Color</span><span class="token punctuation">.</span>blue<span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">.</span><span class="token function">frame</span><span class="token punctuation">(</span>width<span class="token punctuation">:</span> <span class="token number">250</span><span class="token punctuation">,</span> height<span class="token punctuation">:</span> <span class="token number">250</span><span class="token punctuation">)</span>
</span></code></pre>
<h2 id="image-조정하기">Image 조정하기</h2>
<ul>
<li>앞서 사용했던 시스템 아이콘 <code>SF Symbols</code>를 사용하면, 이미지의 색상도 변경할 수 있습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">Image</span><span class="token punctuation">(</span>systemName<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"circle"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">.</span><span class="token function">foregroundColor</span><span class="token punctuation">(</span><span class="token punctuation">.</span>blue<span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>SwiftUI에서 이미지의 크기를 조절하기 위해서는 resizable을 사용하면 됩니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">Image</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"image-name"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">.</span><span class="token function">resizable</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">.</span><span class="token function">frame</span><span class="token punctuation">(</span>width<span class="token punctuation">:</span> <span class="token number">50</span><span class="token punctuation">,</span> height<span class="token punctuation">:</span> <span class="token number">50</span><span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>정해진 사이즈에 이미지를 채우는 방식은, 다음과 같이 지정할 수 있습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">Image</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"image-name"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">.</span><span class="token function">resizable</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">.</span><span class="token function">aspectRatio</span><span class="token punctuation">(</span>contentMode<span class="token punctuation">:</span> <span class="token punctuation">.</span>fill<span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>다음과 같이 SwiftUI에서는 이미지에 그라데이션 효과를 줄 수도 있습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"SwiftUI tutorial by Hohyeon"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">.</span><span class="token function">background</span><span class="token punctuation">(</span><span class="token class-name">LinearGradient</span><span class="token punctuation">(</span>gradient<span class="token punctuation">:</span> <span class="token class-name">Gradient</span><span class="token punctuation">(</span>colors<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token punctuation">.</span>red<span class="token punctuation">,</span> <span class="token punctuation">.</span>blue<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">,</span> startPoint<span class="token punctuation">:</span> <span class="token punctuation">.</span>top<span class="token punctuation">,</span> endPoint<span class="token punctuation">:</span> <span class="token punctuation">.</span>bottom<span class="token punctuation">)</span><span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>배경으로 Image를 사용하기 위해서는 다음과 같이 하면 됩니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"SwiftUI tutorial by Hohyeon"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">.</span><span class="token function">background</span><span class="token punctuation">(</span>
</span><span class="code-line">    <span class="token class-name">Image</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"image-name"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">.</span><span class="token function">resizable</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">.</span><span class="token function">frame</span><span class="token punctuation">(</span>width<span class="token punctuation">:</span> <span class="token number">100</span><span class="token punctuation">,</span> height<span class="token punctuation">:</span> <span class="token number">100</span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">)</span>
</span></code></pre>
<h3 id="asyncimage">AsyncImage</h3>
<ul>
<li>AsyncImage는 SwiftUI에서 비동기적으로 이미지를 로드하고 표시하기 위한 뷰입니다.</li>
<li>iOS 15.0부터 지원되었고, 네트워크나 원격 위치에서 이미지를 가져올 때 특히 유용합니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token comment">// 가장 간단한 형태</span>
</span><span class="code-line"><span class="token class-name">AsyncImage</span><span class="token punctuation">(</span>url<span class="token punctuation">:</span> <span class="token function">URL</span><span class="token punctuation">(</span>string<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"https://example.com/image.jpg"</span></span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token comment">// 이미지 크기 지정</span>
</span><span class="code-line"><span class="token class-name">AsyncImage</span><span class="token punctuation">(</span>url<span class="token punctuation">:</span> <span class="token function">URL</span><span class="token punctuation">(</span>string<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"https://example.com/image.jpg"</span></span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> image <span class="token keyword">in</span>
</span><span class="code-line">    image<span class="token punctuation">.</span><span class="token function">resizable</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">         <span class="token punctuation">.</span><span class="token function">aspectRatio</span><span class="token punctuation">(</span>contentMode<span class="token punctuation">:</span> <span class="token punctuation">.</span>fit<span class="token punctuation">)</span>
</span><span class="code-line">         <span class="token punctuation">.</span><span class="token function">frame</span><span class="token punctuation">(</span>width<span class="token punctuation">:</span> <span class="token number">100</span><span class="token punctuation">,</span> height<span class="token punctuation">:</span> <span class="token number">100</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token comment">// 로딩 상태에 따른 다양한 뷰 처리</span>
</span><span class="code-line"><span class="token class-name">AsyncImage</span><span class="token punctuation">(</span>url<span class="token punctuation">:</span> <span class="token function">URL</span><span class="token punctuation">(</span>string<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"https://example.com/image.jpg"</span></span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> phase <span class="token keyword">in</span>
</span><span class="code-line">    <span class="token keyword">switch</span> phase <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">case</span> <span class="token punctuation">.</span>empty<span class="token punctuation">:</span>
</span><span class="code-line">        <span class="token class-name">ProgressView</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">case</span> <span class="token punctuation">.</span><span class="token function">success</span><span class="token punctuation">(</span><span class="token keyword">let</span> image<span class="token punctuation">)</span><span class="token punctuation">:</span>
</span><span class="code-line">        image<span class="token punctuation">.</span><span class="token function">resizable</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">             <span class="token punctuation">.</span><span class="token function">aspectRatio</span><span class="token punctuation">(</span>contentMode<span class="token punctuation">:</span> <span class="token punctuation">.</span>fit<span class="token punctuation">)</span>
</span><span class="code-line">             <span class="token punctuation">.</span><span class="token function">frame</span><span class="token punctuation">(</span>width<span class="token punctuation">:</span> <span class="token number">100</span><span class="token punctuation">,</span> height<span class="token punctuation">:</span> <span class="token number">100</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">case</span> <span class="token punctuation">.</span>failure<span class="token punctuation">:</span>
</span><span class="code-line">        <span class="token class-name">Image</span><span class="token punctuation">(</span>systemName<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"photo"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">.</span><span class="token function">foregroundColor</span><span class="token punctuation">(</span><span class="token punctuation">.</span>red<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token attribute atrule">@unknown</span> <span class="token keyword">default</span><span class="token punctuation">:</span>
</span><span class="code-line">        <span class="token class-name">EmptyView</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="마무리">마무리</h2>
<ul>
<li>이렇게 해서 SwiftUI에서는 Image를 어떻게 그리는지 알아봤습니다.</li>
</ul>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swiftui-tutorial-text</guid>
      <title>SwiftUI Text 다루기</title>
      <description>SwiftUI에서 Text를 어떻게 다루는지에 대해 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/swiftui-tutorial-text</link>
      <pubDate>Thu, 19 May 2022 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>이번에는 SwiftUI에서 Text를 어떻게 다루는지에 대해 알아보겠습니다.</li>
</ul>
<h2 id="swiftui-text">SwiftUI Text</h2>
<ul>
<li>SwiftUI의 Text는 기본적으로 LocalizedStringKey를 사용합니다.</li>
<li>아래는 Text의 생성자입니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">init</span><span class="token punctuation">(</span>
</span><span class="code-line">    <span class="token omit keyword">_</span> key<span class="token punctuation">:</span> <span class="token class-name">LocalizedStringKey</span><span class="token punctuation">,</span>
</span><span class="code-line">    tableName<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token operator">?</span> <span class="token operator">=</span> <span class="token nil constant">nil</span><span class="token punctuation">,</span>
</span><span class="code-line">    bundle<span class="token punctuation">:</span> <span class="token class-name">Bundle</span><span class="token operator">?</span> <span class="token operator">=</span> <span class="token nil constant">nil</span><span class="token punctuation">,</span>
</span><span class="code-line">    comment<span class="token punctuation">:</span> <span class="token class-name">StaticString</span><span class="token operator">?</span> <span class="token operator">=</span> <span class="token nil constant">nil</span>
</span><span class="code-line"><span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>LocalizedStringKey는 SwiftUI에서 다국어 지원을 쉽게 할 수 있도록 도와주는 타입입니다.</li>
<li>Text 뷰에 문자열을 전달할 때 LocalizedStringKey를 사용하면 Localizable.strings 파일에서 자동으로 번역된 문자열을 가져올수 있습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"hello_world"</span></span><span class="token punctuation">)</span> <span class="token comment">// Localizable.strings에서 번역된 값 사용</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token comment">// en.lproj/Localizable.strings</span>
</span><span class="code-line"><span class="token string-literal"><span class="token string">"hello_world"</span></span> <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"Hello World!"</span></span><span class="token punctuation">;</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token comment">// ko.lproj/Localizable.strings</span>
</span><span class="code-line"><span class="token string-literal"><span class="token string">"hello_world"</span></span> <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"헬로우 월드!"</span></span><span class="token punctuation">;</span>
</span></code></pre>
<h2 id="text-만들기">Text 만들기</h2>
<ul>
<li>기본적으로 Text 레이블은 다음과 같이 만들 수 있습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Hello World"</span></span><span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>그리고 다음과 같이 줄 개수를 제한할 수 있습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit."</span></span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">.</span><span class="token function">lineLimit</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>줄의 개수를 제한하고 싶지 않다면, 숫자 대신 nil 값을 넣어줍니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit."</span></span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">.</span><span class="token function">lineLimit</span><span class="token punctuation">(</span><span class="token nil constant">nil</span><span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>긴 문장에 대해서는 다음과 같이 truncationMode를 사용해 일부를 생략할수도 있습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Lorem ipsum dolor sit amet, consectetur adipiscing elit."</span></span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">.</span><span class="token function">lineLimit</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">.</span><span class="token function">truncationMode</span><span class="token punctuation">(</span><span class="token punctuation">.</span>middle<span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>Text의 줄 간격은 lineSpacing을 다음과 같이 사용하면 조절할 수 있습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Lorem ipsum dolor sit amet, consectetur adipiscing elit."</span></span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">.</span><span class="token function">lineSpacing</span><span class="token punctuation">(</span><span class="token number">50</span><span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>여러 줄에 대한 정렬은 multilineTextAlignment를 통해 제어할 수 있습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Lorem ipsum dolor sit amet, consectetur adipiscing elit."</span></span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">.</span><span class="token function">multilineTextAlignment</span><span class="token punctuation">(</span><span class="token punctuation">.</span>center<span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>Text의 폰트는 font를 통해 변경할 수 있습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Lorem ipsum"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">.</span><span class="token function">font</span><span class="token punctuation">(</span><span class="token punctuation">.</span>largeTitle<span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>Text의 색상을 변경하기 위해서는 foregroundColor를 사용합니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Lorem ipsum"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">.</span><span class="token function">foregroundColor</span><span class="token punctuation">(</span><span class="token class-name">Color</span><span class="token punctuation">.</span>red<span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>Text의 음영색, 배경색을 변경하고 싶다면 background를 사용합니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Lorem ipsum"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">.</span><span class="token function">background</span><span class="token punctuation">(</span><span class="token class-name">Color</span><span class="token punctuation">.</span>yellow<span class="token punctuation">)</span>
</span></code></pre>
<h2 id="label-만들기">Label 만들기</h2>
<ul>
<li>Label은 Text와 Icon을 같이 표시해주는 UI 컴포넌트입니다.</li>
<li>다음과 같이 1번째 파라미터에 String 텍스트를 입력하고 systemImage를 불러올수 있습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">Label</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"동그라미"</span></span><span class="token punctuation">,</span> systemImage<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"circle"</span></span><span class="token punctuation">)</span>
</span></code></pre>
<p><img src="/images/swiftui-tutorial-text-1.png" alt="swiftui-tutorial-text"></p>
<ul>
<li>다음과 같이 <code>font</code>를 통해 Label의 font를 변경할수 있습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">Label</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"동그라미"</span></span><span class="token punctuation">,</span> systemImage<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"circle"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">.</span><span class="token function">font</span><span class="token punctuation">(</span><span class="token punctuation">.</span>title<span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li><code>labelStyle</code>을 통해 Label의 텍스트 혹은 이미지만 표시 할 수도 있습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">Label</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"동그라미"</span></span><span class="token punctuation">,</span> systemImage<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"circle"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">  <span class="token punctuation">.</span><span class="token function">labelStyle</span><span class="token punctuation">(</span><span class="token punctuation">.</span>titleOnly<span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>다음과 같이 텍스트와 아이콘을 완전히 독립적으로 구현할수도 있습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">Label</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Hohyeon Moon"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">.</span><span class="token function">font</span><span class="token punctuation">(</span><span class="token punctuation">.</span>largeTitle<span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span> icon<span class="token punctuation">:</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token class-name">RoundedRectangle</span><span class="token punctuation">(</span>cornerRadius<span class="token punctuation">:</span> <span class="token number">10</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">.</span><span class="token function">fill</span><span class="token punctuation">(</span><span class="token punctuation">.</span>blue<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">.</span><span class="token function">frame</span><span class="token punctuation">(</span>width<span class="token punctuation">:</span> <span class="token number">32</span><span class="token punctuation">,</span> height<span class="token punctuation">:</span> <span class="token number">32</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p><img src="/images/swiftui-tutorial-text-2.png" alt="swiftui-tutorial-text"></p>
<h2 id="마무리">마무리</h2>
<p>이렇게 해서 SwiftUI에서는 Text를 어떻게 다루는지 알아봤습니다.</p>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swiftui-tutorial-action-sheet</guid>
      <title>SwiftUI ActionSheet 띄우기</title>
      <description>SwiftUI에서 ActionSheet를 띄우는 방법에 대해 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/swiftui-tutorial-action-sheet</link>
      <pubDate>Wed, 18 May 2022 18:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>이번에는 SwiftUI에서 ActionSheet를 띄우는 방법에 대해 알아보겠습니다.</li>
</ul>
<h2 id="actionsheet의-현재">ActionSheet의 현재</h2>
<ul>
<li>아래의 ActionSheet는 deprecated 되었습니다.</li>
<li>대신, View 프로토콜의 modifier인 <code>confirmationDialog(...)</code>을 사용해서 ActionSheet을 대체 할 수 있습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token attribute atrule">@State</span> <span class="token keyword">var</span> showingSheet <span class="token operator">=</span> <span class="token boolean">false</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">Button</span><span class="token punctuation">(</span>action<span class="token punctuation">:</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">self</span><span class="token punctuation">.</span>showingSheet <span class="token operator">=</span> <span class="token boolean">true</span>
</span><span class="code-line">    <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Action Sheet 띄우기"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">.</span><span class="token function">confirmationDialog</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"타이틀"</span></span><span class="token punctuation">,</span> isPresented<span class="token punctuation">:</span> $showingSheet<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token class-name">Button</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"제거"</span></span><span class="token punctuation">,</span> role<span class="token punctuation">:</span> <span class="token punctuation">.</span>destructive<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
</span><span class="code-line">      <span class="token class-name">Button</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"취소"</span></span><span class="token punctuation">,</span> role<span class="token punctuation">:</span> <span class="token punctuation">.</span>cancel<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span> 
</span></code></pre>
<h2 id="actionsheet의-과거">ActionSheet의 과거</h2>
<ul>
<li>ActionSheet는 과거에 다음과 같은 형태를 갖고 있었습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">ActionSheet</span><span class="token punctuation">(</span>title<span class="token punctuation">:</span> <span class="token class-name">Text</span><span class="token punctuation">,</span> message<span class="token punctuation">:</span> <span class="token class-name">Text</span><span class="token operator">?</span><span class="token punctuation">,</span> buttons<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">ActionSheet</span><span class="token punctuation">.</span><span class="token class-name">Button</span><span class="token punctuation">]</span><span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>다음 코드와 같이 버튼과 @State 변수를 만들어, 버튼을 누르면 원하는 ActionSheet가 나오게 할 수 있었습니다.</li>
<li>버튼을 누르면, ActionSheet이 활성화되고 옵션 버튼들이 Sheet에 나타나게 됩니다.</li>
<li>iOS 13과 14를 지원하기 위해서는 여전히 ActionSheet을 이렇게 구현해야 합니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token attribute atrule">@State</span> <span class="token keyword">var</span> showingSheet <span class="token operator">=</span> <span class="token boolean">false</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">Button</span><span class="token punctuation">(</span>action<span class="token punctuation">:</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">self</span><span class="token punctuation">.</span>showingSheet <span class="token operator">=</span> <span class="token boolean">true</span>
</span><span class="code-line">    <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Show Action Sheet"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">.</span><span class="token function">actionSheet</span><span class="token punctuation">(</span>isPresented<span class="token punctuation">:</span> $showingSheet<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">ActionSheet</span><span class="token punctuation">(</span>title<span class="token punctuation">:</span> <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Title"</span></span><span class="token punctuation">)</span><span class="token punctuation">,</span> message<span class="token punctuation">:</span> <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"message"</span></span><span class="token punctuation">)</span><span class="token punctuation">,</span> buttons<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token punctuation">.</span><span class="token keyword">default</span><span class="token punctuation">(</span><span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Dismiss"</span></span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">.</span><span class="token function">cancel</span><span class="token punctuation">(</span><span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Cancel"</span></span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>	
</span></code></pre>
<p><img src="/images/swiftui-tutorial-action-sheet-1.gif" alt="swiftui-tutorial-action-sheet"></p>
<h2 id="마무리">마무리</h2>
<ul>
<li>이렇게 해서 SwiftUI에서는 ActionSheet을 어떻게 띄우는지 알아봤습니다.</li>
</ul>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swiftui-tutorial-alert</guid>
      <title>SwiftUI Alert 띄우기</title>
      <description>SwiftUI에서 Alert 창을 띄우는 법에 대해 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/swiftui-tutorial-alert</link>
      <pubDate>Wed, 18 May 2022 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>이번에는 SwiftUI에서 Alert 창을 띄우는 방법에 대해 알아보겠습니다.</li>
</ul>
<h2 id="alert-창의-현재">Alert 창의 현재</h2>
<ul>
<li>과거의 Alert 창은 deprecated 되었습니다.</li>
<li>대신, View 프로토콜의 modifier인 <code>alert(...)</code>을 사용해서 alert 창을 띄울 수 있습니다.</li>
<li>이렇게 iOS 15부터는 <code>alert</code> modifier로 Alert이 대체되었습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token attribute atrule">@State</span> <span class="token keyword">private</span> <span class="token keyword">var</span> showing <span class="token operator">=</span> <span class="token boolean">false</span>
</span><span class="code-line">  
</span><span class="code-line">  <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">Button</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Alert 띄우기"</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        showing <span class="token operator">=</span> <span class="token boolean">true</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">.</span><span class="token function">alert</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"메시지"</span></span><span class="token punctuation">,</span> isPresented<span class="token punctuation">:</span> $showing<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">      <span class="token class-name">Button</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"OK"</span></span><span class="token punctuation">,</span> role<span class="token punctuation">:</span> <span class="token punctuation">.</span>cancel<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h3 id="여러개의-버튼-추가">여러개의 버튼 추가</h3>
<ul>
<li><code>role: .destructive</code>: 빨간색 강조 버튼</li>
<li><code>role: .cancel</code>: 기본 취소 버튼</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token punctuation">.</span><span class="token function">alert</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"옵션 선택"</span></span><span class="token punctuation">,</span> isPresented<span class="token punctuation">:</span> $showAlert<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">Button</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"삭제"</span></span><span class="token punctuation">,</span> role<span class="token punctuation">:</span> <span class="token punctuation">.</span>destructive<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"삭제 선택"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token class-name">Button</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"취소"</span></span><span class="token punctuation">,</span> role<span class="token punctuation">:</span> <span class="token punctuation">.</span>cancel<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span> message<span class="token punctuation">:</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"정말 삭제하시겠습니까?"</span></span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h3 id="데이터-기반">데이터 기반</h3>
<ul>
<li>특정 데이터가 있을 때만 Alert을 표시하려면 Identifiable을 활용할 수도 있습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">AlertData</span><span class="token punctuation">:</span> <span class="token class-name">Identifiable</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> id <span class="token operator">=</span> <span class="token function">UUID</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">let</span> title<span class="token punctuation">:</span> <span class="token class-name">String</span>
</span><span class="code-line">    <span class="token keyword">let</span> message<span class="token punctuation">:</span> <span class="token class-name">String</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentView</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token attribute atrule">@State</span> <span class="token keyword">private</span> <span class="token keyword">var</span> alertData<span class="token punctuation">:</span> <span class="token class-name">AlertData</span><span class="token operator">?</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">Button</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"데이터 기반 알럿"</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            alertData <span class="token operator">=</span> <span class="token class-name">AlertData</span><span class="token punctuation">(</span>title<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"오류"</span></span><span class="token punctuation">,</span> message<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"네트워크 오류가 발생했습니다."</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">alert</span><span class="token punctuation">(</span>alertData<span class="token operator">?</span><span class="token punctuation">.</span>title <span class="token operator">??</span> <span class="token string-literal"><span class="token string">""</span></span><span class="token punctuation">,</span> isPresented<span class="token punctuation">:</span> $alertData<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token class-name">Button</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"확인"</span></span><span class="token punctuation">,</span> role<span class="token punctuation">:</span> <span class="token punctuation">.</span>cancel<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">}</span> message<span class="token punctuation">:</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token class-name">Text</span><span class="token punctuation">(</span>alertData<span class="token operator">?</span><span class="token punctuation">.</span>message <span class="token operator">??</span> <span class="token string-literal"><span class="token string">""</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="alert-창의-과거">Alert 창의 과거</h2>
<ul>
<li>Alert은 다음과 같은 파라미터를 갖고 있었습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">Alert</span><span class="token punctuation">(</span>title<span class="token punctuation">:</span> <span class="token class-name">Text</span><span class="token punctuation">,</span> message<span class="token punctuation">:</span> <span class="token class-name">Text</span><span class="token operator">?</span><span class="token punctuation">,</span> dismissButton<span class="token punctuation">:</span> <span class="token class-name">Alert</span><span class="token punctuation">.</span><span class="token class-name">Button</span><span class="token operator">?</span><span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>다음 코드와 같이 버튼과 @State 변수를 만들어, 버튼을 누르면 원하는 Alert 창이 나오게 할 수 있었습니다.</li>
<li>그리고 iOS 13과 14를 지원하기 위해서는 여전히 Alert을 이렇게 구현해야 합니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">ContentViewNine</span><span class="token punctuation">:</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token attribute atrule">@State</span> <span class="token keyword">private</span> <span class="token keyword">var</span> showingAlert <span class="token operator">=</span> <span class="token boolean">false</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">var</span> body<span class="token punctuation">:</span> <span class="token keyword">some</span> <span class="token class-name">View</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">Button</span><span class="token punctuation">(</span>action<span class="token punctuation">:</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">self</span><span class="token punctuation">.</span>showingAlert <span class="token operator">=</span> <span class="token boolean">true</span>
</span><span class="code-line">        <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Show Alert"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">alert</span><span class="token punctuation">(</span>isPresented<span class="token punctuation">:</span> $showingAlert<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token class-name">Alert</span><span class="token punctuation">(</span>title<span class="token punctuation">:</span> <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Title"</span></span><span class="token punctuation">)</span><span class="token punctuation">,</span> message<span class="token punctuation">:</span> <span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"This is a alert message"</span></span><span class="token punctuation">)</span><span class="token punctuation">,</span> dismissButton<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token keyword">default</span><span class="token punctuation">(</span><span class="token class-name">Text</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Dismiss"</span></span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="마무리">마무리</h2>
<ul>
<li>이렇게 해서 SwiftUI에서는 Alert을 어떻게 띄우는지 알아봤습니다.</li>
</ul>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swiftui-tutorial-xcode-setting</guid>
      <title>SwiftUI 개발 환경 세팅</title>
      <description>SwiftUI를 개발하기 위한 환경을 세팅하는 방법에 대해 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/swiftui-tutorial-xcode-setting</link>
      <pubDate>Tue, 17 May 2022 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>이번에는 SwiftUI를 개발하기 위한 환경을 세팅하는 방법에 대해 알아보겠습니다.</p>
<h2 id="macos-1015-이상-설치">macOS 10.15 이상 설치</h2>
<p>애플 개발자 사이트에 접속합니다. 메뉴에서 Develop > Downloads 로 갑니다. 이곳을 들어가려면 애플 개발자 등록이 되어 있어야 합니다.</p>
<p><img src="/images/swiftui-tutorial-xcode-setting-1.png" alt="swiftui-tutorial-xcode-setting"></p>
<p>여기서 macOS 10.15과 Xcode 11 이상의 버전을 다운로드 받습니다.</p>
<p><img src="/images/swiftui-tutorial-xcode-setting-2.png" alt="swiftui-tutorial-xcode-setting"></p>
<p>다운로드 받은 파일을 실행시켜 macOS 업데이트와 Xcode 설치를 완료합니다.</p>
<h2 id="macos-1014-이하에서는">macOS 10.14 이하에서는?</h2>
<p>macOS 10.14 이하의 운영체제에서 SwiftUI를 개발할 수 있기는 합니다. 하지만 Preview Canvas 기능이 안 된다거나 SwiftUI 문법 자동 완성이 완벽하지 않는 등 제약이 있습니다.</p>
<p>macOS 10.14 이하의 운영체제에서 SwiftUI를 개발하기 위해서는 애플 개발자 사이트에서 Xcode 11만 다운로드 받고 설치하면 됩니다.</p>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swiftui-tutorial-introduction</guid>
      <title>SwiftUI 소개</title>
      <description>애플의 새로운 개발 패러다임인 SwiftUI에 대해 소개합니다</description>
      <link>https://www.hohyeonmoon.com/blog/swiftui-tutorial-introduction</link>
      <pubDate>Mon, 16 May 2022 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>애플의 WWDC 19에서 공개된 SwiftUI는 어느덧 년차가 꽤 되었고, 해를 거치면서 점점 지원되는 기능도 늘고 안정화도 되어가고 있는데요. 이번 글에서는 이러한 SwiftUI가 무엇인지에 대해 알아보도록 하겠습니다.</p>
<h2 id="swiftui-란">SwiftUI 란?</h2>
<p><img src="/images/swiftui-tutorial-introduction-1.png" alt="swiftui-tutorial-introduction"></p>
<p>SwiftUI는 모든 애플 플랫폼(iOS, iPadOS, macOS, visionOS, watchOS, tvOS)에서 사용자 인터페이스를 만들 수 있게 해주는 새로운 개발 패러다임입니다. 쉽게 말해, 한번의 개발로 모든 애플 기기의 사용자 인터페이스를 만들 수 있게 해줍니다.</p>
<p>선언형 방식을 사용해, View의 상태에 따라 UI가 자동으로 갱신되는 특징도 있습니다. 기존 UIKit의 명령형 방식보다 훨씬 직관적이고 간결한 코드를 작성할수 있습니다.</p>
<h2 id="swiftui-vs-uikit">SwiftUI vs UIKit</h2>
<p><img src="/images/swiftui-tutorial-introduction-2.png" alt="swiftui-tutorial-introduction"></p>
<p>애플은 점점 새로운 기능을 SwiftUI 중심으로 지원하고 있고, 대대적으로 홍보 중이기도 합니다. SwiftUI는 선언형 구문과 상태 기반의 랜더링을 채택해 적은 코드로 UI를 빠르게 구현할수 있고, 다양한 애플 플랫폼을 지원할수 있다는 장점도 있습니다.</p>
<p>하지만 여전히 많은 코드는 UIKit 기반으로 작성되어 있고, UIKit은 호환되는 라이브러리나 참고할 리소스가 풍부합니다. 성숙한 프레임워크이기 때문에 안정성도 높고, 세밀한 커스텀도 가능합니다. 그렇기 때문에 쉽게 점유율을 잃지는 않고 있습니다.</p>
<p>SwiftUI와 UIKit에 각각 장단점이 있지만, 새로 시작되는 프로젝트는 SwiftUI를 많이 사용하고 기존의 프로젝트는 일부 화면에 대해서만 SwiftUI를 사용하는 추세입니다.</p>
<h2 id="무엇을-배워야-하나">무엇을 배워야 하나?</h2>
<p><img src="/images/swiftui-tutorial-introduction-3.png" alt="swiftui-tutorial-introduction"></p>
<p>그렇다면 SwiftUI와 UIKit 중 어떤 것을 배워야 할까요? 지금 처음 개발하기 시작했다면, SwiftUI로 시작하는 것을 추천합니다. 점점 SwiftUI가 UIKit 대신 사용될 것이고, 일 자리에서도 SwiftUI를 요구하기 시작할 것입니다. 애플도 이 방향으로 흘러갈 것을 기대할 것이고 많은 개발자 역시 이를 환영할 것입니다.</p>
<p>하지만, 이미 수많은 앱과 시스템이 UIKit 및 Storyboard로 개발되어 있고, 투자되었습니다. 그렇기에 이 개발을 지속하고 유지 보수하기 위해 UIKit 및 Storyboard도 사라지지는 않을 것입니다.</p>
<h2 id="swiftui가-uikit의-대체품인가">SwiftUI가 UIKit의 대체품인가?</h2>
<p><img src="/images/swiftui-tutorial-introduction-4.png" alt="swiftui-tutorial-introduction"></p>
<p>iOS에서는 SwiftUI의 많은 것들이 UIKit 위에서 작동하기 때문에 SwiftUI가 UIKit의 대체품이라고 할 수는 없습니다. SwiftUI가 UIKit의 대체품은 아니지만, iOS 개발자 입장에서는 결국 SwiftUI와 UIKit 중 선택을 해야하기 때문에 고민이 될 것입니다.</p>
<p>UIKit은 SwiftUI가 더 많이 사용되는 미래에도 당분간은 공존할 것으로 보여 숙지는 해야합니다.</p>
<h2 id="swiftui의-호환성">SwiftUI의 호환성</h2>
<p><img src="/images/swiftui-tutorial-introduction-5.png" alt="swiftui-tutorial-introduction"></p>
<p>SwiftUI는 iOS 13, macOS 10.15, tvOS 13, watchOS 6 이후의 운영체제에서 실행됩니다. 즉, 그 이전 버전까지 지원해야 하는 앱이라면 SwiftUI를 고려하는 것은 위험할 수 있습니다.</p>
<p>또, SwiftUI의 일부 기능들은 더욱 최신 운영체제를 요구하기 때문에 이 점도 유의해서 적용해야 합니다.</p>
<h2 id="마무리">마무리</h2>
<p><img src="/images/swiftui-tutorial-introduction-6.png" alt="swiftui-tutorial-introduction"></p>
<p>SwiftUI는 지원 가능한 최소 버전이 정해져있고, 이미 수많은 앱이 UIKit 방식으로 개발되어 있습니다. 그리고 아직은 UIKit에 비해 SwiftUI 관련 자료도 턱없이 부족합니다.</p>
<p>그렇기 때문에, 빠른 시일 내에 UIKit이 사라지는 일이 발생하지 않겠지만, 언젠가는 SwiftUI를 UIKit보다 많이 사용하는 날이 올 것이라고 생각합니다. 그렇기에 애플 플랫폼 개발을 새롭게 시작하는 개발자라면 SwiftUI로 시작하는 가치는 충분한 것 같습니다.</p>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swiftui-tutorial-course-intro</guid>
      <title>SwiftUI 강좌 소개</title>
      <description>애플의 새로운 개발 패러다임인 SwiftUI의 강좌를 소개합니다</description>
      <link>https://www.hohyeonmoon.com/blog/swiftui-tutorial-course-intro</link>
      <pubDate>Sun, 15 May 2022 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p><img src="/images/swiftui-tutorial-course-intro-1.png" alt="swiftui-tutorial-course-intro"></p>
<h2 id="소개">소개</h2>
<p>애플은 WWDC 19에서 애플 플랫폼의 앱을 개발을 위해 새로운 프레임워크인 SwiftUI를 공개했습니다. SwiftUI는 모든 애플 플랫폼(iOS, iPadOS, macOS, visionOS, watchOS, tvOS)의 앱을 만들 수 있게 해줍니다.</p>
<p>이 SwiftUI 강좌 시리즈는 애플 앱 개발의 현재이자 미래인 SwiftUI 프레임워크 사용법에 대해 알아봅니다.</p>
<p>어떤 기술이든, 본격적으로 사용하기에 앞서 기술에 대한 기본적인 지식이 필요합니다. 그러나 SwiftUI 관련 한국어 자료가 부족한 상황이고, 이 강좌는 그 부분을 채워주기 위해 만들어졌습니다. 단, Swift의 기본 문법은 숙지하고 있어야 진행하기 편합니다. Swift 기본 문법은 <a href="https://docs.swift.org/swift-book/documentation/the-swift-programming-language/thebasics/">Swift 공식 문서</a>를 참고하시면 좋습니다.</p>
<p>해당 강좌는 <a href="https://www.youtube.com/hohyeonmoon">유튜브 채널</a>에서도 볼 수 있습니다.</p>
<h2 id="특징">특징</h2>
<p><img src="/images/swiftui-tutorial-course-intro-2.png" alt="swiftui-tutorial-course-intro"></p>
<p>아래에 해당하는 분들에게 추천하는 강좌입니다.</p>
<ul>
<li>아이폰 앱 및 SwiftUI 개발에 입문하고 싶으신 분</li>
<li>iOS, macOS 등 애플 관련 개발을 하고 싶으신 분</li>
<li>Swift 기본 문법을 숙지하신 분</li>
</ul>
<p>iOS, Swift, SwiftUI, Xcode 등의 기술이 사용됩니다. 맥을 필수적으로 필요로 하고, 아이폰까지 있으면 좋습니다. 강좌의 수준은 초급자에게 맞춰져 있습니다.</p>
<h2 id="커리큘럼">커리큘럼</h2>
<p>시작하기</p>
<ul>
<li><a href="/blog/swiftui-tutorial-introduction/">SwiftUI 소개</a></li>
<li><a href="/blog/swiftui-tutorial-xcode-setting/">개발 환경 세팅</a></li>
</ul>
<p>UI 요소</p>
<ul>
<li><a href="/blog/swiftui-tutorial-alert/">Alert 띄우기</a></li>
<li><a href="/blog/swiftui-tutorial-action-sheet/">Action Sheet 사용하기</a></li>
<li><a href="/blog/swiftui-tutorial-text/">Text 다루기</a></li>
<li><a href="/blog/swiftui-tutorial-image/">Image 구현</a></li>
<li><a href="/blog/swiftui-tutorial-textfield/">TextField 다루기</a></li>
<li><a href="/blog/swiftui-tutorial-buttons/">여러 종류의 Buttons</a></li>
<li><a href="/blog/swiftui-tutorial-slider-stepper/">Slider와 Stepper</a></li>
<li><a href="/blog/swiftui-tutorial-picker/">Picker 사용하기</a></li>
</ul>
<p>View 컨테이너</p>
<ul>
<li><a href="/blog/swiftui-tutorial-view/">View 레이아웃</a></li>
<li><a href="/blog/swiftui-tutorial-grid/">Grid 사용하기</a></li>
<li><a href="/blog/swiftui-tutorial-list/">List 만들기</a></li>
<li><a href="/blog/swiftui-tutorial-form/">Form 사용하기</a></li>
<li><a href="/blog/swiftui-tutorial-scrollview/">ScrollView 사용하기</a></li>
<li><a href="/blog/swiftui-tutorial-navigation/">NavigationView 사용하기</a></li>
<li><a href="/blog/swiftui-tutorial-tab-view/">TabView 사용하기</a></li>
</ul>
<p>Extra 기술</p>
<ul>
<li><a href="/blog/swiftui-data-flow/">SwiftUI의 데이터 흐름</a></li>
<li><a href="/blog/swiftui-tutorial-uikit/">SwiftUI와 UIKit 혼용하기</a></li>
<li><a href="/blog/swiftui-tutorial-preview/">Preview 사용하기</a></li>
</ul>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/publisher-and-subscriber</guid>
      <title>Combine의 Publisher와 Subscriber</title>
      <description>Combine의 핵심 요소인 Publisher와 Subscriber에 대해 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/publisher-and-subscriber</link>
      <pubDate>Wed, 15 Dec 2021 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>Combine의 Publisher와 Subscriber에 대해 알아보겠다.</li>
<li>Xcode의 Playground에서 실습을 진행하려고 한다.</li>
</ul>
<h2 id="실습-준비">실습 준비</h2>
<ul>
<li>Playground에서의 실습을 보다 편하게 진행하기 위해</li>
<li>다음과 같은 코드를 Playground의 Sources 폴더 안에 임의의 파일에 작성해두자.</li>
</ul>
<pre><code class="code-highlight"><span class="code-line">import Foundation
</span><span class="code-line">
</span><span class="code-line">public func example(of description: String, action: () -> Void) {
</span><span class="code-line">    print("\n——— Example of:", description, "———")
</span><span class="code-line">    action()
</span><span class="code-line">}
</span></code></pre>
<h2 id="publisher">Publisher</h2>
<ul>
<li>Playground 최상단에 Foundation과 Combine을 import 한다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">import</span> <span class="token class-name">Foundation</span>
</span><span class="code-line"><span class="token keyword">import</span> <span class="token class-name">Combine</span>
</span></code></pre>
<ul>
<li>우선은 Publisher와 비슷한 Notification을 통해 코드를 구현해보자.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token function">example</span><span class="token punctuation">(</span>of<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Publisher"</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> myNotification <span class="token operator">=</span>  <span class="token class-name">Notification</span><span class="token punctuation">.</span><span class="token class-name">Name</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"MyNotification"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">let</span> center <span class="token operator">=</span> <span class="token class-name">NotificationCenter</span><span class="token punctuation">.</span><span class="token keyword">default</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">let</span> observer <span class="token operator">=</span> center<span class="token punctuation">.</span><span class="token function">addObserver</span><span class="token punctuation">(</span>forName<span class="token punctuation">:</span> myNotification<span class="token punctuation">,</span> object<span class="token punctuation">:</span> <span class="token nil constant">nil</span><span class="token punctuation">,</span> queue<span class="token punctuation">:</span> <span class="token nil constant">nil</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">(</span>notification<span class="token punctuation">)</span> <span class="token keyword">in</span>
</span><span class="code-line">        <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Notification received!"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    center<span class="token punctuation">.</span><span class="token function">post</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> myNotification<span class="token punctuation">,</span> object<span class="token punctuation">:</span> <span class="token nil constant">nil</span><span class="token punctuation">)</span>
</span><span class="code-line">    center<span class="token punctuation">.</span><span class="token function">removeObserver</span><span class="token punctuation">(</span>observer<span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>이것이 Publisher로부터 온 출력 값이라고 할 수는 없지만</li>
<li>실행해보면 다음과 같이 출력된다.</li>
<li>실제로 Publisher로부터 값을 받으려면 Subscriber가 필요하다.</li>
</ul>
<pre class="language-bash"><code class="language-bash code-highlight"><span class="code-line">——— Example of: Publisher ———
</span><span class="code-line">Notification received<span class="token operator">!</span>
</span></code></pre>
<h2 id="subscriber">Subscriber</h2>
<ul>
<li>NotificationCenter의 publisher를 sink로 subscribe하는 것을 구현해보자.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token function">example</span><span class="token punctuation">(</span>of<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Subscriber"</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> myNotification <span class="token operator">=</span>  <span class="token class-name">Notification</span><span class="token punctuation">.</span><span class="token class-name">Name</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"MyNotification"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">let</span> publisher <span class="token operator">=</span> <span class="token class-name">NotificationCenter</span><span class="token punctuation">.</span><span class="token keyword">default</span><span class="token punctuation">.</span><span class="token function">publisher</span><span class="token punctuation">(</span><span class="token keyword">for</span><span class="token punctuation">:</span> myNotification<span class="token punctuation">,</span> object<span class="token punctuation">:</span> <span class="token nil constant">nil</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">let</span> center <span class="token operator">=</span> <span class="token class-name">NotificationCenter</span><span class="token punctuation">.</span><span class="token keyword">default</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">let</span> subscription <span class="token operator">=</span> publisher<span class="token punctuation">.</span>sink <span class="token punctuation">{</span> <span class="token omit keyword">_</span> <span class="token keyword">in</span>
</span><span class="code-line">        <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Notification received from a publisher!"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    center<span class="token punctuation">.</span><span class="token function">post</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> myNotification<span class="token punctuation">,</span> object<span class="token punctuation">:</span> <span class="token nil constant">nil</span><span class="token punctuation">)</span>
</span><span class="code-line">    subscription<span class="token punctuation">.</span><span class="token function">cancel</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>실행해보면 다음과 같이 출력된다.</li>
</ul>
<pre class="language-bash"><code class="language-bash code-highlight"><span class="code-line">——— Example of: Subscriber ———
</span><span class="code-line">Notification received from a publisher<span class="token operator">!</span>
</span></code></pre>
<ul>
<li>이제 Just라는 새로운 예시를 보면, Just를 통해 새로운 Publisher를 생성한다.</li>
<li>sink를 통해 publisher를 subscribe 해서 subscription을 생성한다.</li>
<li>그리고 event를 전달 받을 때마다 메세지를 print한다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token function">example</span><span class="token punctuation">(</span>of<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Just"</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> just <span class="token operator">=</span> <span class="token class-name">Just</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Hello world!"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token omit keyword">_</span> <span class="token operator">=</span> just
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">sink</span><span class="token punctuation">(</span>
</span><span class="code-line">            receiveCompletion<span class="token punctuation">:</span> <span class="token punctuation">{</span>
</span><span class="code-line">                <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Received completion"</span></span><span class="token punctuation">,</span> <span class="token short-argument">$0</span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">}</span><span class="token punctuation">,</span>
</span><span class="code-line">            receiveValue<span class="token punctuation">:</span> <span class="token punctuation">{</span>
</span><span class="code-line">                <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Received value"</span></span><span class="token punctuation">,</span> <span class="token short-argument">$0</span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">)</span>    
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>실행해보면 다음과 같이 출력 된다.</li>
</ul>
<pre class="language-bash"><code class="language-bash code-highlight"><span class="code-line">——— Example of: Just ———
</span><span class="code-line">Received value Hello world<span class="token operator">!</span>
</span><span class="code-line">Received completion finished
</span></code></pre>
<ul>
<li>위 코드에다 추가적인 subscriber를 통해 한번 더 subscribe 해보자.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token omit keyword">_</span> <span class="token operator">=</span> just
</span><span class="code-line">  <span class="token punctuation">.</span><span class="token function">sink</span><span class="token punctuation">(</span>
</span><span class="code-line">      receiveCompletion<span class="token punctuation">:</span> <span class="token punctuation">{</span>
</span><span class="code-line">          <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Received completion (another)"</span></span><span class="token punctuation">,</span> <span class="token short-argument">$0</span><span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">}</span><span class="token punctuation">,</span>
</span><span class="code-line">      receiveValue<span class="token punctuation">:</span> <span class="token punctuation">{</span>
</span><span class="code-line">          <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Received value (another)"</span></span><span class="token punctuation">,</span> <span class="token short-argument">$0</span><span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>한번 더 subscription 과정이 이뤄지고, 다음과 같이 출력된다.</li>
</ul>
<pre class="language-bash"><code class="language-bash code-highlight"><span class="code-line">——— Example of: Just ———
</span><span class="code-line">Received value Hello world<span class="token operator">!</span>
</span><span class="code-line">Received completion finished
</span><span class="code-line">Received value <span class="token punctuation">(</span>another<span class="token punctuation">)</span> Hello world<span class="token operator">!</span>
</span><span class="code-line">Received completion <span class="token punctuation">(</span>another<span class="token punctuation">)</span> finished
</span></code></pre>
<ul>
<li>Combine의 또 다른 built-in subscriber인 assign도 살짝 알아보자.</li>
<li><code>assign(to:on:)</code>을 다음과 같이 구현해보자.</li>
<li>didSet이 있는 프로퍼티를 갖고 있는 class를 정의하고 instance를 생성한다.</li>
<li>string array로부터 publisher를 생성한다.</li>
<li>publisher를 subscribe 한다.</li>
<li>생성한 object의 property에 전달 받은 값을 할당한다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token function">example</span><span class="token punctuation">(</span>of<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"assign(to:on:)"</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">class</span> <span class="token class-name">SomeObject</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">var</span> value<span class="token punctuation">:</span> <span class="token class-name">String</span> <span class="token operator">=</span> <span class="token string-literal"><span class="token string">""</span></span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">didSet</span> <span class="token punctuation">{</span>
</span><span class="code-line">                <span class="token function">print</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">let</span> object <span class="token operator">=</span> <span class="token class-name">SomeObject</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">let</span> publisher <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string-literal"><span class="token string">"Hello"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"world!"</span></span><span class="token punctuation">]</span><span class="token punctuation">.</span>publisher
</span><span class="code-line">
</span><span class="code-line">    <span class="token omit keyword">_</span> <span class="token operator">=</span> publisher
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">assign</span><span class="token punctuation">(</span>to<span class="token punctuation">:</span> <span class="token punctuation">\</span><span class="token punctuation">.</span>value<span class="token punctuation">,</span> on<span class="token punctuation">:</span> object<span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>실행해보면 다음과 같이 출력 된다.</li>
</ul>
<pre class="language-bash"><code class="language-bash code-highlight"><span class="code-line">——— Example of: assign<span class="token punctuation">(</span>to:on:<span class="token punctuation">)</span> ——
</span><span class="code-line">Hello
</span><span class="code-line">world<span class="token operator">!</span>
</span></code></pre>
<h2 id="cancellable">Cancellable</h2>
<ul>
<li>Subscriber가 Publisher로부터 더 이상 값을 전달 받고 싶지 않을 때,</li>
<li>resource를 낭비하지 않기 위해 Subscription을 cancel 하는 것이 좋다.</li>
<li>Subscriber는 AnyCancellable instance를 리턴하고,</li>
<li>AnyCancellable은 Cancellable 프로토콜을 따라서, <code>cancel()</code>을 사용하면 된다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line">subscription<span class="token punctuation">.</span><span class="token function">cancel</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span></code></pre>
<h2 id="커스텀-subscriber">커스텀 Subscriber</h2>
<ul>
<li>다음과 같이 커스텀 IntSubscriber를 만들어보자.</li>
<li>우선, 1부터 6까지의 범위 publisher를 만든다.</li>
<li>커스텀 IntSubscriber를 선언하고, Input과 Failure를 명시한다.</li>
<li>3가지 종류의 필수 메소드, receive를 구현한다.</li>
<li>publisher에게 불리는 <code>receive(subscription:)</code>를 .request로 구현한다.</li>
<li>각 값을 print 하고, .max(0)과 동일한 .none을 return 한다.</li>
<li>completion event를 print 한다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token function">example</span><span class="token punctuation">(</span>of<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Custom Subscriber"</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> publisher <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">1</span><span class="token operator">...</span><span class="token number">6</span><span class="token punctuation">)</span><span class="token punctuation">.</span>publisher
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">final</span> <span class="token keyword">class</span> <span class="token class-name">IntSubscriber</span><span class="token punctuation">:</span> <span class="token class-name">Subscriber</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">typealias</span> <span class="token class-name">Input</span> <span class="token operator">=</span> <span class="token class-name">Int</span>
</span><span class="code-line">        <span class="token keyword">typealias</span> <span class="token class-name">Failure</span> <span class="token operator">=</span> <span class="token class-name">Never</span>
</span><span class="code-line">
</span><span class="code-line">        <span class="token keyword">func</span> <span class="token function-definition function">receive</span><span class="token punctuation">(</span>subscription<span class="token punctuation">:</span> <span class="token class-name">Subscription</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            subscription<span class="token punctuation">.</span><span class="token function">request</span><span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token function">max</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">func</span> <span class="token function-definition function">receive</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> input<span class="token punctuation">:</span> <span class="token class-name">Int</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Subscribers</span><span class="token punctuation">.</span><span class="token class-name">Demand</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Received value"</span></span><span class="token punctuation">,</span> input<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token keyword">return</span> <span class="token punctuation">.</span><span class="token keyword">none</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">func</span> <span class="token function-definition function">receive</span><span class="token punctuation">(</span>completion<span class="token punctuation">:</span> <span class="token class-name">Subscribers</span><span class="token punctuation">.</span><span class="token class-name">Completion</span><span class="token operator">&#x3C;</span><span class="token class-name">Never</span><span class="token operator">></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Received completion"</span></span><span class="token punctuation">,</span> completion<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">let</span> subscriber <span class="token operator">=</span> <span class="token class-name">IntSubscriber</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    publisher<span class="token punctuation">.</span><span class="token function">subscribe</span><span class="token punctuation">(</span>subscriber<span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>실행해보면 다음과 같이 출력 된다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line">——— <span class="token class-name">Example</span> of<span class="token punctuation">:</span> <span class="token class-name">Custom</span> <span class="token class-name">Subscriber</span> ———
</span><span class="code-line"><span class="token class-name">Received</span> value <span class="token number">1</span>
</span><span class="code-line"><span class="token class-name">Received</span> value <span class="token number">2</span>
</span><span class="code-line"><span class="token class-name">Received</span> value <span class="token number">3</span>
</span></code></pre>
<h2 id="future">Future</h2>
<ul>
<li>Just와 비슷하게 Future은 비동기 방식으로 하나의 결과를 emit하고 종료한다.</li>
<li>Future를 아래 코드와 같이 사용해보자.</li>
<li><code>Future&#x3C;Int, Never></code>안의 코드는 promise를 생성하고,</li>
<li>일정 시간의 delay 후 integer를 증가시킨다.</li>
<li>Future은 결국 하나의 값을 emit하고 종료되거나, fail 하는 publisher이다.</li>
<li>promise는 typealias로 <code>(Result&#x3C;Output, Failure>) -> Void</code> 이렇게 생겼다.</li>
<li>그 밑의 코드는 integer 1을 3초의 delay 후 증가시키고,</li>
<li>sink subscriber를 통해 value와 completion을 받아오는 것이다.</li>
<li>store에 대해서는 나중에 알아 볼 예정이다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token function">example</span><span class="token punctuation">(</span>of<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Future"</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">futureIncrement</span><span class="token punctuation">(</span>integer<span class="token punctuation">:</span> <span class="token class-name">Int</span><span class="token punctuation">,</span> afterDelay delay<span class="token punctuation">:</span> <span class="token class-name">TimeInterval</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Future</span><span class="token operator">&#x3C;</span><span class="token class-name">Int</span><span class="token punctuation">,</span> <span class="token class-name">Never</span><span class="token operator">></span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">Future</span><span class="token operator">&#x3C;</span><span class="token class-name">Int</span><span class="token punctuation">,</span> <span class="token class-name">Never</span><span class="token operator">></span> <span class="token punctuation">{</span> promise <span class="token keyword">in</span>
</span><span class="code-line">            <span class="token class-name">DispatchQueue</span><span class="token punctuation">.</span><span class="token function">global</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">asyncAfter</span><span class="token punctuation">(</span>deadline<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> delay<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">                <span class="token function">promise</span><span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token function">success</span><span class="token punctuation">(</span>integer <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">let</span> future <span class="token operator">=</span> <span class="token function">futureIncrement</span><span class="token punctuation">(</span>integer<span class="token punctuation">:</span> <span class="token number">1</span><span class="token punctuation">,</span> afterDelay<span class="token punctuation">:</span> <span class="token number">3</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">    future
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">sink</span><span class="token punctuation">(</span>receiveCompletion<span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token function">print</span><span class="token punctuation">(</span><span class="token short-argument">$0</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
</span><span class="code-line">              receiveValue<span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token function">print</span><span class="token punctuation">(</span><span class="token short-argument">$0</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">.</span><span class="token function">store</span><span class="token punctuation">(</span><span class="token keyword">in</span><span class="token punctuation">:</span> <span class="token operator">&#x26;</span>subscriptions<span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>실행해보면 다음과 같이 출력 된다.</li>
</ul>
<pre class="language-bash"><code class="language-bash code-highlight"><span class="code-line">——— Example of: Future ———
</span><span class="code-line"><span class="token number">2</span>
</span><span class="code-line">finished
</span></code></pre>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/combine-introduction</guid>
      <title>SwiftUI와 찰떡궁합인 Combine 소개</title>
      <description>Asynchronous 프로그래밍을 더 쉽고 안전하게 할 수 있게 해주는 Combine 공부</description>
      <link>https://www.hohyeonmoon.com/blog/combine-introduction</link>
      <pubDate>Wed, 01 Dec 2021 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>SwiftUI를 처음에 보면 드는 생각은 'iOS 개발하기 쉬워졌다 간편해졌다' 정도였다.</li>
<li>하지만 사용해볼수록 SwiftUI를 어느정도 이해하면서 깊게 사용하려면, Combine에 대한 이해는 필수적이라고 생각됐다.</li>
<li>Combine은 애플에서 만든 프레임워크인데 'RxSwift의 애플 버전' 정도로 생각하면 된다고 많이들 한다.</li>
</ul>
<h2 id="combine">Combine</h2>
<ul>
<li>그래서 Combine이 무엇이냐면, 그것은 <a href="https://developer.apple.com/documentation/combine">Apple 공식 문서</a>를 보면 자세히 알 수 있다.</li>
<li>요약하자면, Combine은 시간의 흐름에 따라 값을 처리하기 위한 Declarative Swift API를 제공하는 프레임워크인 것이다.</li>
<li>애플은 이미 Timer, NotificationCenter, Core Data 등에 Combine API를 적용했다.</li>
<li>그리고 새로운 SwiftUI 프레임워크에는 Combine을 더 쉽게 적용할 수 있도록 디자인 해놨다고 한다.</li>
<li>Combine의 계층은 아래 그림과 같다.</li>
</ul>
<p><img src="/images/combine-introduction-1.png" alt="combine-introduction"></p>
<h2 id="combine의-장점">Combine의 장점</h2>
<ul>
<li>기존 코드에 비해 Combine 코드가 좋은 이유가 무엇일까.</li>
<li>우선, Combine은 System Level에서 구현되어 있어, 애플이 아닌 다른 user는 사용하지 못하는 부분도 사용한다.</li>
<li>그리고 IBAction이나 delegate 같은 옛 방식을 사용하는 것보다 자동 구현이 많다.</li>
<li>또, 중첩된 클로저 같은 가독성이 안 좋은 기술을 제거하여 코드를 유지보수하기 쉽게 해준다.</li>
<li>결국, Combine은 필수가 아니지만 코드의 퀄리티를 높이는데 도움을 준다.</li>
</ul>
<h2 id="asynchronous-프로그래밍">Asynchronous 프로그래밍</h2>
<ul>
<li>Combine은 Asynchronous(비동기) 프로그래밍을 더 쉽고 안전하게 할 수 있게 해준다.</li>
<li>애플은 Asynchronous 프로그래밍을 이미 다음과 같은 것들에서 사용 중이다.
<ul>
<li>NotificationCenter</li>
<li>Delegate pattern</li>
<li>Grand Central Dispatch</li>
<li>Closures</li>
</ul>
</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token comment">// Thread 1</span>
</span><span class="code-line"><span class="token keyword">var</span> name <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"Hohyeon"</span></span>
</span><span class="code-line"><span class="token function">print</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token comment">// Thread 2</span>
</span><span class="code-line">name <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"Moon"</span></span>
</span><span class="code-line">
</span><span class="code-line"><span class="token comment">// Thread 1</span>
</span><span class="code-line">name <span class="token operator">+=</span> <span class="token string-literal"><span class="token string">" Moon"</span></span>
</span><span class="code-line"><span class="token function">print</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>Asynchronous 프로그래밍은 다음과 같은 멀티 쓰레드 작업시 필요할 수 있다.</li>
<li>이 코드의 name 값이 상황에 따라 Hohyeon Moon이 될 수도 있고</li>
<li>Moon Moon 될 수도 있기에 우리는 Asynchronous 프로그래밍이 필요하다.</li>
</ul>
<h2 id="마무리">마무리</h2>
<ul>
<li>다음 글에서는 Combine의 핵심 요소들에 대해 알아 볼 예정이다.</li>
<li>핵심 요소에는 publishers, subscribers 등이 있다.</li>
</ul>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swift-scrollview-programmatically</guid>
      <title>Swift UIKit 스크롤뷰 코드로 구현하기</title>
      <description>ScrollView를 Swift로 Programmatically 구현하는 방법에 대해 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/swift-scrollview-programmatically</link>
      <pubDate>Sun, 29 Aug 2021 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>WebView의 스크롤뷰에 뷰를 추가하는 작업을 하게되었다.</li>
<li>이 과정에서 스크롤뷰를 Swift로 programmatically 구현하게 되었는데, 이를 복습하고자 한다.</li>
</ul>
<h2 id="viewcontroller에-scrollview-추가">ViewController에 ScrollView 추가</h2>
<ul>
<li>일반적인 스크롤뷰를 뷰컨트롤러에 추가하는 방법은 다음과 같다.</li>
<li>우선 필요한 컴포넌트를 생성한다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">let</span> labelOne<span class="token punctuation">:</span> <span class="token class-name">UILabel</span> <span class="token operator">=</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">let</span> label <span class="token operator">=</span> <span class="token class-name">UILabel</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">  label<span class="token punctuation">.</span>text <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"Scroll Top"</span></span>
</span><span class="code-line">  label<span class="token punctuation">.</span>backgroundColor <span class="token operator">=</span> <span class="token punctuation">.</span>red
</span><span class="code-line">  label<span class="token punctuation">.</span>translatesAutoresizingMaskIntoConstraints <span class="token operator">=</span> <span class="token boolean">false</span>
</span><span class="code-line">  <span class="token keyword">return</span> label
</span><span class="code-line"><span class="token punctuation">}</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">let</span> labelTwo<span class="token punctuation">:</span> <span class="token class-name">UILabel</span> <span class="token operator">=</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">let</span> label <span class="token operator">=</span> <span class="token class-name">UILabel</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">  label<span class="token punctuation">.</span>text <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"Scroll Bottom"</span></span>
</span><span class="code-line">  label<span class="token punctuation">.</span>backgroundColor <span class="token operator">=</span> <span class="token punctuation">.</span>red
</span><span class="code-line">  label<span class="token punctuation">.</span>translatesAutoresizingMaskIntoConstraints <span class="token operator">=</span> <span class="token boolean">false</span>
</span><span class="code-line">  <span class="token keyword">return</span> label
</span><span class="code-line"><span class="token punctuation">}</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">let</span> scrollView<span class="token punctuation">:</span> <span class="token class-name">UIScrollView</span> <span class="token operator">=</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">let</span> scrollView <span class="token operator">=</span> <span class="token class-name">UIScrollView</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">  scrollView<span class="token punctuation">.</span>backgroundColor <span class="token operator">=</span> <span class="token punctuation">.</span>blue
</span><span class="code-line">  scrollView<span class="token punctuation">.</span>translatesAutoresizingMaskIntoConstraints <span class="token operator">=</span> <span class="token boolean">false</span>  
</span><span class="code-line">  <span class="token keyword">return</span> scrollView
</span><span class="code-line"><span class="token punctuation">}</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li><code>viewDidLoad()</code> 라이프 사이클에 오토레이아웃을 추가한다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">override</span> <span class="token keyword">func</span> <span class="token function-definition function">viewDidLoad</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token function">viewDidLoad</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">  <span class="token keyword">self</span><span class="token punctuation">.</span>view<span class="token punctuation">.</span>backgroundColor <span class="token operator">=</span> <span class="token punctuation">.</span>yellow
</span><span class="code-line">  <span class="token keyword">self</span><span class="token punctuation">.</span>view<span class="token punctuation">.</span><span class="token function">addSubview</span><span class="token punctuation">(</span>scrollView<span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">  scrollView<span class="token punctuation">.</span>leadingAnchor<span class="token punctuation">.</span><span class="token function">constraint</span><span class="token punctuation">(</span>equalTo<span class="token punctuation">:</span> view<span class="token punctuation">.</span>leadingAnchor<span class="token punctuation">,</span> constant<span class="token punctuation">:</span> <span class="token number">20</span><span class="token punctuation">)</span><span class="token punctuation">.</span>isActive <span class="token operator">=</span> <span class="token boolean">true</span>
</span><span class="code-line">  scrollView<span class="token punctuation">.</span>topAnchor<span class="token punctuation">.</span><span class="token function">constraint</span><span class="token punctuation">(</span>equalTo<span class="token punctuation">:</span> view<span class="token punctuation">.</span>topAnchor<span class="token punctuation">,</span> constant<span class="token punctuation">:</span> <span class="token number">20</span><span class="token punctuation">)</span><span class="token punctuation">.</span>isActive <span class="token operator">=</span> <span class="token boolean">true</span>
</span><span class="code-line">  scrollView<span class="token punctuation">.</span>trailingAnchor<span class="token punctuation">.</span><span class="token function">constraint</span><span class="token punctuation">(</span>equalTo<span class="token punctuation">:</span> view<span class="token punctuation">.</span>trailingAnchor<span class="token punctuation">,</span> constant<span class="token punctuation">:</span> <span class="token operator">-</span><span class="token number">20</span><span class="token punctuation">)</span><span class="token punctuation">.</span>isActive <span class="token operator">=</span> <span class="token boolean">true</span>
</span><span class="code-line">  scrollView<span class="token punctuation">.</span>bottomAnchor<span class="token punctuation">.</span><span class="token function">constraint</span><span class="token punctuation">(</span>equalTo<span class="token punctuation">:</span> view<span class="token punctuation">.</span>bottomAnchor<span class="token punctuation">,</span> constant<span class="token punctuation">:</span> <span class="token operator">-</span><span class="token number">20</span><span class="token punctuation">)</span><span class="token punctuation">.</span>isActive <span class="token operator">=</span> <span class="token boolean">true</span>
</span><span class="code-line">
</span><span class="code-line">  scrollView<span class="token punctuation">.</span><span class="token function">addSubview</span><span class="token punctuation">(</span>labelOne<span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">  labelOne<span class="token punctuation">.</span>leadingAnchor<span class="token punctuation">.</span><span class="token function">constraint</span><span class="token punctuation">(</span>equalTo<span class="token punctuation">:</span> scrollView<span class="token punctuation">.</span>leadingAnchor<span class="token punctuation">,</span> constant<span class="token punctuation">:</span> <span class="token number">40</span><span class="token punctuation">)</span><span class="token punctuation">.</span>isActive <span class="token operator">=</span> <span class="token boolean">true</span>
</span><span class="code-line">  labelOne<span class="token punctuation">.</span>topAnchor<span class="token punctuation">.</span><span class="token function">constraint</span><span class="token punctuation">(</span>equalTo<span class="token punctuation">:</span> scrollView<span class="token punctuation">.</span>topAnchor<span class="token punctuation">,</span> constant<span class="token punctuation">:</span> <span class="token number">40</span><span class="token punctuation">)</span><span class="token punctuation">.</span>isActive <span class="token operator">=</span> <span class="token boolean">true</span>
</span><span class="code-line">
</span><span class="code-line">  scrollView<span class="token punctuation">.</span><span class="token function">addSubview</span><span class="token punctuation">(</span>labelTwo<span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">  labelTwo<span class="token punctuation">.</span>leadingAnchor<span class="token punctuation">.</span><span class="token function">constraint</span><span class="token punctuation">(</span>equalTo<span class="token punctuation">:</span> scrollView<span class="token punctuation">.</span>leadingAnchor<span class="token punctuation">,</span> constant<span class="token punctuation">:</span> <span class="token number">40</span><span class="token punctuation">)</span><span class="token punctuation">.</span>isActive <span class="token operator">=</span> <span class="token boolean">true</span>
</span><span class="code-line">  labelTwo<span class="token punctuation">.</span>topAnchor<span class="token punctuation">.</span><span class="token function">constraint</span><span class="token punctuation">(</span>equalTo<span class="token punctuation">:</span> scrollView<span class="token punctuation">.</span>topAnchor<span class="token punctuation">,</span> constant<span class="token punctuation">:</span> <span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">.</span>isActive <span class="token operator">=</span> <span class="token boolean">true</span>
</span><span class="code-line">  labelTwo<span class="token punctuation">.</span>bottomAnchor<span class="token punctuation">.</span><span class="token function">constraint</span><span class="token punctuation">(</span>equalTo<span class="token punctuation">:</span> scrollView<span class="token punctuation">.</span>bottomAnchor<span class="token punctuation">,</span> constant<span class="token punctuation">:</span> <span class="token operator">-</span><span class="token number">40</span><span class="token punctuation">)</span><span class="token punctuation">.</span>isActive <span class="token operator">=</span> <span class="token boolean">true</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>이 코드로 나온 결과물은 다음과 같다.</li>
</ul>
<p><img src="/images/swift-scrollview-programmatically-1.gif" alt="swift-scrollview-programmatically"></p>
<h2 id="webview의-scrollview">WebView의 ScrollView</h2>
<ul>
<li>다음 구조와 같이 WebView안에는 스크롤뷰가 있고, 스크롤뷰는 ContentView로 구성되어 있다.</li>
</ul>
<p><img src="/images/swift-scrollview-programmatically-2.png" alt="swift-scrollview-programmatically"></p>
<ul>
<li>그래서 여느 스크롤뷰와 마찬가지로 ContentView에 원하는 뷰를 추가하면 될 것만 같았다.</li>
<li>문제는 WebView안의 스크롤뷰에 뷰를 추가하면 예상과 다르게 작동한다는 것이었다.</li>
<li>WebView안에 추가한 뷰의 터치 이벤트가 작동하지 않는다.</li>
<li>WebView 안의 컴포넌트는 애플에 의해 관리되기 때문에 우리가 컨트롤하기 힘들다.</li>
<li>그래서 웹뷰 스크롤뷰 최하단에 뷰를 추가하고 싶었는데 이를 이렇게는 구현하기 어려웠다.</li>
<li>결국, 추가하고 싶은 <code>LastPageView</code>라는 뷰를 WebView와 같은 계층에 추가하고 스크롤에 대해서 속임수를 썼다.</li>
</ul>
<p><img src="/images/swift-scrollview-programmatically-3.png" alt="swift-scrollview-programmatically"></p>
<ul>
<li>WebView의 스크롤뷰가 스크롤 될 때마다 호출되는 <code>scrollViewDidScroll</code> 델레게이트에 다음과 같은 코드를 작성한다.</li>
<li>추가한 코드는 추가한 <code>LastPageView</code> 뷰의 y 좌표를 스크롤뷰의 포지션에 맞게 변경하는 것이다.</li>
<li>이러면 마치 스크롤뷰 최하단에 추가한 뷰가 있는 것처럼 보이게 된다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">scrollViewDidScroll</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> scrollView<span class="token punctuation">:</span> <span class="token class-name">UIScrollView</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">  positionY <span class="token operator">=</span> scrollView<span class="token punctuation">.</span>contentSize<span class="token punctuation">.</span>height <span class="token operator">-</span> scrollView<span class="token punctuation">.</span>contentOffset<span class="token punctuation">.</span>y <span class="token operator">-</span> view<span class="token punctuation">.</span>frame<span class="token punctuation">.</span>height
</span><span class="code-line">  lastPageViewController<span class="token operator">?</span><span class="token punctuation">.</span>view<span class="token punctuation">.</span>frame<span class="token punctuation">.</span>origin<span class="token punctuation">.</span>y <span class="token operator">=</span> positionY
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/joining-ridi-app-engineer</guid>
      <title>RIDI의 앱 개발자로 입사하면서</title>
      <description>리디북스의 앱 개발자로 입사하고 온보딩하면서 느낀점을 소개해봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/joining-ridi-app-engineer</link>
      <pubDate>Wed, 14 Apr 2021 16:30:00 GMT</pubDate>
      <content:encoded><![CDATA[<h2 id="소개">소개</h2>
<p><img src="/images/joining-ridi-app-engineer-1.jpg" alt="joining-ridi-app-engineer"></p>
<p>리디의 제품 센터에서 모바일 앱 엔지니어로 근무하게 되었다. 리디 제품 센터는 리디북스, 리디셀렉트 등 리디의 주요 제품을 담당하고 있는 곳이다. 나는 이 제품들의 모바일 앱을 개발하는 업무를 맡게 되었다.</p>
<p>간단히 내 소개를 하면, 리디에 입사하기 전 미국에서 대학 생활을 하며 틈틈히 관심 있는 분야에 대해 개발 경험을 쌓고 있었다. 하지만 무언가 부족하다는 느낌이 들었고, 마침 코로나 19로 인해 대학 강의가 온라인이 되면서 학교 생활에 대한 불만이 생겼다. 그래서 차라리 휴학을 하고 제대로 일을 해보자는 결심을 하게 되어 리디에 입사하게 되었다.</p>
<p>이 글에서는 리디에 앱 개발자로 입사하고 느낀점과 진행한 테스크를 소개해보고자 한다.</p>
<h2 id="온보딩과-문화">온보딩과 문화</h2>
<p>입사 한 첫 날부터 적응 할 때까지 신규 입사자의 적응을 돕기 위해 회사에서 많은 노력을 하는 것이 여러 부분에 걸쳐 느꼈다. 입사 당일에 진행한 오티와 팀별 오티까지, 간단한 오티들이었지만 회사와 각 팀이 하고 있는 업무에 대해 조금 더 잘 알 수 있게 되었다. 뿐만 아니라, 입사하고 몇 주 동안 HRBP 팀을 비롯해 같이 일하게 될 팀원들과 점심과 커피를 간단하게 즐기며 조금 더 가까워질 수 있었고, 사내 싱크업이나 팀별 싱크업 미팅과 같은 각종 미팅을 통해 각자의 업무를 조금 더 수월하게 공유하고 개개인에 대해 조금 더 잘 알 수 있었다.</p>
<p>우리 팀 한정인지는 모르겠지만, 리디의 사내 문화 역시 만족스러웠다. 우선, 개인이 원하고 성장하고 싶은 방향을 고려해서 테스크 배정을 한다는 것이 좋았다. 또, 강압적이지 않고 적당히 유연한 분위기는 개발 퍼포먼스를 향상 시켜주었다. 특히, 우리 팀의 리드 개발자분은 수직적인 관계보다는 주니어 개발자들의 입장에서 바라보면서 조금 더 편할 수 있게 해주려는 배려가 온보딩하는데에 큰 도움을 주었다. 근무 시간만 충족한다면, 출퇴근 시간이 자유롭다는 것이나 각종 장비, 운동비 지원부터 코로나 19로 인한 점심 도시락 지원까지 복지도 인상 깊었다.</p>
<h2 id="테스크">테스크</h2>
<p>이제 3개월의 수습기간동안 어떤 업무에 집중했는지 본격적으로 소개해보려고 하는데, 리디만의 좋은 문화와 많은 분들의 도움속에 회사 생활에 자연스럽게 녹아들다보니 업무 역시 보다 집중해서 할 수 있었다고 생각한다.</p>
<p><img src="/images/joining-ridi-app-engineer-2.png" alt="joining-ridi-app-engineer"></p>
<p>리디북스 앱은 현재 여러 개의 탭으로 구성되어 있고, 이 탭들은 Swift/Kotlin과 React Native를 통해 조금씩 다르게 구현되어 있다. 그 중에서 나는 가장 좋아하고 잘 할 수 있는 Swift 구현부를 중점으로 업무를 진행했다.</p>
<p>처음으로 주어진 업무는 리디북스의 앱을 전체적으로 분석하고 도식화 해보는 것이었고, 그 후에는 한 동안 버그를 수정하는데 집중했다. 사용자가 책장을 임의로 정렬하거나 책을 다운로드하면 책장의 정렬이 흐트러지는 버그부터 다음 책으로 넘어가면 타이머가 연동이 되지 않는 버그 등 다양한 버그 수정을 통해 앱 전반의 코드를 이해할 수 있었다.</p>
<p><img src="/images/joining-ridi-app-engineer-3.png" alt="joining-ridi-app-engineer"></p>
<p>그 후에는 앱에서 비중이 있거나 앱을 사용하면 직접적으로 티가 나는 부분을 본격적으로 작업하기 시작했다. 내 서재와 구매 목록 탭을 통합하는 작업을 비롯해, 백엔드 팀에서 새롭게 설계한 API에 맞게 통신부를 구현하거나 데이터를 모델링하는 작업을 했다. 이 중에서도 뷰어의 독서 노트 동기화에 필요한 API 전환 및 레거시 코드 개선이 가장 기억에 남아, 이 부분을 어떻게 개발했는지 조금 더 자세히 소개해보려 한다.</p>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">import</span> <span class="token class-name">HTTPURLKit</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">Annotations</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token keyword">struct</span> <span class="token class-name">FetchResponse</span><span class="token punctuation">:</span> <span class="token class-name">Decodable</span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">  <span class="token keyword">struct</span> <span class="token class-name">FetchRequest</span><span class="token punctuation">:</span> <span class="token class-name">Requestable</span><span class="token punctuation">,</span> <span class="token class-name">Encodable</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">typealias</span> <span class="token class-name">Parameters</span> <span class="token operator">=</span> <span class="token class-name">EmptyParameters</span>
</span><span class="code-line">    <span class="token keyword">typealias</span> <span class="token class-name">ResponseBody</span> <span class="token operator">=</span> <span class="token class-name">FetchResponse</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token operator">...</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">var</span> url<span class="token punctuation">:</span> <span class="token constant">URL</span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token keyword">var</span> validations<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">Validation</span><span class="token punctuation">]</span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">  <span class="token keyword">struct</span> <span class="token class-name">ChangeRequest</span><span class="token punctuation">:</span> <span class="token class-name">Requestable</span><span class="token punctuation">,</span> <span class="token class-name">Encodable</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">typealias</span> <span class="token class-name">Parameters</span> <span class="token operator">=</span> <span class="token keyword">Self</span>
</span><span class="code-line">    <span class="token keyword">typealias</span> <span class="token class-name">ResponseBody</span> <span class="token operator">=</span> <span class="token class-name">EmptyResponse</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token operator">...</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">var</span> url<span class="token punctuation">:</span> <span class="token constant">URL</span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token keyword">var</span> httpMethod<span class="token punctuation">:</span> <span class="token class-name">URLRequest</span><span class="token punctuation">.</span><span class="token class-name">HTTPMethod</span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token keyword">var</span> validations<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">Validation</span><span class="token punctuation">]</span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token keyword">var</span> parameterEncodingStrategy<span class="token punctuation">:</span> <span class="token class-name">ParameterEncodingStrategy</span><span class="token operator">?</span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p>독서 노트 동기화를 위해 설계한 API 통신은 다음과 같은 response와 request 형태를 갖는다. HTTPURLKit은 URLKit에 포함된 패키지로 리디에서 자체 개발 되었는데, 애플의 프레임워크나 Alamofire 같은 써드파티 프레임워크가 업데이트 되어도 최대한 영향을 받지 않기 위해 만들어졌다고 한다.</p>
<p>사용 법은 꽤 심플하다. 여느 Swift 데이터 모델링과 마찬가지로 API에 맞게 Codable을 준수하는 response나 request 구조를 작성하고 여기에 추가적으로 response나 request 구조체가 Requestable을 준수하도록 하면 된다. Parameters, ResponseBody 등을 지정하고 url, httpMethod와 같은 몇 가지 변수를 설정하면 된다.</p>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">import</span> <span class="token class-name">RealmSwift</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">Annotation</span><span class="token punctuation">:</span> <span class="token class-name">Object</span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token attribute atrule">@objc</span><span class="token punctuation">(</span><span class="token class-name">AnnotationChunk</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">AnnotationChunk</span><span class="token punctuation">:</span> <span class="token class-name">NSObject</span><span class="token punctuation">,</span> <span class="token class-name">NSCoding</span><span class="token punctuation">,</span> <span class="token class-name">Codable</span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span>
</span></code></pre>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">import</span> <span class="token class-name">RealmSwift</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token attribute atrule">@objcMembers</span>
</span><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">NewAnnotation</span><span class="token punctuation">:</span> <span class="token class-name">Object</span><span class="token punctuation">,</span> <span class="token class-name">Codable</span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span>
</span></code></pre>
<p>리디북스 앱은 로컬에 독서 노트 데이터를 저장하기 위해 NSObject도 사용했었고, Realm의 오브젝트도 사용했었는데 앞으로는 이를 Realm으로만 관리하기 위해 통합 작업을 진행했다.</p>
<p>기존에는 두 종류의 데이터를 호환해주기 위해 Realm 오브젝트인 Annotation과 NSObject인 AnnotationChunk를 혼용해서 사용했다면, 이번 작업을 통해 NewAnnotation이라는 Realm 오브젝트이자 Swift의 Codable을 준수하는 객체만 사용할 예정이다.</p>
<p>NewAnnotation이 Realm 오브젝트인 동시에 Codable을 준수하기 때문에 위에서 설계한 API 통신의 response나 request에도 바로 사용할 수 있고, Realm 데이터베이스에도 바로 접근할 수 있었는데 여기서 조심할 점은 Realm은 하나의 쓰레드에서만 작동 할 수 있기 때문에 NewAnnotation 객체를 사용할 때 managed, unmanaged 객체를 구분해서 사용해야 한다.</p>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">import</span> <span class="token class-name">RxHTTPURLKit</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">final</span> <span class="token keyword">class</span> <span class="token class-name">AnnotationSynchronizer</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token operator">...</span>
</span><span class="code-line">  
</span><span class="code-line">  <span class="token keyword">func</span> <span class="token function-definition function">synchronize</span><span class="token punctuation">(</span>completion<span class="token punctuation">:</span> <span class="token attribute atrule">@escaping</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> syncedAnnotations<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">NewAnnotation</span><span class="token punctuation">]</span><span class="token operator">?</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Void</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">Session</span><span class="token punctuation">.</span>ridiAPIShared<span class="token punctuation">.</span>rx<span class="token punctuation">.</span><span class="token function">request</span><span class="token punctuation">(</span>
</span><span class="code-line">        <span class="token class-name">Annotations</span><span class="token punctuation">.</span><span class="token class-name">ChangeRequest</span><span class="token punctuation">(</span><span class="token operator">...</span><span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">)</span>
</span><span class="code-line">      <span class="token punctuation">.</span><span class="token function">subscribe</span><span class="token punctuation">(</span>onSuccess<span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token omit keyword">_</span> <span class="token keyword">in</span>
</span><span class="code-line">        <span class="token operator">...</span>
</span><span class="code-line">      <span class="token punctuation">}</span><span class="token punctuation">,</span> onError<span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token omit keyword">_</span> <span class="token keyword">in</span> 
</span><span class="code-line">        <span class="token operator">...</span>
</span><span class="code-line">      <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line">  
</span><span class="code-line">  <span class="token operator">...</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p>실질적인 API 통신은 Rx 방식을 따른다. 특별할것 없는 방식이지만, URLKit의 일부인 RxHTTPURLKit를 import 해서 보다 편하게 API 통신을 한다. 이렇게 해서 완성된 일련의 동기화 과정은 sychronize 함수를 독서 노트 동기화가 필요한 시점마다 호출해서 진행하면 된다.</p>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">import</span> <span class="token class-name">RealmSwift</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">Realm</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token operator">...</span>
</span><span class="code-line">  
</span><span class="code-line">  <span class="token keyword">static</span> <span class="token keyword">func</span> <span class="token function-definition function">annotationConfiguration</span><span class="token punctuation">(</span>fileUrl url<span class="token punctuation">:</span> <span class="token constant">URL</span><span class="token punctuation">,</span> forBook book<span class="token punctuation">:</span> <span class="token class-name">Book</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Configuration</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> configuration <span class="token operator">=</span> <span class="token class-name">Configuration</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token operator">...</span>
</span><span class="code-line">
</span><span class="code-line">    configuration<span class="token punctuation">.</span>migrationBlock <span class="token operator">=</span> <span class="token class-name">RealmMigrationBlocks</span><span class="token punctuation">.</span><span class="token function">annotationRealmMigrationBlock</span><span class="token punctuation">(</span>book<span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token operator">...</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">import</span> <span class="token class-name">RealmSwift</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">RealmMigrationBlocks</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token operator">...</span>
</span><span class="code-line">
</span><span class="code-line">  <span class="token keyword">static</span> <span class="token keyword">func</span> <span class="token function-definition function">annotationRealmMigrationBlock</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> book<span class="token punctuation">:</span> <span class="token class-name">Book</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token punctuation">(</span><span class="token class-name">Migration</span><span class="token punctuation">,</span> <span class="token class-name">UInt64</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Void</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">return</span> <span class="token punctuation">{</span> migration<span class="token punctuation">,</span> oldSchemaVersion <span class="token keyword">in</span>
</span><span class="code-line">      <span class="token operator">...</span>
</span><span class="code-line">
</span><span class="code-line">      <span class="token keyword">if</span> oldSchemaVersion <span class="token operator">&#x3C;</span> <span class="token number">7</span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">  <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">  <span class="token operator">...</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p>API가 변경되면서 받아오는 데이터의 종류가 달라졌기 때문에, 데이터베이스의 구조도 달라졌다. 그러다보니, Realm 데이터베이스를 마이그레이션 하는 작업도 필요하게 되었는데, Realm은 Core Data에 비하면 마이그레이션 작업 역시 정말 간단했다.</p>
<p>Realm의 configuration 부분에 migrationBlock 형태로 마이그레이션에 필요한 코드를 넘기면 되는데, 자세한건 설명하기 어렵지만, 간단히 말해 데이터베이스의 schemaVersion을 올리고 버전에 따라 실행해줘야 하는 마이그레이션 코드를 작성하면 된다.</p>
<p><img src="/images/joining-ridi-app-engineer-4.png" alt="joining-ridi-app-engineer"></p>
<p>이렇게해서 개발이 완료된 feature은 리디 리포지토리에 Pull Request로 등록한다. 그러면 팀의 리드 개발자가 리뷰를 진행하게 되고, 리뷰가 완료되면 개발 브랜치에 merge가 된다.</p>
<p><img src="/images/joining-ridi-app-engineer-5.png" alt="joining-ridi-app-engineer"></p>
<p>이번 독서 노트 동기화 작업은 겉으로는 크게 드러나지 않지만, 기존과 같은 결과물을 나타내면서도 내부적으로 많은 개선이 있었다는데 만족했다.</p>
<h2 id="마무리">마무리</h2>
<p>리디는 '적합한 대우와 지속적인 성장 가능성이 공존하는 환경'을 꽤나 잘 갖춘 기업이라는 생각을 하게 되었다. 온보딩 기간동안 생각보다 많은 것을 느끼고 알게 되었지만, 사실 나는 이제 막 걸음마를 뗀 개발자로 앞으로의 리디 생활이 더욱 기대된다.</p>
<p>P.S. 이 글은 <a href="https://www.ridicorp.com/story/onboarding-a-junior-engineer/">리디 홈페이지</a>에도 업로드 되어있다.</p>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/live-photo-support</guid>
      <title>Swift UIKit Live Photo 다루기</title>
      <description>애플 플랫폼에서 유용하게 사용되는 Live Photo를 다뤄봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/live-photo-support</link>
      <pubDate>Mon, 12 Oct 2020 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>이번에는 애플 생태계(iOS, iPadOS, macOS)에서는 유용하게 사용되는 Live Photo에 대해 알아보겠다.</li>
<li>Live Photo는 기본적으로 사진인데, 촬영 순간의 앞뒤 장면도 담겨있다는 특징이 있다.</li>
<li>Live Photo를 저장하고 불러오는 방법, 그리고 Video 포맷으로 변환하는 방법을 알아보겠다.</li>
</ul>
<h2 id="live-photo-저장하기">Live Photo 저장하기</h2>
<ul>
<li>Live Photo의 구조를 들여다보면, 하나의 Live Photo는 하나의 사진과 하나의 영상으로 이뤄져있다.</li>
<li>그래서 Live Photo를 저장한다고 하면, 한 쌍의 사진과 영상을 저장하는 것과 같다.</li>
<li>이 부분에서는 Live Photo를 사용자의 사진보관함에 저장하는 방법을 알아보겠다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">var</span> livePhotoResource<span class="token punctuation">:</span> <span class="token punctuation">(</span>pairedImage<span class="token punctuation">:</span> <span class="token constant">URL</span><span class="token punctuation">,</span> pairedVideo<span class="token punctuation">:</span> <span class="token constant">URL</span><span class="token punctuation">)</span><span class="token operator">?</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">saveToLibrary</span><span class="token punctuation">(</span>livePhotoResource<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">(</span>success<span class="token punctuation">)</span> <span class="token keyword">in</span>
</span><span class="code-line">    <span class="token keyword">if</span> success <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"라이브포토가 사진에 저장되었습니다"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"에러가 발생했습니다"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>livePhotoResource는 한 쌍의 사진과 영상을 묶은 tuple 타입이다.</li>
<li>다음과 같이 saveToLibrary function에 임의의 livePhotoResource를 넣어 저장하면 된다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">saveToLibrary</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> resources<span class="token punctuation">:</span> <span class="token class-name">LivePhotoResources</span><span class="token punctuation">,</span> completion<span class="token punctuation">:</span> <span class="token attribute atrule">@escaping</span> <span class="token punctuation">(</span><span class="token class-name">Bool</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Void</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">PHPhotoLibrary</span><span class="token punctuation">.</span><span class="token function">shared</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">performChanges</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">let</span> creationRequest <span class="token operator">=</span> <span class="token class-name">PHAssetCreationRequest</span><span class="token punctuation">.</span><span class="token function">forAsset</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token keyword">let</span> options <span class="token operator">=</span> <span class="token class-name">PHAssetResourceCreationOptions</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">        creationRequest<span class="token punctuation">.</span><span class="token function">addResource</span><span class="token punctuation">(</span>with<span class="token punctuation">:</span> <span class="token class-name">PHAssetResourceType</span><span class="token punctuation">.</span>pairedVideo<span class="token punctuation">,</span> fileURL<span class="token punctuation">:</span> resources<span class="token punctuation">.</span>pairedVideo<span class="token punctuation">,</span> options<span class="token punctuation">:</span> options<span class="token punctuation">)</span>
</span><span class="code-line">        creationRequest<span class="token punctuation">.</span><span class="token function">addResource</span><span class="token punctuation">(</span>with<span class="token punctuation">:</span> <span class="token class-name">PHAssetResourceType</span><span class="token punctuation">.</span>photo<span class="token punctuation">,</span> fileURL<span class="token punctuation">:</span> resources<span class="token punctuation">.</span>pairedImage<span class="token punctuation">,</span> options<span class="token punctuation">:</span> options<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span><span class="token punctuation">,</span> completionHandler<span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token punctuation">(</span>success<span class="token punctuation">,</span> error<span class="token punctuation">)</span> <span class="token keyword">in</span>
</span><span class="code-line">        <span class="token keyword">if</span> error <span class="token operator">!=</span> <span class="token nil constant">nil</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token function">print</span><span class="token punctuation">(</span>error <span class="token keyword">as</span> <span class="token keyword">Any</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">        <span class="token function">completion</span><span class="token punctuation">(</span>success<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>saveToLibrary는 이렇게 생겼는데, 결국 한 쌍의 사진과 영상을 사진보관함에 추가하는 방식이다.</li>
</ul>
<h2 id="live-photo-불러오기">Live Photo 불러오기</h2>
<ul>
<li>이번에는 Live Photo를 사진보관함으로부터 불러오는 방법에 대해 알아보겠다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">let</span> livePhotoVideoURL<span class="token punctuation">:</span> <span class="token constant">URL</span><span class="token operator">?</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">imagePickerController</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> picker<span class="token punctuation">:</span> <span class="token class-name">UIImagePickerController</span><span class="token punctuation">,</span> didFinishPickingMediaWithInfo info<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">UIImagePickerController</span><span class="token punctuation">.</span><span class="token class-name">InfoKey</span> <span class="token punctuation">:</span> <span class="token keyword">Any</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">if</span> <span class="token keyword">let</span> mediaType <span class="token operator">=</span> info<span class="token punctuation">[</span><span class="token class-name">UIImagePickerController</span><span class="token punctuation">.</span><span class="token class-name">InfoKey</span><span class="token punctuation">.</span>mediaType<span class="token punctuation">]</span> <span class="token keyword">as</span><span class="token operator">?</span> <span class="token class-name">NSString</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">if</span> mediaType <span class="token operator">==</span> <span class="token constant">kUTTypeLivePhoto</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">guard</span> <span class="token keyword">let</span> livePhoto <span class="token operator">=</span> info<span class="token punctuation">[</span><span class="token class-name">UIImagePickerController</span><span class="token punctuation">.</span><span class="token class-name">InfoKey</span><span class="token punctuation">.</span>livePhoto<span class="token punctuation">]</span> <span class="token keyword">as</span><span class="token operator">?</span> <span class="token class-name">PHLivePhoto</span> <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">            <span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">extractResources</span><span class="token punctuation">(</span>from<span class="token punctuation">:</span> livePhoto<span class="token punctuation">,</span> to<span class="token punctuation">:</span> someURL<span class="token punctuation">,</span> completion<span class="token punctuation">:</span> <span class="token punctuation">{</span> resources <span class="token keyword">in</span>
</span><span class="code-line">                <span class="token keyword">self</span><span class="token punctuation">.</span>livePhotoVideoURL <span class="token operator">=</span> resources<span class="token operator">?</span><span class="token punctuation">.</span>pairedVideo
</span><span class="code-line">            <span class="token punctuation">}</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>    
</span></code></pre>
<ul>
<li>우선, 사진보관함의 내용물을 불러오기 위해 Image Picker를 사용해야 한다.</li>
<li>Image Picker는 사용할줄 안다고 가정하고 넘어가겠다.</li>
<li>Image Picker의 info를 통해 불러온 미디어가 Live Photo이면, 이를 PHLivePhoto로 캐스팅한다.</li>
<li>캐스팅해서 얻은 값을 extractResources에 넣고, 나온 값이 해당 Live Photo의 URL이다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">extractResources</span><span class="token punctuation">(</span>from livePhoto<span class="token punctuation">:</span> <span class="token class-name">PHLivePhoto</span><span class="token punctuation">,</span> to directoryURL<span class="token punctuation">:</span> <span class="token constant">URL</span><span class="token punctuation">,</span> completion<span class="token punctuation">:</span> <span class="token attribute atrule">@escaping</span> <span class="token punctuation">(</span><span class="token class-name">LivePhotoResources</span><span class="token operator">?</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Void</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> assetResources <span class="token operator">=</span> <span class="token class-name">PHAssetResource</span><span class="token punctuation">.</span><span class="token function">assetResources</span><span class="token punctuation">(</span><span class="token keyword">for</span><span class="token punctuation">:</span> livePhoto<span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">var</span> keyPhotoURL<span class="token punctuation">:</span> <span class="token constant">URL</span><span class="token operator">?</span>
</span><span class="code-line">    <span class="token keyword">var</span> videoURL<span class="token punctuation">:</span> <span class="token constant">URL</span><span class="token operator">?</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">for</span> resource <span class="token keyword">in</span> assetResources <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">let</span> buffer <span class="token operator">=</span> <span class="token class-name">NSMutableData</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token keyword">let</span> options <span class="token operator">=</span> <span class="token class-name">PHAssetResourceRequestOptions</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">        <span class="token class-name">PHAssetResourceManager</span><span class="token punctuation">.</span><span class="token keyword">default</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">requestData</span><span class="token punctuation">(</span><span class="token keyword">for</span><span class="token punctuation">:</span> resource<span class="token punctuation">,</span> options<span class="token punctuation">:</span> options<span class="token punctuation">,</span> dataReceivedHandler<span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token punctuation">(</span>data<span class="token punctuation">)</span> <span class="token keyword">in</span>
</span><span class="code-line">            buffer<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">(</span>error<span class="token punctuation">)</span> <span class="token keyword">in</span>
</span><span class="code-line">            <span class="token keyword">if</span> error <span class="token operator">==</span> <span class="token nil constant">nil</span> <span class="token punctuation">{</span>
</span><span class="code-line">                <span class="token keyword">if</span> resource<span class="token punctuation">.</span>type <span class="token operator">==</span> <span class="token punctuation">.</span>pairedVideo <span class="token punctuation">{</span>
</span><span class="code-line">                    videoURL <span class="token operator">=</span> <span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">saveAssetResource</span><span class="token punctuation">(</span>resource<span class="token punctuation">,</span> to<span class="token punctuation">:</span> directoryURL<span class="token punctuation">,</span> resourceData<span class="token punctuation">:</span> buffer <span class="token keyword">as</span> <span class="token class-name">Data</span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">                    keyPhotoURL <span class="token operator">=</span> <span class="token keyword">self</span><span class="token punctuation">.</span><span class="token function">saveAssetResource</span><span class="token punctuation">(</span>resource<span class="token punctuation">,</span> to<span class="token punctuation">:</span> directoryURL<span class="token punctuation">,</span> resourceData<span class="token punctuation">:</span> buffer <span class="token keyword">as</span> <span class="token class-name">Data</span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token punctuation">}</span>
</span><span class="code-line">            <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">                <span class="token function">print</span><span class="token punctuation">(</span>error <span class="token keyword">as</span> <span class="token keyword">Any</span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token function">completion</span><span class="token punctuation">(</span><span class="token punctuation">(</span>keyPhotoURL<span class="token operator">!</span><span class="token punctuation">,</span> videoURL<span class="token operator">!</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>extractResources는 이렇게 생겼다.</li>
<li>PHAssetResourceManager의 default()의 requestData 이 부분이 핵심이다.</li>
<li>videoURL과 keyPhotoURL을 받아, completion을 통해 튜플 값으로 넘겨주는 것이다.</li>
</ul>
<h2 id="live-photo를-video로">Live Photo를 Video로</h2>
<ul>
<li>위 내용들을 잘 이해했다면, Live Photo를 Video를 변환하는 것은 의외로 간단하다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">if</span> <span class="token class-name">FileManager</span><span class="token punctuation">.</span><span class="token keyword">default</span><span class="token punctuation">.</span><span class="token function">fileExists</span><span class="token punctuation">(</span>atPath<span class="token punctuation">:</span> livePhotoVideoURL<span class="token punctuation">.</span>path<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token class-name">PHPhotoLibrary</span><span class="token punctuation">.</span><span class="token function">shared</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">performChanges</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">let</span> videoURL <span class="token operator">=</span> <span class="token class-name">Foundation</span><span class="token punctuation">.</span><span class="token function">URL</span><span class="token punctuation">(</span>fileURLWithPath<span class="token punctuation">:</span> livePhotoVideoURL<span class="token punctuation">.</span>path<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token class-name">PHAssetChangeRequest</span><span class="token punctuation">.</span><span class="token function">creationRequestForAssetFromVideo</span><span class="token punctuation">(</span>atFileURL<span class="token punctuation">:</span> videoURL<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">(</span>success<span class="token punctuation">,</span> error<span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Void</span> <span class="token keyword">in</span>
</span><span class="code-line">        <span class="token keyword">if</span> success <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"비디오가 사진에 저장되었습니다"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token function">print</span><span class="token punctuation">(</span>error<span class="token punctuation">.</span>debugDescription<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>앞서, 사진보관함으로부터 Live Photo의 Paired Video URL을 불러왔었다.</li>
<li>해당 URL을 PHPhotoLibrary에 저장하면 끝이다.</li>
</ul>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/programming-study-mistake</guid>
      <title>프로그래밍 독학할 때 하는 실수</title>
      <description>프로그래밍 독학을 하며 가장 많이 하는 실수에 대해 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/programming-study-mistake</link>
      <pubDate>Wed, 10 Jun 2020 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>프로그래밍은 다른 어떠한 과목보다 독학을 통해 많이 배우는 편이다.</li>
<li>독학하기 위한 환경과 자료가 인터넷 세상에 잘 갖춰져 있기 때문이다.</li>
<li>그러나 누군가의 지도 없이 독학을 통해 배우다보면, 아무래도 배움이 느려지는 경향이 있다.</li>
<li>그 이유는 계획을 주체적으로 진행하는 능력이 부족하거나, 엉뚱한 방향으로 나아가기 때문이다.</li>
<li>전자에 대해서는 지난 <a href="/blog/coding-self-study/">코딩 독학을 위한 공부 방법</a>에서 알아봤다.</li>
<li>이번에는 후자 즉, 프로그래밍 독학을 하다 흔히 범하지만, 하지 말아야 할 실수에 대해 알아보겠다.</li>
</ul>
<h2 id="실습">실습</h2>
<ul>
<li>끊임없이 공부만 하는 것은, 코딩 독학을 하다보면 가장 많이 하는 실수이다.</li>
<li>어차피 프로그래머에게 공부할 영역은 끝이 없으니, 공부만 하는 것은 미련할 수 있다.
<ul>
<li>어떠한 분야든 배움의 끝이란 없겠지만, 프로그래밍은 더 심하다.</li>
<li>오죽하면, 프로그래머란 평생 공부하는 직업이다라는 말이 나오겠나.</li>
<li>기존에 존재하는 프로그래밍 지식을 모두 배우는 것도 말이 안되지만,</li>
<li>프로그래밍은 끝도 없이 공부할게 생겨나기에, 그것을 모두 공부하는 것은 더더욱 말이 안된다.</li>
<li>기술이 빠르게 발전함에 따라, 그에 해당하는 해야하는 공부도 덩달아 빠르게 늘어난다.</li>
</ul>
</li>
<li>또, 실습 진행을 방해하는 요소들도 꽤 많다.
<ul>
<li>우선, 어떤 프로젝트를 진행해야 할지 감이 안 잡힌다.</li>
<li>그리고 코딩 공부를 해본 사람이라면 느낀적이 있겠지만,</li>
<li>이것도 알아야 할 것 같고 저것도 알아야 할 것 같다.</li>
<li>그래서 아직 실습을 위한 준비가 안 되었다고 느끼는 사람들도 꽤 있다.</li>
<li>게다가 하나씩 공부하며 알아가는 것만으로도 나름 재미가 쏠쏠하다.</li>
</ul>
</li>
<li>하지만, 필자는 작은 프로젝트더라도, 프로젝트를 정해 배운것을 적용해보는 것을 추천한다.
<ul>
<li>프로그래머는 실습 위주의 직업이다.</li>
<li>배우기만 해서는 얻는 것도 없고, 다 배울 수도 없다.</li>
</ul>
</li>
<li>공부를 했다면, 실습 프로젝트에 적용하는 것을 반드시 기억하자.</li>
</ul>
<h2 id="습관">습관</h2>
<ul>
<li>프로그래밍 독학을 하며 그 다음으로 많이 범하는 실수는,</li>
<li>초반에 너무 무리해서 점점 흐지부지 되다 결국 포기하는 것이다.
<ul>
<li>많은 사람들이 초반에는 매우 의욕적이다.</li>
<li>하지만 인간에게는 한정된 열정과 집중력이 있다.</li>
<li>초반에 그 열정과 집중력을 쏟아버리면, 나중에 부족해질 수 있다.</li>
<li>한마디로, 번 아웃되어 코딩 독학에 실패하는 것이다.</li>
</ul>
</li>
<li>결국, 성공적으로 독학을 하기 위해서는 매일 적당히 프로그래밍하는 습관을 들여야 한다.
<ul>
<li>말이 쉽지, 쉽지 않은 일인 것을 잘 안다.</li>
<li>하지만, 프로그래밍 하는 것을 한 번만 생활화하면 그다지 어려운 일도 아니다.</li>
<li>오히려, 안하는 날이 허전하고 이상하게 느껴진다.</li>
</ul>
</li>
<li>매일 꾸준하게 적당한 시간만큼 코딩해서 프로그래밍을 습관화 해보자.</li>
</ul>
<h2 id="목표">목표</h2>
<ul>
<li>마지막으로 소개 할 실수는, '나태함'이다.
<ul>
<li>인간은 기본적으로 게으른 동물이란 말이 있다.</li>
<li>컴퓨터도 인간의 게으름을 상쇄하기 위해 개발 되었다는 말이 있다.</li>
<li>이런 인간의 특성은 지도자가 없는 독학에서 더 두드러지게 나타난다.</li>
</ul>
</li>
<li>이런 나태함을 그나마 방지하기 위해서는 기간과 목표를 설정해야 한다.
<ul>
<li>어떠한 기간내에 정한 목표를 달성하려면 나태해지기 비교적 어렵다.</li>
<li>단, 적당한 기간과 실현 가능한 목표를 설정하는 것이 중요하다.</li>
<li>하지만 개인적으로, 한 분야를 독학하며 한 번도 안 나태해진 적은 없는것 같다.</li>
<li>간절한 목표가 있는 특수한 케이스가 아니라면, 대부분 그럴 것이다.</li>
<li>그렇기에 나태해지더라도, 잘 극복하고 다시 본 궤도에 진입하는 것도 중요하다.</li>
</ul>
</li>
<li>적당한 기간과 목표를 설정해서, 나태해지는 것을 방지해보자.</li>
</ul>
<h2 id="마무리">마무리</h2>
<ul>
<li>이렇게 해서, 프로그래밍 독학을 하다 쉽게 범할 수 있지만, 해서는 안 될 실수들을 알아봤다.</li>
<li>결론적으로 요약 해보자면, 다음과 같이 요약해볼 수 있다.
<ul>
<li>공부도 좋지만 실습을 반드시 해보자.</li>
<li>무리하기보다는 프로그래밍을 습관화하자.</li>
<li>기간과 목표를 정해서 나태해지지 말자.</li>
</ul>
</li>
<li>코딩이 의무 교육이 된 시대인만큼, 프로그래밍 공부에 모두 성공해보자.</li>
</ul>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/programmer-and-math</guid>
      <title>프로그래밍과 수학의 관계</title>
      <description>프로그래밍과 수학의 관계에 대해 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/programmer-and-math</link>
      <pubDate>Tue, 05 May 2020 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>이번에는 프로그래밍과 수학의 관계를 알아보려고 합니다.</li>
<li>수학을 못해도 프로그래머가 될 수 있는지.</li>
<li>수학은 왜 항상 프로그래밍과 같이 언급되는지.</li>
<li>개발하는 분야별로 수학의 필요성은 어떠한지 등 알아보겠습니다.</li>
</ul>
<h2 id="수학-못해도-됩니다">수학 못해도 됩니다</h2>
<ul>
<li>수학을 못해도 프로그래머가 될 수 있습니다.</li>
<li>여기서 프로그래머가 될 수 있냐는 것은, 좋은 프로그래머가 될 수 있냐는 것입니다.</li>
<li>수학을 못해도 좋은 프로그래머가 될 수 있습니다.</li>
</ul>
<h2 id="정말-그럴까요">정말 그럴까요</h2>
<ul>
<li>그럼 왜 수학을 잘 해야 프로그래밍을 잘 할 수 있다는 말이 나온 것일까요.</li>
<li>그것은 수학과 프로그래밍이 연관이 없는 것은 아니기 때문입니다.</li>
<li>프로그래밍을 잘하는데에는 여러 요인이 있겠지만, 논리력이 큰 비중을 차지합니다.</li>
<li>그런데 수학을 잘한다는 것은 숫자를 활용한 논리력이 좋다는 것입니다.</li>
<li>수학을 잘하면 논리력 자체가 좋을 확률이 높고, 곧 프로그래밍도 잘 할 확률이 높습니다.</li>
<li>결국, 수학을 잘 하면 프로그래밍을 잘 할 확률이 높지만,</li>
<li>수학을 못해도 논리력이 좋다면 프로그래밍을 잘 하는데 지장이 없습니다.</li>
</ul>
<h2 id="정말-그렇습니다">정말 그렇습니다</h2>
<ul>
<li>실제로 수학을 못하는데도 프로그래밍을 잘하는 경우가 있습니다.</li>
<li>숫자에 흥미를 느끼지 못했거나, 어떠한 이유로 수학을 안했거나 못했을 뿐</li>
<li>논리력 자체는 좋은 경우입니다.</li>
</ul>
<h2 id="언제나-있는-예외">언제나 있는 예외</h2>
<ul>
<li>다만, 논리력과 더불어, 수학적 지식이 더 많이 요구되는 개발 분야가 있습니다.</li>
<li>데이터 사이언스, 머신러닝 개발, 비디오 게임 개발을 하고 싶다면</li>
<li>수학을 천재 같이는 아니어도 어느정도 잘 하는 것이 좋습니다.</li>
</ul>
<h2 id="마무리">마무리</h2>
<ul>
<li>이렇게해서 좋은 프로그래머가 되려면 수학은 못해도 된다는 점과</li>
<li>프로그래밍과 수학은 직접적으로 연관되어 있지는 않지만, 공통적으로 논리력이 중요하다는 것.</li>
<li>그리고 실제로 수학을 못해도 프로그래밍을 잘하는 경우와</li>
<li>데이터 사이언스, 머신러닝, 비디오 게임 개발은</li>
<li>수학이 어느정도는 요구된다는 점을 알아봤습니다.</li>
</ul>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/ai-ml-dl-relation</guid>
      <title>인공지능, 머신러닝, 딥 러닝 관계</title>
      <description>인공지능, 머신러닝, 딥 러닝의 차이점과 관계 그리고 의미에 대해 공부</description>
      <link>https://www.hohyeonmoon.com/blog/ai-ml-dl-relation</link>
      <pubDate>Wed, 25 Mar 2020 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>이번 글에서는 흔히 사용되는 AI 용어 정리를 해볼 생각입니다.</li>
<li>인공지능, 머신러닝, 딥 러닝의 차이점과 관계 그리고 의미를 알아보겠습니다.</li>
<li>또, 데이터 사이언스는 이러한 AI와 무슨 관계가 있는지 알아보겠습니다.</li>
</ul>
<h2 id="ai-용어-관계">AI 용어 관계</h2>
<p><img src="/images/ai-ml-dl-relation-1.png" alt="ai-ml-dl-relation"></p>
<ul>
<li>대표적인 3가지 AI 용어 인공지능, 머신러닝, 딥 러닝의 관계부터 알아보겠습니다.</li>
<li>AI는 Artificial Intelligence의 줄인말로, 번역하면 인공지능입니다.</li>
<li>이러한 인공지능 안에 머신러닝이 있고, 머신러닝 안에 딥 러닝이 있습니다.</li>
</ul>
<h2 id="인공지능이란">인공지능이란?</h2>
<ul>
<li>그렇다면 AI, 인공지능은 무엇일까요?</li>
<li>AI는 크게 General AI와 Narrow AI로 나눌 수 있습니다.</li>
<li>영화속의 AI는 주로 General AI로, 인간이 하는 행동을 모두 잘합니다.</li>
<li>하지만, 현재 시장에서 다루는 AI는 Narrow AI로 작은 범위의 것을 잘합니다.</li>
<li>Narrow AI에는 사진 속 얼굴 인식, 스마트 스피커 음성 인식 등이 있습니다.</li>
</ul>
<h2 id="머신러닝이란">머신러닝이란?</h2>
<p><img src="/images/ai-ml-dl-relation-2.png" alt="ai-ml-dl-relation"></p>
<ul>
<li>이러한 Narrow AI를 학습시키기 위해서 ML이 존재합니다.</li>
<li>ML은 AI를 달성하기 위한 수단이나 AI를 사용하고 있는 시스템을 일컫는데요.</li>
<li>요즘 가장 대표적인 학습 방법에는 Supervised Learning이 있습니다.</li>
<li>명시적인 답이 있는 input label에서 output을 얻는것을 Supervised Learning이라고 하는데요.</li>
<li>Supervised Learning에 대해 보다 자세히 알고싶다면 블로그 글을 참고해주세요.</li>
</ul>
<h2 id="딥-러닝이란">딥 러닝이란?</h2>
<p><img src="/images/ai-ml-dl-relation-3.png" alt="ai-ml-dl-relation"></p>
<ul>
<li>Deep Learning은 ML을 달성하기 위한 방법으로, Neural Network를 이용합니다.</li>
<li>Neural Network는 한국말로 신경망이고 사진처럼 생겼는데요.</li>
<li>이것이 여러 Layer로 구성되어 있으면 Deep Neural Network가 됩니다.</li>
<li>최근 강력해진 프로세싱과 많아진 Data 덕분에, 여러 Layer를 통해 학습하는 것이 가능해졌습니다.</li>
<li>그러면서 Deep Learning을 통한 AI 개발이 인기를 끌기 시작한 것입니다.</li>
</ul>
<h2 id="데이터-사이언스">데이터 사이언스</h2>
<p><img src="/images/ai-ml-dl-relation-4.png" alt="ai-ml-dl-relation"></p>
<ul>
<li>Data Science는 데이터 셋에서 유의미한 결론을 내는 작업을 일컫습니다.</li>
<li>즉, Data를 통해 어떠한 유의미한 것을 얻는다면 Data Science라고 할 수 있습니다.</li>
<li>굳이 AI와의 관계를 따지자면, 사진과 같이 AI와 일부 겹치지만 직접적인 관계는 없습니다.</li>
</ul>
<h2 id="마무리">마무리</h2>
<ul>
<li>이렇게해서 우리가 흔히 AI, 인공지능이라고 하는 분야의 용어를 정리해봤습니다.</li>
<li>인공지능, 머신러닝, 딥 러닝의 차이점과 관계를 알아보고, 각 용어에 대해 간략히 알아봤습니다.</li>
</ul>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/turi-create-python</guid>
      <title>Turi Create과 Python</title>
      <description>ML 환경을 셋업하고 Turi Create과 Python을 통한 Core ML 개발에 대해 알아보기</description>
      <link>https://www.hohyeonmoon.com/blog/turi-create-python</link>
      <pubDate>Sun, 15 Mar 2020 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>이번 글에서 알아볼 내용은 다음과 같다.</li>
<li>Anaconda 설치 방법 및 Conda 명령어.</li>
<li>Terminal 명령어로 ML 환경 셋업.</li>
<li>Python와 Swift 언어의 차이점.</li>
<li>Turi Create을 통한 Core ML 개발.</li>
</ul>
<h2 id="anaconda-설치">Anaconda 설치</h2>
<ul>
<li><a href="https://www.anaconda.com/download/#macos">링크</a>에서 설치 파일을 다운로드 한다.</li>
<li>설치 파일을 실행한다.</li>
</ul>
<pre><code class="language-terminal code-highlight"><span class="code-line">sh Anaconda3-2019.07-MacOSX-x86_64.sh
</span></code></pre>
<ul>
<li>Home 디렉토리 .zshrc 파일을 생성하고 다음 줄을 추가한다.</li>
</ul>
<pre><code class="language-terminal code-highlight"><span class="code-line">export PATH="/Users/&#x3C;username>/anaconda3/bin":"${PATH}"
</span></code></pre>
<h2 id="conda-명령어">Conda 명령어</h2>
<ul>
<li>설치한 Anaconda를 위한 커맨드라인 명령어를 알아보겠다.</li>
</ul>
<pre><code class="language-terminal code-highlight"><span class="code-line">// 새 env 생성
</span><span class="code-line">conda create -n &#x3C;env name>
</span><span class="code-line">
</span><span class="code-line">// env 복제
</span><span class="code-line">conda create -n &#x3C;new env name> --clone &#x3C;existing env name>
</span><span class="code-line">
</span><span class="code-line">// env activate
</span><span class="code-line">conda activate &#x3C;env name>
</span><span class="code-line">
</span><span class="code-line">// 필요한 패키치 한 번에 설치
</span><span class="code-line">pip install -r requirements.txt
</span><span class="code-line">
</span><span class="code-line">// Jupyter Notebook 시작
</span><span class="code-line">jupyter notebook &#x3C;directory path>
</span><span class="code-line">
</span><span class="code-line">// env deactivate
</span><span class="code-line">conda deactivate
</span><span class="code-line">
</span><span class="code-line">// env 제거
</span><span class="code-line">conda remove -n &#x3C;env name> --all
</span></code></pre>
<h2 id="ml-환경-셋업">ML 환경 셋업</h2>
<ul>
<li>이제 conda를 이용해 ML 개발을 위한 환경을 셋업 해보겠다.</li>
<li>새로운 env를 생성한다.</li>
</ul>
<pre><code class="language-terminal code-highlight"><span class="code-line">conda create -n mlenv python=3.7
</span></code></pre>
<ul>
<li>env를 활성화한다.</li>
</ul>
<pre><code class="language-terminal code-highlight"><span class="code-line">conda activate mlenv
</span></code></pre>
<ul>
<li>필요한 패키지를 설치한다.</li>
</ul>
<pre><code class="language-terminal code-highlight"><span class="code-line">conda install numpy pandas matplotlib seaborn scipy scikit-learn scikit-image ipython jupyter
</span></code></pre>
<ul>
<li>Jupyter Notebook을 실행한다.</li>
</ul>
<pre><code class="language-terminal code-highlight"><span class="code-line">jupyter notebook
</span></code></pre>
<h2 id="python과-swift">Python과 Swift</h2>
<ul>
<li>ML은 주로 Python이나 R 같은 프로그래밍 언어로 개발된다.</li>
<li>필자는 Python을 사용할 예정인데, Swift와의 주요 문법 차이를 알아보겠다.</li>
<li>Python은 {} 대신 indent를 한다.</li>
</ul>
<pre class="language-python"><code class="language-python code-highlight"><span class="code-line"><span class="token keyword">if</span> a <span class="token operator">==</span> b<span class="token punctuation">:</span>
</span><span class="code-line">    <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">'a and b are equal'</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">if</span> a <span class="token operator">></span> c<span class="token punctuation">:</span>
</span><span class="code-line">        <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">'and a is also greater than c'</span><span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>Python은 nil 대신 None을 사용한다.</li>
<li>하지만 optional 개념이 없다.</li>
<li>Python은 == 대신 is를 사용한다.</li>
<li>변수나 상수 선언을 위해 var이나 let 같은 키워드가 필요없다.</li>
<li>Python의 List와 For Loop은 Swift와 상당히 비슷하다.</li>
<li>Python은 count 대신 len을 사용한다.</li>
</ul>
<pre class="language-python"><code class="language-python code-highlight"><span class="code-line">mylist <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">]</span> mylist<span class="token punctuation">.</span>append<span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span> <span class="token keyword">if</span> mylist<span class="token punctuation">:</span>
</span><span class="code-line">    <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">'mylist is not empty'</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">for</span> value <span class="token keyword">in</span> mylist<span class="token punctuation">:</span>
</span><span class="code-line">    <span class="token keyword">print</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">'List length: %d'</span> <span class="token operator">%</span> <span class="token builtin">len</span><span class="token punctuation">(</span>mylist<span class="token punctuation">)</span><span class="token punctuation">)</span>
</span></code></pre>
<h2 id="turi-create">Turi Create</h2>
<ul>
<li>Turi Create로 Transfer Learning을 해보겠다.</li>
<li>우선, 기존의 mlenv가 활성화된 상태에서 Turi를 설치한다.</li>
</ul>
<pre><code class="language-terminal code-highlight"><span class="code-line">pip install -U turicreate==5.8
</span></code></pre>
<ul>
<li>그리고 Jupyter Notebook을 실행한다.</li>
</ul>
<pre><code class="language-terminal code-highlight"><span class="code-line">jupyter notebook
</span></code></pre>
<ul>
<li>지금부터의 코드들은 Jupyter Notebook에서 실행 할 것이다.</li>
<li>필요한 패키지를 불러온다.</li>
</ul>
<pre class="language-python"><code class="language-python code-highlight"><span class="code-line"><span class="token keyword">import</span> turicreate <span class="token keyword">as</span> tc
</span><span class="code-line"><span class="token keyword">import</span> matplotlib<span class="token punctuation">.</span>pyplot <span class="token keyword">as</span> plt
</span></code></pre>
<ul>
<li>이미지 Data Set을 불러온다.</li>
<li>해당 Data Set은 <a href="https://wolverine.raywenderlich.com/books/mlt/snacks.zip">여기서</a> 다운 받을 수 있다.</li>
</ul>
<pre class="language-python"><code class="language-python code-highlight"><span class="code-line">train_data <span class="token operator">=</span> tc<span class="token punctuation">.</span>image_analysis<span class="token punctuation">.</span>load_images<span class="token punctuation">(</span><span class="token string">"snacks/train"</span><span class="token punctuation">,</span> with_path<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>path 값을 Data로부터 불러온다.</li>
</ul>
<pre class="language-python"><code class="language-python code-highlight"><span class="code-line">path <span class="token operator">=</span> train_data<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">[</span><span class="token string">"path"</span><span class="token punctuation">]</span>
</span></code></pre>
<ul>
<li>다음 코드를 실행해 SFrame이 label이라는 새로운 열을 갖게한다.</li>
</ul>
<pre class="language-python"><code class="language-python code-highlight"><span class="code-line"><span class="token keyword">import</span> os
</span><span class="code-line">train_data<span class="token punctuation">[</span><span class="token string">"label"</span><span class="token punctuation">]</span> <span class="token operator">=</span> train_data<span class="token punctuation">[</span><span class="token string">"path"</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token builtin">apply</span><span class="token punctuation">(</span><span class="token keyword">lambda</span> path<span class="token punctuation">:</span> os<span class="token punctuation">.</span>path<span class="token punctuation">.</span>basename<span class="token punctuation">(</span>os<span class="token punctuation">.</span>path<span class="token punctuation">.</span>split<span class="token punctuation">(</span>path<span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>이제 드디어 Turi와 Train Data를 이용해 model을 생성한다.</li>
</ul>
<pre class="language-python"><code class="language-python code-highlight"><span class="code-line">model <span class="token operator">=</span> tc<span class="token punctuation">.</span>image_classifier<span class="token punctuation">.</span>create<span class="token punctuation">(</span>train_data<span class="token punctuation">,</span> target<span class="token operator">=</span><span class="token string">"label"</span><span class="token punctuation">,</span> model<span class="token operator">=</span><span class="token string">"VisionFeaturePrint_Scene"</span><span class="token punctuation">,</span> verbose<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">,</span> max_iterations<span class="token operator">=</span><span class="token number">50</span><span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>검증하기 위한 Test Data를 불러온다.</li>
</ul>
<pre class="language-python"><code class="language-python code-highlight"><span class="code-line">test_data <span class="token operator">=</span> tc<span class="token punctuation">.</span>image_analysis<span class="token punctuation">.</span>load_images<span class="token punctuation">(</span><span class="token string">"snacks/test"</span><span class="token punctuation">,</span> with_path<span class="token operator">=</span><span class="token boolean">True</span><span class="token punctuation">)</span>
</span><span class="code-line">test_data<span class="token punctuation">[</span><span class="token string">"label"</span><span class="token punctuation">]</span> <span class="token operator">=</span> test_data<span class="token punctuation">[</span><span class="token string">"path"</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token builtin">apply</span><span class="token punctuation">(</span><span class="token keyword">lambda</span> path<span class="token punctuation">:</span> os<span class="token punctuation">.</span>path<span class="token punctuation">.</span>basename<span class="token punctuation">(</span>os<span class="token punctuation">.</span>path<span class="token punctuation">.</span>split<span class="token punctuation">(</span>path<span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>Test Data를 통해 model을 검증하고 그 결과 값을 출력해본다.</li>
</ul>
<pre class="language-python"><code class="language-python code-highlight"><span class="code-line">metrics <span class="token operator">=</span> model<span class="token punctuation">.</span>evaluate<span class="token punctuation">(</span>test_data<span class="token punctuation">)</span>
</span><span class="code-line"><span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"Accuracy: "</span><span class="token punctuation">,</span> metrics<span class="token punctuation">[</span><span class="token string">"accuracy"</span><span class="token punctuation">]</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"Precision: "</span><span class="token punctuation">,</span> metrics<span class="token punctuation">[</span><span class="token string">"precision"</span><span class="token punctuation">]</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"Recall: "</span><span class="token punctuation">,</span> metrics<span class="token punctuation">[</span><span class="token string">"recall"</span><span class="token punctuation">]</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"Confusion Matrix:\n"</span><span class="token punctuation">,</span> metrics<span class="token punctuation">[</span><span class="token string">"confusion_matrix"</span><span class="token punctuation">]</span><span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>model을 Turi Create 포맷으로 저장한다.</li>
</ul>
<pre class="language-python"><code class="language-python code-highlight"><span class="code-line">model<span class="token punctuation">.</span>save<span class="token punctuation">(</span><span class="token string">"HealthySnacks.model"</span><span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>다음과 같이 model을 Core ML 형식으로 추출 할 수도 있다.</li>
</ul>
<pre class="language-python"><code class="language-python code-highlight"><span class="code-line">model<span class="token punctuation">.</span>export_coreml<span class="token punctuation">(</span><span class="token string">"HealthySnacks.mlmodel"</span><span class="token punctuation">)</span>
</span></code></pre>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swift-git-github</guid>
      <title>Git과 Github</title>
      <description>분산 버전 관리 시스템인 Git과 Github에 대해 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/swift-git-github</link>
      <pubDate>Tue, 25 Feb 2020 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>Git이란 개발자가 작성한 소스 코드 관리를 위한 "분산 버전 관리 시스템"입니다.</li>
<li>그렇다면 분산 버전 관리 시스템이란 무엇이고 일반 버전 관리 시스템과는 어떻게 다를까요?</li>
</ul>
<h2 id="버전-관리-시스템">버전 관리 시스템</h2>
<p><img src="/images/swift-git-github-1.png" alt="swift-git-github"></p>
<ul>
<li>버전 관리 시스템이란 이름에서도 나타나듯이, 프로젝트 파일의 변경사항을 추적할 수 있도록 도와주는 시스템입니다.</li>
<li>사용자가 변경한 모든 내용을 버전별로 관리하고, 이것이 저장되는 곳을 repository라고 부르는 것입니다.</li>
<li>그리고 사용자가 repository에 변경 내용을 저장하는 것을 commit이라고 합니다.</li>
<li>일반 버전 관리 시스템은 하나의 중앙 저장소에 사용자들이 변경사항을 전달합니다.</li>
</ul>
<h2 id="분산-버전-관리-시스템">분산 버전 관리 시스템</h2>
<ul>
<li>분산 버전 관리 시스템은 개인 저장소를 갖고 있다는 점에서 차이가 있습니다.</li>
<li>즉, 작업공간 ↔ 외부 저장소라는 일반적인 패턴에서 작업공간 ↔ 개인 저장소 ↔ 외부 저장소라는 패턴으로 변경하는 것입니다.</li>
<li>이를 통해, 네트워크에 연결이 되어 있지 않은 상황에서도 작업을 할 수 있게 되었습니다.</li>
<li>그리고 모두에게 공개하고 싶지는 않은 사항을 개인 저장소에서 개인적으로 작업해볼수 있게 되었습니다.</li>
</ul>
<h2 id="git이란">Git이란?</h2>
<ul>
<li>이러한 분산 버전 관리 시스템의 한 종류가 Git입니다.</li>
<li>빠른 속도와 성능을 바탕으로 했고, 분산 작업이 가능합니다.</li>
<li>Git에는 staging area가 존재해 index라는 추가적인 과정을 거칩니다.</li>
<li>또한, Git의 가장 대표적인 특징은 branch 모델이 존재한다는 것입니다.</li>
</ul>
<h2 id="git의-구조">Git의 구조</h2>
<p><img src="/images/swift-git-github-2.png" alt="swift-git-github"></p>
<ul>
<li>Work Space > Index > Internal Storage > External Storage</li>
<li>Git은 이 순서를 거쳐서 소스코드 버전이 관리됩니다.</li>
<li>Work Space는 현재 프로젝트의 작업이 이뤄지는 곳입니다.</li>
<li>Index는 Work Space의 내용이 Internal Storage에 저장되기 전에 올려가는 중간 단계 공간입니다.</li>
<li>Internal Storage는 Git이 설치된 컴퓨터 저장공간입니다.</li>
<li>External Storage는 외부에 저장되는 중앙 저장소로 Github가 이에 해당하는 대표적인 서비스입니다.</li>
</ul>
<h2 id="branch-모델">Branch 모델</h2>
<p><img src="/images/swift-git-github-3.png" alt="swift-git-github"></p>
<ul>
<li>Git에는 Branch 모델이라는 대표적인 기능이 있습니다.</li>
<li>그림과 같이 개발 중에 가지치기(Branch)를 통해 따로 개발했다가, 나중에 합치는(Merge) 기능입니다.</li>
<li>Branch 모델은 Commit을 통해 Head를 생성하다 Branch를 통해 새로운 가지를 치고.</li>
<li>Checkout으로 작업환경을 변경해서 Merge로 최종적으로 합치는 방법입니다.</li>
</ul>
<h2 id="github란">Github란?</h2>
<ul>
<li>위에서도 언급했지만, Github란 Git이라는 시스템의 일부를 서비스하는 서비스 이름입니다.</li>
<li>조금 더 자세히 말해서, Github는 중앙 저장소 서비스를 제공하는 서비스입니다.</li>
<li>원래 Github는 저장소에 올린 소스코드를 공개한다는 조건하에 무료로 서비스를 제공해줬습니다.</li>
<li>하지만, 만약 소스코드를 공개하고 싶지 않거나 감추고 싶다면 Github에 돈을 지불하고 서비스를 사용해야 했습니다.</li>
<li>무료로 서비스를 사용하고 싶어하다보니, 많은 소스코드가 공개되었고 자연스럽게 소스코드를 공유하는 문화가 생겼습니다.</li>
<li>이는 Github가 지금처럼 크게 성장한 주요 원인이기도 합니다.</li>
<li>현재는 Private Repository도 무료가 되었습니다.</li>
</ul>
<h2 id="git-최종-정리">Git 최종 정리</h2>
<p><img src="/images/swift-git-github-4.png" alt="swift-git-github"></p>
<ul>
<li>git은 분산 버전 관리 시스템으로 프로젝트 변경 이력을 관리하는데 도움을 줍니다.</li>
<li>git의 작업이 이뤄지는 저장소의 시점을 work tree라고 하고 branch 생성을 통해서 다양한 시점의 작업이 가능합니다.</li>
<li>branch를 현재 작업tree로 변경하기 위해서는 “checkout”명령을 통해서 변경 가능합니다.</li>
<li>index영역이 존재해서 work tree에서 작업한 내용을 곧바로 내부 저장소에 저장하지 않고,</li>
<li>선별적으로 저장할 내용을 add 할 수 있습니다.</li>
<li>commit 명령을 통해 index에 있는 변경, 내용을 내부 저장소에 저장 할 수 있습니다.</li>
<li>외부 저장소를 이용해서 중앙 집중 저장소로 사용할 수 있습니다.</li>
<li>대표적인 외부 저장소로는 Github란 서비스가 있습니다.</li>
<li>push &#x26; pull을 통해 외부 저장소에 데이터를 저장하고 불러올 수 있습니다.</li>
<li>clone 명령어를 통해서 외부 저장소를 내부 저장소로 복제 할수 있습니다.</li>
</ul>
<h2 id="git-추가-내용">Git 추가 내용</h2>
<ul>
<li>Cherry-pick이란 다른 branch의 commit을 골라오는 것입니다.</li>
<li>Reset을 하면 해당하는 commit 상태로 reset 되고 그 이후의 commit은 사라집니다.</li>
<li>Reset은 soft, mixed, hard reset이 존재합니다.</li>
<li>Revert이란 이전 commit 내역을 그대로 남겨둔채 해당하는 commit만 되돌리는 것입니다.</li>
</ul>
<h2 id="참고">참고</h2>
<ul>
<li>Cherry-pick: <a href="https://cselabnotes.com/kr/2021/03/31/56/">삐멜 소프트웨어 엔지니어 블로그</a></li>
<li>Reset, revert: <a href="https://www.lainyzine.com/ko/article/git-reset-and-git-revert-and-git-commit-amend/">LainyZine: 프로그래머 가이드</a></li>
</ul>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swift-enum</guid>
      <title>Swift Enum</title>
      <description>Swift 언어에서의 enum에 대해 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/swift-enum</link>
      <pubDate>Mon, 30 Dec 2019 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>이번 글에서는 Swift 언어에서의 enum에 대해 알아보도록 하겠다.</li>
</ul>
<h2 id="열거형-enum">열거형 enum</h2>
<ul>
<li>열거형이란 그룹에 대한 연관된 값을 정의하고 사용하는 것이 가능한 타입을 말한다.</li>
<li>단, 스위프트에서의 열거형 enum은 항목 그 자체가 고유의 값으로,</li>
<li>해당 항목에 값을 매칭 시킬 필요가 없다.</li>
<li>열거형 enum에는 원시값(rawValue)이라는 형태로 실제값을 부여할수도 있다.</li>
</ul>
<h2 id="열거형-문법">열거형 문법</h2>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">enum</span> <span class="token operator">&#x3C;</span>열거형 이름<span class="token operator">></span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">case</span> <span class="token operator">&#x3C;</span>열거 항목<span class="token number">1</span><span class="token operator">></span>
</span><span class="code-line">    <span class="token keyword">case</span> <span class="token operator">&#x3C;</span>열거 항목<span class="token number">2</span><span class="token operator">></span>
</span><span class="code-line">    <span class="token keyword">case</span> <span class="token operator">&#x3C;</span>열거 항목<span class="token number">3</span><span class="token operator">></span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>즉, 다음과 같이 사용할 수 있는 것이다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">enum</span> <span class="token class-name">CompassPoint</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">case</span> north
</span><span class="code-line">    <span class="token keyword">case</span> south
</span><span class="code-line">    <span class="token keyword">case</span> east
</span><span class="code-line">    <span class="token keyword">case</span> west
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token keyword">var</span> directionToHead <span class="token operator">=</span> <span class="token class-name">CompassPoint</span><span class="token punctuation">.</span>west
</span></code></pre>
<h2 id="열거형-switch문">열거형 Switch문</h2>
<ul>
<li>다음과 같이 열거형을 switch문을 활용해 사용할수 있다.</li>
<li>많은 경우, 열거형은 switch문과 함께 사용된다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">switch</span> directionToHead <span class="token punctuation">{</span>
</span><span class="code-line"><span class="token keyword">case</span> <span class="token punctuation">.</span>north<span class="token punctuation">:</span>
</span><span class="code-line">    <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Lots of planets have a north"</span></span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token keyword">case</span> <span class="token punctuation">.</span>south<span class="token punctuation">:</span>
</span><span class="code-line">    <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Watch out for penguins"</span></span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token keyword">case</span> <span class="token punctuation">.</span>east<span class="token punctuation">:</span>
</span><span class="code-line">    <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Where the sun rises"</span></span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token keyword">case</span> <span class="token punctuation">.</span>west<span class="token punctuation">:</span>
</span><span class="code-line">    <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Where the skies are blue"</span></span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="associated-values">Associated Values</h2>
<ul>
<li>열거형에는 다음과 같이 값을 지정하고 지정한 값을 불러올수도 있다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">enum</span> <span class="token class-name">Barcode</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">case</span> <span class="token function">upc</span><span class="token punctuation">(</span><span class="token class-name">Int</span><span class="token punctuation">,</span> <span class="token class-name">Int</span><span class="token punctuation">,</span> <span class="token class-name">Int</span><span class="token punctuation">,</span> <span class="token class-name">Int</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">case</span> <span class="token function">qrCode</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token comment">// 연관 열거형 값 지정</span>
</span><span class="code-line"><span class="token keyword">var</span> productBarcode<span class="token punctuation">:</span><span class="token class-name">Barcode</span> <span class="token operator">=</span> <span class="token class-name">Barcode</span><span class="token punctuation">.</span><span class="token function">upc</span><span class="token punctuation">(</span><span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">85909</span><span class="token punctuation">,</span> <span class="token number">51226</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">)</span>
</span><span class="code-line">productBarcode <span class="token operator">=</span> <span class="token punctuation">.</span><span class="token function">qrCode</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"ABCDEFGHIJKLMNOP"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token comment">// 연관 열거형 값 불러오기</span>
</span><span class="code-line"><span class="token keyword">switch</span> productBarcode <span class="token punctuation">{</span>
</span><span class="code-line">	<span class="token keyword">case</span> <span class="token punctuation">.</span><span class="token function">upc</span><span class="token punctuation">(</span><span class="token keyword">let</span> numberSystem<span class="token punctuation">,</span> <span class="token keyword">let</span> manufacturer<span class="token punctuation">,</span> <span class="token keyword">let</span> product<span class="token punctuation">,</span> <span class="token keyword">let</span> check<span class="token punctuation">)</span><span class="token punctuation">:</span>
</span><span class="code-line">	    <span class="token function">print</span><span class="token punctuation">(</span>"<span class="token constant">UPC</span><span class="token punctuation">:</span> <span class="token punctuation">\</span><span class="token punctuation">(</span>numberSystem<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">\</span><span class="token punctuation">(</span>manufacturer<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">\</span><span class="token punctuation">(</span>product<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">\</span><span class="token punctuation">(</span>check<span class="token punctuation">)</span><span class="token punctuation">.</span>”<span class="token punctuation">)</span>
</span><span class="code-line">	<span class="token keyword">case</span> <span class="token punctuation">.</span><span class="token function">qrCode</span><span class="token punctuation">(</span><span class="token keyword">let</span> productCode<span class="token punctuation">)</span><span class="token punctuation">:</span>
</span><span class="code-line">	    <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"QR code: </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">productCode</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">."</span></span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="raw-values">Raw Values</h2>
<ul>
<li>다음과 같이 열거형에 원시값을 지정해줄수도 있다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">enum</span> <span class="token class-name">ASCIIControlCharacter</span><span class="token punctuation">:</span> <span class="token class-name">Character</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">case</span> tab <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"\t"</span></span>
</span><span class="code-line">    <span class="token keyword">case</span> lineFeed <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"\n"</span></span>
</span><span class="code-line">    <span class="token keyword">case</span> carriageReturn <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"\r"</span></span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token comment">//Index 1씩 증가</span>
</span><span class="code-line"><span class="token keyword">enum</span> <span class="token class-name">Planet</span><span class="token punctuation">:</span> <span class="token class-name">Int</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">case</span> mercury<span class="token operator">=</span><span class="token number">1</span><span class="token punctuation">,</span> venus<span class="token punctuation">,</span> earth<span class="token punctuation">,</span> mars<span class="token punctuation">,</span> jupiter<span class="token punctuation">,</span> saturn<span class="token punctuation">,</span> uranus<span class="token punctuation">,</span> neptune
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token comment">//String은 기본 항목이 String으로 지정</span>
</span><span class="code-line"><span class="token keyword">enum</span> <span class="token class-name">CompassPoint</span><span class="token punctuation">:</span> <span class="token class-name">String</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">case</span> north<span class="token punctuation">,</span> south<span class="token punctuation">,</span> east<span class="token punctuation">,</span> west
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swift-error-handling</guid>
      <title>Swift Error Handling</title>
      <description>Swift에서 Error를 Handling 하는 방법에 대해 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/swift-error-handling</link>
      <pubDate>Sun, 29 Dec 2019 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>Swift는 Error 프로토콜을 통해 error handling을 네이티브하게 지원한다.</li>
</ul>
<h2 id="error-enum">Error enum</h2>
<ul>
<li>다음과 같이 Error 프로토콜을 채택해 간단하게 Error enum을 만들 수 있게 해준다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">enum</span> <span class="token class-name">ValidationError</span><span class="token punctuation">:</span> <span class="token class-name">Error</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">case</span> tooShort
</span><span class="code-line">    <span class="token keyword">case</span> tooLong
</span><span class="code-line">    <span class="token keyword">case</span> <span class="token function">invalidCharacterFound</span><span class="token punctuation">(</span><span class="token class-name">Character</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="throws--throw">throws &#x26; throw</h2>
<ul>
<li>throws와 throw를 이용해 다음과 같이 위에서 만든 Error enum을 사용할 수 있다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token comment">// throws function으로 만들고</span>
</span><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">validate</span><span class="token punctuation">(</span>username<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">guard</span> username<span class="token punctuation">.</span>count <span class="token operator">></span> <span class="token number">3</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token comment">// error 타입을 throw 한다</span>
</span><span class="code-line">        <span class="token keyword">throw</span> <span class="token class-name">ValidationError</span><span class="token punctuation">.</span>tooShort
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">guard</span> username<span class="token punctuation">.</span>count <span class="token operator">&#x3C;</span> <span class="token number">15</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token comment">// error 타입을 throw 한다    </span>
</span><span class="code-line">        <span class="token keyword">throw</span> <span class="token class-name">ValidationError</span><span class="token punctuation">.</span>tooLong
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">    <span class="token keyword">for</span> character <span class="token keyword">in</span> username <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">guard</span> character<span class="token punctuation">.</span>isLetter <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token comment">// error 타입을 throw 한다            </span>
</span><span class="code-line">            <span class="token keyword">throw</span> <span class="token class-name">ValidationError</span><span class="token punctuation">.</span><span class="token function">invalidCharacterFound</span><span class="token punctuation">(</span>character<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="try-키워드">try 키워드</h2>
<ul>
<li>throws 함수를 호출 할 때는 try 키워드를 사용해야 한다.</li>
<li>try 키워드는 throw된 error를 handle 해준다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">userDidPickName</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> username<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">do</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">try</span> <span class="token function">validate</span><span class="token punctuation">(</span>username<span class="token punctuation">:</span> username<span class="token punctuation">)</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token comment">// validate에 성공했을 때</span>
</span><span class="code-line">        <span class="token function">submit</span><span class="token punctuation">(</span>username<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token comment">// validate에 실패했을 때</span>
</span><span class="code-line">        <span class="token comment">// error 변수는 catch문 내에 자동으로 생성된다</span>
</span><span class="code-line">        errorLabel<span class="token punctuation">.</span>text <span class="token operator">=</span> error<span class="token punctuation">.</span>localizedDescription
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>위 코드를 실행시켜 validate에 실패하면 다음과 같이 error 문구를 나타낼 것이다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">The</span> operation couldn’t be completed<span class="token punctuation">.</span> <span class="token punctuation">(</span><span class="token class-name">App</span><span class="token punctuation">.</span><span class="token class-name">ValidationError</span> error <span class="token number">0</span><span class="token punctuation">.</span><span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>조금 더 명확하게 error를 구분하기 위해 아래와 같이 할 수 있다.</li>
</ul>
<h2 id="localizederror">LocalizedError</h2>
<ul>
<li>LocalizedError를 채택해 다음과 같이 ValidationError를 확장한다.</li>
<li>errorDescription 프로퍼티를 implement해서 원하는 에러 메시지를 구현할 수 있다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">ValidationError</span><span class="token punctuation">:</span> <span class="token class-name">LocalizedError</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> errorDescription<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token operator">?</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">switch</span> <span class="token keyword">self</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">case</span> <span class="token punctuation">.</span>tooShort<span class="token punctuation">:</span>
</span><span class="code-line">            <span class="token keyword">return</span> <span class="token class-name">NSLocalizedString</span><span class="token punctuation">(</span>
</span><span class="code-line">                <span class="token string-literal"><span class="token string">"Your username needs to be at least 4 characters long"</span></span><span class="token punctuation">,</span>
</span><span class="code-line">                comment<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">""</span></span>
</span><span class="code-line">            <span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token keyword">case</span> <span class="token punctuation">.</span>tooLong<span class="token punctuation">:</span>
</span><span class="code-line">            <span class="token keyword">return</span> <span class="token class-name">NSLocalizedString</span><span class="token punctuation">(</span>
</span><span class="code-line">                <span class="token string-literal"><span class="token string">"Your username can't be longer than 14 characters"</span></span><span class="token punctuation">,</span>
</span><span class="code-line">                comment<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">""</span></span>
</span><span class="code-line">            <span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token keyword">case</span> <span class="token punctuation">.</span><span class="token function">invalidCharacterFound</span><span class="token punctuation">(</span><span class="token keyword">let</span> character<span class="token punctuation">)</span><span class="token punctuation">:</span>
</span><span class="code-line">            <span class="token keyword">let</span> format <span class="token operator">=</span> <span class="token class-name">NSLocalizedString</span><span class="token punctuation">(</span>
</span><span class="code-line">                <span class="token string-literal"><span class="token string">"Your username can't contain the character '%@'"</span></span><span class="token punctuation">,</span>
</span><span class="code-line">                comment<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">""</span></span>
</span><span class="code-line">            <span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">            <span class="token keyword">return</span> <span class="token class-name">String</span><span class="token punctuation">(</span>format<span class="token punctuation">:</span> format<span class="token punctuation">,</span> <span class="token class-name">String</span><span class="token punctuation">(</span>character<span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>그러면 이제 아래와 같이 무엇이 error인지 더 자세히 알려줄것이다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">Your</span> username can't contain the character '<span class="token operator">-</span>'
</span></code></pre>
<h2 id="참고">참고</h2>
<ul>
<li><a href="https://www.swiftbysundell.com/basics/error-handling/">Swift by Sundell, Error Handling</a></li>
<li><a href="https://docs.swift.org/swift-book/LanguageGuide/ErrorHandling.html">Apple Swift 5.1, Error Handling</a></li>
</ul>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swift-codable</guid>
      <title>Swift의 Codable</title>
      <description>Swift의 Codable로 JSON Encoding 및 Decoding 하는 방법에 대해 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/swift-codable</link>
      <pubDate>Sat, 28 Dec 2019 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li><code>Codable</code> API는 개발자가 JSON 같은 데이터를 쉽게 encode 및 decode 할 수 있게 해준다.</li>
<li>사실, <code>Codable</code>은 <code>Encodable</code>과 <code>Decodable</code> Protocol의 type alias이다.</li>
</ul>
<h2 id="자동화">자동화</h2>
<ul>
<li><code>Encodable</code>이든 <code>Decodable</code>을 채택하면 자동으로 필요한 stored property를 encode 혹은 decode 한다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">struct</span> <span class="token class-name">User</span><span class="token punctuation">:</span> <span class="token class-name">Codable</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> name<span class="token punctuation">:</span> <span class="token class-name">String</span>
</span><span class="code-line">    <span class="token keyword">var</span> age<span class="token punctuation">:</span> <span class="token class-name">Int</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="encode">Encode</h2>
<ul>
<li>다음과 같이 <code>JSONEncoder</code>를 통해 JSON 데이터로 쉽게 encode 할 수 있게 된다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">do</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> user <span class="token operator">=</span> <span class="token class-name">User</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Hohyeon"</span></span><span class="token punctuation">,</span> age<span class="token punctuation">:</span> <span class="token number">22</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">let</span> encoder <span class="token operator">=</span> <span class="token class-name">JSONEncoder</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">let</span> data <span class="token operator">=</span> <span class="token keyword">try</span> encoder<span class="token punctuation">.</span><span class="token function">encode</span><span class="token punctuation">(</span>user<span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Whoops, I did it again: </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">error</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="decode">Decode</h2>
<ul>
<li>다음과 같이 <code>JSONDecoder</code>를 통해 JSON 데이터를 쉽게 decode 할 수도 있다.</li>
<li>다음 코드를 실행하면 정확히 우리가 넣었던 JSON 데이터가 나올 것이다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">let</span> decoder <span class="token operator">=</span> <span class="token class-name">JSONDecoder</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token keyword">let</span> secondUser <span class="token operator">=</span> <span class="token keyword">try</span> decoder<span class="token punctuation">.</span><span class="token function">decode</span><span class="token punctuation">(</span><span class="token class-name">User</span><span class="token punctuation">.</span><span class="token keyword">self</span><span class="token punctuation">,</span> from<span class="token punctuation">:</span> data<span class="token punctuation">)</span>
</span></code></pre>
<h2 id="문제점">문제점</h2>
<ul>
<li>JSON 데이터 형식이 개발자가 원하는 형식이면 상관 없지만 그렇지 않으면 문제가 있다.</li>
<li>다음과 같은 JSON 코드를 decode 하려고 했다고 생각해보자.</li>
<li>위의 코드를 사용해 자동으로 encode 및 decode 할 수 없을 것이다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token string-literal"><span class="token string">"user_data"</span></span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token string-literal"><span class="token string">"full_name"</span></span><span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"Hohyeon Moon"</span></span><span class="token punctuation">,</span>
</span><span class="code-line">        <span class="token string-literal"><span class="token string">"user_age"</span></span><span class="token punctuation">:</span> <span class="token number">22</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="해결법">해결법</h2>
<ul>
<li>여러 해결 방법이 있지만, 그 중에서 제일 간단하고 효율적인 방법에 대해 알아보겠다.</li>
<li>User 구조체를 확장해, Codable을 채택한 CodingData 구조체를 만든다.</li>
<li>그리고 그 안에 다시 Codable을 채택한 Container 구조체를 만든다.</li>
<li>Container 안에 JSON 데이터의 camelCase 변수명을 만든다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">User</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">struct</span> <span class="token class-name">CodingData</span><span class="token punctuation">:</span> <span class="token class-name">Codable</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">struct</span> <span class="token class-name">Container</span><span class="token punctuation">:</span> <span class="token class-name">Codable</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">var</span> fullName<span class="token punctuation">:</span> <span class="token class-name">String</span>
</span><span class="code-line">            <span class="token keyword">var</span> userAge<span class="token punctuation">:</span> <span class="token class-name">Int</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">        <span class="token keyword">var</span> userData<span class="token punctuation">:</span> <span class="token class-name">Container</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>그리고 다음과 같이 User.CodingData 타입을 확장해 User 인스턴스에 값을 넣어준다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">User</span><span class="token punctuation">.</span><span class="token class-name">CodingData</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> user<span class="token punctuation">:</span> <span class="token class-name">User</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">return</span> <span class="token class-name">User</span><span class="token punctuation">(</span>
</span><span class="code-line">            name<span class="token punctuation">:</span> userData<span class="token punctuation">.</span>fullName<span class="token punctuation">,</span>
</span><span class="code-line">            age<span class="token punctuation">:</span> userData<span class="token punctuation">.</span>userAge
</span><span class="code-line">        <span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>snake_case를 camelCase로 변경하기 위해 convertFromSnakeCase를 사용한다.</li>
<li>직접 decode 하는 대신, User.CodingData의 인스턴스를 decode 하고 그것을 user로 convert 한다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">let</span> decoder <span class="token operator">=</span> <span class="token class-name">JSONDecoder</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">decoder<span class="token punctuation">.</span>keyDecodingStrategy <span class="token operator">=</span> <span class="token punctuation">.</span>convertFromSnakeCase
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">let</span> codingData <span class="token operator">=</span> <span class="token keyword">try</span> decoder<span class="token punctuation">.</span><span class="token function">decode</span><span class="token punctuation">(</span><span class="token class-name">User</span><span class="token punctuation">.</span><span class="token class-name">CodingData</span><span class="token punctuation">.</span><span class="token keyword">self</span><span class="token punctuation">,</span> from<span class="token punctuation">:</span> data<span class="token punctuation">)</span>
</span><span class="code-line"><span class="token keyword">let</span> user <span class="token operator">=</span> codingData<span class="token punctuation">.</span>user
</span></code></pre>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swift-closure</guid>
      <title>Swift의 Closure</title>
      <description>Swift의 핵심 개념인 Closure에 대해 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/swift-closure</link>
      <pubDate>Fri, 27 Dec 2019 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>Swift의 Closure를 다루기 전에 알아야하는 개념이 있다.</li>
<li>바로 일급 객체라는 것이다.</li>
</ul>
<h2 id="일급-객체">일급 객체</h2>
<ul>
<li>
<p>다음과 같은 조건을 만족하는 것을 일급 객체라고 할 수 있다.</p>
<ul>
<li>변수나 데이터 구조안에 담을 수 있다.</li>
<li>파라미터로 전달 할 수 있다.</li>
<li>반환값(return value)으로 사용할 수 있다.</li>
<li>할당에 사용된 이름과 관계없이 고유한 구별이 가능하다.</li>
<li>동적으로 프로퍼티 할당이 가능하다.</li>
</ul>
</li>
<li>
<p>우리가 Swift에서 알고 있는 대부분의 것은 일급 객체라고 할 수 있지만.</p>
</li>
<li>
<p>Method는 일급 객체가 아니고, Closure가 존재하는 이유이기도 하다.</p>
</li>
</ul>
<h2 id="closure의-유형">Closure의 유형</h2>
<ul>
<li>Closure의 유형은 3가지로 나눠볼수 있다.
<ul>
<li>Global function</li>
<li>Nested function</li>
<li>Closure expressions</li>
</ul>
</li>
</ul>
<h2 id="global-function">Global function</h2>
<ul>
<li>Global function은 우리가 흔히 알고 있는 함수이다.</li>
<li>클래스 밖의 함수라고 할 수 있다.</li>
</ul>
<h2 id="nested-function">Nested function</h2>
<ul>
<li>Nested function은 중첩 함수라고 말한다.</li>
<li>함수 내부에서 다시 함수를 정의해서 사용하는 함수이다.</li>
<li>외부에는 숨겨져 있고, 선언된 함수 내부에서만 호출이 가능하다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">chooseStepFunction</span><span class="token punctuation">(</span>backward<span class="token punctuation">:</span> <span class="token class-name">Bool</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token punctuation">(</span><span class="token class-name">Int</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Int</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">stepForward</span><span class="token punctuation">(</span>input<span class="token punctuation">:</span> <span class="token class-name">Int</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Int</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> input <span class="token operator">+</span> <span class="token number">1</span> <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">stepBackward</span><span class="token punctuation">(</span>input<span class="token punctuation">:</span> <span class="token class-name">Int</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Int</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> input <span class="token operator">-</span> <span class="token number">1</span> <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">return</span> backward <span class="token operator">?</span> stepBackward <span class="token punctuation">:</span> stepForward
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="closure-expressions">Closure expressions</h2>
<ul>
<li>이것이 흔히 클로저라고 불리는 유형이다.</li>
<li>문법은 다음과 같다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token punctuation">{</span><span class="token punctuation">(</span>parameters<span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token keyword">return</span> type <span class="token keyword">in</span>
</span><span class="code-line">    statements
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="클로저의-변수-할당">클로저의 변수 할당</h2>
<ul>
<li>클로저는 일급 객체이기 때문에 변수에 할당될 수 있다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">let</span> closureValue <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token punctuation">(</span>name<span class="token punctuation">:</span><span class="token class-name">String</span><span class="token punctuation">)</span> <span class="token keyword">in</span> <span class="token function">print</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span> <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token function">closureValue</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"hohyeonmoon"</span></span><span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>또한, 함수의 인자 값으로 전달될 수 있다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">closureOperation</span><span class="token punctuation">(</span>then closure<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Void</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">	<span class="token comment">// Some code</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="클로저-축약하기">클로저 축약하기</h2>
<ul>
<li>Swift에서의 클로저는 다른 언어에서보다 유연하다.</li>
<li>그래서 보다 자유롭게 축약하거나 변형할 수 있다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token comment">// 이랬던 코드가</span>
</span><span class="code-line"><span class="token keyword">let</span> string <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"Hello, world!"</span></span><span class="token punctuation">.</span><span class="token function">transformWords</span><span class="token punctuation">(</span>using<span class="token punctuation">:</span> <span class="token punctuation">{</span> word <span class="token keyword">in</span>
</span><span class="code-line">    <span class="token keyword">return</span> word<span class="token punctuation">.</span><span class="token function">lowercased</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token comment">// 이렇게 축약된다</span>
</span><span class="code-line"><span class="token keyword">let</span> string <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"Hello, world!"</span></span><span class="token punctuation">.</span>transformWords <span class="token punctuation">{</span> <span class="token short-argument">$0</span><span class="token punctuation">.</span><span class="token function">lowercased</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>후행 클로저를 사용해 함수의 파라미터를 축약할 수 있다.</li>
<li>$0과 같은 인자 값을 사용해 첫 번째 인자값을 대체할 수 있다.</li>
<li>단일 표현 클로저에서는 return 키워드를 생략할 수 있다.</li>
</ul>
<h2 id="trailing-closures">Trailing Closures</h2>
<ul>
<li>Trailing Closure로 마지막 파라미터 값으로 들어오는 Closure를 생략할 수 있다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token comment">// 함수 선언</span>
</span><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">someFunction</span> <span class="token punctuation">(</span>closure<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Void</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">	<span class="token comment">// Something</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token comment">// 일반적인 함수 사용</span>
</span><span class="code-line"><span class="token function">someFunction</span> <span class="token punctuation">(</span>closure<span class="token punctuation">:</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token comment">// Something</span>
</span><span class="code-line"><span class="token punctuation">}</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token comment">// Trailing Closure 사용</span>
</span><span class="code-line"><span class="token function">someFunction</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token comment">// Something</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="capturing-values">Capturing Values</h2>
<ul>
<li>Closure는 주변의 value를 포착(capture)한다.</li>
<li>다음 코드를 보자.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">makeIncrementer</span><span class="token punctuation">(</span>forIncrement amount<span class="token punctuation">:</span> <span class="token class-name">Int</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Int</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> runningTotal <span class="token operator">=</span> <span class="token number">0</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">incrementer</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Int</span> <span class="token punctuation">{</span>
</span><span class="code-line">        runningTotal <span class="token operator">+=</span> amount
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">return</span> runningTotal
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">return</span> incrementer
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>incrementer 함수를 떼어놓고 보자.</li>
<li>없는 runningTotal과 amount를 사용하고 있다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">incrementer</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Int</span> <span class="token punctuation">{</span>
</span><span class="code-line">    runningTotal <span class="token operator">+=</span> amount
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">return</span> runningTotal
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>그래서 주변 value를 capture 해서 사용한다.</li>
<li>그래서 다음과 같이 코드를 반복 실행하면, 값이 계속 증가하게 된다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">let</span> incrementByTen <span class="token operator">=</span> <span class="token function">makeIncrementer</span><span class="token punctuation">(</span>forIncrement<span class="token punctuation">:</span> <span class="token number">10</span><span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token function">incrementByTen</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token comment">// returns a value of 10</span>
</span><span class="code-line"><span class="token function">incrementByTen</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token comment">// returns a value of 20</span>
</span><span class="code-line"><span class="token function">incrementByTen</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token comment">// returns a value of 30</span>
</span></code></pre>
<h2 id="escaping-closure">Escaping Closure</h2>
<ul>
<li>@escaping을 통해 escaping closure을 사용할 수 있다.</li>
<li>Escaping Closure는 기본값인 nonescape closure와 다른 점이 몇가지 있다.</li>
<li>다음 코드와 같이 전달 받은 closure를 함수 외부에서 사용할 수 있다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">var</span> completionHandlers<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Void</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">someFunctionWithEscapingClosure</span><span class="token punctuation">(</span>completionHandler<span class="token punctuation">:</span> <span class="token attribute atrule">@escaping</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Void</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    completionHandlers<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>completionHandler<span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>또, Escaping Closure는 함수가 종료된 뒤에도 메모리에 잡아둔다.</li>
<li>그래서 비동기 프로그래밍을 할 때도 매우 유리하다.</li>
</ul>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swift-in-app-purchase</guid>
      <title>Swift Non-Consumable 인앱 결제 구현하기</title>
      <description>Swift UIKit으로 만드는 iOS 앱에서 Non-Consumable 인앱 결제를 구현해봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/swift-in-app-purchase</link>
      <pubDate>Thu, 26 Dec 2019 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<h2 id="4가지-인앱-결제-방식">4가지 인앱 결제 방식</h2>
<ul>
<li>
<p>인앱 결제란 이름 그대로 앱 내에서 결제하는 것을 말한다.</p>
</li>
<li>
<p>이 글에서는 이 중에서 Non-Consumable 인앱 결제 구현 방법을 알아보겠다.</p>
</li>
<li>
<p>애플 앱스토어의 인앱 결제에는 4가지 종류가 있다.</p>
<ul>
<li>Consumable : 한 번 이상 구매가 가능하고 소비될 수 있다.</li>
<li>Non-Consumable : 한 번만 구매가 가능하고 영구적으로 소유된다.</li>
<li>Non-Renewing Subscription : 일정 기간 동안만 사용될 수 있다.</li>
<li>Auto-Renewing Subscription : 반복되는 구독 방식의 인앱 결제.</li>
</ul>
</li>
</ul>
<h2 id="인앱-결제-기본-작업">인앱 결제 기본 작업</h2>
<ul>
<li>다음과 같이 인앱 결제를 위한 기본 작업을 해준다.</li>
<li><a href="https://developer.apple.com">애플 개발자 사이트</a>에서 Apple ID를 만든다.</li>
<li>개발자 Agreements를 확인하고 동의한다.</li>
</ul>
<p><img src="/images/swift-in-app-purchase-1.png" alt="swift-in-app-purchase"></p>
<ul>
<li><a href="https://appstoreconnect.apple.com">App Store Connects</a>에서 앱을 생성한다.</li>
</ul>
<p><img src="/images/swift-in-app-purchase-2.png" alt="swift-in-app-purchase"></p>
<ul>
<li>Feature에서 인앱 결제를 생성한다.</li>
<li>Users and Access → Sandbox → Testers에서 유저를 생성한다.</li>
</ul>
<h2 id="non-consumable-구현">Non-Consumable 구현</h2>
<ul>
<li>In-App Purchase를 도와주는 아래 소스코드를 프로젝트에 추가한다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token comment">// IAPHelper.swift</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">import</span> <span class="token class-name">StoreKit</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">public</span> <span class="token keyword">typealias</span> <span class="token class-name">ProductIdentifier</span> <span class="token operator">=</span> <span class="token class-name">String</span>
</span><span class="code-line"><span class="token keyword">public</span> <span class="token keyword">typealias</span> <span class="token class-name">ProductsRequestCompletionHandler</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token omit keyword">_</span> success<span class="token punctuation">:</span> <span class="token class-name">Bool</span><span class="token punctuation">,</span> <span class="token omit keyword">_</span> products<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">SKProduct</span><span class="token punctuation">]</span><span class="token operator">?</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Void</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">Notification</span><span class="token punctuation">.</span><span class="token class-name">Name</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">static</span> <span class="token keyword">let</span> <span class="token class-name">IAPHelperPurchaseNotification</span> <span class="token operator">=</span> <span class="token class-name">Notification</span><span class="token punctuation">.</span><span class="token class-name">Name</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"IAPHelperPurchaseNotification"</span></span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">open</span> <span class="token keyword">class</span> <span class="token class-name">IAPHelper</span><span class="token punctuation">:</span> <span class="token class-name">NSObject</span>  <span class="token punctuation">{</span>    
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">let</span> productIdentifiers<span class="token punctuation">:</span> <span class="token class-name">Set</span><span class="token operator">&#x3C;</span><span class="token class-name">ProductIdentifier</span><span class="token operator">></span>
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">var</span> purchasedProductIdentifiers<span class="token punctuation">:</span> <span class="token class-name">Set</span><span class="token operator">&#x3C;</span><span class="token class-name">ProductIdentifier</span><span class="token operator">></span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">var</span> productsRequest<span class="token punctuation">:</span> <span class="token class-name">SKProductsRequest</span><span class="token operator">?</span>
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">var</span> productsRequestCompletionHandler<span class="token punctuation">:</span> <span class="token class-name">ProductsRequestCompletionHandler</span><span class="token operator">?</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">public</span> <span class="token keyword">init</span><span class="token punctuation">(</span>productIds<span class="token punctuation">:</span> <span class="token class-name">Set</span><span class="token operator">&#x3C;</span><span class="token class-name">ProductIdentifier</span><span class="token operator">></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        productIdentifiers <span class="token operator">=</span> productIds
</span><span class="code-line">
</span><span class="code-line">        <span class="token keyword">for</span> productIdentifier <span class="token keyword">in</span> productIds <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">let</span> purchased <span class="token operator">=</span> <span class="token class-name">UserDefaults</span><span class="token punctuation">.</span>standard<span class="token punctuation">.</span><span class="token function">bool</span><span class="token punctuation">(</span>forKey<span class="token punctuation">:</span> productIdentifier<span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line">            <span class="token keyword">if</span> purchased <span class="token punctuation">{</span>
</span><span class="code-line">                purchasedProductIdentifiers<span class="token punctuation">.</span><span class="token function">insert</span><span class="token punctuation">(</span>productIdentifier<span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Previously purchased: </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">productIdentifier</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">                <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Not purchased: </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">productIdentifier</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">        <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token keyword">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span>        
</span><span class="code-line">        <span class="token class-name">SKPaymentQueue</span><span class="token punctuation">.</span><span class="token keyword">default</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token keyword">self</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">IAPHelper</span> <span class="token punctuation">{</span>    
</span><span class="code-line">    <span class="token keyword">public</span> <span class="token keyword">func</span> <span class="token function-definition function">requestProducts</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> completionHandler<span class="token punctuation">:</span> <span class="token attribute atrule">@escaping</span> <span class="token class-name">ProductsRequestCompletionHandler</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        productsRequest<span class="token operator">?</span><span class="token punctuation">.</span><span class="token function">cancel</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        productsRequestCompletionHandler <span class="token operator">=</span> completionHandler        
</span><span class="code-line">        productsRequest <span class="token operator">=</span> <span class="token class-name">SKProductsRequest</span><span class="token punctuation">(</span>productIdentifiers<span class="token punctuation">:</span> productIdentifiers<span class="token punctuation">)</span>
</span><span class="code-line">        productsRequest<span class="token operator">!</span><span class="token punctuation">.</span>delegate <span class="token operator">=</span> <span class="token keyword">self</span>
</span><span class="code-line">        productsRequest<span class="token operator">!</span><span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">public</span> <span class="token keyword">func</span> <span class="token function-definition function">buyProduct</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> product<span class="token punctuation">:</span> <span class="token class-name">SKProduct</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Buying </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">product<span class="token punctuation">.</span>productIdentifier</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">..."</span></span><span class="token punctuation">)</span>        
</span><span class="code-line">        <span class="token keyword">let</span> payment <span class="token operator">=</span> <span class="token class-name">SKPayment</span><span class="token punctuation">(</span>product<span class="token punctuation">:</span> product<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token class-name">SKPaymentQueue</span><span class="token punctuation">.</span><span class="token keyword">default</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>payment<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">public</span> <span class="token keyword">func</span> <span class="token function-definition function">isProductPurchased</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> productIdentifier<span class="token punctuation">:</span> <span class="token class-name">ProductIdentifier</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Bool</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">return</span> purchasedProductIdentifiers<span class="token punctuation">.</span><span class="token function">contains</span><span class="token punctuation">(</span>productIdentifier<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token keyword">func</span> <span class="token function-definition function">canMakePayments</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Bool</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">return</span> <span class="token class-name">SKPaymentQueue</span><span class="token punctuation">.</span><span class="token function">canMakePayments</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">public</span> <span class="token keyword">func</span> <span class="token function-definition function">restorePurchases</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token class-name">SKPaymentQueue</span><span class="token punctuation">.</span><span class="token keyword">default</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">restoreCompletedTransactions</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">IAPHelper</span><span class="token punctuation">:</span> <span class="token class-name">SKProductsRequestDelegate</span> <span class="token punctuation">{</span>    
</span><span class="code-line">    <span class="token keyword">public</span> <span class="token keyword">func</span> <span class="token function-definition function">productsRequest</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> request<span class="token punctuation">:</span> <span class="token class-name">SKProductsRequest</span><span class="token punctuation">,</span> didReceive response<span class="token punctuation">:</span> <span class="token class-name">SKProductsResponse</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Loaded list of products..."</span></span><span class="token punctuation">)</span>        
</span><span class="code-line">        <span class="token keyword">let</span> products <span class="token operator">=</span> response<span class="token punctuation">.</span>products
</span><span class="code-line">        productsRequestCompletionHandler<span class="token operator">?</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">,</span> products<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token function">clearRequestAndHandler</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">for</span> p <span class="token keyword">in</span> products <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Found product: </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">p<span class="token punctuation">.</span>productIdentifier</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string"> </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">p<span class="token punctuation">.</span>localizedTitle</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string"> </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">p<span class="token punctuation">.</span>price<span class="token punctuation">.</span>floatValue</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">public</span> <span class="token keyword">func</span> <span class="token function-definition function">request</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> request<span class="token punctuation">:</span> <span class="token class-name">SKRequest</span><span class="token punctuation">,</span> didFailWithError error<span class="token punctuation">:</span> <span class="token class-name">Error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Failed to load list of products."</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Error: </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">error<span class="token punctuation">.</span>localizedDescription</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>        
</span><span class="code-line">        productsRequestCompletionHandler<span class="token operator">?</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">,</span> <span class="token nil constant">nil</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token function">clearRequestAndHandler</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">func</span> <span class="token function-definition function">clearRequestAndHandler</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        productsRequest <span class="token operator">=</span> <span class="token nil constant">nil</span>
</span><span class="code-line">        productsRequestCompletionHandler <span class="token operator">=</span> <span class="token nil constant">nil</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">extension</span> <span class="token class-name">IAPHelper</span><span class="token punctuation">:</span> <span class="token class-name">SKPaymentTransactionObserver</span> <span class="token punctuation">{</span>    
</span><span class="code-line">    <span class="token keyword">public</span> <span class="token keyword">func</span> <span class="token function-definition function">paymentQueue</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> queue<span class="token punctuation">:</span> <span class="token class-name">SKPaymentQueue</span><span class="token punctuation">,</span> updatedTransactions transactions<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">SKPaymentTransaction</span><span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">for</span> transaction <span class="token keyword">in</span> transactions <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">switch</span> <span class="token punctuation">(</span>transaction<span class="token punctuation">.</span>transactionState<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">case</span> <span class="token punctuation">.</span>purchased<span class="token punctuation">:</span>
</span><span class="code-line">                <span class="token function">complete</span><span class="token punctuation">(</span>transaction<span class="token punctuation">:</span> transaction<span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token keyword">break</span><span class="token label important">
</span></span><span class="code-line"><span class="token label important">            case</span> <span class="token punctuation">.</span>failed<span class="token punctuation">:</span>
</span><span class="code-line">                <span class="token function">fail</span><span class="token punctuation">(</span>transaction<span class="token punctuation">:</span> transaction<span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token keyword">break</span><span class="token label important">
</span></span><span class="code-line"><span class="token label important">            case</span> <span class="token punctuation">.</span>restored<span class="token punctuation">:</span>
</span><span class="code-line">                <span class="token function">restore</span><span class="token punctuation">(</span>transaction<span class="token punctuation">:</span> transaction<span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token keyword">break</span><span class="token label important">
</span></span><span class="code-line"><span class="token label important">            case</span> <span class="token punctuation">.</span>deferred<span class="token punctuation">:</span>
</span><span class="code-line">                <span class="token keyword">break</span><span class="token label important">
</span></span><span class="code-line"><span class="token label important">            case</span> <span class="token punctuation">.</span>purchasing<span class="token punctuation">:</span>
</span><span class="code-line">                <span class="token keyword">break</span>
</span><span class="code-line">            <span class="token attribute atrule">@unknown</span> <span class="token keyword">default</span><span class="token punctuation">:</span>
</span><span class="code-line">                <span class="token function">fatalError</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">func</span> <span class="token function-definition function">complete</span><span class="token punctuation">(</span>transaction<span class="token punctuation">:</span> <span class="token class-name">SKPaymentTransaction</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"complete..."</span></span><span class="token punctuation">)</span>        
</span><span class="code-line">        <span class="token function">deliverPurchaseNotificationFor</span><span class="token punctuation">(</span>identifier<span class="token punctuation">:</span> transaction<span class="token punctuation">.</span>payment<span class="token punctuation">.</span>productIdentifier<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token class-name">SKPaymentQueue</span><span class="token punctuation">.</span><span class="token keyword">default</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">finishTransaction</span><span class="token punctuation">(</span>transaction<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">func</span> <span class="token function-definition function">restore</span><span class="token punctuation">(</span>transaction<span class="token punctuation">:</span> <span class="token class-name">SKPaymentTransaction</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">guard</span> <span class="token keyword">let</span> productIdentifier <span class="token operator">=</span> transaction<span class="token punctuation">.</span>original<span class="token operator">?</span><span class="token punctuation">.</span>payment<span class="token punctuation">.</span>productIdentifier <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">        <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"restore... </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">productIdentifier</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>        
</span><span class="code-line">        <span class="token function">deliverPurchaseNotificationFor</span><span class="token punctuation">(</span>identifier<span class="token punctuation">:</span> productIdentifier<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token class-name">SKPaymentQueue</span><span class="token punctuation">.</span><span class="token keyword">default</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">finishTransaction</span><span class="token punctuation">(</span>transaction<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">func</span> <span class="token function-definition function">fail</span><span class="token punctuation">(</span>transaction<span class="token punctuation">:</span> <span class="token class-name">SKPaymentTransaction</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"fail..."</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">if</span> <span class="token keyword">let</span> transactionError <span class="token operator">=</span> transaction<span class="token punctuation">.</span>error <span class="token keyword">as</span> <span class="token class-name">NSError</span><span class="token operator">?</span><span class="token punctuation">,</span>
</span><span class="code-line">            <span class="token keyword">let</span> localizedDescription <span class="token operator">=</span> transaction<span class="token punctuation">.</span>error<span class="token operator">?</span><span class="token punctuation">.</span>localizedDescription<span class="token punctuation">,</span>
</span><span class="code-line">            transactionError<span class="token punctuation">.</span>code <span class="token operator">!=</span> <span class="token class-name">SKError</span><span class="token punctuation">.</span>paymentCancelled<span class="token punctuation">.</span>rawValue <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"Transaction Error: </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">localizedDescription</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token class-name">SKPaymentQueue</span><span class="token punctuation">.</span><span class="token keyword">default</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">finishTransaction</span><span class="token punctuation">(</span>transaction<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">func</span> <span class="token function-definition function">deliverPurchaseNotificationFor</span><span class="token punctuation">(</span>identifier<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token operator">?</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">guard</span> <span class="token keyword">let</span> identifier <span class="token operator">=</span> identifier <span class="token keyword">else</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line">        purchasedProductIdentifiers<span class="token punctuation">.</span><span class="token function">insert</span><span class="token punctuation">(</span>identifier<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token class-name">UserDefaults</span><span class="token punctuation">.</span>standard<span class="token punctuation">.</span><span class="token keyword">set</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">,</span> forKey<span class="token punctuation">:</span> identifier<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token class-name">NotificationCenter</span><span class="token punctuation">.</span><span class="token keyword">default</span><span class="token punctuation">.</span><span class="token function">post</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token class-name">IAPHelperPurchaseNotification</span><span class="token punctuation">,</span> object<span class="token punctuation">:</span> identifier<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>이 IAPHelper 스위프트 파일이 사실 인앱 결제의 대부분을 차지한다.</li>
<li>이제 구입을 원하는 Controller에 다음과 같은 구조체를 만든다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">public</span> <span class="token keyword">struct</span> <span class="token class-name">InAppProducts</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">let</span> product <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"(인앱 Product ID)"</span></span>
</span><span class="code-line">    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">let</span> productIdentifiers<span class="token punctuation">:</span> <span class="token class-name">Set</span><span class="token operator">&#x3C;</span><span class="token class-name">ProductIdentifier</span><span class="token operator">></span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token class-name">InAppProducts</span><span class="token punctuation">.</span>product<span class="token punctuation">]</span>
</span><span class="code-line">    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">let</span> store <span class="token operator">=</span> <span class="token class-name">IAPHelper</span><span class="token punctuation">(</span>productIds<span class="token punctuation">:</span> <span class="token class-name">InAppProducts</span><span class="token punctuation">.</span>productIdentifiers<span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>그리고 원하는 구입 버튼 action에 다음과 같이 코드를 작성한다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">InAppProducts</span><span class="token punctuation">.</span>store<span class="token punctuation">.</span><span class="token function">buyProduct</span><span class="token punctuation">(</span>product<span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>이제 결제가 되는지 확인해볼 차례이다.</li>
<li>참고로 인앱 결제는 시뮬레이터에서는 작동하지 않는다.</li>
<li>아이폰 Settings → iTunes &#x26; App Store에서 로그아웃한다.</li>
<li>결제 버튼을 눌러보면, 로그인 창이 뜬다.</li>
<li>생성했던 Sandbox 유저 로그인 정보를 입력한다.</li>
<li>Sandbox 유저로 테스트 결제가 완료된다.</li>
<li>복원 기능을 사용하기 위해서는 다음과 같이하면 된다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token class-name">InAppProducts</span><span class="token punctuation">.</span>store<span class="token punctuation">.</span><span class="token function">restorePurchases</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span></code></pre>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/react-js-github-pages-deploy</guid>
      <title>React JS를 Github Pages에 호스팅하기</title>
      <description>React JS 라이브러리를 Github Pages에 호스팅하는 방법을 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/react-js-github-pages-deploy</link>
      <pubDate>Fri, 03 May 2019 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>페이스북의 React JS 라이브러리를 Github Pages에 호스팅하는 방법을 알아보는 글 입니다.</li>
</ul>
<h2 id="react-js란">React JS란</h2>
<ul>
<li>웹은 기본적으로 front-end와 back-end로 나뉩니다.</li>
<li>front-end는 client쪽의 작업을 말합니다.</li>
<li>back-end는 server쪽의 작업을 말합니다.</li>
<li>React JS는 페이스북에서 만든 프론트엔드 라이브러리입니다.</li>
<li>React JS를 정확히 정의하려면 별도의 글을 써야할만큼 복잡하지만.</li>
<li>쉽게 말해 user interface 만드는 것을 도와주는 라이브러리입니다.</li>
</ul>
<h2 id="github-pages란">Github Pages란</h2>
<ul>
<li>Github Pages는 정적인 페이지를 호스팅 해주는 서비스입니다.</li>
<li>많은 호스팅 서비스 중에 Github Pages를 선택한 이유는 다음과 같습니다.</li>
<li>호스팅하는 소스코드를 공개할 경우 무료입니다.</li>
<li>깃허브 리포지토리의 소스코드를 직접 호스팅해줍니다.</li>
<li>무료인것도 좋지만, 깃허브 리포지토리를 직접 호스팅해주는 것은 굉장한 강점입니다.</li>
<li>버전 관리 시스템인 Git을 통해 안정적으로 코드를 관리할 수 있습니다.</li>
</ul>
<h2 id="웹-앱-호스팅하기">웹 앱 호스팅하기</h2>
<ul>
<li>이제 React JS로 만든 웹 앱을 Github Pages에 호스팅하는 방법을 알아보겠습니다.</li>
<li>준비사항 : 코드 에디터, Git, Node.js, npm, Github 계정</li>
<li>위 준비사항을 본인 컴퓨터에 준비해주세요.</li>
<li>React JS 앱을 만들 디렉토리로 이동합니다.</li>
</ul>
<pre><code class="language-terminal code-highlight"><span class="code-line">$ cd /Users/username
</span></code></pre>
<ul>
<li>npm으로 React 패키지를 설치합니다.</li>
</ul>
<pre><code class="language-terminal code-highlight"><span class="code-line">$ npm install -g create-react-app
</span></code></pre>
<ul>
<li>새로운 React JS 앱을 생성합니다.</li>
</ul>
<pre><code class="language-terminal code-highlight"><span class="code-line">$ create-react-app appname
</span></code></pre>
<ul>
<li>생성된 앱을 실행합니다.</li>
</ul>
<pre><code class="language-terminal code-highlight"><span class="code-line">$ cd appname
</span><span class="code-line">$ npm start
</span></code></pre>
<ul>
<li>이제 Github에 새로운 리포지토리를 생성합니다.</li>
</ul>
<p><img src="/images/react-js-github-pages-deploy-1.png" alt="react-js-github-pages-deploy"></p>
<ul>
<li>로컬 React 프로젝트에 Git을 추가해 리포지토리로 만듭니다.</li>
</ul>
<pre><code class="language-terminal code-highlight"><span class="code-line">$ git init
</span><span class="code-line">$ git add .
</span><span class="code-line">$ git commit -m 'initial commit'
</span></code></pre>
<ul>
<li>Git을 push 합니다.</li>
</ul>
<pre><code class="language-terminal code-highlight"><span class="code-line">$ git remote add origin https://github.com/username/repository-name.git
</span><span class="code-line">$ git push origin master
</span></code></pre>
<ul>
<li>npm을 사용해 gh-pages 패키지를 설치합니다.</li>
</ul>
<pre><code class="language-terminal code-highlight"><span class="code-line">$ npm install --save gh-pages
</span></code></pre>
<ul>
<li>React 프로젝트의 package.json 파일을 수정합니다.</li>
<li>homepage 주소를 수정하고 predeploy와 deploy를 scripts에 추가합니다.</li>
</ul>
<p><img src="/images/react-js-github-pages-deploy-2.png" alt="react-js-github-pages-deploy"></p>
<ul>
<li>마지막으로 React 앱을 deploy합니다.</li>
</ul>
<pre><code class="language-terminal code-highlight"><span class="code-line">$ npm run deploy
</span></code></pre>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/method-good-programmer</guid>
      <title>좋은 프로그래머가 되려면</title>
      <description>좋은 프로그래머가 되는 방법에 대한 개인적인 의견을 남겨봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/method-good-programmer</link>
      <pubDate>Sun, 21 Apr 2019 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>2019년 현재, IT와 테크가 워낙 핫하기도 하고, 어디에든 접목될 수 있으니, 많은 사람들이 IT 관련 직종을 원하곤 합니다. 그중에서도 프로그래머는 가장 유망하고 미래가 밝은 직종으로 평가를 받고 있습니다.</p>
<p>위키피디아에 따르면, 프로그래머란 ‘컴퓨터 프로그래밍을 하고 컴퓨터 소프트웨어를 개발하는 사람을 말한다’라고 하는데요. 이번에는 이러한 프로그래머가 되는 법에 대해 알아보겠습니다.</p>
<h2 id="언어보다는-분야를">언어보다는 분야를</h2>
<p>처음 프로그래밍을 시작하면 어떤 언어로 시작해야 하나요?라는 질문을 많이 합니다. 그러나 언어를 선택하기에 앞서 선택해야 할 것이 있습니다.</p>
<p>본인의 목표나 관심에 맞는 프로그래밍 분야를 선택하는 것입니다. 예를 들어, 본인이 아이폰 앱에 흥미가 있다면, 모바일 애플리케이션이라는 분야를 선택하라는 것입니다.</p>
<h2 id="선택했다면-언어를">선택했다면 언어를</h2>
<p>분야를 선택했다면 언어를 선택하기 훨씬 수월해집니다.</p>
<p>아이폰 앱에 관심이 있다면 스위프트 프로그래밍 언어를 배우면 됩니다. 안드로이드 앱에 관심이 있다면 코틀린이나 자바를 배우면 됩니다.</p>
<p>웹 프로그래밍에 관심이 있다면 HTML, CSS를 기본적으로 익히고 자바스크립트와 추가적인 언어를 배우면 됩니다.</p>
<p>이렇듯 분야를 선택해놓으면, 언어의 선택 범위가 자연스레 좁아집니다. 좁아진 범위 중에서 전망이나 추가적인 쓰임새를 조사하고 참고해서 배울 언어를 결정하면 됩니다.</p>
<h2 id="공부에-빠져보자">공부에 빠져보자</h2>
<p>이제 공부를 시작할 때입니다. 개인적으로 프로그래밍은 독학을 통해 공부하는 것이 가장 효과적이라고 생각하는데요.</p>
<p>코딩 공부법에 대한 내용은 지난 번에 따로 자세히 다룬 <a href="/blog/coding-self-study">코딩 독학을 위한 공부 방법</a>를 참고해주세요.</p>
<h2 id="실제로-적용해보자">실제로 적용해보자</h2>
<p>어느 정도의 공부를 했다면, 슬슬 지겨워지기 시작했다면, 배운 내용을 실제로 적용할 때가 된 것입니다. 간단하더라도, 실제로 적용해봅니다.</p>
<p>프로그래밍에 있어 가장 좋은 선생님은 검색엔진 구글입니다. 구글을 효과적으로 사용하는 법은 <a href="/blog/googling-tips">구글링 하는법과 꿀팁 총정리</a>를 참고해주세요.</p>
<h2 id="끊임없는-공부">끊임없는 공부</h2>
<p>이런 일련의 과정을 거쳐 어떠한 결과물을 만들었다면, 프로그래머 세계에 첫 발을 디뎠다고 할 수 있습니다.</p>
<p>하지만 이것이 시작일뿐입니다. 빠른 속도로 끊임없이 발전하는 IT 세상에서는 지식보다 지식을 습득하는 능력이 중요하다고 생각합니다.</p>
<p>그렇기에 좋은 프로그래머가 되려면 공부를 습관화하고 끊임없이 발전해야 합니다.</p>
<h2 id="마무리">마무리</h2>
<p>제가 우수하거나 좋은 프로그래머이기 때문에 이런 말을 할 수 있는 것이 아닙니다. 실제로 저는 아직 한참 부족한 프로그래머입니다. 또, 저를 포함한 다른 많은 프로그래머들도 위와 같은 내용을 인지하고 있을 것입니다.</p>
<p>하지만 보통 이것을 실제로 실천하는 노력이 부족하거나 능력이 따라주지 못하기 때문에 아무나 좋은 프로그래머가 될 수는 없는 것입니다.</p>
<p>이 영상이 처음 프로그래밍을 시작하는 분들에게는 이런 방향으로 하면 프로그래머가 될 수 있다는 것을 알려주고, 어느 정도 프로그래머의 길을 걷고 있는 분들에게는 동기부여를 줬으면 좋겠습니다.</p>
<p>여러분은 좋은 프로그래머가 되는 방법에는 무엇이 있다고 생각하시나요? 영상의 댓글로 여러분의 생각을 남겨주세요.</p>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/airpods-3-iphone-se-2</guid>
      <title>에어팟 프로부터 아이폰 SE2까지</title>
      <description>에어팟 프로부터 아이폰 SE2까지 애플이 준비하고 있는 제품의 루머에 대해 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/airpods-3-iphone-se-2</link>
      <pubDate>Sat, 13 Apr 2019 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>애플이 노이즈캔슬링이 탑재된 에어팟3(에어팟 프로)를 준비하고 있다는 루머가 나왔습니다.</li>
<li>루머의 대가인 궈밍치에 의하면 에어팟은 완전히 새로운 디자인으로 올해 말이나 내년 초쯤에 출시할 수 있다고 합니다.</li>
<li>애플은 오늘 iOS 13.2의 첫 번째 베타 버전을 공개했는데요.</li>
<li>해당 베타 버전에서는 고무 팁이 있는 완전히 리디자인된 에어팟 아이콘의 모습을 볼 수 있었습니다.</li>
<li>이러한 고무 팁이 있는 디자인은 노이즈캔슬링 기능을 제공하기 위함으로 추측됩니다.</li>
</ul>
<p><img src="/images/airpods-3-iphone-se-2-1.png" alt="airpods-3-iphone-se-2"></p>
<ul>
<li>해당 에어팟3 이미지는 접근성 설정에 관련된 폴더에서 발견할 수 있었는데요.</li>
<li>새로운 에어팟은 접근성 관련 기능을 추가로 제공할 것으로 보입니다.</li>
</ul>
<p><img src="/images/airpods-3-iphone-se-2-2.jpg" alt="airpods-3-iphone-se-2"></p>
<ul>
<li>또한, 지난달 유출되었던 에어팟의 사진이 이번 에어팟3 아이콘의 모습과 상당히 비슷해 재조명 받고 있습니다.</li>
</ul>
<p><img src="/images/airpods-3-iphone-se-2-3.png" alt="airpods-3-iphone-se-2"></p>
<ul>
<li>전문 유출가 정도 되는 궈밍치에 의하면, 상대적으로 저렴한 아이폰인 아이폰 SE2는 2020년 1분기에 나올 것이고</li>
<li>아이폰 8과 동일한 폼 팩터를 사용할 것이라고 합니다.</li>
<li>하지만 A13 칩과 3기가 램을 탑재해 뛰어난 성능을 보여줄 것으로 기대했습니다.</li>
<li>애플은 아이폰 SE2를 통해 아이폰의 스마트폰 시장 점유율을 높여</li>
<li>최근 공을 들이고 있는 서비스 사업에 도움을 줄 것을- 기대한다고 합니다.</li>
</ul>
<p><img src="/images/airpods-3-iphone-se-2-4.jpg" alt="airpods-3-iphone-se-2"></p>
<ul>
<li>아직까지 아이폰 6 또는 아이폰 6 플러스를 사용하고 있는 사용자가 많다고 하는데요.</li>
<li>이 사용자들에게 있어 아이폰 SE2는 최고의 업그레이드 옵션이 될 것으로 보입니다.</li>
<li>그 이유는 아이폰 SE2는 이 사용자들이 불만을 갖고 있는 페이스 ID와</li>
<li>흉측한(?) 멀티 카메라 대신 터치 ID와 싱글 카메라를 유지할 것이기 때문입니다.</li>
</ul>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/coding-self-study</guid>
      <title>코딩 독학을 위한 공부 방법</title>
      <description>코딩 독학을 잘 하기 위한 공부 비법에 대해 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/coding-self-study</link>
      <pubDate>Thu, 31 Jan 2019 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>많은 분들이 코딩 공부를 시작하고는 싶은데, 어떻게 시작해야 할지 몰라 선뜻 시작을 못하곤 합니다. 그래서 이번에는 코딩 독학을 어떻게 시작하면 좋을지, 좋은 코딩 공부법에는 어떤 것이 있을지 소개해보려 합니다.</p>
<p>프로그래밍 독학을 효율적으로 진행하기 위해서는 1. 코딩 공부의 목표를 설정하고 2. 어떤 프로그래밍 언어를 배우기 시작할지 선택하고 3. 코딩 공부 방법을 선택하고 진행하는 것을 추천합니다. 각 단계에 대해 조금 더 자세히 설명해보도록 하겠습니다.</p>
<h2 id="목표-설정하기">목표 설정하기</h2>
<p>어떤 것이든 목표 혹은 동기가 있다면, 훨씬 재밌고 신속하게 진행할 수 있습니다. 코딩 역시 마찬가지입니다. 어떠한 목표를 가지고 코딩 공부를 시작하는 것과 그렇지 않은 것에는 큰 차이가 있습니다.</p>
<p>예를 들어, OO 앱이라는 구체적인 목표를 갖고 코딩 공부를 시작한 A 군과 단순히 코딩 분야가 유망해서 코딩 공부를 시작한 B 군은 전혀 다를 것입니다. 기초적인 코딩 공부로 시작하는 것은 똑같겠지만, A 군은 OO 앱을 만들기 위해 그에 관련된 추가적인 공부를 당연하게 이어서 하게 될 것이고, B 군은 기초 공부를 끝냈다면 다시 어떤 공부를 추가적으로 해야 할지 고민하기 시작할 것입니다. 그뿐만 아니라, 자신의 목표에 한 걸음 한 걸음 다가가는 느낌을 받으며 공부를 한다면, 훨씬 흥미로울 것입니다.</p>
<p>한마디로, 소박하더라도 만들고 싶은 무언가를 정하라는 것입니다. 그것이 웹 애플리케이션이 됐든, 아이폰 혹은 안드로이드 앱이 됐든 말입니다.</p>
<h2 id="언어-선택하기">언어 선택하기</h2>
<p>만들고 싶은 무엇인가를 설정했다면, 그것을 만들기에 적합한 프로그래밍 언어가 있을 것입니다. 예를 들어, 아이폰 앱을 만들기 위해서는 스위프트 언어가 필요할 것이고, 안드로이드 앱을 만들기 위해서는 자바나 코틀린 언어가 필요할 것입니다.</p>
<p>어떤 프로그램을 만들기 위해 어떤 언어가 필요하다를 일일이 설명하기에는 만들 수 있는 프로그램의 종류가 워낙 다양하기도 하고, 의미도 없습니다. 스스로 검색해서 이 프로그램을 만들기 위해서는 이 프로그래밍 언어가 필요하겠구나를 찾아내는 것도 하나의 능력입니다.</p>
<p>결론적으로, 목표를 만들기 위한 프로그래밍 언어를 검색해서 조사합니다.</p>
<h2 id="공부-방법-선택하기">공부 방법 선택하기</h2>
<p>이제 본격적으로 코딩 공부를 할 때입니다. 코딩 공부를 하는 방법에는 크게 두 가지가 있습니다. 독학하는 것과 학교 또는 학원에서 수강하는 것입니다. 둘 중에 무엇을 더 추천하지는 않습니다. 사람마다 자신에게 적합한 방법이 다르기 때문이죠.</p>
<p>저는 학교 수업, 학원 강의, 독학 모두 시도 해봤는데요. 독학이 가장 잘 맞았습니다. 학교 또는 학원을 통해 공부하다 보면, 1차적으로 내용을 받아들이고 2차적으로 혼자 다시 학습해야 하기 때문에 효율적이지 못했습니다. 하지만 독학은 내용을 받아들이는 동시에 내 것을 만들 수 있어 시간과 노력을 절약하고 직접 코딩 작성하는데 집중할 수 있었습니다.</p>
<p>코딩 독학도 크게 두 가지로 나눌 수 있습니다. 책으로 하는 독학과 영상으로 하는 독학으로 말입니다. 책과 영상 중에서 저는 책을 더 선호합니다. 빨리 진행하고 싶을 때는 빨리 진행하고 천천히 진행하고 싶을 때는 천천히 진행할 수 있어 속도 조절이 가능했기 때문이죠. 하지만 진도가 더디거나 흥미를 잃었을 때는 영상도 도움이 많이 되었습니다.</p>
<p>개인적으로, 모든 방법을 시도해보고 본인에게 가장 잘 맞는 방법을 선택하는 것을 추천합니다.</p>
<h2 id="그-이후">그 이후</h2>
<p>여기서부터는 개인의 참을성과 꾸준함이 큰 영향을 미칠 것입니다. 공부하는 과정이 지루할 수도 있고, 목표한 앱을 만들다가 막힐 수도 있습니다. 하지만 설정한 목표를 향해 어떠한 어려움이 있어도, 묵묵히 참고 공부하며 개발한다면 한 단계 성장하게 될 것입니다.</p>
<p>개발이 지루하거나 막히는 것이 생길 때, 우리에게는 구글과 인터넷이라는 아주 큰 도우미가 있다는 것을 잊지 않았으면 좋겠습니다. 구글을 검색하면 시간은 조금 걸릴 수도 있겠지만, 웬만한 문제를 해결할 수 있습니다. 인터넷 각 코딩 분야의 커뮤니티에서는 응원이나 문제에 대한 도움을 받을 수도 있습니다.</p>
<p>이렇게해서, 첫 번째로 목표한 무엇인가를 완성했다면, 새로운 또 다른 프로젝트를 기획하고 진행해서 새로운 분야를 탐구하는 것을 추천합니다. 하지만 이가 조금 싫증 난다면, 팀을 구성해 그룹 프로젝트를 진행하거나 네트워킹 기회가 주어진다면 자신에게 적합한 멘토를 구하는 것도 적극 추천합니다.</p>
<h2 id="마무리">마무리</h2>
<p>이렇게해서 코딩 독학을 위한 효과적인 공부 방법을 알아봤는데요. 코딩과 관련해서 궁금한 주제를 Contact로 남겨주시면 제가 다룰 수 있는 범위내에서 다뤄보도록 하겠습니다.</p>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/programmer-desk-setup</guid>
      <title>프로그래머의 데스크셋업</title>
      <description>데스크셋업까지 논리적인 프로그래머의 데스크셋업을 소개합니다</description>
      <link>https://www.hohyeonmoon.com/blog/programmer-desk-setup</link>
      <pubDate>Fri, 11 Jan 2019 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>개발자는 대부분의 시간을 책상 앞에서 보내기도 하고, 사무실 책상 인테리어는 개발자의 집중력에 큰 영향을 끼칩니다. 개발자들이 유독 책상 정리에 신경을 많이 쓰는 이유라고 생각하는데요. 이번에는 제가 오랜 시간 유지하고 있는 책상 인테리어를 소개해볼까 합니다.</p>
<p>데스크 셋업은 1. 책상의 위치를 어떻게 배치하느냐 2. 책상 위를 어떻게 구성하느냐가 가장 관건일듯한데요. 이 순서대로 소개해보도록 하겠습니다.</p>
<h2 id="책상-위치">책상 위치</h2>
<p><img src="/images/developer-desk-setup-1.png" alt="developer-desk-setup"></p>
<p>개인적으로 책상의 위치는 벽에 붙이기보다는 벽으로부터 일정 공간 떨어뜨려 놓습니다. 벽에 붙여놓으면 넓어 보인다는 장점이 있지만, 항상 벽을 보고 작업해야 하고 상대적으로 아늑한 느낌이 덜해서 집중이 덜 되는 경향이 있습니다.</p>
<p>하지만, 이렇게 책상을 적당히 벽에서 떨어뜨려 놓으면, 책상에 앉았을 때 아늑한 느낌을 받으면서도 공간을 효율적으로 사용할 수 있습니다.</p>
<p>또, 필요한 물건이 손 뻗는 곳에 있는 것을 좋아해서 기억 자 형태의 책상 배치를 선호하는데요. 책상 옆에 선반을 보조 책상처럼 배치해 기억자 형태의 책상을 구성하면서도 아늑함을 더해봤습니다.</p>
<h2 id="책상-위-구성">책상 위 구성</h2>
<p><img src="/images/developer-desk-setup-2.png" alt="developer-desk-setup"></p>
<p>굉장히 사소하지만, 각각의 책상 인테리어 소품들은 그곳에 배치된 나름의 이유가 있는데요. 제가 책상 위 인테리어에 있어 가장 중요하게 생각하는 것은 아무것도 없는 듯 심플 하면서도 있을 물건은 가까이에 다 있어야 한다는 것입니다.</p>
<p>저에게 있어 있을 물건이란, 1. 자주 사용하는 기기 2. 학업에 필요한 물건인데요. 자주 사용하는 기기는 애플워치, 아이폰, 아이패드, 맥북 등의 애플 기기와 외장하드, 헤드폰 등의 주변기기입니다. 학업에 필요한 물건에는 책, 연습장, 필기구 등이 있습니다.</p>
<p>이 물건들을 사용 빈도에 따라 순서를 매겨보면, 1. 맥북 2. 아이폰 3. 주변기기 4. 아이패드 &#x26; 학용품 정도인데요. 가장 많이 사용하는 맥북과 아이폰만 책상 위에 두고, 그다음 순서인 주변기기와 아이패드를 제일 가까운 수납 공간인 책상 서랍에 보관합니다. 학용품과 나머지 필요 물건은 서랍장이자 보조 책상인 선반에 보관합니다.</p>
<h2 id="마무리">마무리</h2>
<p>이렇게 제가 정착하고 있는 책상 인테리어를 소개해봤는데요. 콘텐츠가 마음에 들었다면, 영상의 좋아요와 댓글 남겨주시면 감사하겠습니다.</p>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/developer-programming-laptop</guid>
      <title>개발자를 위한 프로그래밍 노트북 추천</title>
      <description>개발자를 위한 프로그래밍 노트북을 추천해봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/developer-programming-laptop</link>
      <pubDate>Thu, 03 Jan 2019 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>이번에는 <strong>개발자를 위한 프로그래밍 노트북</strong>을 추천해보려 하는데요.</p>
<ul>
<li><strong>맥과 윈도우 중</strong> 어떤 운영체제의 노트북이 프로그래밍을 위해 더 좋을지</li>
<li><strong>프로그래밍 분야별</strong>로 어떤 노트북이 더 좋을지</li>
<li><strong>상황에 따라</strong> 어떤 노트북이 더 좋을지 순서로 알아볼까 합니다.</li>
</ul>
<p>하지만 이는 특정 상황에 한정된 노트북 추천이기도 하고, 개인적인 의견이 섞여 있기 때문에 무조건 이 노트북이 가장 좋다라고 단정 지을 수는 없을것 같습니다.</p>
<h2 id="맥-vs-윈도우">맥 vs 윈도우</h2>
<p><img src="/images/developer-programming-laptop-1.png" alt="developer-programming-laptop"></p>
<p><a href="/blog/mac-windows-coding-laptop">지난 글</a>에서도 낸 결론이지만, 저는 프로그래밍 노트북으로는 맥과 윈도우 중 맥을 더 선호합니다.</p>
<p>하지만 맥이 조금 더 편하다는 것이지 윈도우로 프로그래밍을 못하거나 하기 힘든 것은 아닙니다. 윈도우 자체에서도 대부분의 프로그래밍이 가능하고 윈도우에 리눅스를 설치하거나 가상화 프로그램을 사용해 대부분의 프로그래밍을 할 수 있습니다.</p>
<p>다만, iOS나 macOS 프로그래밍 등 애플 운영체제 관련 프로그래밍은 맥북에서만 가능하기 때문에 이가 하고 싶다면, 맥은 필수에 가깝습니다. 이 내용은 <a href="/blog/mac-windows-coding-laptop">지난 글</a>에서 더욱 자세히 다루니 참고해주세요.</p>
<h2 id="프로그래밍-분야별-노트북-추천">프로그래밍 분야별 노트북 추천</h2>
<p><img src="/images/developer-programming-laptop-2.png" alt="developer-programming-laptop"></p>
<p>프로그래밍 분야는 워낙 다양해서 모든 분야를 다룰수는 없겠지만, 제가 다뤄본 프로그래밍 분야에 적합한 노트북에 대해 알아보려고 합니다.</p>
<p>우선, 모바일 앱 개발을 위한 노트북으로는 맥을 많이 선호합니다. 모바일 앱은 크게 iOS와 안드로이드로 나뉘는데요. 앞서 말했듯이, iOS 앱 개발은 맥에서만 가능한 반면, 안드로이드 앱은 맥과 윈도우에서 모두 가능합니다.</p>
<p>웹 프로그래밍을 위한 노트북 역시 맥을 선호합니다. 대부분의 웹은 리눅스를 기반으로 하는데요. macOS는 리눅스와 같은 유닉스 기반의 운영체제이기 때문에 터미널을 사용해 쉽게 웹 개발을 할 수 있습니다. 반면, 윈도우는 MS-DOS나 파워쉘을 사용해서 아무래도 웹 개발을 위해서는 추가적인 노력이 필요합니다.</p>
<h2 id="상황에-따른-노트북-추천">상황에 따른 노트북 추천</h2>
<p>맥북을 기준으로 가격과 휴대성을 더 중요하게 생각하는 사용자라면, 이번에 새로 나온 맥북에어 2018을 추천합니다. 성능도 웬만한 프로그래밍을 하기에는 충분히 좋고 휴대성이나 배터리도 맥북프로에 비해 강점을 보입니다.</p>
<p>하지만, 성능을 더 중요하게 생각하는 사용자라면, 당연하게도 맥북프로 시리즈를 추천합니다. 조금 더 무겁지만, 그 만큼 더 좋은 퍼포먼스를 보여주기 때문이죠.</p>
<p>맥북프로 13인치와 15인치 역시 마찬가지입니다. 디스플레이 크기, 배터리 등 다른 여러 요인도 있겠지만, 가장 큰 차이점은 결국 휴대성과 성능입니다. 적당한 휴대성과 성능을 원한다면 맥북프로 13인치를, 휴대성은 떨어져도 뛰어난 성능을 원한다면 맥북프로 15인치를 추천합니다.</p>
<p>윈도우 노트북 중에서는 휴대용으로 마이크로소프트 서피스 프로 또는 델 XPS 13인치를 추천합니다. 또, 적당한 휴대성과 어느정도의 강력한 퍼포먼스를 위해서라면 서비스 북 또는 델 XPS 15인치를 추천합니다.</p>
<p>다만, 윈도우 노트북은 워낙 종류가 많고 직접 사용해보지 못한 제품이 너무나도 많아 추천하는데 한계가 있는것 같습니다. </p>
<h2 id="마무리">마무리</h2>
<p>이번에는 개발자를 위한 노트북 추천을 해봤는데요. 코딩과 관련해서 궁금한 주제를 Contact로 남겨주시면 제가 다룰 수 있는 범위내에서 다뤄보도록 하겠습니다.</p>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/ipad-pro-11-unboxing</guid>
      <title>아이패드 프로 11 개봉기</title>
      <description>새로운 아이패드 프로 11 개봉기입니다</description>
      <link>https://www.hohyeonmoon.com/blog/ipad-pro-11-unboxing</link>
      <pubDate>Mon, 15 Oct 2018 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>안녕하세요! 새로운 아이패드 프로 11로 오랫만에 인사드리네요.</p>
<p>이번 아이패드는 오랫만의 풀체인지 아이패드입니다. 아이패드 프로의 디자인부터 애플펜슬 2까지 모든 면에서 많은 것이 달라진 아이패드인데요. 개봉하면서 알아보도록 할까요?</p>
<h2 id="기본-정보">기본 정보</h2>
<p><img src="/images/ipad-pro-11-unboxing-1.jpeg" alt="ipad-pro-11-unboxing"></p>
<p>보시다시피 베젤 다이어트가 확실히 되었습니다. 태블릿에 베젤이 너무 없는것이 아니냐는 걱정도 있지만, 써보면 알겠죠? 디스플레이는 아이폰 XR에서 사용되었던 리퀴드 레티나 디스플레이가 탑재되었다고 하고.</p>
<p>페이스 ID를 지원하는 최초의 아이패드입니다. 어떤 각도에서든 페이스 ID를 사용할 수 있고, 기본적으로 베젤이 사라지면서 아이폰 X에 처음으로 적용되었던 제스처들이 동일하게 적용됩니다.</p>
<p>프로세서는 A12X 바이오닉 프로세서가 탑재되어 엄청난 긱벤치 점수를 보여주고 있는데요. 벌써부터, 이 성능에 대한 기대가 많더라구요.</p>
<h2 id="신기능">신기능</h2>
<p><img src="/images/ipad-pro-11-unboxing-2.png" alt="ipad-pro-11-unboxing"></p>
<p>아이패드 프로 3세대와 함께 애플펜슬 2세대 역시 출시 되었는데요. 애플펜슬 2는 무선 충전을 지원해서, 아이패드에 부착 수납하면 자동으로 페어링과 충전이 됩니다. 제스처 기능도 추가되어 조금 더 편리하게 사용할수도 있다고 합니다.</p>
<p><img src="/images/ipad-pro-11-unboxing-3.jpeg" alt="ipad-pro-11-unboxing"></p>
<p>새로운 스마트 키보드, 스마트 키보드 폴리오도 공개되었는데요. 기존의 스마트 키보드보다 조금 더 유연한 사용 각도를 지원하고 조금 더 견고해졌다고 합니다.</p>
<p><img src="/images/ipad-pro-11-unboxing-4.jpeg" alt="ipad-pro-11-unboxing"></p>
<p>그리고 이번 아이패드 프로 2018에는 iOS 기기 최초로 USB-C 타입이 탑재되어 카메라에 있는 데이터 전송등이 조금 더 편해졌습니다. 하지만 여전히, USB-C를 통한 파일 전송이 완전히 자유로운 것은 아닙니다.</p>
<h2 id="코멘트">코멘트</h2>
<p><img src="/images/ipad-pro-11-unboxing-5.jpg" alt="ipad-pro-11-unboxing"></p>
<p>역대 아이패드 중에 단연 가장 얇고 가볍고 강력한 이번 아이패드 프로 11. 이제 애플의 아이패드는 디스플레이, 성능, 휴대성, 배터리 등 모든 면에서 PC를 능가하는듯 합니다. 단 한 가지를 제외하고 말입니다. PC의 역할을 아이패드는 못한다는 것.</p>
<p><img src="/images/ipad-pro-11-unboxing-6.png" alt="ipad-pro-11-unboxing"></p>
<p>물론, 어도비 포토샵 CC도 그렇고 점점 아이패드에서도 전문가용 프로그램이 지원되기 시작하지만, 아직은 많이 부족합니다.</p>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/apple-watch-series-4-unboxing</guid>
      <title>애플워치 시리즈 4 개봉기</title>
      <description>애플워치 시리즈 4를 개봉해봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/apple-watch-series-4-unboxing</link>
      <pubDate>Mon, 24 Sep 2018 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>안녕하세요. 이번에는 저번 아이폰 Xs 맥스 개봉기 영상에서 말했듯이 애플워치 시리즈 4를 갖고 왔습니다. 제가 구입한 제품은 애플워치 시리즈 4 골드 스테인리스 스포츠 밴드 모델인데요. 바로 개봉부터 해보도록 하겠습니다.</p>
<h2 id="개봉">개봉</h2>
<p><img src="/images/apple-watch-series-4-unboxing-1.jpg" alt="apple-watch-series-4-unboxing"></p>
<p>애플워치 4는 디자인이 전작과 많이 달라졌습니다. 우선, 베젤리스 디스플레이가 탑재되어, 화면 크기 확 커졌고, 더 얇아졌습니다. 디지털 크라운의 호불호가 갈렸던 빨간색 점도 조금 더 멋지게 변경되었구요.</p>
<h2 id="기본정보">기본정보</h2>
<p><img src="/images/apple-watch-series-4-unboxing-2.jpg" alt="apple-watch-series-4-unboxing"></p>
<p>앞서 말했듯이, 애플워치 시리즈 4는 애플워치 시리즈 3와 비교했을때, 딱 봐도 많이 달라졌습니다. 디스플레이가 커졌고, 두께가 얇아졌으며, 디지털 크라운의 디자인과 스피커와 마이크의 위치도 전체적으로 달라졌습니다. 그러면서도 워치 밴드는 호환이 된다니, 반가운 소식입니다.</p>
<p>애플워치 4는 뒷면의 디자인 역시 많이 변경 되었는데요. 기존의 복잡해 보였던 애플워치 3와는 달리 조금 더 심플해지면서도 기능은 많아졌습니다.</p>
<p>골드 스테인리스 색상이 추가 되었지만, 애플워치 에디션 버전은 없어졌습니다. 기존과 마찬가지로, GPS 버전과 셀룰러 버전, 그리고 작은 버전과 큰 버전이 있습니다.</p>
<p>S4 프로세서가 탑재되었고, 배터리는 최대 18시간 지속된다고 합니다. 스피커의 음량도 50% 커졌습니다.</p>
<h2 id="신기능">신기능</h2>
<p><img src="/images/apple-watch-series-4-unboxing-3.png" alt="apple-watch-series-4-unboxing"></p>
<p>애플워치 시리즈 4의 새로운 기능은 크게 디스플레이, 디지털 크라운, ECG를 비롯한 건강 관련 기능으로 나눠볼 수 있습니다.</p>
<p>디스플레이는 베젤리스 디자인이 채택되며, 같은 폼팩터에도 화면은 커졌습니다. 커진 화면에 알맞게 watchOS의 UI도 더 많은 정보를 표시하도록 변경 되었다고 합니다. 뒷면의 디자인도 크게 변경 되었는데요. 전자 심장 센서가 탑재 되었다고 합니다.</p>
<p>전자 심장 센서 덕분에 전문적인 ECG 기능까지 사용할 수 있게 되었는데요. 심작 박동의 그래프를 실시간으로 그려준다고 합니다. 하지만 아쉽게도, 이 기능은 아직은 미국 식약청에서만 허가 승인이나서, 미국에서만 사용이 가능하다고 합니다.</p>
<p>디지털 크라운 역시 크게 변했는데요. 호불호가 갈리던 빨간점이 테두리만 빨간색으로 변경되며, 멋지게 변경되었습니다. 또, 디지털 크라운을 돌릴때 햅틱 피드백이 와서 더욱 실감나게 사용할 수 있고, 더욱 많은 부품을 작은 공간에 넣는데 성공했다고 합니다.</p>
<h2 id="후기-및-마무리">후기 및 마무리</h2>
<p>이번 애플 이벤트는 아이폰보다 애플워치에 중점이 맞춰졌다고 느껴질만큼, 애플워치 시리즈 4가 많이 변화했습니다. 그러나 개인적으로는, 이 변화가 그렇게 유용한지는 모르겠습니다. 대부분의 신기능이 있으면 좋지만 없어도 그만이라는 생각을 들게 합니다.</p>
<p>스마트 워치에 더 이상 추가할 수 있는 기능이 있나 싶으면서도, 애플이 만든 제품이기에 조금 더 기대하게 되는 것은 사실입니다.</p>
<p>이것으로 애플워치 시리즈 4 개봉기를 마치겠습니다. 아이폰 Xs 맥스도 그렇고 애플워치 시리즈 4도 그렇고 기대한것보다는 실망스럽지만, 조금 더 사용해보고 시간이 되는대로 리뷰도 진행해보겠습니다.</p>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/iphone-xs-max-unboxing</guid>
      <title>아이폰 XS 맥스 개봉기</title>
      <description>아이폰 Xs 시리즈 중 더 큰 화면을 갖고 있는 아이폰 Xs 맥스를 개봉해봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/iphone-xs-max-unboxing</link>
      <pubDate>Sat, 22 Sep 2018 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>이번에는 요즘 가장 핫하디 핫한 아이폰 Xs 시리즈 중 더 큰 화면을 갖고 있는 아이폰 Xs 맥스를 개봉해보려고 합니다. 빨리 열어보고 싶은 마음뿐이니, 먼저 개봉부터 해볼까요?</p>
<h2 id="개봉">개봉</h2>
<p><img src="/images/iphone-xs-max-unboxing-1.jpg" alt="iphone-xs-max-unboxing"></p>
<p>아이폰 Xs는 아이폰 X과 디자인상 큰 차이는 없습니다. 하지만 골드 색상이 추가 되었고, 화면 사이즈가 커진 아이폰 Xs 맥스가 추가 되었죠.</p>
<p>비닐을 잘 뜯어보면, 간단 설명서가 가장 먼저 보입니다. 간단 설명서 밑에는 아이폰 Xs 맥스 본체가 있고, 우선 본체는 옆에 두고 구성품을 살펴보면, 라이트닝 이어팟과 라이트닝 케이블 그리고 무려 5W 충전 어댑터가 포함되어 있습니다.</p>
<p>간단 설명서에는 늘 그랬듯이, 간단한 설명이 적혀 있고, 애플 스티커가 있습니다.</p>
<p>본체는 아이폰 X과 디자인 차이가 크게 없어서 그런지, 골드 색상이라는 점을 제외하고는 크게 감흥이 없습니다. 그런데 정말 크긴 큽니다. 아이폰 플러스 시리즈를 처음 봤을 때와 비슷한 느낌인데요. 보다 큽니다.</p>
<h2 id="기본-정보">기본 정보</h2>
<p><img src="/images/iphone-xs-max-unboxing-2.png" alt="iphone-xs-max-unboxing"></p>
<p>앞서 말했듯이, 아이폰 Xs와 아이폰 Xs 맥스는 기존 아이폰 X과 외관상 차이가 거의 없습니다. 굳이 차이점을 말하자면, 골드 색상과 맥스 사이즈가 추가되었고 하단 좌측 마이크 구멍이 3개로 줄었습니다. 대칭을 강조하던 애플이 왜 이런 디자인을 채택 했는지는 잘 이해가되지 않습니다.</p>
<p>이번 아이폰 Xs는 64GB, 256GB, 512GB 세 가지 용량으로 출시되었고, A12 바이오닉 칩이 탑재 되었습니다. 발표 당시 새로운 A12 프로세서에 대한 자랑을 많이 하더군요.</p>
<p>배터리는 아이폰 X보다 오래 지속된다고 하는데요. 아이폰 Xs는 0.5시간, 아이폰 Xs 맥스는 1.5시간 더 오래 간다고 합니다.</p>
<h2 id="신기능-정보">신기능 정보</h2>
<p><img src="/images/iphone-xs-max-unboxing-3.png" alt="iphone-xs-max-unboxing"></p>
<p>이번 아이폰의 새로운 기능은 크게 디스플레이, 페이스 ID, A12 바이오닉 프로세서, 카메라로 구분지어 볼 수 있습니다.</p>
<p>우선, 인치당 픽셀수는 같지만 디스플레이가 보다 커진 아이폰 Xs 맥스가 등장했습니다. 아이폰 X과 동일한 OLED 디스플레이이지만, 색 표현이 더욱 생생하다고 합니다. 그리고 IP68 방수 방진이 적용되었고, 스마트폰 중에서 가장 강도 높은 유리가 사용 되었습니다.</p>
<p>페이스 ID는 2세대까지는 아니지만, 알고리즘의 개선으로 빨라졌다고 합니다.</p>
<p>A12 바이오닉 프로세서는 크게 CPU, GPU, 뉴럴 엔진으로 나뉘어져 있는데요. CPU는 6코어로 빠르고 강력하고 효율적이라고 합니다. GPU는 애플이 직접 디자인했고, 최대 50% 빨라졌다고 합니다. 뉴럴 엔진은 8코어로 A11 바이오닉 프로세서보다 Core ML이 최대 9배 빠르게 작동한다고 합니다.</p>
<p>이번 아이폰에서 가장 많이 발전된 부분 중 하나는 카메라일 것입니다. 애플에 의하면, 카메라 센서, 프로세서, 분석 알고리즘 등이 모두 개선되며, 사진과 영상의 결과물이 좋아졌다고 합니다. 스마트 HDR 기술이 적용되었고, 심도 조절이 가능하게 되었습니다.</p>
<p>그 외에도 eSim을 사용하는 듀얼 심이 적용되었고, 스피커도 더욱 와이드하고 커졌습니다.</p>
<h2 id="간단-후기">간단 후기</h2>
<p>애플의 혁신력(?)이 예전만 하지 못하다는 느낌은 어쩔 수 없는것 같습니다. 어찌보면 스마트폰의 한계라고도 할 수 있겠죠. 하지만 똑같은 제품으로 이룰 수 있는 최대 이윤을 뽑는대만 너무 집중하는거 같아 조금 아쉽기는 합니다.</p>
<p>게다가 잡스 시절처럼 이벤트 내용의 비밀 유지가 잘 되지 않아 애플 이벤트를 생중계로 시청하는 맛도 덜해졌습니다. 실제로 발표되는 내용이 예전만 하지 못한것도 있구요. 또, 날이 갈수록 광고 영상만 발전하는것 같습니다.</p>
<h2 id="마무리">마무리</h2>
<p>이것으로 아이폰 Xs 맥스 개봉기 영상을 마치겠는데요. 이번에 애플워치 시리즈 4 역시 같이 구매를 한 만큼, 조만간 애플워치 시리즈 4 개봉기도 진행하려고 합니다.</p>
<p>이런 콘텐츠를 더 보고 싶다면, 영상의 좋아요와 구독 그리고 알림 설정까지 해주시면 감사하겠습니다.</p>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/googling-tips</guid>
      <title>구글링 하는법과 꿀팁 총정리</title>
      <description>코딩의 기본, 구글링 하는법에 대해 알아보고 꿀팁을 공유해봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/googling-tips</link>
      <pubDate>Sat, 15 Sep 2018 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>코딩을 하다보면 모르는 것이 생기거나, 막히는 부분이 생겨 프로젝트 진행이 더뎌지는 일이 허다한데요. 이럴때, 개발자들에게 있어 구글은 정말 산소 같은 존재입니다. 구글에서 코딩에 대한 대부분의 자료가 검색되기 때문이죠.</p>
<p>그리고 이렇게 구글 검색을 통해 새로운 자료를 얻는 것을 흔히 "구글링"이라고 말하는데요. 이번에는 코딩의 기본, 구글링 하는법에 대해 알아보고 꿀팁을 공유해볼까 합니다.</p>
<h2 id="반드시-포함하기--">반드시 포함하기 " "</h2>
<p><img src="/images/googling-tips-1.png" alt="googling-tips"></p>
<p><code>“아이폰” 리뷰</code></p>
<p>이렇게 검색하면 아이폰이라는 단어는 반드시 포함한 검색 결과를 보여줍니다.</p>
<h2 id="반드시-제외하기--">반드시 제외하기 -</h2>
<p><img src="/images/googling-tips-2.png" alt="googling-tips"></p>
<p><code>-갤럭시 스마트폰</code></p>
<p>-기호를 사용해서 검색하면 뒤에 오는 단어가 반드시 제외 되는데요. 다음과 같이 검색하면 갤럭시가 제외된 스마트폰 결과를 보여줍니다.</p>
<h2 id="유사-검색-">유사 검색 ~</h2>
<p><img src="/images/googling-tips-3.png" alt="googling-tips"></p>
<p><code>~검색어</code></p>
<p>물결 기호를 사용하면, 물결 기호 뒤에 오는 검색어에 유사 검색 결과가 나타납니다.</p>
<h2 id="유추-검색-">유추 검색 *</h2>
<p><img src="/images/googling-tips-4.png" alt="googling-tips"></p>
<p><code>아이폰*</code></p>
<p>"*"은 유추 검색을 할 때 사용되는데요. 다음과 같이 검색하면 아이폰 6,7,8 등의 검색 결과가 나타나겠죠?</p>
<h2 id="또는-검색-or">또는 검색 or</h2>
<p><img src="/images/googling-tips-5.png" alt="googling-tips"></p>
<p><code>아이폰or갤럭시</code></p>
<p>이렇게 검색하면 아이폰과 갤럭시에 대한 검색 결과가 동시에 검색됩니다.</p>
<h2 id="범위-검색-">범위 검색 ..</h2>
<p><img src="/images/googling-tips-6.png" alt="googling-tips"></p>
<p><code>아이폰 5..6</code></p>
<p>어떤 숫자의 범위를 지정할때는 .. 을 사용합니다. 예를들어, 아이폰 5..6으로 검색하면 아이폰 5와 아이폰 6 사이의 아이폰에 대한 검색 결과가 나옵니다.</p>
<h2 id="사이트-검색-site">사이트 검색 site:</h2>
<p><img src="/images/googling-tips-7.png" alt="googling-tips"></p>
<p><code>아이폰 site:hohyeonmoon.com</code></p>
<p>특정 사이트 내에서 검색하고 싶을때는 site: 를 사용하면 됩니다. 예를들어, 제 사이트내의 아이폰 컨텐츠를 검색하고 싶다면 아이폰 site:hohyeonmoon.com 으로 검색하면 됩니다.</p>
<h2 id="파일-검색-filetype">파일 검색 filetype:</h2>
<p><img src="/images/googling-tips-8.png" alt="googling-tips"></p>
<p><code>아이폰 filetype:gif</code></p>
<p>특정 파일 유형을 검색하고 싶을 때는 filetype: 을 사용하면 됩니다. 다음과 같은 검색은 아이폰에 대한 gif 즉, 아이폰 움짤 결과를 보여줍니다.</p>
<h2 id="사전-검색-define">사전 검색 define:</h2>
<p><img src="/images/googling-tips-9.png" alt="googling-tips"></p>
<p><code>define:코딩</code></p>
<p>어떤 단어의 정의를 알고 싶다면, define: 을 사용해서 define:coding과 같이 검색하면 됩니다. 이렇게 하면, 코딩에 대한 정의를 알려주겠죠.</p>
<h2 id="마무리">마무리</h2>
<p>구글링 요령은 마치 코딩 명령어와도 일부 유사한데요. 이렇게해서 조금 더 효과적으로 구글링 하는 법에 대해 알아봤습니다. 단순한 검색이지만, 어떻게 사용하느냐에 따라 활용성은 무궁무진할 수 있습니다.</p>
<p>특히, 개발자 같은 경우, 같은 검색엔진과 같은 검색 결과에도 어떻게 결과를 분석하느냐에 따라 해당 자료의 가치는 몇배가 될 수 있죠.</p>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/mac-windows-coding-laptop</guid>
      <title>맥과 윈도우, 최고의 코딩 노트북</title>
      <description>맥과 윈도우 중 어떤 노트북이 코딩에 좋을지 추천해봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/mac-windows-coding-laptop</link>
      <pubDate>Tue, 11 Sep 2018 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>제 주변의 개발자 같은 경우 대부분 맥을 사용하는 경향이 있습니다. 미국에서 대학 생활을 하고 있어서 그럴 수도 있지만, 오랫만에 한국을 와보니 한국도 예외는 아니라는 생각이 들더군요.</p>
<p>프로그래밍을 하는 개발자들에게 맥을 사용하기 위한 좋은 이유가 있습니다. 이번 영상에서는 맥과 윈도우를 비교해보고 프로그래밍을 하기 좋은 노트북은 어떤 것인가에 대해 알아보려고 합니다. 미리 답변을 드리자면, 맥을 추천합니다. 자세한 이유는 알아보도록 하죠.</p>
<h2 id="유닉스-기반의-맥">유닉스 기반의 맥</h2>
<p><img src="/images/mac-windows-coding-laptop-1.png" alt="mac-windows-coding-laptop"></p>
<p>중학생때 이후로 저는 애플에 빠져 살았고, 유독 애플을 좋아하는 사용자입니다. 그럼에도 객관적으로 맥이 적어도 개발자에게 있어서는 윈도우보다 낫다고 주장할 수 있는 이유는 맥은 유닉스 기반이기 때문입니다. 그리고 유닉스 기반이기 때문에 터미널이라는 앱이 존재합니다.</p>
<p>터미널은 개발자에게 있어 필수적인 존재입니다. 대부분의 개발자는 터미널을 많이 사용하고, 사용할줄 알아야만 합니다.</p>
<p>물론, 윈도우에도 맥의 터미널과 비슷한 것이 존재합니다. CMD라고 불리는데요. 이것의 문제는 MS-DOS 기반이라는 것이고 이것은 마이크로소프트를 제외하고는 많이 사용하지 않습니다. 파워쉘이라는 터미널도 새로 생겼지만, 이것 역시 비슷한 문제점을 갖고 있습니다.</p>
<p>그렇다면 왜 유닉스 기반의 터미널만 많이 사용되는 것일까요? 그 이유는 요즘의 웹 서버, 백엔드, 데이터베이스 등 대부분의 것들이 유닉스 기반에서 작동되기 때문입니다. 이것들은 주로 무료이고 오픈소스인 리눅스 위에 설치되어 있습니다.</p>
<p>윈도우에서 유닉스의 터미널을 에뮬레이션을 통해 설치할수는 있습니다. 문제는 매번 업데이트에 신경 써야하고, 많은 경우에 잘 작동하지 않습니다.</p>
<p>최근 들어, 마이크로소프트가 윈도우 10에서는 유닉스 기반의 터미널을 지원하기 시작한것으로 알고는 있습니다. 하지만 그럼에도 아직까지 대부분의 개발자는 마음 편하게 맥을 사용합니다.</p>
<h2 id="여러가지로-우월한-맥">여러가지로 우월한 맥</h2>
<p><img src="/images/mac-windows-coding-laptop-2.png" alt="mac-windows-coding-laptop"></p>
<p>그 외에도, iOS 혹은 macOS 등 애플 제품을 개발하고 싶다면 맥은 필수입니다. 디자이너에게도 Sketch 같은 앱이 맥에만 있는 경우가 많습니다. 백엔드 개발자에게도 루비가 네이티브로 작동하는 맥이 좋을 것입니다. 요즘 같은 크로스 플랫폼 시대에는 무엇이든 개발 가능한 맥이 좋을 것입니다.</p>
<p>그리고 이 부분은 개발자에게만 해당하는 내용은 아닙니다만, 맥이 최근들어 QC(Quality Control)가 낮아지고 완성도가 떨어졌다고는 하지만 다른 노트북에 비하면 여전히 압도적으로 품질이나 마감이 훌륭합니다.</p>
<p>이는 하드웨어에만 해당하는 내용이 아닙니다. 몇년 전에 비해 격차가 많이 줄어들기는 했지만, 소프트웨어 역시 맥이 윈도우에 비해 좋다고 생각합니다. 윈도우 10이 급속도로 최적화되며 격차가 많이 좁혀진것이 사실이지만, 느려지는 속도나 여러가지 체감 성능은 여전히 맥이 낫다고 생각합니다.</p>
<p>또, 맥은 나중에 중고로 판매할때도 좋습니다. 흔히 가격 방어라고 하는데요. 중고 제품의 가격이 상대적으로 높게 책정됩니다.</p>
<h2 id="마무리">마무리</h2>
<p>이렇게 말하고나니, 맥을 사라고 강요하는 느낌인데요. 사실 사용자의 필요에 따라 최고의 노트북은 바뀔수도 있다고 생각합니다. 예를들어, 닷넷 개발자나 게임 개발자에게는 윈도우가 더 좋을 수 있습니다.</p>
<p>맥과 윈도우 둘다 장단점이 있습니다. 하지만 개인적으로 두 운영체제를 모두 사용해봤을때는 개발자에게 있어 맥이 주는 장점이 윈도우가 주는 장점보다 훨씬 많다고 생각합니다.</p>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/coding-text-editor-recommend</guid>
      <title>코드 에디터 혹은 텍스트 에디터 추천</title>
      <description>대중적으로 인기가 많고 개인적으로 가장 만족스럽게 사용했던 코드 에디터를 소개해봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/coding-text-editor-recommend</link>
      <pubDate>Tue, 14 Aug 2018 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>안녕하세요! 코딩에는 보안, 웹, 앱, 머신러닝 등 정말 다양한 분야가 존재하는데요. 이런 다양한 분야만큼이나 코드 에디터 또한 다양하게 존재합니다.</p>
<p>물론, 여러 분야에서 공통적으로 인기가 있는 코드 에디터도 있고 특정 분야에서만 인기가 있는 코드 에디터도 있습니다. 그러나 이번에는 대중적으로 인기가 많고 개인적으로 가장 만족스럽게 사용했던 코드 에디터를 소개해보려 합니다.</p>
<h2 id="1-아톰">1. 아톰</h2>
<p><img src="/images/coding-text-editor-recommend-1.png" alt="coding-text-editor-recommend"></p>
<p><a href="https://atom.io">아톰 홈페이지</a></p>
<p>첫 번째는 아톰입니다. 아톰은 깃허브에서 개발한 오픈소스이자 무료인 에디터인데요. macOS, 리눅스, 윈도우를 모두 지원하고 웬만한 프로그래밍 언어를 지원합니다.</p>
<p>개인적으로 생각하는 아톰의 장점에는 괜찮은 인터페이스 디자인과 강력한 플러그인 등이 있다고 생각합니다. 아톰의 UI는 직접 사용해보면 금방 느끼겠지만, 꽤나 편하고 예쁜 편입니다.</p>
<p>그리고 특히 외국에서 유명한 플러그인 Emmet을 비롯해 강력한 플러그인이 많다는 점이 좋습니다.</p>
<p>그러나 텍스트 에디터 치고는 다소 무겁다는 단점도 존재하는데요. 소스 코드의 용량이 매우 크면 사용시 굉장히 느려지는 경우도 더러 있었습니다.</p>
<h2 id="2-브라켓">2. 브라켓</h2>
<p><img src="/images/coding-text-editor-recommend-2.png" alt="coding-text-editor-recommend"></p>
<p><a href="http://brackets.io">브라켓 홈페이지</a></p>
<p>두 번째는 브라켓입니다. 브라켓은 어도비에서 개발한 오픈소스 에디터입니다. 브라켓은 솔직히 한 가지 기능을 제외하면 큰 장점이 없다고도 할 수 있습니다.</p>
<p>그러나 이 한 가지 기능 때문에 브라켓은 프론트엔드 개발자들에게 유독 많이 사용되는데요. 이 기능의 이름은 '라이브 프리뷰'입니다. 라이브 프리뷰는 파일이 저장되지 않은 상태에서도 실시간으로 크롬에 반영시켜 줍니다.</p>
<p>이 기능이 얼마나 유용한지는 직접 사용해보면 확실히 체감할 것입니다. 브라우저의 캐시 문제로 여러 고난을 겪는 웹 개발자에게 있어 정말 꿀 같은 기능입니다. 이 기능은 플러그인 형태로는 구현되기 힘든지 다른 어떤 에디터에서도 이 기능을 찾아보기 힘듭니다.</p>
<h2 id="3-서브라임-텍스트">3. 서브라임 텍스트</h2>
<p><img src="/images/coding-text-editor-recommend-3.png" alt="coding-text-editor-recommend"></p>
<p><a href="https://www.sublimetext.com">서브라임 홈페이지</a></p>
<p>마지막은 서브라임 텍스트입니다. 서브라임 텍스트는 macOS, 리눅스, 윈도우를 모두 지원하고 기본적으로 무료로 사용할수 있지만, 라이센스 구입은 유료입니다.</p>
<p>서브라임 텍스트의 최대 장점은 가벼움인데요. 다른 에디터들에 비해 용량이 큰 소스코드를 다루더라도 성능 저하가 적은 편입니다. 그 외에도 강력한 탐색 기능과 자동완성 기능 등이 있어 큰 인기를 끌고 있습니다.</p>
<p>하지만 오픈소스가 아니라는 단점, 윈도우 버전에서 한글 입력시 한 글자 늦게 타이핑 되는 현상이 있다는 단점이 있습니다. 그러나 두 번째 단점은 IMESupport 플러그인으로 해결이 가능합니다.</p>
<h2 id="4-vs-code">4. VS Code</h2>
<p><img src="/images/coding-text-editor-recommend-4.png" alt="coding-text-editor-recommend"></p>
<p><a href="https://code.visualstudio.com">VS Code 홈페이지</a></p>
<p>추가적으로 VS Code를 소개해보려고 하는데요. VS Code는 무료이고 강력합니다. 요즘 많이 사용하는 자바스크립트에 대해 특히 강점을 갖고 있습니다. 다양한 Extension 혹은 확장 플러그인이 존재해서 매우 강력합니다.</p>
<p>윈도우, macOS, 리눅스 등 다양한 플랫폼에서 지원되고, 마이크로소프트가 개발하기 때문에 개발 중단에 대한 위험이 비교적 낮습니다.</p>
<h2 id="마무리">마무리</h2>
<p>이렇게해서 총 4가지 코드 에디터를 추천 해봤는데요. 이는 개인적인 의견이고 사람에 따라 혹은 작업하고 있는 코딩 분야에 따라 다를 수 있습니다!</p>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/programming-language-selection</guid>
      <title>어떤 프로그래밍 언어를 배워야할까</title>
      <description>코딩 입문자가 어떤 프로그래밍 언어를 배워야할지에 대한 의견을 내봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/programming-language-selection</link>
      <pubDate>Wed, 08 Aug 2018 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p><img src="/images/programming-language-selection-1.png" alt="programming-language-selection"></p>
<p>저는 프로그래밍이 처음인 혹은 막 입문한 사람인데요. 어떤 프로그래밍 언어를 배워야하나요? 저는 개인적으로 사람에 따라 다르다고 생각합니다.</p>
<h2 id="목적">목적</h2>
<p>어떠한 목적을 가지고 프로그래밍 언어를 배우려고 한다면, 그 목적에 맞는 프로그래밍 언어는 당연히 존재할 것입니다. 그러나 정해진 특별히 없이 프로그래밍을 처음 시작하셨다면, 어떤 언어로 배우기 시작하느냐보다는 어떤 언어에든 대부분 공통적으로 존재하는 기본적인 내용을 학습하고 코딩에 익숙해지는 것이 더 중요하다고 생각합니다.</p>
<p>어떠한 프로그래밍 언어든지 기본적으로 해당 언어를 실행하는 방법, 해당 언어의 문법, 디버깅 하는 방법을 익히는 것이 매우 중요합니다. 그리고 이러한 것들은 어떤 프로그래밍 언어에서든 비슷하거나 유사할겁니다.</p>
<h2 id="케이스">케이스</h2>
<p>개인적으로는 자바를 통해 프로그래밍에 입문했습니다. 학교의 컴퓨터 싸이언스 수업이 자바를 통해 진행되었기 때문이죠. 자바에서는 반복문, 조건문, 변수, 함수, 자료구조 등을 배웠고, 자바를 실행하기 위한 환경 세팅 등도 배웠습니다. 자바를 통해 기본을 익히고 나서는, 자바의 이해를 돕기 위해 C언어도 배워봤고 HTML, CSS, 자바스크립트 등 웹 분야의 언어도 배워봤습니다. 그러다 결국 가장 좋아하는 애플 제품의 앱을 만들기 위해 스위프트를 배우기 시작했습니다.</p>
<p>이렇듯 사람마다 본인에게 가장 적합한 프로그래밍 언어가 있고, 모두에게 공통되게 좋은 프로그래밍 언어는 존재하지 않습니다. 다만, 저는 개인적으로 현재 많이 사용되고 있는 프로그래밍 언어로 입문하시는 것을 추천합니다. 그 이유는, 많이 사용되고 있어야 배울때 도움 받을 곳이 많기 때문입니다.</p>
<p>2018년 현재 가장 핫한 프로그래밍 언어에는 파이썬, 자바스크립트, 스위프트 등이 있고 전통적으로 많이 사용되고 있는 언어에는 자바, C++, PHP 등이 있습니다.</p>
<h2 id="상황">상황</h2>
<p>그 다음으로는 각 상황에 적합한 프로그래밍 언어를 추천해보려고 합니다. iOS 앱이나 macOS 앱 등 애플에 관련한 앱을 만들고싶다면, 당연히 스위프트를 배워야할 것입니다. 안드로이드 앱을 만들고 싶다, 자바나 코틀린을 추천합니다. 데이터 사이언스를 위한 데이터 분석을 하고 싶다면 파이썬을 추천합니다. 웹사이트를 개발하고 싶다면 하나의 언어로 서버쪽과 클라이언트쪽을 모두 만들 수 있는 자바스크립트를 추천합니다.</p>
<h2 id="마무리">마무리</h2>
<p>네 이렇게해서 처음 프로그래밍을 시작하거나 프로그래밍에 막 입문한 분이 배워야할 프로그래밍 언어에 대해 알아봤는데요. 다시 한번 간단히 정리하자면, 프로그래밍 언어는 종류와 목적이 다양하기 때문에 모두에게 절대적으로 좋은 프로그래밍 언어란 없습니다.</p>
<p>물론, 저도 프로그래밍을 처음 시작할때 어떤 언어로 시작해야 할지 굉장히 고민도 많이하고 많이 물어보고 다녔습니다. 그러나 지금 생각해보면, 당시 어떤 언어를 배우느냐보다는 어떤 언어이든 잘 배우는 것이 중요하다는 생각이 들어 해당 영상을 이렇게 만들게 되었습니다. 하나의 언어를 제대로 배웠다면, 앞으로 어떤 언어를 추가적으로 배워야할지 조금 더 쉽게 선택할 수 있을 것입니다.</p>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swift-infinite-scrolling</guid>
      <title>Swift UIKit 테이블 뷰 무한 스크롤링</title>
      <description>자그마한 프로젝트를 진행하면서 사용한 무한 스크롤링을 소개합니다</description>
      <link>https://www.hohyeonmoon.com/blog/swift-infinite-scrolling</link>
      <pubDate>Fri, 13 Jul 2018 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>최근 조그맣게 시작한 개인 프로젝트가 있다.</li>
<li>무엇인가를 키우는 사람을 위한 SNS iOS 앱을 만드는 프로젝트이다.</li>
<li>아직 기획도 채 끝나지 않은 초기 단계에 있는 프로젝트이다.</li>
<li>프로젝트를 진행하면서 사용하는 기술들을 남겨보고자 한다.</li>
</ul>
<h2 id="무한-스크롤링">무한 스크롤링</h2>
<ul>
<li>SNS의 최고 미덕은 '끊임없이 스크롤 되는 피드'라고 생각한다.</li>
<li>그래서 기초적인 디자인을 배치한 뒤, 바로 무한 스크롤부터 구현하기 시작했다.</li>
<li>이 무한 스크롤은 결국 흔히 '피드'라고 불리는 부분에 사용될 것이다.</li>
<li>이것을 구현하기 위해 테이블 뷰를 사용할지, 아니면 컬렉션 뷰를 사용할지 고민을 많이 했다.</li>
<li>하지만 개인 프로젝트인 만큼, 잘못되면 나중에 고치자는 생각으로</li>
<li>조금 더 간단한 테이블 뷰를 사용해서 구현하기 시작했다.</li>
<li>테이블 뷰를 오토 레이아웃으로 정렬한 뒤, 테이블 뷰 셀을 테이블 뷰에 넣었다.</li>
<li>사실 이 글을 작성할 때는 뒤의 기능들까지 구현한 상태여서 추가적인 테이블 뷰 셀이 존재한다.</li>
</ul>
<h2 id="구현">구현</h2>
<ul>
<li>그리고 이 테이블 뷰 셀을 갖고 프로그래밍적으로 구현하기 시작한다.</li>
<li>그 전에, 해당 뷰 컨트롤러에 커스텀 클래스를 연결해주고,</li>
</ul>
<p><img src="/images/swift-infinite-scrolling-2.png" alt="swift-infinite-scrolling"></p>
<ul>
<li>테이블 뷰를 dataSource와 delegate 연결해준다.</li>
</ul>
<p><img src="/images/swift-infinite-scrolling-1.png" alt="swift-infinite-scrolling"></p>
<ul>
<li>그러면 기본 준비는 다 되었다.</li>
<li>이제 다음과 같이 코드를 구현 해준다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">import</span> <span class="token class-name">UIKit</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">HomeViewController</span><span class="token punctuation">:</span> <span class="token class-name">UIViewController</span><span class="token punctuation">,</span> <span class="token class-name">UITableViewDataSource</span><span class="token punctuation">,</span> <span class="token class-name">UITableViewDelegate</span>
</span><span class="code-line"><span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token attribute atrule">@IBOutlet</span> <span class="token keyword">weak</span> <span class="token keyword">var</span> tableView<span class="token punctuation">:</span> <span class="token class-name">UITableView</span><span class="token operator">!</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">var</span> fetchingMore <span class="token operator">=</span> <span class="token boolean">false</span>
</span><span class="code-line">    <span class="token keyword">var</span> items <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">9</span><span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">]</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">override</span> <span class="token keyword">func</span> <span class="token function-definition function">viewDidLoad</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token function">viewDidLoad</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">let</span> loadingNib <span class="token operator">=</span> <span class="token class-name">UINib</span><span class="token punctuation">(</span>nibName<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"LoadingCell"</span></span><span class="token punctuation">,</span> bundle<span class="token punctuation">:</span> <span class="token nil constant">nil</span><span class="token punctuation">)</span>
</span><span class="code-line">        tableView<span class="token punctuation">.</span><span class="token function">register</span><span class="token punctuation">(</span>loadingNib<span class="token punctuation">,</span> forCellReuseIdentifier<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"loadingCell"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">numberOfSections</span><span class="token punctuation">(</span><span class="token keyword">in</span> tableView<span class="token punctuation">:</span> <span class="token class-name">UITableView</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Int</span>
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">return</span> <span class="token number">3</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">tableView</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> tableView<span class="token punctuation">:</span> <span class="token class-name">UITableView</span><span class="token punctuation">,</span> numberOfRowsInSection section<span class="token punctuation">:</span> <span class="token class-name">Int</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Int</span>
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">if</span> section <span class="token operator">==</span> <span class="token number">0</span>
</span><span class="code-line">        <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">return</span> <span class="token number">1</span>
</span><span class="code-line">        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> section <span class="token operator">==</span> <span class="token number">1</span>
</span><span class="code-line">        <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">return</span> items<span class="token punctuation">.</span>count
</span><span class="code-line">        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> section <span class="token operator">==</span> <span class="token number">2</span> <span class="token operator">&#x26;&#x26;</span> fetchingMore
</span><span class="code-line">        <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">return</span> <span class="token number">1</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">return</span> <span class="token number">0</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">tableView</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> tableView<span class="token punctuation">:</span> <span class="token class-name">UITableView</span><span class="token punctuation">,</span> cellForRowAt indexPath<span class="token punctuation">:</span> <span class="token class-name">IndexPath</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">UITableViewCell</span>
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">if</span> indexPath<span class="token punctuation">.</span>section <span class="token operator">==</span> <span class="token number">0</span>
</span><span class="code-line">        <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">let</span> cell <span class="token operator">=</span> tableView<span class="token punctuation">.</span><span class="token function">dequeueReusableCell</span><span class="token punctuation">(</span>withIdentifier<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"storyCell"</span></span><span class="token punctuation">,</span> <span class="token keyword">for</span><span class="token punctuation">:</span> indexPath<span class="token punctuation">)</span>
</span><span class="code-line">            
</span><span class="code-line">            <span class="token keyword">return</span> cell            
</span><span class="code-line">        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> indexPath<span class="token punctuation">.</span>section <span class="token operator">==</span> <span class="token number">1</span>
</span><span class="code-line">        <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">let</span> cell <span class="token operator">=</span> tableView<span class="token punctuation">.</span><span class="token function">dequeueReusableCell</span><span class="token punctuation">(</span>withIdentifier<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"tableCell"</span></span><span class="token punctuation">,</span> <span class="token keyword">for</span><span class="token punctuation">:</span> indexPath<span class="token punctuation">)</span> <span class="token keyword">as</span><span class="token operator">!</span> <span class="token class-name">FeedTableViewCell</span>
</span><span class="code-line">            cell<span class="token punctuation">.</span>username<span class="token punctuation">.</span><span class="token function">setTitle</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"User </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">items<span class="token punctuation">[</span>indexPath<span class="token punctuation">.</span>row<span class="token punctuation">]</span></span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">,</span> <span class="token keyword">for</span><span class="token punctuation">:</span> <span class="token punctuation">.</span>normal<span class="token punctuation">)</span>
</span><span class="code-line">            
</span><span class="code-line">            <span class="token keyword">return</span> cell
</span><span class="code-line">        <span class="token punctuation">}</span> <span class="token keyword">else</span>
</span><span class="code-line">        <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">let</span> cell <span class="token operator">=</span> tableView<span class="token punctuation">.</span><span class="token function">dequeueReusableCell</span><span class="token punctuation">(</span>withIdentifier<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"loadingCell"</span></span><span class="token punctuation">,</span> <span class="token keyword">for</span><span class="token punctuation">:</span> indexPath<span class="token punctuation">)</span> <span class="token keyword">as</span><span class="token operator">!</span> <span class="token class-name">LoadingCell</span>
</span><span class="code-line">            cell<span class="token punctuation">.</span>spinner<span class="token punctuation">.</span><span class="token function">startAnimating</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">            
</span><span class="code-line">            <span class="token keyword">return</span> cell
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">scrollViewDidScroll</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> scrollView<span class="token punctuation">:</span> <span class="token class-name">UIScrollView</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">let</span> offsetY <span class="token operator">=</span> scrollView<span class="token punctuation">.</span>contentOffset<span class="token punctuation">.</span>y
</span><span class="code-line">        <span class="token keyword">let</span> contentHeight <span class="token operator">=</span> scrollView<span class="token punctuation">.</span>contentSize<span class="token punctuation">.</span>height
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">if</span> offsetY <span class="token operator">></span> contentHeight <span class="token operator">-</span> scrollView<span class="token punctuation">.</span>frame<span class="token punctuation">.</span>height
</span><span class="code-line">        <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">if</span> <span class="token operator">!</span>fetchingMore
</span><span class="code-line">            <span class="token punctuation">{</span>
</span><span class="code-line">                <span class="token function">beginBatchFetch</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">func</span> <span class="token function-definition function">beginBatchFetch</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">        fetchingMore <span class="token operator">=</span> <span class="token boolean">true</span>
</span><span class="code-line">        tableView<span class="token punctuation">.</span><span class="token function">reloadSections</span><span class="token punctuation">(</span><span class="token class-name">IndexSet</span><span class="token punctuation">(</span>integer<span class="token punctuation">:</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">,</span> with<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token keyword">none</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token class-name">DispatchQueue</span><span class="token punctuation">.</span>main<span class="token punctuation">.</span><span class="token function">asyncAfter</span><span class="token punctuation">(</span>deadline<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token number">0.25</span><span class="token punctuation">,</span> execute<span class="token punctuation">:</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">let</span> newItems <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">self</span><span class="token punctuation">.</span>items<span class="token punctuation">.</span>count<span class="token operator">...</span><span class="token keyword">self</span><span class="token punctuation">.</span>items<span class="token punctuation">.</span>count <span class="token operator">+</span> <span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">.</span>map <span class="token punctuation">{</span> index <span class="token keyword">in</span> index <span class="token punctuation">}</span>
</span><span class="code-line">            <span class="token keyword">self</span><span class="token punctuation">.</span>items<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>contentsOf<span class="token punctuation">:</span> newItems<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token keyword">self</span><span class="token punctuation">.</span>fetchingMore <span class="token operator">=</span> <span class="token boolean">false</span>
</span><span class="code-line">            <span class="token keyword">self</span><span class="token punctuation">.</span>tableView<span class="token punctuation">.</span><span class="token function">reloadData</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>    
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>부분적으로 살펴보면,</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">import</span> <span class="token class-name">UIKit</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">HomeViewController</span><span class="token punctuation">:</span> <span class="token class-name">UIViewController</span><span class="token punctuation">,</span> <span class="token class-name">UITableViewDataSource</span><span class="token punctuation">,</span> <span class="token class-name">UITableViewDelegate</span>
</span><span class="code-line"><span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token attribute atrule">@IBOutlet</span> <span class="token keyword">weak</span> <span class="token keyword">var</span> tableView<span class="token punctuation">:</span> <span class="token class-name">UITableView</span><span class="token operator">!</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">var</span> fetchingMore <span class="token operator">=</span> <span class="token boolean">false</span>
</span><span class="code-line">    <span class="token keyword">var</span> items <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">9</span><span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">]</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">override</span> <span class="token keyword">func</span> <span class="token function-definition function">viewDidLoad</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">super</span><span class="token punctuation">.</span><span class="token function">viewDidLoad</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">let</span> loadingNib <span class="token operator">=</span> <span class="token class-name">UINib</span><span class="token punctuation">(</span>nibName<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"LoadingCell"</span></span><span class="token punctuation">,</span> bundle<span class="token punctuation">:</span> <span class="token nil constant">nil</span><span class="token punctuation">)</span>
</span><span class="code-line">        tableView<span class="token punctuation">.</span><span class="token function">register</span><span class="token punctuation">(</span>loadingNib<span class="token punctuation">,</span> forCellReuseIdentifier<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"loadingCell"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token operator">...</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>이 부분은 피드 페이지를 위한 뷰 컨트롤러 HomeViewController의 시작 부분이다.</li>
<li>HomeViewController 클래스를 만들고, 기본적으로 UIViewController를 상속 시켜준다.</li>
<li>그리고 테이블 뷰를 위한 클래스들을 상속 시켜준다.</li>
<li>UITableViewDataSource, UITableViewDelegate를 말이다.</li>
<li>그리고 나서는 tableView라는 UITableView형의 IBOoutlet 변수를 만들어주고,</li>
<li>fetchingMore 변수와 items 배열을 생성했다.</li>
<li>viewDidLoad는 뷰가 화면에 로드 되면 호출되는 함수이다.</li>
<li>뷰 로드를 하면서 loadingCell을 생성하기 위해 저렇게 구현했다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">numberOfSections</span><span class="token punctuation">(</span><span class="token keyword">in</span> tableView<span class="token punctuation">:</span> <span class="token class-name">UITableView</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Int</span>
</span><span class="code-line"><span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">return</span> <span class="token number">3</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">tableView</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> tableView<span class="token punctuation">:</span> <span class="token class-name">UITableView</span><span class="token punctuation">,</span> numberOfRowsInSection section<span class="token punctuation">:</span> <span class="token class-name">Int</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Int</span>
</span><span class="code-line"><span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">if</span> section <span class="token operator">==</span> <span class="token number">0</span>
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">return</span> <span class="token number">1</span>
</span><span class="code-line">    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> section <span class="token operator">==</span> <span class="token number">1</span>
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">return</span> items<span class="token punctuation">.</span>count
</span><span class="code-line">    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> section <span class="token operator">==</span> <span class="token number">2</span> <span class="token operator">&#x26;&#x26;</span> fetchingMore
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">return</span> <span class="token number">1</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">return</span> <span class="token number">0</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">tableView</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> tableView<span class="token punctuation">:</span> <span class="token class-name">UITableView</span><span class="token punctuation">,</span> cellForRowAt indexPath<span class="token punctuation">:</span> <span class="token class-name">IndexPath</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">UITableViewCell</span>
</span><span class="code-line"><span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">if</span> indexPath<span class="token punctuation">.</span>section <span class="token operator">==</span> <span class="token number">0</span>
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">let</span> cell <span class="token operator">=</span> tableView<span class="token punctuation">.</span><span class="token function">dequeueReusableCell</span><span class="token punctuation">(</span>withIdentifier<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"storyCell"</span></span><span class="token punctuation">,</span> <span class="token keyword">for</span><span class="token punctuation">:</span> indexPath<span class="token punctuation">)</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">return</span> cell            
</span><span class="code-line">    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> indexPath<span class="token punctuation">.</span>section <span class="token operator">==</span> <span class="token number">1</span>
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">let</span> cell <span class="token operator">=</span> tableView<span class="token punctuation">.</span><span class="token function">dequeueReusableCell</span><span class="token punctuation">(</span>withIdentifier<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"tableCell"</span></span><span class="token punctuation">,</span> <span class="token keyword">for</span><span class="token punctuation">:</span> indexPath<span class="token punctuation">)</span> <span class="token keyword">as</span><span class="token operator">!</span> <span class="token class-name">FeedTableViewCell</span>
</span><span class="code-line">        cell<span class="token punctuation">.</span>username<span class="token punctuation">.</span><span class="token function">setTitle</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"User </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">items<span class="token punctuation">[</span>indexPath<span class="token punctuation">.</span>row<span class="token punctuation">]</span></span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">,</span> <span class="token keyword">for</span><span class="token punctuation">:</span> <span class="token punctuation">.</span>normal<span class="token punctuation">)</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">return</span> cell
</span><span class="code-line">    <span class="token punctuation">}</span> <span class="token keyword">else</span>
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">let</span> cell <span class="token operator">=</span> tableView<span class="token punctuation">.</span><span class="token function">dequeueReusableCell</span><span class="token punctuation">(</span>withIdentifier<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"loadingCell"</span></span><span class="token punctuation">,</span> <span class="token keyword">for</span><span class="token punctuation">:</span> indexPath<span class="token punctuation">)</span> <span class="token keyword">as</span><span class="token operator">!</span> <span class="token class-name">LoadingCell</span>
</span><span class="code-line">        cell<span class="token punctuation">.</span>spinner<span class="token punctuation">.</span><span class="token function">startAnimating</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">return</span> cell
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">scrollViewDidScroll</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> scrollView<span class="token punctuation">:</span> <span class="token class-name">UIScrollView</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> offsetY <span class="token operator">=</span> scrollView<span class="token punctuation">.</span>contentOffset<span class="token punctuation">.</span>y
</span><span class="code-line">    <span class="token keyword">let</span> contentHeight <span class="token operator">=</span> scrollView<span class="token punctuation">.</span>contentSize<span class="token punctuation">.</span>height
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">if</span> offsetY <span class="token operator">></span> contentHeight <span class="token operator">-</span> scrollView<span class="token punctuation">.</span>frame<span class="token punctuation">.</span>height
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">if</span> <span class="token operator">!</span>fetchingMore
</span><span class="code-line">        <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token function">beginBatchFetch</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">beginBatchFetch</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">{</span>
</span><span class="code-line">    fetchingMore <span class="token operator">=</span> <span class="token boolean">true</span>
</span><span class="code-line">    tableView<span class="token punctuation">.</span><span class="token function">reloadSections</span><span class="token punctuation">(</span><span class="token class-name">IndexSet</span><span class="token punctuation">(</span>integer<span class="token punctuation">:</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">,</span> with<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token keyword">none</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token class-name">DispatchQueue</span><span class="token punctuation">.</span>main<span class="token punctuation">.</span><span class="token function">asyncAfter</span><span class="token punctuation">(</span>deadline<span class="token punctuation">:</span> <span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token number">0.25</span><span class="token punctuation">,</span> execute<span class="token punctuation">:</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">let</span> newItems <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">self</span><span class="token punctuation">.</span>items<span class="token punctuation">.</span>count<span class="token operator">...</span><span class="token keyword">self</span><span class="token punctuation">.</span>items<span class="token punctuation">.</span>count <span class="token operator">+</span> <span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">.</span>map <span class="token punctuation">{</span> index <span class="token keyword">in</span> index <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token keyword">self</span><span class="token punctuation">.</span>items<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>contentsOf<span class="token punctuation">:</span> newItems<span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token keyword">self</span><span class="token punctuation">.</span>fetchingMore <span class="token operator">=</span> <span class="token boolean">false</span>
</span><span class="code-line">        <span class="token keyword">self</span><span class="token punctuation">.</span>tableView<span class="token punctuation">.</span><span class="token function">reloadData</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>이 부분들은 tableView의 delegate 메소드들이다.</li>
</ul>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/cpp-binary-tree</guid>
      <title>C++ 이진 검색 정렬</title>
      <description>C++로 이진 검색 트리 정렬을 구현해봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/cpp-binary-tree</link>
      <pubDate>Sat, 07 Jul 2018 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<h2 id="이진-검색-트리-문제">이진 검색 트리 문제</h2>
<p>출처 : <a href="https://www.acmicpc.net/problem/1539">백준 알고리즘</a></p>
<h3 id="문제">문제</h3>
<p>P는 크기가 N인 배열이다. P에는 0보다 크거나 같고, N-1보다 작거나 같은 정수가 중복 없이 채워져 있다. 이진 검색 트리는 루트가 있는 이진 트리로, 각각의 노드에 정수 값이 저장되어 있는 트리이다. 이진 검색 트리를 P배열을 이용해서 만드는 법은 다음과 같다. 일단 root를 만들고 거기에 P[0]의 값을 넣은 후에 다음과 같은 과정을 거친다.</p>
<pre class="language-cpp"><code class="language-cpp code-highlight"><span class="code-line"><span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i<span class="token operator">=</span><span class="token number">1</span><span class="token punctuation">;</span> i<span class="token operator">&#x3C;=</span>n<span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token function">insert</span><span class="token punctuation">(</span>root<span class="token punctuation">,</span> P<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p>여기서 insert함수는 다음과 같다.</p>
<pre class="language-cpp"><code class="language-cpp code-highlight"><span class="code-line"><span class="token keyword">void</span> <span class="token function">insert</span><span class="token punctuation">(</span>Vertex V<span class="token punctuation">,</span> <span class="token keyword">int</span> X<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">if</span> <span class="token punctuation">(</span>x <span class="token operator">&#x3C;</span> V에 저장되어 있는 수<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">if</span> <span class="token punctuation">(</span>V가 왼쪽 자식이 있으면<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token function">insert</span><span class="token punctuation">(</span>V의 왼쪽 자식<span class="token punctuation">,</span> X<span class="token punctuation">)</span><span class="token punctuation">;</span>
</span><span class="code-line">        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">            V의 왼쪽 자식을 새로 만들고<span class="token punctuation">,</span> 그 곳에 X를 저장함
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">if</span> <span class="token punctuation">(</span>V가 오른쪽 자식이 있으면<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token function">insert</span><span class="token punctuation">(</span>V의 오른쪽 자식<span class="token punctuation">,</span> X<span class="token punctuation">)</span><span class="token punctuation">;</span>
</span><span class="code-line">        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">            V의 오른쪽 자식을 새로 만들고<span class="token punctuation">,</span> 그 곳에 X를 저장함
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<p>N과, 배열 P에 있는 수가 주어졌을 때, P로 이진 검색 트리를 만들었을 때, 모든 노드의 높이의 합을 출력하는 프로그램을 작성하시오. 트리의 높이는 루트에서 부터의 거리 + 1이다.</p>
<h3 id="입력">입력</h3>
<p>첫째 줄에 N이 주어진다. N은 250,000보다 작거나 같은 자연수이다. 둘째 줄부터 N개의 줄에 P[0]부터 P[N-1]의 원소가 한 줄에 하나씩 들어온다.</p>
<pre class="language-cpp"><code class="language-cpp code-highlight"><span class="code-line">ex<span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token number">10</span>  
</span><span class="code-line"><span class="token number">9</span>  
</span><span class="code-line"><span class="token number">1</span>  
</span><span class="code-line"><span class="token number">4</span>  
</span><span class="code-line"><span class="token number">3</span>  
</span><span class="code-line"><span class="token number">2</span>  
</span><span class="code-line"><span class="token number">5</span>  
</span><span class="code-line"><span class="token number">6</span>  
</span><span class="code-line"><span class="token number">7</span>  
</span><span class="code-line"><span class="token number">8</span>  
</span><span class="code-line"><span class="token number">0</span>
</span></code></pre>
<h3 id="출력">출력</h3>
<p>주어진 P배열로 이진 검색 트리를 만들었을 때, 높이의 합을 출력한다. 이 값은 2^63보다 작다.</p>
<pre class="language-cpp"><code class="language-cpp code-highlight"><span class="code-line">ex<span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token number">40</span>
</span></code></pre>
<h3 id="풀이">풀이</h3>
<pre class="language-cpp"><code class="language-cpp code-highlight"><span class="code-line"><span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string">&#x3C;iostream></span></span>
</span><span class="code-line"><span class="token keyword">using</span> <span class="token keyword">namespace</span> std<span class="token punctuation">;</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token keyword">int</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">int</span> n<span class="token punctuation">;</span>
</span><span class="code-line">    cin <span class="token operator">>></span> n<span class="token punctuation">;</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">if</span><span class="token punctuation">(</span>n<span class="token operator">&#x3C;=</span><span class="token number">250000</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">int</span> height<span class="token punctuation">[</span>n<span class="token punctuation">]</span><span class="token punctuation">;</span>
</span><span class="code-line">        <span class="token keyword">int</span> list<span class="token punctuation">[</span>n<span class="token punctuation">]</span><span class="token punctuation">;</span>
</span><span class="code-line">        <span class="token keyword">int</span> sum <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">int</span> i<span class="token operator">=</span><span class="token number">0</span><span class="token punctuation">;</span> i<span class="token operator">&#x3C;</span>n<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">int</span> data<span class="token punctuation">;</span>
</span><span class="code-line">            cin <span class="token operator">>></span> data<span class="token punctuation">;</span>
</span><span class="code-line">            
</span><span class="code-line">            <span class="token keyword">int</span> front <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
</span><span class="code-line">            <span class="token keyword">int</span> back <span class="token operator">=</span> i<span class="token punctuation">;</span>
</span><span class="code-line">            <span class="token keyword">int</span> size <span class="token operator">=</span> i<span class="token punctuation">;</span>
</span><span class="code-line">            
</span><span class="code-line">            <span class="token keyword">int</span> spot<span class="token punctuation">;</span>
</span><span class="code-line">            <span class="token keyword">int</span> leftHeight<span class="token punctuation">;</span>
</span><span class="code-line">            <span class="token keyword">int</span> rightHeight<span class="token punctuation">;</span>
</span><span class="code-line">            
</span><span class="code-line">            <span class="token keyword">while</span><span class="token punctuation">(</span>front<span class="token operator">&#x3C;</span>back<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">                <span class="token keyword">int</span> mid <span class="token operator">=</span> <span class="token punctuation">(</span>front<span class="token operator">+</span>back<span class="token punctuation">)</span> <span class="token operator">/</span> <span class="token number">2</span><span class="token punctuation">;</span>
</span><span class="code-line">                
</span><span class="code-line">                <span class="token keyword">if</span><span class="token punctuation">(</span>list<span class="token punctuation">[</span>mid<span class="token punctuation">]</span><span class="token operator">&#x3C;</span>data<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">                    front <span class="token operator">=</span> mid <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span>
</span><span class="code-line">                <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">                    back <span class="token operator">=</span> mid<span class="token punctuation">;</span>
</span><span class="code-line">                <span class="token punctuation">}</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">            
</span><span class="code-line">            spot <span class="token operator">=</span> back<span class="token punctuation">;</span>
</span><span class="code-line">            
</span><span class="code-line">            <span class="token keyword">if</span><span class="token punctuation">(</span>spot<span class="token operator">></span><span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">                leftHeight <span class="token operator">=</span> height<span class="token punctuation">[</span>spot<span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
</span><span class="code-line">            <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">                leftHeight <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">            
</span><span class="code-line">            <span class="token keyword">if</span><span class="token punctuation">(</span>spot<span class="token operator">&#x3C;</span>size<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">                rightHeight <span class="token operator">=</span> height<span class="token punctuation">[</span>spot<span class="token punctuation">]</span><span class="token punctuation">;</span>
</span><span class="code-line">            <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">                rightHeight <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">            
</span><span class="code-line">            <span class="token keyword">if</span><span class="token punctuation">(</span>spot <span class="token operator">&#x3C;</span> size<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">                <span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">int</span> j<span class="token operator">=</span>size<span class="token punctuation">;</span> j<span class="token operator">></span>spot<span class="token punctuation">;</span> j<span class="token operator">--</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">                    list<span class="token punctuation">[</span>j<span class="token punctuation">]</span> <span class="token operator">=</span> list<span class="token punctuation">[</span>j<span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
</span><span class="code-line">                    height<span class="token punctuation">[</span>j<span class="token punctuation">]</span> <span class="token operator">=</span> height<span class="token punctuation">[</span>j<span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
</span><span class="code-line">                <span class="token punctuation">}</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">            
</span><span class="code-line">            <span class="token keyword">if</span><span class="token punctuation">(</span>leftHeight<span class="token operator">></span>rightHeight<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">                height<span class="token punctuation">[</span>spot<span class="token punctuation">]</span> <span class="token operator">=</span> leftHeight<span class="token operator">+</span><span class="token number">1</span><span class="token punctuation">;</span>
</span><span class="code-line">            <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">                height<span class="token punctuation">[</span>spot<span class="token punctuation">]</span> <span class="token operator">=</span> rightHeight<span class="token operator">+</span><span class="token number">1</span><span class="token punctuation">;</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">            
</span><span class="code-line">            list<span class="token punctuation">[</span>spot<span class="token punctuation">]</span> <span class="token operator">=</span> data<span class="token punctuation">;</span>
</span><span class="code-line">            sum <span class="token operator">+=</span> height<span class="token punctuation">[</span>spot<span class="token punctuation">]</span><span class="token punctuation">;</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        
</span><span class="code-line">        cout <span class="token operator">&#x3C;&#x3C;</span> sum <span class="token operator">&#x3C;&#x3C;</span> endl<span class="token punctuation">;</span>
</span><span class="code-line">        <span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
</span><span class="code-line">    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">        cout <span class="token operator">&#x3C;&#x3C;</span> <span class="token string">"Over range"</span> <span class="token operator">&#x3C;&#x3C;</span> endl<span class="token punctuation">;</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/cpp-insertion-sort</guid>
      <title>C++ 삽입 정렬</title>
      <description>C++로 삽입 정렬을 구현해봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/cpp-insertion-sort</link>
      <pubDate>Fri, 06 Jul 2018 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<h2 id="삽입-정렬-설명">삽입 정렬 설명</h2>
<p>정렬이란 숫자 배열을 오름차순 또는 내림차순으로 순서대로 나열하는 것을 의미합니다. 그 중 삽입 정렬(Insertion Sort)는 숫자 배열의 모든 요소를 앞에서부터 차례대로 이미 정렬된 배열 부분과 비교하여, 자신의 위치를 찾아 삽입함으로써 정렬을 완성하는 알고리즘입니다.</p>
<h2 id="삽입-정렬-문제">삽입 정렬 문제</h2>
<p>출처 : <a href="https://www.acmicpc.net/problem/2750">백준 알고리즘</a></p>
<h3 id="문제">문제</h3>
<p>N개의 수가 주어졌을 때, 이를 오름차순으로 정렬하는 프로그램을 작성하시오.</p>
<h3 id="입력">입력</h3>
<p>첫째 줄에 수의 개수 <code>N(1 &#x3C;= N &#x3C;= 1,000)</code>이 주어진다. 둘째 줄부터 N개의 줄에는 숫자가 주어진다. 이 수는 절대값이 1,000보다 작거나 같은 정수이다. 수는 중복되지 않는다.</p>
<h3 id="출력">출력</h3>
<p>첫째 줄부터 N개의 줄에 오름차순으로 정렬한 결과를 한 줄에 하나씩 출력한다.</p>
<h3 id="풀이">풀이</h3>
<pre class="language-cpp"><code class="language-cpp code-highlight"><span class="code-line"><span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string">&#x3C;iostream></span></span>
</span><span class="code-line"><span class="token keyword">using</span> <span class="token keyword">namespace</span> std<span class="token punctuation">;</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token keyword">int</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">int</span> n<span class="token punctuation">;</span>
</span><span class="code-line">    cin <span class="token operator">>></span> n<span class="token punctuation">;</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">int</span> arr<span class="token punctuation">[</span>n<span class="token punctuation">]</span><span class="token punctuation">;</span>
</span><span class="code-line">    <span class="token keyword">int</span> key<span class="token punctuation">;</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">int</span> i<span class="token operator">=</span><span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&#x3C;</span> n<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        cin <span class="token operator">>></span> arr<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">int</span> i<span class="token operator">=</span><span class="token number">1</span><span class="token punctuation">;</span> i <span class="token operator">&#x3C;</span> n<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">int</span> j<span class="token punctuation">;</span>
</span><span class="code-line">        key <span class="token operator">=</span> arr<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">for</span><span class="token punctuation">(</span>j<span class="token operator">=</span>i<span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">;</span> j<span class="token operator">>=</span><span class="token number">0</span><span class="token punctuation">;</span> j<span class="token operator">--</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">if</span><span class="token punctuation">(</span>arr<span class="token punctuation">[</span>j<span class="token punctuation">]</span> <span class="token operator">></span> key<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">                arr<span class="token punctuation">[</span>j<span class="token operator">+</span><span class="token number">1</span><span class="token punctuation">]</span> <span class="token operator">=</span> arr<span class="token punctuation">[</span>j<span class="token punctuation">]</span><span class="token punctuation">;</span>
</span><span class="code-line">            <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">                <span class="token keyword">break</span><span class="token punctuation">;</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        
</span><span class="code-line">        arr<span class="token punctuation">[</span>j<span class="token operator">+</span><span class="token number">1</span><span class="token punctuation">]</span> <span class="token operator">=</span> key<span class="token punctuation">;</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">int</span> i<span class="token operator">=</span><span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&#x3C;</span> n<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        cout <span class="token operator">&#x3C;&#x3C;</span> arr<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">&#x3C;&#x3C;</span> endl<span class="token punctuation">;</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
</span><span class="code-line"><span class="token punctuation">}</span> 
</span></code></pre>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/cpp-queue-data-structure</guid>
      <title>C++ 큐 자료구조</title>
      <description>C++로 큐 자료구조를 구현해봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/cpp-queue-data-structure</link>
      <pubDate>Thu, 05 Jul 2018 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<h2 id="큐-설명">큐 설명</h2>
<p>큐는 뒤쪽에 새로운 항목을 삽입하고 앞쪽의 항목을 제거하는 리스트입니다. 이런 리스트가 왜 필요할까요? 알고리즘에서 임시 리스트에 객체를 추가하고 나중에 이 리스트에서 객체를 꺼내려고 하는 경우가 많습니다.</p>
<p>이러한 큐를 가리켜 FIFO라고도 하는데요. 이는 first-in, first-out의 약자로 먼저 들어온 것이 먼저 나간다는 의미를 갖고 있습니다.</p>
<h2 id="큐-문제">큐 문제</h2>
<p>출처 : <a href="https://www.acmicpc.net/problem/10845">백준 알고리즘</a></p>
<h3 id="문제">문제</h3>
<p>정수를 저장하는 큐를 구현한 다음, 입력으로 주어지는 명령을 처리하는 프로그램을 작성하시오.</p>
<p>명령은 총 여섯 가지이다.</p>
<ul>
<li>push X: 정수 X를 큐에 넣는 연산이다.</li>
<li>pop: 큐에서 가장 앞에 있는 정수를 빼고, 그 수를 출력한다. 만약 큐에 들어있는 정수가 없는 경우에는 -1을 출력한다.</li>
<li>size: 큐에 들어있는 정수의 개수를 출력한다.</li>
<li>empty: 큐가 비어있으면 1, 아니면 0을 출력한다.</li>
<li>front: 큐의 가장 앞에 있는 정수를 출력한다. 만약 큐에 들어있는 정수가 없는 경우에는 -1을 출력한다.</li>
<li>back: 큐의 가장 뒤에 있는 정수를 출력한다. 만약 큐에 들어있는 정수가 없는 경우에는 -1을 출력한다.</li>
</ul>
<h3 id="입력">입력</h3>
<p>첫째 줄에 주어지는 명령의 수 <code>N (1 &#x3C;= N &#x3C;= 10,000)</code>이 주어진다. 둘째 줄부터 N개의 줄에는 명령이 하나씩 주어진다. 주어지는 정수는 1보다 크거나 같고, 100,000보다 작거나 같다. 문제에 나와있지 않은 명령이 주어지는 경우는 없다.</p>
<pre class="language-cpp"><code class="language-cpp code-highlight"><span class="code-line">ex<span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token number">15</span>  
</span><span class="code-line">push <span class="token number">1</span>  
</span><span class="code-line">push <span class="token number">2</span>  
</span><span class="code-line">front  
</span><span class="code-line">back  
</span><span class="code-line">size  
</span><span class="code-line">empty  
</span><span class="code-line">pop  
</span><span class="code-line">pop  
</span><span class="code-line">pop  
</span><span class="code-line">size  
</span><span class="code-line">empty  
</span><span class="code-line">pop  
</span><span class="code-line">push <span class="token number">3</span>  
</span><span class="code-line">empty  
</span><span class="code-line">front
</span></code></pre>
<h3 id="출력">출력</h3>
<p>출력해야하는 명령이 주어질 때마다, 한 줄에 하나씩 출력한다.</p>
<pre class="language-cpp"><code class="language-cpp code-highlight"><span class="code-line">ex<span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token number">1</span>  
</span><span class="code-line"><span class="token number">2</span>  
</span><span class="code-line"><span class="token number">2</span>  
</span><span class="code-line"><span class="token number">0</span>  
</span><span class="code-line"><span class="token number">1</span>  
</span><span class="code-line"><span class="token number">2</span>  
</span><span class="code-line"><span class="token operator">-</span><span class="token number">1</span>  
</span><span class="code-line"><span class="token number">0</span>  
</span><span class="code-line"><span class="token number">1</span>  
</span><span class="code-line"><span class="token operator">-</span><span class="token number">1</span>  
</span><span class="code-line"><span class="token number">0</span>  
</span><span class="code-line"><span class="token number">3</span>
</span></code></pre>
<h3 id="풀이">풀이</h3>
<pre class="language-cpp"><code class="language-cpp code-highlight"><span class="code-line"><span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string">&#x3C;iostream></span></span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token keyword">using</span> <span class="token keyword">namespace</span> std<span class="token punctuation">;</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token keyword">int</span> stack<span class="token punctuation">[</span><span class="token number">10000</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
</span><span class="code-line"><span class="token keyword">int</span> ind <span class="token operator">=</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">;</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token keyword">void</span> <span class="token function">push</span><span class="token punctuation">(</span><span class="token keyword">int</span> x<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    stack<span class="token punctuation">[</span><span class="token operator">++</span>ind<span class="token punctuation">]</span> <span class="token operator">=</span> x<span class="token punctuation">;</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token keyword">int</span> <span class="token function">empty</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">if</span> <span class="token punctuation">(</span>ind <span class="token operator">&#x3C;</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">return</span> <span class="token number">1</span><span class="token punctuation">;</span>
</span><span class="code-line">    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token keyword">void</span> <span class="token function">pop</span><span class="token punctuation">(</span><span class="token punctuation">)</span>  <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">empty</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        cout <span class="token operator">&#x3C;&#x3C;</span> <span class="token string">"-1"</span> <span class="token operator">&#x3C;&#x3C;</span> <span class="token string">"\n"</span><span class="token punctuation">;</span>
</span><span class="code-line">    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">        cout <span class="token operator">&#x3C;&#x3C;</span> stack<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token operator">&#x3C;&#x3C;</span> <span class="token string">"\n"</span><span class="token punctuation">;</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">int</span> i<span class="token operator">=</span><span class="token number">0</span><span class="token punctuation">;</span> i<span class="token operator">&#x3C;</span>ind<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            stack<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span> stack<span class="token punctuation">[</span>i<span class="token operator">+</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        
</span><span class="code-line">        stack<span class="token punctuation">[</span>ind<span class="token operator">--</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line"> 
</span><span class="code-line"><span class="token keyword">int</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">int</span> n<span class="token punctuation">;</span>
</span><span class="code-line">    cin <span class="token operator">>></span> n<span class="token punctuation">;</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&#x3C;</span> n<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        string command<span class="token punctuation">;</span>
</span><span class="code-line">        cin <span class="token operator">>></span> command<span class="token punctuation">;</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token string">"push"</span> <span class="token operator">==</span> command<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">int</span> x<span class="token punctuation">;</span> 
</span><span class="code-line">            cin <span class="token operator">>></span> x<span class="token punctuation">;</span>
</span><span class="code-line">            <span class="token function">push</span><span class="token punctuation">(</span>x<span class="token punctuation">)</span><span class="token punctuation">;</span>
</span><span class="code-line">        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token string">"pop"</span> <span class="token operator">==</span> command<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token function">pop</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</span><span class="code-line">        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token string">"empty"</span> <span class="token operator">==</span> command<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            cout <span class="token operator">&#x3C;&#x3C;</span> <span class="token function">empty</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&#x3C;&#x3C;</span> <span class="token string">"\n"</span><span class="token punctuation">;</span>
</span><span class="code-line">        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token string">"back"</span> <span class="token operator">==</span> command<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">empty</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">                cout <span class="token operator">&#x3C;&#x3C;</span> <span class="token string">"-1"</span> <span class="token operator">&#x3C;&#x3C;</span> <span class="token string">"\n"</span><span class="token punctuation">;</span>
</span><span class="code-line">            <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">                cout <span class="token operator">&#x3C;&#x3C;</span> stack<span class="token punctuation">[</span>ind<span class="token punctuation">]</span> <span class="token operator">&#x3C;&#x3C;</span> endl<span class="token punctuation">;</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token string">"front"</span> <span class="token operator">==</span> command<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">empty</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">                cout <span class="token operator">&#x3C;&#x3C;</span> <span class="token string">"-1"</span> <span class="token operator">&#x3C;&#x3C;</span> <span class="token string">"\n"</span><span class="token punctuation">;</span>
</span><span class="code-line">            <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">                cout <span class="token operator">&#x3C;&#x3C;</span> stack<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token operator">&#x3C;&#x3C;</span> endl<span class="token punctuation">;</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token string">"size"</span> <span class="token operator">==</span> command<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            cout <span class="token operator">&#x3C;&#x3C;</span> ind<span class="token operator">+</span><span class="token number">1</span> <span class="token operator">&#x3C;&#x3C;</span> endl<span class="token punctuation">;</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/cpp-stack-data-structure</guid>
      <title>C++ 스택 자료구조</title>
      <description>C++로 스택 자료구조를 구현해봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/cpp-stack-data-structure</link>
      <pubDate>Wed, 04 Jul 2018 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<h2 id="스택-설명">스택 설명</h2>
<p>스택은 배열과 비슷하지만 기능이 제한되어 있습니다. 맨 위에 새 요소를 추가하고, 제거할 때도 맨 위의 요소를 제거 합니다. 이는 알고리즘 구현시 임시 목록에 객체를 추가한 다음 나중에 목록에서 객체를 꺼내려고 할 때 필요합니다.</p>
<p>스택을 가리켜 LIFO 라고도 하는데요. 이는 Last-in, First out의 약자로 마지막으로 들어온 요소가 가장 먼저 제거되는 요소라는 의미입니다.</p>
<h2 id="스택-문제">스택 문제</h2>
<p>출처 : <a href="https://www.acmicpc.net/problem/10828">백준 알고리즘</a></p>
<h3 id="문제">문제</h3>
<p>정수를 저장하는 스택을 구현한 다음, 입력으로 주어지는 명령을 처리하는 프로그램을 작성하시오.</p>
<p>명령은 총 다섯 가지이다.</p>
<ul>
<li>push X: 정수 X를 스택에 넣는 연산이다.</li>
<li>pop: 스택에서 가장 위에 있는 정수를 빼고, 그 수를 출력한다. 만약 스택에 들어있는 정수가 없는 경우에는 -1을 출력한다.</li>
<li>size: 스택에 들어있는 정수의 개수를 출력한다.</li>
<li>empty: 스택이 비어있으면 1, 아니면 0을 출력한다.</li>
<li>top: 스택의 가장 위에 있는 정수를 출력한다. 만약 스택에 들어있는 정수가 없는 경우에는 -1을 출력한다.</li>
</ul>
<h3 id="입력">입력</h3>
<p>첫째 줄에 주어지는 명령의 수 <code>N (1 &#x3C;= N &#x3C;= 10,000)</code>이 주어진다. 둘째 줄부터 N개의 줄에는 명령이 하나씩 주어진다. 주어지는 정수는 1보다 크거나 같고, 100,000보다 작거나 같다. 문제에 나와있지 않은 명령이 주어지는 경우는 없다.</p>
<pre class="language-cpp"><code class="language-cpp code-highlight"><span class="code-line">ex<span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token number">14</span>  
</span><span class="code-line">push <span class="token number">1</span>  
</span><span class="code-line">push <span class="token number">2</span>  
</span><span class="code-line">top  
</span><span class="code-line">size  
</span><span class="code-line">empty  
</span><span class="code-line">pop  
</span><span class="code-line">pop  
</span><span class="code-line">pop  
</span><span class="code-line">size  
</span><span class="code-line">empty  
</span><span class="code-line">pop  
</span><span class="code-line">push <span class="token number">3</span>  
</span><span class="code-line">empty  
</span><span class="code-line">top
</span></code></pre>
<h3 id="출력">출력</h3>
<p>출력해야하는 명령이 주어질 때마다, 한 줄에 하나씩 출력한다.</p>
<pre class="language-cpp"><code class="language-cpp code-highlight"><span class="code-line">ex<span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token number">2</span>  
</span><span class="code-line"><span class="token number">2</span>  
</span><span class="code-line"><span class="token number">0</span>  
</span><span class="code-line"><span class="token number">2</span>  
</span><span class="code-line"><span class="token number">1</span>  
</span><span class="code-line"><span class="token operator">-</span><span class="token number">1</span>  
</span><span class="code-line"><span class="token number">0</span>  
</span><span class="code-line"><span class="token number">1</span>  
</span><span class="code-line"><span class="token operator">-</span><span class="token number">1</span>  
</span><span class="code-line"><span class="token number">0</span>  
</span><span class="code-line"><span class="token number">3</span>
</span></code></pre>
<h3 id="풀이">풀이</h3>
<pre class="language-cpp"><code class="language-cpp code-highlight"><span class="code-line"><span class="token macro property"><span class="token directive-hash">#</span><span class="token directive keyword">include</span> <span class="token string">&#x3C;iostream></span></span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token keyword">using</span> <span class="token keyword">namespace</span> std<span class="token punctuation">;</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token keyword">int</span> stack<span class="token punctuation">[</span><span class="token number">10000</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
</span><span class="code-line"><span class="token keyword">int</span> ind <span class="token operator">=</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">;</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token keyword">void</span> <span class="token function">push</span><span class="token punctuation">(</span><span class="token keyword">int</span> x<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    stack<span class="token punctuation">[</span><span class="token operator">++</span>ind<span class="token punctuation">]</span> <span class="token operator">=</span> x<span class="token punctuation">;</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token keyword">int</span> <span class="token function">empty</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">if</span> <span class="token punctuation">(</span>ind <span class="token operator">&#x3C;</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">return</span> <span class="token number">1</span><span class="token punctuation">;</span>
</span><span class="code-line">    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token keyword">void</span> <span class="token function">pop</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">empty</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        cout <span class="token operator">&#x3C;&#x3C;</span> <span class="token string">"-1"</span> <span class="token operator">&#x3C;&#x3C;</span> <span class="token string">"\n"</span><span class="token punctuation">;</span>
</span><span class="code-line">    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">        cout <span class="token operator">&#x3C;&#x3C;</span> stack<span class="token punctuation">[</span>ind<span class="token punctuation">]</span> <span class="token operator">&#x3C;&#x3C;</span> <span class="token string">"\n"</span><span class="token punctuation">;</span>
</span><span class="code-line">        stack<span class="token punctuation">[</span>ind<span class="token operator">--</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line"> 
</span><span class="code-line"><span class="token keyword">int</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">int</span> n<span class="token punctuation">;</span>
</span><span class="code-line">    cin <span class="token operator">>></span> n<span class="token punctuation">;</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&#x3C;</span> n<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">        string command<span class="token punctuation">;</span>
</span><span class="code-line">        cin <span class="token operator">>></span> command<span class="token punctuation">;</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token string">"push"</span> <span class="token operator">==</span> command<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">int</span> x<span class="token punctuation">;</span> 
</span><span class="code-line">            cin <span class="token operator">>></span> x<span class="token punctuation">;</span>
</span><span class="code-line">            <span class="token function">push</span><span class="token punctuation">(</span>x<span class="token punctuation">)</span><span class="token punctuation">;</span>
</span><span class="code-line">        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token string">"top"</span> <span class="token operator">==</span> command<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">empty</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">                cout <span class="token operator">&#x3C;&#x3C;</span> <span class="token string">"-1"</span> <span class="token operator">&#x3C;&#x3C;</span> <span class="token string">"\n"</span><span class="token punctuation">;</span>
</span><span class="code-line">            <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">                cout <span class="token operator">&#x3C;&#x3C;</span> stack<span class="token punctuation">[</span>ind<span class="token punctuation">]</span> <span class="token operator">&#x3C;&#x3C;</span> <span class="token string">"\n"</span><span class="token punctuation">;</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token string">"pop"</span> <span class="token operator">==</span> command<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token function">pop</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</span><span class="code-line">        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token string">"empty"</span> <span class="token operator">==</span> command<span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">            cout <span class="token operator">&#x3C;&#x3C;</span> <span class="token function">empty</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&#x3C;&#x3C;</span> <span class="token string">"\n"</span><span class="token punctuation">;</span>
</span><span class="code-line">        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">            cout <span class="token operator">&#x3C;&#x3C;</span> ind <span class="token operator">+</span> <span class="token number">1</span> <span class="token operator">&#x3C;&#x3C;</span> <span class="token string">"\n"</span><span class="token punctuation">;</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/cpp-data-structure-algorithms</guid>
      <title>C++ 자료구조 알고리즘</title>
      <description>C++로 자료구조와 알고리즘을 작성해봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/cpp-data-structure-algorithms</link>
      <pubDate>Sun, 21 Jan 2018 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>이곳에는 대표적인 알고리즘과 자료구조를 C++로 작성해서 게시할 예정입니다.</p>
<p>이 프로젝트의 목표는 알고리즘이 어떻게 작동하는지 설명하는 것입니다. 그래서 재활용이 가능한 라이브러리 형태의 코드를 작성하는 것보다는 명확하고 가독성 좋은 코드를 작성할 것입니다.</p>
<h2 id="시작하기">시작하기</h2>
<ul>
<li><a href="/blog/cpp-stack-data-structure">스택 자료구조 (Stack)</a></li>
<li><a href="/blog/cpp-queue-data-structure">큐 자료구조 (Queue)</a></li>
<li><a href="/blog/cpp-insertion-sort">삽입 정렬 (Insertion)</a></li>
<li><a href="/blog/cpp-binary-tree">이진 검색 정렬 (Binary Search)</a></li>
</ul>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/macos-icloud-drive-app</guid>
      <title>macOS에서 iCloud Drive 앱 생성하는 방법</title>
      <description>맥북에서 아이클라우드 드라이브 앱을 생성하는 방법에 대해 소개합니다</description>
      <link>https://www.hohyeonmoon.com/blog/macos-icloud-drive-app</link>
      <pubDate>Sun, 10 Dec 2017 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>이번 포스팅에서는 맥북에서 아이클라우드 드라이브 앱을 생성하는 방법에 대해 소개해볼까 합니다. 여기서 앱이란 별도의 앱을 설치한다는 의미는 아니고, 바로가기 아이콘을 생성한다는 것입니다.</p>
<p>아이폰에는 아이클라우드 드라이브 앱이 존재해서, 클라우드에 접근하기 편한데요. 오히려 개방성이 높은 macOS에 해당 앱이 존재하지 않아서, 파인더를 추가적으로 거쳐 접근해야 하는 불편함이 있습니다.</p>
<h2 id="맥북-용-아이클라우드-드라이브-앱-생성하기">맥북 용 아이클라우드 드라이브 앱 생성하기</h2>
<p><img src="/images/macos-icloud-drive-app-1.png" alt="macos-icloud-drive-app"></p>
<p>가장 먼저 파인더를 실행합니다. 파인더가 열리면 'Shift + Command + G'를 입력합니다. 그리고 밑의 디렉터리를 입력합니다.</p>
<pre><code class="language-terminal code-highlight"><span class="code-line">/System/Library/CoreServices/Finder.app/Contents/Applications/
</span></code></pre>
<p><img src="/images/macos-icloud-drive-app-2.png" alt="macos-icloud-drive-app"></p>
<p>해당 디렉터리로 이동하면, 몇 가지 서비스의 아이콘이 보입니다. 이 중 원하는 서비스의 아이콘을 독에 드래그 앤 드롭합니다.</p>
<p><img src="/images/macos-icloud-drive-app-3.png" alt="macos-icloud-drive-app"></p>
<p>독에 위치한 아이콘을 볼 수 있습니다. 독의 아이콘을 통해 더 쉽게 접근할 수 있게 되는데요. 이렇게 해서, 아이클라우드 드라이브의 간단한 사용법 소개를 마치겠습니다.</p>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/macos-high-sierra-clean-install</guid>
      <title>macOS 부팅 디스크 만들고 클린설치 하기</title>
      <description>macOS 하이 시에라 부팅 디스크를 만들고 맥 클린설치를 진행해봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/macos-high-sierra-clean-install</link>
      <pubDate>Sun, 08 Oct 2017 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>이번 포스트에서는 macOS 하이 시에라 부팅 디스크를 만들고 맥 클린설치를 진행해보도록 하겠습니다.</p>
<p>지난 26일 애플에서 macOS 하이 시에라를 새롭게 공개했습니다. 새로운 운영체제가 공개될 때마다 맥 사용자들 사이에서는 클린설치를 통해 업데이트 해야 하나, 그냥 업데이트를 진행해도 되나 등 의견이 갈리곤 합니다. 사용자마다 생각이 다르겠지만, 각자의 생각에 맞게 진행하면 된다고 생각합니다.</p>
<h2 id="부팅-디스크-제작-및-맥-클린설치">부팅 디스크 제작 및 맥 클린설치</h2>
<p><img src="/images/macos-high-sierra-clean-install-1.png" alt="macos-high-sierra-clean-install"></p>
<ul>
<li>새로운 macOS 하이 시에라 인스톨러를 <a href="https://itunes.apple.com/kr/app/macos-high-sierra/id1246284741">다운로드</a>합니다.</li>
<li>다운로드 완료 후 나타나는 인스톨러 창은 닫습니다.</li>
<li>파인더 > 응용 프로그램에서 다운로드 받은 파일을 찾습니다.</li>
<li>찾은 파일을 우클릭해서 '패키지 내용 보기'를 선택합니다.</li>
<li>Content > Resources를 순서대로 들어갑니다.</li>
<li>응용 프로그램 > 유틸리티 > 터미널을 순서대로 들어갑니다.</li>
<li>터미널 창에 sudo와 공백 한 칸을 입력합니다.</li>
<li>4번에서 열었던 창의 createinstallmedia를 터미널 창에 드래그합니다.</li>
<li>터미널 창에 --volume과 공백 한 칸을 입력합니다.</li>
<li>맥 부팅 usb에 사용 될 USB를 맥에 연결합니다.</li>
<li>맥 클린설치 과정이 거의 끝나갑니다. USB를 터미널 창에 드래그합니다.</li>
<li>터미널 창에 --applicationpath와 공백 한 칸을 입력합니다.</li>
<li>파인더 > 응용 프로그램에 들어가서 macOS 하이 시에라 인스톨러를 터미널 창에 드래그합니다.</li>
<li>터미널 명령어가 완성 되었습니다. return 키를 누릅니다.</li>
<li>프롬트가 물어볼때 'Y'를 입력하고 return 키를 누릅니다.</li>
<li>맥os usb가 제작됩니다. 몇 십분 정도 소요되는 과정이 진행되고 부팅용 USB 설치가 끝납니다.</li>
<li>이제 재부팅을 해주고, 부팅 시 option 키를 눌러 제작된 USB 부팅 디스크를 선택합니다.</li>
</ul>
<h2 id="마무리">마무리</h2>
<p>하이 시에라 클린설치 방법을 진행해봤는데요. 맥 클린설치는 다른 운영체제에 비해 유독 논쟁이 심합니다. 그 이유는 애플이 자체적으로 콤보 업데이트를 지원하기 때문이기도 하고, macOS는 다른 컴퓨터 운영체제보다 크게 노화가 오지 않는다는 의견이 많기 때문입니다.</p>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swift-userdefault</guid>
      <title>Swift UserDefault로 데이터 저장</title>
      <description>Swift에서 UserDefault로 데이터를 저장하는 방법에 대해 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/swift-userdefault</link>
      <pubDate>Mon, 25 Sep 2017 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>앞선 글 들에서는 Run Time에서의 데이터 저장만 고려했다.</li>
<li>이번 글에서는 데이터를 영구적으로 저장하는 방법에 대해 알아보겠다.</li>
<li>데이터를 저장하는 방법에는 File, Core Data, Backend DB 등이 있다.</li>
<li>그 중 이 글에서는 plist를 이용해 데이터를 영구적으로 저장하는 방법을 알아보겠다.</li>
</ul>
<h2 id="userdefaults">UserDefaults</h2>
<ul>
<li>UserDefaults를 사용하는 방법은 다음 순서를 따른다.
<ul>
<li>UserDefaults를 통해 plist에 데이터를 저장한다.</li>
<li>UserDefaults는 사용자의 정보를 저장하는 싱글톤 인스턴스이다.</li>
<li>간단한 사용자 정보를 저장 및 불러오는게 가능하지만, 내부적으로 plist 파일에 저장되기 때문에 보안상 강력하지는 않다.</li>
</ul>
</li>
</ul>
<h2 id="주요-항목">주요 항목</h2>
<ul>
<li>UserDefaults의 주요 항목에는 다음과 같은 것들이 있다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">open</span> <span class="token keyword">class</span> <span class="token keyword">var</span> standard<span class="token punctuation">:</span> <span class="token class-name">UserDefaults</span> <span class="token punctuation">{</span> <span class="token keyword">get</span> <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token comment">// 데이터 불러오기</span>
</span><span class="code-line"><span class="token keyword">open</span> <span class="token keyword">func</span> <span class="token function-definition function">object</span><span class="token punctuation">(</span>forKey defaultName<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token keyword">Any</span><span class="token operator">?</span>
</span><span class="code-line"><span class="token keyword">open</span> <span class="token keyword">func</span> <span class="token function-definition function">string</span><span class="token punctuation">(</span>forKey defaultName<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">String</span><span class="token operator">?</span>
</span><span class="code-line"><span class="token keyword">open</span> <span class="token keyword">func</span> <span class="token function-definition function">array</span><span class="token punctuation">(</span>forKey defaultName<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token punctuation">[</span><span class="token keyword">Any</span><span class="token punctuation">]</span><span class="token operator">?</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token comment">// 데이터 저장하기</span>
</span><span class="code-line"><span class="token keyword">open</span> <span class="token keyword">func</span> <span class="token function-definition function">set</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> value<span class="token punctuation">:</span> <span class="token keyword">Any</span><span class="token operator">?</span><span class="token punctuation">,</span> forKey defaultName<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token comment">// 데이터 지우기 </span>
</span><span class="code-line"><span class="token keyword">open</span> <span class="token keyword">func</span> <span class="token function-definition function">removeObject</span><span class="token punctuation">(</span>forKey defaultName<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">)</span>
</span></code></pre>
<h2 id="userdefaults-예제">UserDefaults 예제</h2>
<ul>
<li>UserDefaults의 주요 항목들을 다음과 같이 사용할 수 있다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token comment">// 데이터 저장</span>
</span><span class="code-line"><span class="token class-name">UserDefaults</span><span class="token punctuation">.</span>standard<span class="token punctuation">.</span><span class="token keyword">set</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"hohyeon"</span></span><span class="token punctuation">,</span> forKey<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"userID"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token comment">// 데이터 불러오기</span>
</span><span class="code-line"><span class="token keyword">let</span> aUser<span class="token punctuation">:</span><span class="token class-name">String</span> <span class="token operator">=</span> <span class="token class-name">UserDefaults</span><span class="token punctuation">.</span>standard<span class="token punctuation">.</span><span class="token function">object</span><span class="token punctuation">(</span>forKey<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"UserID"</span></span><span class="token punctuation">)</span> <span class="token keyword">as</span><span class="token operator">!</span> <span class="token class-name">String</span> 
</span><span class="code-line"><span class="token keyword">let</span> bUser<span class="token punctuation">:</span><span class="token class-name">String</span> <span class="token operator">=</span> <span class="token class-name">UserDefaults</span><span class="token punctuation">.</span>standard<span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span>forKey<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"UserID"</span></span><span class="token punctuation">)</span><span class="token operator">!</span>
</span></code></pre>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/xcode-ui-design</guid>
      <title>Xcode UI 디자인 가이드</title>
      <description>Xcode의 기초 UI 디자인을 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/xcode-ui-design</link>
      <pubDate>Tue, 19 Sep 2017 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>이번 글에서는 Xcode의 기초 UI 디자인을 알아보도록 하겠다.</li>
</ul>
<h2 id="픽셀과-포인트">픽셀과 포인트</h2>
<ul>
<li>해상도에는 픽셀이라는 개념과 포인트라는 개념이 있다.</li>
<li>픽셀과 포인트는 비슷한듯 다른 개념이다.</li>
<li>픽셀은 실제 이미지 사이즈를 나타내고, 포인트는 화면에 표시되는 이미지 사이즈를 나타낸다.</li>
<li>픽셀 = 포인트 x 비율</li>
<li>즉, 여러 포인트가 모여 하나의 픽셀을 나타내게 되는 것이다.</li>
</ul>
<h2 id="레티나-디스플레이">레티나 디스플레이</h2>
<ul>
<li>애플의 레티나 디스플레이가 밀집된 포인트의 대표적인 예시이다.</li>
<li>여러 포인트가 밀집되어 하나의 픽셀을 나타내면 무엇이 좋냐면,</li>
<li>이미지를 더욱 디테일하게 표현할 수 있어 더욱 생생하게 우리 눈에 보인다.</li>
</ul>
<p><img src="/images/xcode-ui-design-1.png" alt="xcode-ui-design"></p>
<ul>
<li>@2x는 2개의 포인트가 하나의 픽셀을 구성하는 것이고,</li>
<li>@3x는 3개의 포인트가 하나의 픽셀을 구성하는 것이다.</li>
<li>아이폰8 등 기존의 레티나 디스플레이가 @2x의 밀집도를 갖고 있고,</li>
<li>아이폰8 플러스 등 레티나 HD 디스플레이가 @3x의 밀집도를 갖고 있다.</li>
</ul>
<h2 id="좌표계">좌표계</h2>
<ul>
<li>좌표계는 View 기준 좌측 상단이 (0,0)이다.</li>
</ul>
<p><img src="/images/xcode-ui-design-2.png" alt="xcode-ui-design"></p>
<ul>
<li>View의 위치는 상대적으로 상위뷰를 기준으로 잡는다.</li>
</ul>
<p><img src="/images/xcode-ui-design-3.png" alt="xcode-ui-design"></p>
<h2 id="프레임워크란">프레임워크란</h2>
<ul>
<li>프로그래밍에서 프레임워크란 특정 운영체제를 위한</li>
<li>응용 프로그램 표준 구조를 구현하는 클래스와 라이브러리의 모임이다.</li>
<li>대표적으로 애플에서 iOS를 위해 UIKit 프레임워크를 제공한다.</li>
<li>코코아터치 프레임워크에 추가된 UI 관련 기능의 클래스가 모여있는 프레임워크이다.</li>
</ul>
<p><img src="/images/xcode-ui-design-4.png" alt="xcode-ui-design"></p>
<ul>
<li>애플에서 제공해주는 구현된 클래스들은 Xcoded에서 Command + Shift + O 단축키를 통해 찾아볼 수 있다.</li>
</ul>
<h2 id="uikit-구성-요소">UIKit 구성 요소</h2>
<ul>
<li>UIView는 가장 기본이 되는 View로, UIComponent들의 조합으로 화면이 구성된다.</li>
<li>iOS 화면 구성은 UIView의 집합으로 되어 있다.</li>
<li>그 외에도, UILabel과 UIImageView 등 다양한 클래스가 존재한다.</li>
</ul>
<h2 id="uikit-예제">UIKit 예제</h2>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token comment">//UIView 예제</span>
</span><span class="code-line"><span class="token keyword">let</span> newView <span class="token operator">=</span> <span class="token class-name">UIView</span><span class="token punctuation">(</span>frame<span class="token punctuation">:</span> <span class="token class-name">CGRect</span><span class="token punctuation">(</span>x<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span> y<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span> width<span class="token punctuation">:</span> <span class="token number">100</span><span class="token punctuation">,</span> height<span class="token punctuation">:</span> <span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">newView<span class="token punctuation">.</span>backgroundColor <span class="token operator">=</span> <span class="token class-name">UIColor</span><span class="token punctuation">.</span>green
</span><span class="code-line"><span class="token keyword">self</span><span class="token punctuation">.</span>view<span class="token punctuation">.</span><span class="token function">addSubview</span><span class="token punctuation">(</span>newView<span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token comment">//UILabel 예제</span>
</span><span class="code-line"><span class="token keyword">let</span> newLb <span class="token operator">=</span> <span class="token class-name">UILabel</span><span class="token punctuation">(</span>frame<span class="token punctuation">:</span> <span class="token class-name">CGRect</span><span class="token punctuation">(</span>x<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span> y<span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span> width<span class="token punctuation">:</span> <span class="token number">100</span><span class="token punctuation">,</span> height<span class="token punctuation">:</span> <span class="token number">30</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">newLb<span class="token punctuation">.</span>text <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"테스트"</span></span>
</span><span class="code-line">newLb<span class="token punctuation">.</span>textColor <span class="token operator">=</span> <span class="token class-name">UIColor</span><span class="token punctuation">.</span>gray
</span><span class="code-line">newView<span class="token punctuation">.</span><span class="token function">addSubview</span><span class="token punctuation">(</span>newLb<span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token comment">//UIImageView 예제</span>
</span><span class="code-line"><span class="token keyword">let</span> newImgV <span class="token operator">=</span> <span class="token class-name">UIImageView</span><span class="token punctuation">(</span>frame<span class="token punctuation">:</span> <span class="token class-name">CGRect</span><span class="token punctuation">(</span>x<span class="token punctuation">:</span> <span class="token number">5</span><span class="token punctuation">,</span> y<span class="token punctuation">:</span> <span class="token number">5</span><span class="token punctuation">,</span> width<span class="token punctuation">:</span> <span class="token number">90</span><span class="token punctuation">,</span> height<span class="token punctuation">:</span> <span class="token number">90</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">newImgV<span class="token punctuation">.</span>image <span class="token operator">=</span> <span class="token class-name">UIImage</span><span class="token punctuation">(</span>named<span class="token punctuation">:</span><span class="token string-literal"><span class="token string">"img.png"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">newImgV<span class="token punctuation">.</span>contentMode <span class="token operator">=</span> <span class="token class-name">UIViewContentMode</span><span class="token punctuation">.</span>scaleAspectFit newView<span class="token punctuation">.</span><span class="token function">addSubview</span><span class="token punctuation">(</span>newImgV<span class="token punctuation">)</span>
</span></code></pre>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swift-switch-case</guid>
      <title>Swift Switch-Case문</title>
      <description>Swift에서 Swift-Case문을 사용하는 방법에 대해 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/swift-switch-case</link>
      <pubDate>Thu, 14 Sep 2017 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>스위프트에도 여느 프로그래밍 언어와 마찬가지로 조건문이 있다.</li>
<li>대표적으로 if-else문과 switch-case문이 사용된다.</li>
<li>if-else문은 <a href="/blog/swift-variable-if-else/">지난 글</a>을 통해 알아봤다.</li>
<li>이번에는 switch-case문에 대해 알아보겠다.</li>
</ul>
<h2 id="switch문">Switch문</h2>
<ul>
<li>패턴 비교문이라고도 하는 Switch문은 가장 첫 번째 매칭되는 패턴의 구문이 실행된다.</li>
<li>Switch문의 문법과 예제를 통해 조금 더 살펴보도록 하자.</li>
</ul>
<h2 id="switch문-문법">Switch문 문법</h2>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">switch</span> value <span class="token punctuation">{</span>
</span><span class="code-line"><span class="token keyword">case</span> value1<span class="token punctuation">:</span>
</span><span class="code-line">    respond to value <span class="token number">1</span>
</span><span class="code-line"><span class="token keyword">case</span> value2<span class="token punctuation">,</span>
</span><span class="code-line">     value3<span class="token punctuation">:</span>
</span><span class="code-line">    respond to value <span class="token number">2</span> or <span class="token number">3</span>
</span><span class="code-line"><span class="token keyword">default</span><span class="token punctuation">:</span>
</span><span class="code-line">    otherwise<span class="token punctuation">,</span> <span class="token keyword">do</span> something <span class="token keyword">else</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>각 상태는 키워드 case를 통해 나타낼수 있다.</li>
<li>case 상태 끝에 콜론 ':'을 붙여 패턴을 종료한다.</li>
<li>하나의 case문이 종료되면 switch문이 종료된다.</li>
<li>또한 switch문은 모든 경우를 커버하기 위해서 마지막에 default 키워드를 사용해야 한다.</li>
<li>단, default 키워드 없이도 모든 경우가 커버 되었다면, default 키워드가 없어도 된다.</li>
</ul>
<h2 id="switch문-interval-matching">Switch문 Interval Matching</h2>
<ul>
<li>Switch문 Interval Matching이란 범위 연산자를 활용해,</li>
<li>단순히 값을 매칭하는 것을 넘어 다양한 패턴을 통해 매칭하는 것을 말한다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">interSwitch</span><span class="token punctuation">(</span>count<span class="token punctuation">:</span><span class="token class-name">Int</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">let</span> countedThings <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"moons orbiting Saturn"</span></span>
</span><span class="code-line">    <span class="token keyword">let</span> naturalCount<span class="token punctuation">:</span> <span class="token class-name">String</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">switch</span> count <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">case</span> <span class="token number">0</span><span class="token punctuation">:</span>
</span><span class="code-line">        naturalCount <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"no"</span></span>
</span><span class="code-line">    <span class="token keyword">case</span> <span class="token number">1</span><span class="token operator">..&#x3C;</span><span class="token number">5</span><span class="token punctuation">:</span>        
</span><span class="code-line">        naturalCount <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"a few"</span></span>
</span><span class="code-line">    <span class="token keyword">case</span> <span class="token number">5</span><span class="token operator">..&#x3C;</span><span class="token number">12</span><span class="token punctuation">:</span>        
</span><span class="code-line">        naturalCount <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"several"</span></span>
</span><span class="code-line">    <span class="token keyword">case</span> <span class="token number">12</span><span class="token operator">..&#x3C;</span><span class="token number">100</span><span class="token punctuation">:</span>        
</span><span class="code-line">        naturalCount <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"dozens of"</span></span>
</span><span class="code-line">    <span class="token keyword">case</span> <span class="token number">100</span><span class="token operator">..&#x3C;</span><span class="token number">1000</span><span class="token punctuation">:</span>        
</span><span class="code-line">        naturalCount <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"hundreds of"</span></span>
</span><span class="code-line">    <span class="token keyword">default</span><span class="token punctuation">:</span>
</span><span class="code-line">        naturalCount <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"many"</span></span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"There are </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">naturalCount</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string"> </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">countedThings</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">."</span></span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="switch문-튜플-매칭">Switch문 튜플 매칭</h2>
<ul>
<li>튜플과 와일드카드를 이용해서 Switch문에서 여러개의 값을 동시에 확인할 수 있다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">getPoint</span><span class="token punctuation">(</span>somePoint<span class="token punctuation">:</span><span class="token punctuation">(</span><span class="token class-name">Int</span><span class="token punctuation">,</span><span class="token class-name">Int</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">switch</span> somePoint
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">case</span> <span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
</span><span class="code-line">        <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"</span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">somePoint</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string"> is at the origin"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">case</span> <span class="token punctuation">(</span><span class="token omit keyword">_</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
</span><span class="code-line">        <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"</span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">somePoint</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string"> is on the x-axis"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">case</span> <span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token omit keyword">_</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
</span><span class="code-line">        <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"</span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">somePoint</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string"> is on the y-axis"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">case</span> <span class="token punctuation">(</span><span class="token operator">-</span><span class="token number">2</span><span class="token operator">...</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">2</span><span class="token operator">...</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
</span><span class="code-line">        <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"</span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">somePoint</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string"> is inside the box"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">default</span><span class="token punctuation">:</span>
</span><span class="code-line">        <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"</span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">somePoint</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string"> is outside of the box"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="switch문-값-바인딩">Switch문 값 바인딩</h2>
<ul>
<li>Switch문에서 값 바인딩을 통해 case 내부에서 사용되는 임시 값으로 매칭 시킬 수 있다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">getPoint</span><span class="token punctuation">(</span>somePoint<span class="token punctuation">:</span><span class="token punctuation">(</span><span class="token class-name">Int</span><span class="token punctuation">,</span><span class="token class-name">Int</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">switch</span> somePoint
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">case</span> <span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
</span><span class="code-line">        <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"</span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">somePoint</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string"> is at the origin"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">case</span> <span class="token punctuation">(</span><span class="token keyword">let</span> x<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
</span><span class="code-line">        <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"on the x-axis with an x value of </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">x</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">case</span> <span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token keyword">let</span> y<span class="token punctuation">)</span><span class="token punctuation">:</span>
</span><span class="code-line">        <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"on the y-axis with an y value of </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">y</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">case</span> <span class="token punctuation">(</span><span class="token operator">-</span><span class="token number">2</span><span class="token operator">...</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token operator">-</span><span class="token number">2</span><span class="token operator">...</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">:</span>
</span><span class="code-line">        <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"</span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">somePoint</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string"> is inside the box"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">default</span><span class="token punctuation">:</span>
</span><span class="code-line">        <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"</span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">somePoint</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string"> is outside of the box"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="switch문-where문">Switch문 where문</h2>
<ul>
<li>where문의 추가로 조건을 더욱 세부화할 수도 있다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">wherePoint</span><span class="token punctuation">(</span>point<span class="token punctuation">:</span><span class="token punctuation">(</span><span class="token class-name">Int</span><span class="token punctuation">,</span><span class="token class-name">Int</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">switch</span> point
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">case</span> <span class="token keyword">let</span> <span class="token punctuation">(</span>x<span class="token punctuation">,</span> y<span class="token punctuation">)</span> <span class="token keyword">where</span> x <span class="token operator">==</span> y<span class="token punctuation">:</span>
</span><span class="code-line">        <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"(</span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">x</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">, </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">y</span><span class="token interpolation-punctuation punctuation">)</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string"> is on the line x == y"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">case</span> <span class="token keyword">let</span> <span class="token punctuation">(</span>x<span class="token punctuation">,</span> y<span class="token punctuation">)</span> <span class="token keyword">where</span> x <span class="token operator">==</span> <span class="token operator">-</span>y<span class="token punctuation">:</span>
</span><span class="code-line">        <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"(</span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">x</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">, </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">y</span><span class="token interpolation-punctuation punctuation">)</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string"> is on the line x == -y"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token keyword">case</span> <span class="token keyword">let</span> <span class="token punctuation">(</span>x<span class="token punctuation">,</span> y<span class="token punctuation">)</span><span class="token punctuation">:</span>
</span><span class="code-line">        <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"(</span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">x</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">, </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">y</span><span class="token interpolation-punctuation punctuation">)</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string"> is just some arbitrary point"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>   
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swift-optional</guid>
      <title>Swift Optional</title>
      <description>Swift 언어에서의 optional에 대해 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/swift-optional</link>
      <pubDate>Fri, 08 Sep 2017 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>이번 글에서는 Swift 언어에서의 optional에 대해 알아보도록 하겠다.</li>
</ul>
<h2 id="옵셔널">옵셔널</h2>
<ul>
<li><a href="/blog/swift-tuple-modifier">지난 글의 스위프트 특이타입</a>에서 nil은 아무것도 없는 상태라는 것을 알아봤다.</li>
<li>변수만 선언되어 있고, 아직 인스턴스가 할당되기 전의 상태이다.</li>
<li>옵셔널은 이러한 nil을 체크해서 에러가 발생하는 것을 막기 위해 사용한다.</li>
<li>옵셔널은 두 가지 가능성을 가질 수 있다.</li>
<li>한 가지는 값이 있음을 나타내는 nil이 아님을 확신하는 !와</li>
<li>다른 한 가지는 nil의 가능성을 내포하는 ?이다.</li>
</ul>
<h2 id="옵셔널-타입">옵셔널 타입</h2>
<ul>
<li>Int?, String?, Double? 등이 옵셔널 타입이다.</li>
<li>이는 Int, String, Double과는 엄연히 다른 타입이다.</li>
<li>옵셔널 타입은 unwrapping을 통해 사용될 수 있다.</li>
<li>Unwrapping 하는 방법에는 3가지가 존재한다.</li>
<li>forced unwrapping, optional binding, early exit</li>
</ul>
<h2 id="forced-unwrapping">Forced unwrapping</h2>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">testFuc</span><span class="token punctuation">(</span>optionalStr<span class="token punctuation">:</span><span class="token class-name">String</span><span class="token operator">?</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>    
</span><span class="code-line">    <span class="token keyword">if</span> optionalStr <span class="token operator">!=</span> <span class="token nil constant">nil</span> <span class="token punctuation">{</span>        
</span><span class="code-line">        <span class="token keyword">let</span> unwrapStr<span class="token punctuation">:</span><span class="token class-name">String</span> <span class="token operator">=</span> optionalStr<span class="token operator">!</span>        
</span><span class="code-line">        <span class="token function">print</span><span class="token punctuation">(</span>unwrapStr<span class="token punctuation">)</span>        
</span><span class="code-line">    <span class="token punctuation">}</span>    
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>이는 옵셔널 변수의 값이 nil이 아니라면 !를 통해 옵셔널 변수를 문자열 변수로 변경하는 함수이다.</li>
</ul>
<h2 id="optional-binding">Optional binding</h2>
<ul>
<li>옵셔널 바인딩은 if let이라는 스위프트의 새로운 문법을 통해</li>
<li>만약 옵셔널 변수의 값이 nil이 아니라면 옵셔널 변수를 unwrapping 해주는 것이다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">testFuc</span><span class="token punctuation">(</span>optionalStr<span class="token punctuation">:</span><span class="token class-name">String</span><span class="token operator">?</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">if</span> <span class="token keyword">let</span> unwrapStr <span class="token operator">=</span> optionalStr
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token function">print</span><span class="token punctuation">(</span>unwrapStr<span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="early-exit">Early exit</h2>
<ul>
<li>guard let else문은 조건값이 거짓일때 실행된다.</li>
<li>즉, 옵셔널 변수의 값이 nil 값이 대괄호안의 코드가 실행된다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">testFuc</span><span class="token punctuation">(</span>optionalStr<span class="token punctuation">:</span><span class="token class-name">String</span><span class="token operator">?</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>    
</span><span class="code-line">    <span class="token keyword">guard</span> <span class="token keyword">let</span> unwrapStr<span class="token punctuation">:</span><span class="token class-name">String</span> <span class="token operator">=</span> optionalStr <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">}</span>    
</span><span class="code-line">    <span class="token function">print</span><span class="token punctuation">(</span>unwrapStr<span class="token punctuation">)</span>    
</span><span class="code-line">    <span class="token keyword">else</span> 
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="optional-chaining">Optional Chaining</h2>
<ul>
<li>인스턴스의 프로퍼티나 메소드에 접근하기 위해 옵셔널 체인 연사자를 사용한다.</li>
<li>다음과 같이 말이다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">var</span> displayLabel<span class="token punctuation">:</span> <span class="token class-name">UILabel</span><span class="token operator">?</span>
</span><span class="code-line">displayLabel<span class="token operator">?</span><span class="token punctuation">.</span>text <span class="token operator">=</span> “displayLabel에 옵셔널 체이닝 사용”
</span></code></pre>
<h2 id="nil-coalescing">nil-coalescing</h2>
<ul>
<li>이 기능으로 nil 값일 경우 기본값을 지정해 줄 수 있다.</li>
<li>?? 기호를 사용한다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">let</span> defaultImagePath <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"/images/default.png"</span></span>
</span><span class="code-line"><span class="token keyword">let</span> heartPath <span class="token operator">=</span> imagePaths<span class="token punctuation">[</span>“image”<span class="token punctuation">]</span> <span class="token operator">??</span> defaultImagePath
</span></code></pre>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swift-tuple-modifier</guid>
      <title>Swift Tuple 및 Modifier</title>
      <description>Swift의 Tuple과 Modifier에 대해 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/swift-tuple-modifier</link>
      <pubDate>Sun, 03 Sep 2017 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<h2 id="스위프트-튜플">스위프트 튜플</h2>
<ul>
<li>튜플은 정해지지 않은 데이터 타입의 묶음을 말한다.</li>
<li>소괄호 () 안에 여러가지 타입을 묶어서 새로운 튜플 타입을 생성할 수 있다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token punctuation">(</span><span class="token class-name">Int</span><span class="token punctuation">,</span> <span class="token class-name">Int</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">(</span><span class="token class-name">Int</span><span class="token punctuation">,</span> <span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">Int</span><span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>또, 각 타입마다 이름을 지정해 줄수도 있다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">,</span> height<span class="token punctuation">:</span> <span class="token class-name">Double</span><span class="token punctuation">)</span>
</span></code></pre>
<h2 id="튜플-예시">튜플 예시</h2>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">var</span> person<span class="token punctuation">:</span> <span class="token punctuation">(</span>name<span class="token punctuation">:</span><span class="token class-name">String</span><span class="token punctuation">,</span> age<span class="token punctuation">:</span> <span class="token class-name">Int</span><span class="token punctuation">,</span> height<span class="token punctuation">:</span> <span class="token class-name">Double</span><span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"이름 : "</span></span> <span class="token operator">+</span> person<span class="token punctuation">.</span>name<span class="token punctuation">)</span>
</span><span class="code-line"><span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"나이 : </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">person<span class="token punctuation">.</span>age</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"키 : </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">person<span class="token punctuation">.</span>height</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span></code></pre>
<h2 id="스위프트의-특이-타입">스위프트의 특이 타입</h2>
<ul>
<li>스위프트에는 다른 프로그래밍 언어에는 존재하지 않는 특이한 타입이 존재한다.</li>
<li>Any, AnyObject, nil이 그것이다.</li>
<li>Any는 스위프트 내의 모든 타입을 나타낸다.</li>
<li>AnyObject는 스위프트 내의 모든 객체 타입을 나타낸다.</li>
<li>즉, 모든 클래스의 상위에 위치한다.</li>
<li>Objectiv-C NSObject를 대체하기 위해 만들어졌다.</li>
<li>nil은 데이터가 아예 없음을 나타내는 키워드이다.</li>
<li>Any의 사용 예시는 다음과 같다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">var</span> a<span class="token punctuation">:</span> <span class="token keyword">Any</span> <span class="token operator">=</span> <span class="token number">3</span>
</span><span class="code-line"><span class="token keyword">var</span> b<span class="token punctuation">:</span> <span class="token keyword">Any</span> <span class="token operator">=</span> <span class="token number">5</span>
</span><span class="code-line"><span class="token keyword">var</span> c <span class="token operator">=</span> a <span class="token operator">+</span> b <span class="token comment">// 에러 발생. Any 타입은 + 연산자가 지원하지 않음</span>
</span></code></pre>
<h2 id="모듈--소스파일">모듈 &#x26; 소스파일</h2>
<ul>
<li>모듈이란 배포할 코드의 묶음 단위로써, 프레임워크, 라이브러리, 어플리케이션 등이 모듈의 단위이다.</li>
<li>소스파일은 하나의 스위프트 파일을 일컫는다.</li>
</ul>
<h2 id="스위프트-접근-제어자">스위프트 접근 제어자</h2>
<ul>
<li>스위프트의 캡슐화와 은닉화를 위해 사용되는 접근 제어자는 5가지 종류가 있다.</li>
<li>Open은 모듈 외부까지 접근 가능하다.</li>
<li>public도 모듈 외부까지 접근 가능하다.</li>
<li>internal은 모듈 내부에서 접근 가능하고, 기본 지정 값이다.</li>
<li>fileprivate은 파일 내부에서만 접근 가능하다.</li>
<li>private은 기능 정의 내부에서만 접근 가능하다.</li>
</ul>
<h2 id="open-vs-public">Open vs public</h2>
<ul>
<li>위의 설명에서는 Open과 public의 차이점을 알 수 없었다.</li>
<li>Open과 public 모두 전체 공개 접근 제어자이기 때문이다.</li>
<li>단, Open은 모듈 밖에서도 클래스 및 클래스 멤버가 상속될 수 있고,</li>
<li>public은 모듈 밖에서 클래스 상속 및 클래스 멤버 재정의가 될 수 없다.</li>
</ul>
<h2 id="함수-추가-문법">함수 추가 문법</h2>
<ul>
<li><a href="/blog/swift-loop-function/">지난 글</a>에서 함수에 대해 알아본적이 있다.</li>
<li>사실, 함수의 모든 문법에 대해 알아본것은 아니다.</li>
<li>당시에는 인수 레이블(argument label)을 생략했다.</li>
</ul>
<p><img src="/images/swift-tuple-modifier-1.png" alt="swift-tuple-modifier"></p>
<ul>
<li>인수 레이블은 함수 호출시 사용되는 이름표이고,</li>
<li>매개변수는 함수 내부에서 사용되는 변수명이다.</li>
<li>인수 레이블은 생략이 가능하고,</li>
<li>생략 되었을때는 매개변수명이 인수 레이블로 사용된다.</li>
</ul>
<h2 id="in-out-키워드">In-Out 키워드</h2>
<ul>
<li>기본적으로 함수의 매개변수는 상수값이다.</li>
<li>그러나 In-Out 키워드를 통해 매개변수의 값을 변수로 변경할 수 있다.</li>
<li>다음과 같이 말이다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">swapInts</span><span class="token punctuation">(</span><span class="token omit keyword">_</span> a<span class="token punctuation">:</span> <span class="token keyword">inout</span> <span class="token class-name">Int</span><span class="token punctuation">,</span> <span class="token omit keyword">_</span> b<span class="token punctuation">:</span> <span class="token keyword">inout</span> <span class="token class-name">Int</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">{</span>
</span><span class="code-line">	<span class="token keyword">let</span> temp <span class="token operator">=</span> a
</span><span class="code-line">	a <span class="token operator">=</span> b
</span><span class="code-line">	b <span class="token operator">=</span> temp
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>그리고 In-Out 키워드가 적용된 함수는 함수를 호출할때 인수 앞에 &#x26; 키워드를 붙여줘야 한다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">var</span> someInt <span class="token operator">=</span> <span class="token number">2</span>
</span><span class="code-line"><span class="token keyword">var</span> anotherInt <span class="token operator">=</span> <span class="token number">4</span>
</span><span class="code-line"><span class="token function">swapInts</span><span class="token punctuation">(</span><span class="token operator">&#x26;</span>someInt<span class="token punctuation">,</span> <span class="token operator">&#x26;</span>anotherInt<span class="token punctuation">)</span>
</span></code></pre>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swift-inheritence-polymorphism</guid>
      <title>Swift 클래스의 상속과 다형성</title>
      <description>Swift에서 Class의 상속과 다형성에 대해 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/swift-inheritence-polymorphism</link>
      <pubDate>Sat, 02 Sep 2017 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>이번 글에서는 <a href="/blog/swift-oop/">객체지향 프로그래밍</a>의 주요 특징인</li>
<li>상속성과 다형성에 대해서 조금 더 자세히 살펴보겠다.</li>
</ul>
<h2 id="클래스의-상속">클래스의 상속</h2>
<ul>
<li>클래스의 상속은 Subclassing이라고도 하는데,</li>
<li>기존에 구현 되어있는 클래스를 확장하고 변형하는 것을 말한다.</li>
<li>부모 클래스와 자식 클래스로 관계를 표현하고,</li>
<li>상속을 하면 할 수록 더욱 확장되는 구조를 갖고 있다.</li>
</ul>
<h2 id="상속하는-방법">상속하는 방법</h2>
<ul>
<li>클래스의 상속은 다음과 같이 콜론뒤에 상속할 클래스명을 적어서 수행할수 있다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">UniversityStudent</span><span class="token punctuation">:</span> <span class="token class-name">Student</span>
</span><span class="code-line"><span class="token punctuation">{</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="상속-관계-예시">상속 관계 예시</h2>
<p><img src="/images/swift-inheritence-polymorphism-1.png" alt="swift-inheritence-polymorphism"></p>
<h2 id="다형성">다형성</h2>
<ul>
<li>객체지향 프로그래밍의 다형성은 주로 오버라이딩과 오버로딩을 의미한다.</li>
</ul>
<h2 id="오버라이딩">오버라이딩</h2>
<ul>
<li>오버라이딩이란 부모 클래스에게서 상속 받은 메서드를 그대로 사용하지 않고,</li>
<li>자식 클래스에 맞게 변경하여 사용하는 것이다.</li>
<li>예를들어, 위 상속 관계 예시 사진에서.</li>
<li>Person 클래스의 eat 메서드는 집밥을 먹게 하고,</li>
<li>Student 클래스의 eat 메서드는 급식을 먹게하고,</li>
<li>UniversityStudent 클래스의 eat 메서드는 학식을 먹게 하는 것이다.</li>
</ul>
<h2 id="오버로딩">오버로딩</h2>
<ul>
<li>오버로딩은 같은 이름의 함수를 매개변수에 따라 다양하게 구현하는 것을 의미한다.</li>
<li>예를들어, add라는 같은 이름의 함수라고 해도.</li>
<li>입력 받는 매개변수의 갯수에 따라 다르게 구현할 수 있는 것이다.</li>
</ul>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swift-class-object</guid>
      <title>Swift 클래스 및 객체</title>
      <description>Swift의 Class와 Object에 대해 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/swift-class-object</link>
      <pubDate>Fri, 01 Sep 2017 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li><a href="/blog/swift-oop/">지난 글</a>에서도 Swift의 클래스와 객체에 대해 열심히 이야기하긴 했지만,</li>
<li>이번 글에서도 클래스와 객체에 대한 이야기를 이어가려고 한다.</li>
</ul>
<h2 id="스위프트-클래스-구조">스위프트 클래스 구조</h2>
<ul>
<li>클래스는 키워드 'class'를 통해 생성된다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">ClassName</span>
</span><span class="code-line"><span class="token punctuation">{</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>클래스의 프로퍼티란 객체가 갖고 있는 속성이다.</li>
<li>즉, 다음과 같은 변수들이 될 수 있겠다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">ClassName</span>
</span><span class="code-line"><span class="token punctuation">{</span>
</span><span class="code-line">	<span class="token keyword">var</span> name<span class="token punctuation">:</span> <span class="token class-name">String</span> <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"스위프트 프로그래밍"</span></span>
</span><span class="code-line">	<span class="token keyword">var</span> grade<span class="token punctuation">:</span> <span class="token class-name">Int</span> <span class="token operator">=</span> <span class="token number">100</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="객체-만들기">객체 만들기</h2>
<p><img src="/images/swift-class-object-1.png" alt="swift-class-object"></p>
<ul>
<li>객체를 만든다는 것은 곧, 클래스의 인스턴스를 생성하는 것이다.</li>
<li>다음과 같이 만들 수 있다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">var</span> exampleInstance<span class="token punctuation">:</span> <span class="token class-name">ClassName</span> <span class="token operator">=</span> <span class="token class-name">ClassName</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>그런데 여기서 ClassName()은 사실상 ClassName.init()과 같다.</li>
<li>밑에서 소개할 초기화에 대한 내용이 이를 설명해준다.</li>
</ul>
<h2 id="초기화">초기화</h2>
<ul>
<li>클래스는 기본적으로 다음과 같이 초기화가 이뤄진다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">{</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>그래서 엄밀히 따지면, ClassName.init()이라고 초기화해줘야 하는데.</li>
<li>ClassName()과 같이 생략해서 초기화 할 수도 있는 것이다.</li>
<li>그런데 이 초기화를 다음과 같이 사용자화 할 수도 있다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">ClassName</span>
</span><span class="code-line"><span class="token punctuation">{</span>
</span><span class="code-line">	<span class="token keyword">var</span> name<span class="token punctuation">:</span> <span class="token class-name">String</span> <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"스위프트 프로그래밍"</span></span>
</span><span class="code-line">	<span class="token keyword">var</span> grade<span class="token punctuation">:</span> <span class="token class-name">Int</span> <span class="token operator">=</span> <span class="token number">100</span>
</span><span class="code-line">    
</span><span class="code-line">	<span class="token keyword">init</span><span class="token punctuation">(</span>name<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">,</span> grade<span class="token punctuation">:</span> <span class="token class-name">Int</span><span class="token punctuation">)</span>
</span><span class="code-line">	<span class="token punctuation">{</span>
</span><span class="code-line">		<span class="token keyword">self</span><span class="token punctuation">.</span>name <span class="token operator">=</span> name
</span><span class="code-line">		<span class="token keyword">self</span><span class="token punctuation">.</span>grade <span class="token operator">=</span> grade
</span><span class="code-line">	<span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swift-oop</guid>
      <title>Swift 객체지향 프로그래밍</title>
      <description>Swift에서 하는 객체지향 프로그래밍에 대해 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/swift-oop</link>
      <pubDate>Wed, 30 Aug 2017 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>프로그래밍에도 코드를 조금 더 효율적으로 만들고 작성하기 위한 패러다임이 존재한다.</li>
<li>절차 지향형 프로그래밍, 객체지향형 프로그래밍, 함수형 프로그래밍, 논리형 프로그래밍 등이 존재한다.</li>
<li>한편, Swift 언어는 객체지향형, 함수형, 프로토콜 지향 프로그래밍을 모두 다룰 수 있는 언어이다.</li>
<li>단, iOS 프레임워크가 객체지향형 프로그래밍으로 구현되어 있어서, 객체지향 프로그래밍을 하도록 권장한다.</li>
</ul>
<h2 id="객체지향-프로그래밍">객체지향 프로그래밍</h2>
<ul>
<li>객체지향 프로그래밍은 프로그램을 명령어의 집합으로 보는 것을 넘어, 여러 객체들의 모임으로 보는 것이다.</li>
<li>각각의 객체는 메시지를 주고 받을 수 있으며, 데이터를 처리할 수 있다.</li>
</ul>
<h2 id="oop-기본-구성">OOP 기본 구성</h2>
<ul>
<li>객체지향 프로그래밍의 기본 구성 요소에는 클래스, 객체, 메소드, 메시지 등이 존재한다.</li>
<li>클래스는 같은 종류의 집단에 속하는 속성과 행위를 정의한 것으로, 사용자 정의 데이터형이라고 할 수 있다.</li>
<li>객체는 클래스의 인스턴스로, 자신만의 속성과 행위를 갖고 있다.</li>
<li>또, 위 클래스와 객체의 설명에서 속성과 행위는 각각 변수와 함수라고 할 수 있다.</li>
</ul>
<h2 id="클래스-vs-객체">클래스 vs 객체</h2>
<p><img src="/images/swift-oop-1.png" alt="swift-oop"></p>
<ul>
<li>클래스와 객체는 쉽게 헷갈릴 수 있는 개념이다.</li>
<li>클래스와 객체는 위에서도 소개했듯이 엄밀하게 따지면 다른 개념이다.</li>
<li>사용자 정의 데이터형인 클래스의 인스턴스가 객체인 것이다.</li>
<li>클래스와 객체는 실생활의 붕어빵 만드는 기계와 붕어빵에 비유해볼 수 있다.</li>
<li>붕어빵을 만드는 기계는 클래스이고, 붕어빵은 기계로 만들어진 실제 객체인 것이다.</li>
<li>자동차 도면과, 실제로 출고된 자동차도 클래스와 객체의 또다른 예시가 될 수 있다.</li>
<li>즉, 클래스 파일을 메모리에 올리면 객체화가 되고,</li>
<li>객체들의 속성과 명령어가 실행되면서 프로그램이 실행되는 것이다.</li>
</ul>
<h2 id="oop-특징">OOP 특징</h2>
<ul>
<li>객체지향 프로그래밍의 특징에는 5가지 큰 특징이 있다.</li>
<li>추상화, 캡슐화, 은닉화, 상속성, 다형성이 그 주인공이다.</li>
<li>추상화는 객체들의 공통적인 부분을 뽑아내서 따로 구현해놓는 것을 말한다.</li>
<li>그러나 공통적인 부분만 뽑아내기 때문에 구체적인 정보를 담지는 못하고,</li>
<li>추상적인 정보가 주로 모여있어 '추상'화가 특징인 것이다.</li>
<li>캡슐화와 은닉화는 보통 같이 발생하는 특성이다.</li>
<li>객체의 속성과 행위를 하나로 묶고(캡슐화), 실제 구현 내용 일부를 외부에 감추는(은닉화) 것이다.</li>
<li>상속성은 상위의 것을 하위의 것이 물려받을 수 있는 특징을 말한다.</li>
<li>주로 하나의 클래스가 갖고 있는 속성과 행위를 다른 클래스가 물려받을 때 사용한다.</li>
<li>다형성은 하나의 메소드나 클래스를 다양한 방법으로 동작시키는 것을 의미한다.</li>
<li>오버로딩이나 오버라이딩이 이것의 대표적인 예시이다.</li>
<li>오버로딩은 같은 이름의 함수를 파라미터에 따라 다양하게 구현하는 것을 의미하고,</li>
<li>오버라이딩은 상위 클래스가 가지고 있는 메소드가 하위 클래스로 상속되어,</li>
<li>하위 클래스에서 재정의해서 사용하는 것을 의미한다.</li>
</ul>
<h2 id="swift-클래스의-구조">Swift 클래스의 구조</h2>
<p>객체지향 프로그래밍 언어인 Swift 클래스의 기본적인 구조는 다음과 같습니다.</p>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">class</span> <span class="token class-name">ClassName</span> <span class="token punctuation">:</span> superClass
</span><span class="code-line"><span class="token punctuation">{</span>
</span><span class="code-line">	<span class="token keyword">var</span> vName1 <span class="token operator">=</span> <span class="token number">1</span>
</span><span class="code-line">	<span class="token keyword">var</span> vName2 <span class="token operator">=</span> <span class="token number">4</span>
</span><span class="code-line">    
</span><span class="code-line">	<span class="token keyword">func</span> <span class="token function-definition function">fName1</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token keyword">Any</span>
</span><span class="code-line">	<span class="token punctuation">{</span>
</span><span class="code-line">	<span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">	<span class="token keyword">func</span> <span class="token function-definition function">fName2</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token keyword">Any</span>
</span><span class="code-line">	<span class="token punctuation">{</span>
</span><span class="code-line">	<span class="token punctuation">}</span>	
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swift-xcode-usage</guid>
      <title>Swift Xcode 사용법</title>
      <description>Swift 언어의 IDE인 Xcode 사용법을 간단히 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/swift-xcode-usage</link>
      <pubDate>Tue, 22 Aug 2017 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>이번 글에서는 Swift 언어의 IDE인 Xcode 사용법을 간단히 알아보겠다.</li>
<li>마지막에는, <a href="/blog/swift-loop-function/">지난 글</a>에서 다룬 반복문의 더 많은 예제를 살펴보도록 하겠다.</li>
</ul>
<h2 id="xcode-간단한-사용법">Xcode 간단한 사용법</h2>
<ul>
<li>애플 개발자 사이트 또는 맥 앱스토어에서 Xcode 설치를 진행하고, 실행한다.</li>
<li>그러면 다음과 같은 화면이 나타난다.</li>
<li>새로운 프로젝트 생성을 위해 'Create a new Xcode project'를 선택한다.</li>
<li>앱을 만들기 위한 템플릿 설정이 나온다.</li>
<li>우선, 가장 간단한 'Single View Application'을 선택해본다.</li>
<li>그러면 다음과 같이 템플릿이 설정되고 프로젝트에 대한 정보를 입력하는 창이 나타난다.</li>
<li>'Product Name'에는 임의로 원하는 이름을 입력한다.</li>
<li>나머지 옵션도 일단 테스트를 위한 프로젝트인만큼 원하는대로 설정한다.</li>
<li>단, Language는 반드시 Swift로 설정하고 Next를 눌러 다음으로 넘어가면,</li>
<li>저장 위치를 설정하는 화면이 나타난다.</li>
<li>여기서는 'Create Git repository on' 옵션해제 하는것만 주의하면 된다.</li>
<li>나중에 깃이라는 시스템을 활용할때만 필요한 옵션이기 때문이다.</li>
<li>개발할 수 있는 화면이 나타난다.</li>
<li>작업 환경은 크게 윗네부분을 '툴바', 왼쪽 부분을 '네비게이터',</li>
<li>가운데 메인 부분을 '에디터', 오른쪽 부분을 '유틸리티',</li>
<li>가운데 부분을 '디버그 공간'이라고 한다.</li>
</ul>
<p><img src="/images/swift-xcode-usage-1.png" alt="swift-xcode-usage"></p>
<ul>
<li>Xcode는 대략적으로 이렇게 생겼다.</li>
<li>이번 글에서는 Xcode에 대해 이쯤만 알아두고,</li>
<li>실제로 어플을 만들어야 할 때 본격적으로 알아보도록 하겠다.</li>
</ul>
<h2 id="더-많은-스위프트-반복문-예제">더 많은 스위프트 반복문 예제</h2>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token comment">// 윤년 구하는 문제</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">check</span><span class="token punctuation">(</span>leapYear<span class="token punctuation">:</span><span class="token class-name">Int</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">String</span>
</span><span class="code-line"><span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">if</span> leapYear <span class="token operator">%</span> <span class="token number">4</span> <span class="token operator">==</span> <span class="token number">0</span>
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">if</span> leapYear <span class="token operator">%</span> <span class="token number">100</span> <span class="token operator">==</span> <span class="token number">0</span>
</span><span class="code-line">        <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">if</span> leapYear <span class="token operator">%</span> <span class="token number">400</span> <span class="token operator">==</span> <span class="token number">0</span>
</span><span class="code-line">            <span class="token punctuation">{</span>
</span><span class="code-line">                <span class="token keyword">return</span> <span class="token string-literal"><span class="token string">"</span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">leapYear</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">년은 윤년입니다."</span></span>
</span><span class="code-line">            <span class="token punctuation">}</span> <span class="token keyword">else</span>
</span><span class="code-line">            <span class="token punctuation">{</span>
</span><span class="code-line">                <span class="token keyword">return</span> <span class="token string-literal"><span class="token string">"</span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">leapYear</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">년은 윤년이 아닙니다."</span></span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">}</span> <span class="token keyword">else</span>
</span><span class="code-line">        <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">return</span> <span class="token string-literal"><span class="token string">"</span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">leapYear</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">년은 윤년입니다."</span></span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span> <span class="token keyword">else</span>
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">return</span> <span class="token string-literal"><span class="token string">"</span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">leapYear</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">년은 윤년이 아닙니다."</span></span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token function">print</span><span class="token punctuation">(</span><span class="token function">check</span><span class="token punctuation">(</span>leapYear<span class="token punctuation">:</span> <span class="token number">400</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line">    
</span><span class="code-line">    
</span><span class="code-line"><span class="token comment">// 각 자리수 더하는 함수</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">addAllDigit</span><span class="token punctuation">(</span>num<span class="token punctuation">:</span><span class="token class-name">Int</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Int</span>
</span><span class="code-line"><span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> returnValue<span class="token punctuation">:</span><span class="token class-name">Int</span> <span class="token operator">=</span> <span class="token number">0</span>
</span><span class="code-line">    <span class="token keyword">var</span> doubleNum<span class="token punctuation">:</span><span class="token class-name">Int</span> <span class="token operator">=</span> num
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">while</span> doubleNum <span class="token operator">></span> <span class="token number">0</span>
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">        returnValue <span class="token operator">=</span> returnValue <span class="token operator">+</span> <span class="token punctuation">(</span>doubleNum <span class="token operator">%</span> <span class="token number">10</span><span class="token punctuation">)</span>
</span><span class="code-line">        doubleNum <span class="token operator">=</span> doubleNum <span class="token operator">/</span> <span class="token number">10</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">return</span> returnValue
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token function">print</span><span class="token punctuation">(</span><span class="token function">addAllDigit</span><span class="token punctuation">(</span>num<span class="token punctuation">:</span> <span class="token number">5792</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line">    
</span><span class="code-line">    
</span><span class="code-line"><span class="token comment">// 숫자 리버스 함수</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">reverse</span><span class="token punctuation">(</span>num<span class="token punctuation">:</span><span class="token class-name">Int</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Int</span>
</span><span class="code-line"><span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> returnValue<span class="token punctuation">:</span><span class="token class-name">Int</span> <span class="token operator">=</span> <span class="token number">0</span>
</span><span class="code-line">    <span class="token keyword">var</span> doubleNum<span class="token punctuation">:</span><span class="token class-name">Int</span> <span class="token operator">=</span> num
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">while</span> doubleNum <span class="token operator">></span> <span class="token number">0</span>
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">        returnValue <span class="token operator">=</span> returnValue <span class="token operator">*</span> <span class="token number">10</span>
</span><span class="code-line">        returnValue <span class="token operator">=</span> returnValue <span class="token operator">+</span> doubleNum <span class="token operator">%</span> <span class="token number">10</span>
</span><span class="code-line">        doubleNum <span class="token operator">=</span> doubleNum <span class="token operator">/</span> <span class="token number">10</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">return</span> returnValue
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token function">print</span><span class="token punctuation">(</span><span class="token function">reverse</span><span class="token punctuation">(</span>num<span class="token punctuation">:</span> <span class="token number">1234</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line">    
</span><span class="code-line">    
</span><span class="code-line"><span class="token comment">// 별 그리기</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">drawStar</span><span class="token punctuation">(</span>line<span class="token punctuation">:</span><span class="token class-name">Int</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> value<span class="token punctuation">:</span><span class="token class-name">String</span> <span class="token operator">=</span> <span class="token string-literal"><span class="token string">""</span></span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">for</span> index <span class="token keyword">in</span> <span class="token number">1</span><span class="token operator">...</span>line
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">for</span> <span class="token omit keyword">_</span> <span class="token keyword">in</span> index<span class="token operator">..&#x3C;</span>line
</span><span class="code-line">        <span class="token punctuation">{</span>
</span><span class="code-line">            value <span class="token operator">=</span> value <span class="token operator">+</span> <span class="token string-literal"><span class="token string">" "</span></span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token keyword">for</span> <span class="token omit keyword">_</span> <span class="token keyword">in</span> <span class="token number">1</span><span class="token operator">...</span><span class="token punctuation">(</span>index <span class="token operator">*</span> <span class="token number">2</span> <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token punctuation">{</span>
</span><span class="code-line">            value <span class="token operator">=</span> value <span class="token operator">+</span> <span class="token string-literal"><span class="token string">"*"</span></span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        
</span><span class="code-line">        <span class="token function">print</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span>
</span><span class="code-line">        value <span class="token operator">=</span> <span class="token string-literal"><span class="token string">""</span></span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token function">drawStar</span><span class="token punctuation">(</span>line<span class="token punctuation">:</span> <span class="token number">5</span><span class="token punctuation">)</span>
</span></code></pre>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swift-collection-types</guid>
      <title>Swift Collection Types</title>
      <description>Swift의 Collection Types에 대해 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/swift-collection-types</link>
      <pubDate>Mon, 21 Aug 2017 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>Swift의 Collection Types에 대해서 알아보겠다.</li>
</ul>
<h2 id="swift-collection-types">Swift Collection Types</h2>
<ul>
<li>Swift Collection Types에는 3가지 종류가 있다.</li>
<li>'배열', '집합', '사전'이 그 주인공이다.</li>
<li>각 콜렉션 타입의 대략적인 구도는 다음 사진과 같다.</li>
</ul>
<p><img src="/images/swift-collection-types-1.png" alt="swift-collection-types"></p>
<h2 id="swift-배열">Swift 배열</h2>
<ul>
<li>하나씩 자세히 알아보겠다.</li>
<li>배열은 인덱스와 그에에 대응하는 데이터로 이뤄진 자료 구조를 의미한다.</li>
<li>배열의 기본 문법은 다음과 같다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">var</span> someInts<span class="token punctuation">:</span><span class="token class-name">Array</span><span class="token operator">&#x3C;</span><span class="token class-name">Int</span><span class="token operator">></span> <span class="token operator">=</span> <span class="token class-name">Array</span><span class="token operator">&#x3C;</span><span class="token class-name">Int</span><span class="token operator">></span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>하지만 배열을 나타낼때 기본 문법을 축약해서도 나타낼수 있고, 이를 더 많이 사용한다.</li>
<li>축약 문법은 다음과 같다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">var</span> someInts<span class="token punctuation">:</span><span class="token punctuation">[</span><span class="token class-name">Int</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token class-name">Int</span><span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>배열 리터럴 문법은 대괄호를 사용하고, 다음과 같이 사용할 수 있다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">var</span> someInts<span class="token punctuation">:</span><span class="token punctuation">[</span><span class="token class-name">Int</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">]</span>
</span></code></pre>
<ul>
<li>한편, 배열의 인덱스는 0부터 시작하고, 인덱스를 통해 배열의 값을 가져올 수 있다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">var</span> someInts<span class="token punctuation">:</span><span class="token punctuation">[</span><span class="token class-name">Int</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">]</span> 
</span><span class="code-line">
</span><span class="code-line"><span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"</span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">someInts<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span></span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token comment">//1이 출력됩니다.</span>
</span></code></pre>
<h2 id="swift-집합">Swift 집합</h2>
<ul>
<li>스위프트 집합은 같은 타입의 데이터가 순서 없이 모여있는 자료구조이다.</li>
<li>집합의 문법은 다음과 같다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">var</span> someInts<span class="token punctuation">:</span><span class="token class-name">Set</span><span class="token operator">&#x3C;</span><span class="token class-name">Int</span><span class="token operator">></span> <span class="token operator">=</span> <span class="token class-name">Set</span><span class="token operator">&#x3C;</span><span class="token class-name">Int</span><span class="token operator">></span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>집합은 배열과 달리 축약 문법이 없고, 배열과 같은 리터럴 문법을 사용한다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">var</span> someInts<span class="token punctuation">:</span><span class="token class-name">Set</span><span class="token operator">&#x3C;</span><span class="token class-name">Int</span><span class="token operator">></span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">,</span><span class="token number">4</span><span class="token punctuation">]</span>
</span></code></pre>
<ul>
<li>집합에는 연산이 있다는 장점이 있다.</li>
<li>다음과 같은 연산을 할 수 있습니다.</li>
</ul>
<p><img src="/images/swift-collection-types-2.png" alt="swift-collection-types"></p>
<ul>
<li>집합 Set 연산의 사용 예시는 다음과 같다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">var</span> oddDigits <span class="token punctuation">:</span> <span class="token class-name">Set</span> <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">9</span> <span class="token punctuation">]</span> 
</span><span class="code-line"><span class="token keyword">let</span> evenDigits <span class="token punctuation">:</span> <span class="token class-name">Set</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">]</span> 
</span><span class="code-line"><span class="token keyword">let</span> primeDigits <span class="token punctuation">:</span> <span class="token class-name">Set</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">]</span> 
</span><span class="code-line">    
</span><span class="code-line">oddDigits<span class="token punctuation">.</span><span class="token function">intersection</span><span class="token punctuation">(</span>evenDigits<span class="token punctuation">)</span> 
</span><span class="code-line">oddDigits<span class="token punctuation">.</span><span class="token function">symmetricDifference</span><span class="token punctuation">(</span>primeDigits<span class="token punctuation">)</span>
</span></code></pre>
<h2 id="swift-딕셔너리">Swift 딕셔너리</h2>
<ul>
<li>Swift 딕셔너리 순서가 정해져 있지 않은 데이터에,</li>
<li>키 값을 통해 구분할 수 있는 자료구조이다.</li>
<li>Dictionary의 문법은 다음과 같다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">var</span> someInts<span class="token punctuation">:</span><span class="token class-name">Dictionary</span><span class="token operator">&#x3C;</span><span class="token class-name">String</span><span class="token punctuation">,</span><span class="token class-name">Int</span><span class="token operator">></span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token class-name">String</span><span class="token punctuation">:</span><span class="token class-name">Int</span><span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>Dictionary의 축약 문법은 다음과 같다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">var</span> someInts<span class="token punctuation">:</span><span class="token punctuation">[</span><span class="token class-name">String</span><span class="token punctuation">:</span><span class="token class-name">Int</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token class-name">String</span><span class="token punctuation">:</span><span class="token class-name">Int</span><span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span></code></pre>
<ul>
<li>Dictionary의 리터럴 문법은 다음과 같다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">var</span> airports<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">String</span><span class="token punctuation">:</span><span class="token class-name">String</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string-literal"><span class="token string">"ICH"</span></span><span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"인천공항"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"CJU"</span></span><span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"제주공항"</span></span><span class="token punctuation">]</span>
</span></code></pre>
<ul>
<li>Dictionary의 데이터는 키 값을 통해 불러올 수 있다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">var</span> airports<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">String</span><span class="token punctuation">:</span><span class="token class-name">String</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string-literal"><span class="token string">"ICH"</span></span><span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"인천공항"</span></span><span class="token punctuation">]</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"</span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">airports<span class="token punctuation">[</span><span class="token string-literal"><span class="token string">"ICH"</span></span><span class="token punctuation">]</span></span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token comment">//인천공항 을 출력.</span>
</span></code></pre>
<h2 id="여태까지-개념을-이용한-스위프트-예제">여태까지 개념을 이용한 스위프트 예제</h2>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token comment">// 요일 구하기    </span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">getWeekDay</span><span class="token punctuation">(</span>atMonth<span class="token punctuation">:</span> <span class="token class-name">Int</span><span class="token punctuation">,</span> day<span class="token punctuation">:</span> <span class="token class-name">Int</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">String</span>
</span><span class="code-line"><span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> week<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">String</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string-literal"><span class="token string">"Sat"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"Sun"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"Mon"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"Tues"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"Wed"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"Thur"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"Fri"</span></span><span class="token punctuation">]</span>
</span><span class="code-line">    <span class="token keyword">var</span> value<span class="token punctuation">:</span> <span class="token class-name">Int</span> <span class="token operator">=</span> <span class="token number">0</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">if</span> atMonth <span class="token operator">==</span> <span class="token number">1</span>
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">        value <span class="token operator">=</span> day
</span><span class="code-line">    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> atMonth <span class="token operator">==</span> <span class="token number">2</span>
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">        value <span class="token operator">=</span> <span class="token number">31</span> <span class="token operator">+</span> day
</span><span class="code-line">    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> atMonth <span class="token operator">==</span> <span class="token number">3</span>
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">        value <span class="token operator">=</span> <span class="token number">59</span> <span class="token operator">+</span> day
</span><span class="code-line">    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> atMonth <span class="token operator">==</span> <span class="token number">4</span>
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">        value <span class="token operator">=</span> <span class="token number">90</span> <span class="token operator">+</span> day
</span><span class="code-line">    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> atMonth <span class="token operator">==</span> <span class="token number">5</span>
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">        value <span class="token operator">=</span> <span class="token number">120</span> <span class="token operator">+</span> day
</span><span class="code-line">    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> atMonth <span class="token operator">==</span> <span class="token number">6</span>
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">        value <span class="token operator">=</span> <span class="token number">151</span> <span class="token operator">+</span> day
</span><span class="code-line">    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> atMonth <span class="token operator">==</span> <span class="token number">7</span>
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">        value <span class="token operator">=</span> <span class="token number">181</span> <span class="token operator">+</span> day
</span><span class="code-line">    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> atMonth <span class="token operator">==</span> <span class="token number">8</span>
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">        value <span class="token operator">=</span> <span class="token number">212</span> <span class="token operator">+</span> day
</span><span class="code-line">    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> atMonth <span class="token operator">==</span> <span class="token number">9</span>
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">        value <span class="token operator">=</span> <span class="token number">243</span> <span class="token operator">+</span> day
</span><span class="code-line">    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> atMonth <span class="token operator">==</span> <span class="token number">10</span>
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">        value <span class="token operator">=</span> <span class="token number">273</span> <span class="token operator">+</span> day
</span><span class="code-line">    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> atMonth <span class="token operator">==</span> <span class="token number">11</span>
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">        value <span class="token operator">=</span> <span class="token number">304</span> <span class="token operator">+</span> day
</span><span class="code-line">    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> atMonth <span class="token operator">==</span> <span class="token number">12</span>
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">        value <span class="token operator">=</span> <span class="token number">334</span> <span class="token operator">+</span> day
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">return</span> week<span class="token punctuation">[</span>value <span class="token operator">%</span> <span class="token number">7</span><span class="token punctuation">]</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token function">print</span><span class="token punctuation">(</span><span class="token function">getWeekDay</span><span class="token punctuation">(</span>atMonth<span class="token punctuation">:</span> <span class="token number">9</span><span class="token punctuation">,</span> day<span class="token punctuation">:</span> <span class="token number">7</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line">    
</span><span class="code-line">    
</span><span class="code-line"><span class="token comment">// 중복 숫자 줄이기</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">shoter</span><span class="token punctuation">(</span>num<span class="token punctuation">:</span> <span class="token class-name">Int</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">String</span>
</span><span class="code-line"><span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> num <span class="token operator">=</span> num
</span><span class="code-line">    <span class="token keyword">var</span> list<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">Int</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
</span><span class="code-line">    <span class="token keyword">var</span> value<span class="token punctuation">:</span> <span class="token class-name">String</span> <span class="token operator">=</span> <span class="token string-literal"><span class="token string">""</span></span>
</span><span class="code-line">    <span class="token keyword">var</span> count<span class="token punctuation">:</span> <span class="token class-name">Int</span> <span class="token operator">=</span> <span class="token number">0</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">while</span> num <span class="token operator">></span> <span class="token number">0</span>
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">        list<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>num <span class="token operator">%</span> <span class="token number">10</span><span class="token punctuation">)</span>
</span><span class="code-line">        num <span class="token operator">=</span> num <span class="token operator">/</span> <span class="token number">10</span>
</span><span class="code-line">        count <span class="token operator">=</span> count <span class="token operator">+</span> <span class="token number">1</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">for</span> index <span class="token keyword">in</span> <span class="token number">0</span><span class="token operator">..&#x3C;</span><span class="token punctuation">(</span>count <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">if</span> index <span class="token operator">==</span> count <span class="token operator">-</span> <span class="token number">2</span>
</span><span class="code-line">        <span class="token punctuation">{</span>
</span><span class="code-line">            value <span class="token operator">=</span> <span class="token class-name">String</span><span class="token punctuation">(</span>list<span class="token punctuation">[</span>index<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">+</span> value
</span><span class="code-line">        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> list<span class="token punctuation">[</span>index<span class="token punctuation">]</span> <span class="token operator">==</span> list<span class="token punctuation">[</span>index <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">]</span>
</span><span class="code-line">        <span class="token punctuation">{</span>
</span><span class="code-line">           
</span><span class="code-line">        <span class="token punctuation">}</span> <span class="token keyword">else</span>
</span><span class="code-line">        <span class="token punctuation">{</span>
</span><span class="code-line">            value <span class="token operator">=</span> <span class="token class-name">String</span><span class="token punctuation">(</span>list<span class="token punctuation">[</span>index<span class="token punctuation">]</span><span class="token punctuation">)</span> <span class="token operator">+</span> value
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">return</span> value
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token function">print</span><span class="token punctuation">(</span><span class="token function">shoter</span><span class="token punctuation">(</span>num<span class="token punctuation">:</span> <span class="token number">112233355</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line">    
</span><span class="code-line">    
</span><span class="code-line"><span class="token comment">// 소수 찾기</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">allPrimeNumber</span><span class="token punctuation">(</span>endNum<span class="token punctuation">:</span> <span class="token class-name">Int</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Array</span><span class="token operator">&#x3C;</span><span class="token class-name">Int</span><span class="token operator">></span>
</span><span class="code-line"><span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> list<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">Int</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
</span><span class="code-line">    <span class="token keyword">var</span> num<span class="token punctuation">:</span> <span class="token class-name">Int</span> <span class="token operator">=</span> <span class="token number">2</span>
</span><span class="code-line">    <span class="token keyword">var</span> index<span class="token punctuation">:</span> <span class="token class-name">Int</span> <span class="token operator">=</span> <span class="token number">0</span>
</span><span class="code-line">    <span class="token keyword">var</span> comp<span class="token punctuation">:</span> <span class="token class-name">Int</span> <span class="token operator">=</span> <span class="token number">1</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">for</span> <span class="token omit keyword">_</span> <span class="token keyword">in</span> <span class="token number">0</span><span class="token operator">...</span><span class="token punctuation">(</span>endNum <span class="token operator">-</span> <span class="token number">2</span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">        list<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>num<span class="token punctuation">)</span>
</span><span class="code-line">        num <span class="token operator">=</span> num <span class="token operator">+</span> <span class="token number">1</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">while</span> index <span class="token operator">&#x3C;</span> list<span class="token punctuation">.</span>count
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">while</span> comp <span class="token operator">&#x3C;</span> list<span class="token punctuation">.</span>count
</span><span class="code-line">        <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">if</span> list<span class="token punctuation">[</span>comp<span class="token punctuation">]</span> <span class="token operator">%</span> list<span class="token punctuation">[</span>index<span class="token punctuation">]</span> <span class="token operator">==</span> <span class="token number">0</span>
</span><span class="code-line">            <span class="token punctuation">{</span>
</span><span class="code-line">                list<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span>at<span class="token punctuation">:</span> comp<span class="token punctuation">)</span>
</span><span class="code-line">            <span class="token punctuation">}</span> <span class="token keyword">else</span>
</span><span class="code-line">            <span class="token punctuation">{</span>
</span><span class="code-line">                comp <span class="token operator">=</span> comp <span class="token operator">+</span> <span class="token number">1</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">        
</span><span class="code-line">        index <span class="token operator">=</span> index <span class="token operator">+</span> <span class="token number">1</span>
</span><span class="code-line">        comp <span class="token operator">=</span> index <span class="token operator">+</span> <span class="token number">1</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">return</span> list
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token function">print</span><span class="token punctuation">(</span><span class="token function">allPrimeNumber</span><span class="token punctuation">(</span>endNum<span class="token punctuation">:</span> <span class="token number">30</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line">    
</span><span class="code-line">    
</span><span class="code-line"><span class="token comment">// 시저 암호</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">ceasar</span><span class="token punctuation">(</span>data<span class="token punctuation">:</span> <span class="token class-name">Array</span><span class="token operator">&#x3C;</span><span class="token class-name">String</span><span class="token operator">></span><span class="token punctuation">,</span> keyNum<span class="token punctuation">:</span> <span class="token class-name">Int</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Array</span><span class="token operator">&#x3C;</span><span class="token class-name">String</span><span class="token operator">></span>
</span><span class="code-line"><span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> list<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">String</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>
</span><span class="code-line">    <span class="token keyword">var</span> alphabet<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">String</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string-literal"><span class="token string">"a"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"b"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"c"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"d"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"e"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"f"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"g"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"h"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"i"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"j"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"k"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"l"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"m"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"n"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"o"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"p"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"q"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"r"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"s"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"t"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"u"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"v"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"w"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"x"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"y"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"z"</span></span><span class="token punctuation">]</span>
</span><span class="code-line">    <span class="token keyword">var</span> <span class="token class-name">Alphabet</span><span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token class-name">String</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string-literal"><span class="token string">"A"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"B"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"C"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"D"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"E"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"F"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"G"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"H"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"I"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"J"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"K"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"L"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"M"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"N"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"O"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"P"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"Q"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"R"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"S"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"T"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"U"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"V"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"W"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"X"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"Y"</span></span><span class="token punctuation">,</span> <span class="token string-literal"><span class="token string">"Z"</span></span><span class="token punctuation">]</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">for</span> num <span class="token keyword">in</span> <span class="token number">0</span><span class="token operator">..&#x3C;</span>data<span class="token punctuation">.</span>count
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">for</span> index <span class="token keyword">in</span> <span class="token number">0</span><span class="token operator">..&#x3C;</span>alphabet<span class="token punctuation">.</span>count
</span><span class="code-line">        <span class="token punctuation">{</span>
</span><span class="code-line">            <span class="token keyword">var</span> index <span class="token operator">=</span> index
</span><span class="code-line">            <span class="token keyword">if</span> data<span class="token punctuation">[</span>num<span class="token punctuation">]</span> <span class="token operator">==</span> alphabet<span class="token punctuation">[</span>index<span class="token punctuation">]</span>
</span><span class="code-line">            <span class="token punctuation">{</span>
</span><span class="code-line">                <span class="token keyword">if</span> <span class="token punctuation">(</span>index <span class="token operator">+</span> keyNum<span class="token punctuation">)</span> <span class="token operator">></span> <span class="token number">25</span>
</span><span class="code-line">                <span class="token punctuation">{</span>
</span><span class="code-line">                    index <span class="token operator">=</span> index <span class="token operator">-</span> <span class="token number">26</span>
</span><span class="code-line">                    list<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>alphabet<span class="token punctuation">[</span>index <span class="token operator">+</span> keyNum<span class="token punctuation">]</span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token punctuation">}</span> <span class="token keyword">else</span>
</span><span class="code-line">                <span class="token punctuation">{</span>
</span><span class="code-line">                    list<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>alphabet<span class="token punctuation">[</span>index <span class="token operator">+</span> keyNum<span class="token punctuation">]</span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token punctuation">}</span>
</span><span class="code-line">            <span class="token punctuation">}</span><span class="token keyword">else</span> <span class="token keyword">if</span> data<span class="token punctuation">[</span>num<span class="token punctuation">]</span> <span class="token operator">==</span> <span class="token class-name">Alphabet</span><span class="token punctuation">[</span>index<span class="token punctuation">]</span>
</span><span class="code-line">            <span class="token punctuation">{</span>
</span><span class="code-line">                <span class="token keyword">if</span> <span class="token punctuation">(</span>index <span class="token operator">+</span> keyNum<span class="token punctuation">)</span> <span class="token operator">></span> <span class="token number">25</span>
</span><span class="code-line">                <span class="token punctuation">{</span>
</span><span class="code-line">                    index <span class="token operator">=</span> index <span class="token operator">-</span> <span class="token number">26</span>
</span><span class="code-line">                    list<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span><span class="token class-name">Alphabet</span><span class="token punctuation">[</span>index <span class="token operator">+</span> keyNum<span class="token punctuation">]</span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token punctuation">}</span> <span class="token keyword">else</span>
</span><span class="code-line">                <span class="token punctuation">{</span>
</span><span class="code-line">                    list<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span><span class="token class-name">Alphabet</span><span class="token punctuation">[</span>index <span class="token operator">+</span> keyNum<span class="token punctuation">]</span><span class="token punctuation">)</span>
</span><span class="code-line">                <span class="token punctuation">}</span>
</span><span class="code-line">            <span class="token punctuation">}</span>
</span><span class="code-line">        <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">return</span> list
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token function">print</span><span class="token punctuation">(</span><span class="token function">ceasar</span><span class="token punctuation">(</span>data<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string-literal"><span class="token string">"a"</span></span><span class="token punctuation">,</span><span class="token string-literal"><span class="token string">"D"</span></span><span class="token punctuation">,</span><span class="token string-literal"><span class="token string">"x"</span></span><span class="token punctuation">]</span><span class="token punctuation">,</span> keyNum<span class="token punctuation">:</span> <span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span></code></pre>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swift-loop-function</guid>
      <title>Swift 반복문과 함수</title>
      <description>Swift의 반복문과 함수에 대해서 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/swift-loop-function</link>
      <pubDate>Sun, 20 Aug 2017 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li><a href="/blog/swift-variable-if-else/">지난 글에서 스위프트의 변수와 조건문</a>에 대해 알아본데에 이어</li>
<li>스위프트의 반복문과 함수에 대해서 알아보겠다.</li>
</ul>
<h2 id="반복문이란">반복문이란?</h2>
<p><img src="/images/swift-loop-function-1.png" alt="swift-loop-function"></p>
<ul>
<li>반복문이란 반복적으로 코드가 실행되게 만드는 구문을 말한다.</li>
<li>스위프트에는 while 문과 for-in 문이 대표적이다.</li>
</ul>
<h2 id="while-문">while 문</h2>
<ul>
<li>while 문의 문법은 다음과 같고,</li>
<li>해당 조건이 참일 경우에만 코드가 반복해서 실행된다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">while</span> 조건
</span><span class="code-line"><span class="token punctuation">{</span>
</span><span class="code-line">	<span class="token comment">//실행 코드</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="while-문-예제">while 문 예제</h2>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token comment">//실습 구구단</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token keyword">var</span> dan<span class="token punctuation">:</span><span class="token class-name">Int</span> <span class="token operator">=</span> <span class="token number">3</span>
</span><span class="code-line"><span class="token keyword">var</span> gugu<span class="token punctuation">:</span><span class="token class-name">Int</span> <span class="token operator">=</span> <span class="token number">1</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token keyword">while</span> gugu <span class="token operator">&#x3C;</span> <span class="token number">10</span>
</span><span class="code-line"><span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> value <span class="token operator">=</span> gugu <span class="token operator">*</span> dan
</span><span class="code-line">    <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"3 x </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">gugu</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string"> = </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">value</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    gugu <span class="token operator">=</span> gugu <span class="token operator">+</span> <span class="token number">1</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line">    
</span><span class="code-line">    
</span><span class="code-line"><span class="token comment">//실습 삼각수</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token keyword">var</span> inputValue<span class="token punctuation">:</span><span class="token class-name">Int</span> <span class="token operator">=</span> <span class="token number">15</span>
</span><span class="code-line"><span class="token keyword">var</span> totalNum<span class="token punctuation">:</span><span class="token class-name">Int</span> <span class="token operator">=</span> <span class="token number">0</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token keyword">while</span> inputValue <span class="token operator">></span> <span class="token number">0</span>
</span><span class="code-line"><span class="token punctuation">{</span>
</span><span class="code-line">    totalNum <span class="token operator">=</span> totalNum <span class="token operator">+</span> inputValue
</span><span class="code-line">    inputValue <span class="token operator">=</span> inputValue <span class="token operator">-</span> <span class="token number">1</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token function">print</span><span class="token punctuation">(</span>totalNum<span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line">    
</span><span class="code-line">    
</span><span class="code-line"><span class="token comment">//실습 삼각수</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token keyword">var</span> inputValue<span class="token punctuation">:</span><span class="token class-name">Int</span> <span class="token operator">=</span> <span class="token number">14</span>
</span><span class="code-line"><span class="token keyword">var</span> totalNum<span class="token punctuation">:</span><span class="token class-name">Int</span> <span class="token operator">=</span> <span class="token number">0</span>
</span><span class="code-line">    
</span><span class="code-line">totalNum <span class="token operator">=</span> inputValue <span class="token operator">*</span> <span class="token punctuation">(</span>inputValue <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token operator">/</span> <span class="token number">2</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token function">print</span><span class="token punctuation">(</span>totalNum<span class="token punctuation">)</span>
</span></code></pre>
<h2 id="for-in-문">for-in 문</h2>
<ul>
<li>for-in 문을 알아보기에 앞서 범위 연산자에 대해서 알아보자.</li>
<li>범위 연산자는 <code>a...b</code> 또는 <code>a..&#x3C;b</code> 으로 표현된다.</li>
<li>첫 번째는 a~b까지 정수형 숫자를 의미하고,</li>
<li>두 번째는 a~b-1까지 정수형 숫자를 의미한다.</li>
<li>스위프트에서는 다른 언어에서는 흔히 사용되는 for문 대신, for-in 문을 사용한다.</li>
<li>문법이 다음과 같다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">for</span> element <span class="token keyword">in</span> sequenceData
</span><span class="code-line"><span class="token punctuation">{</span>
</span><span class="code-line">	<span class="token comment">//실행 코드</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="for-in-문-예제">for-in 문 예제</h2>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token comment">// 실습 구구단</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token keyword">for</span> gugu <span class="token keyword">in</span> <span class="token number">1</span><span class="token operator">...</span><span class="token number">9</span>
</span><span class="code-line"><span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">for</span> dan <span class="token keyword">in</span> <span class="token number">1</span><span class="token operator">...</span><span class="token number">9</span>
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"</span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">gugu</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string"> x </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">dan</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string"> = </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">gugu<span class="token operator">*</span>dan</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line">    <span class="token function">print</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="스위프트-함수">스위프트 함수</h2>
<ul>
<li>함수는 작은 단위의 프로그램 즉, 명령문의 묶음이다.</li>
<li>프로그래밍에서 함수를 사용하는 이유는 간단하다.</li>
<li>코드 재사용으로 인해 시간, 메모리 공간, 크기를 절약 할 수 있고,</li>
<li>가독성 및 유지보수가 우수하기 때문이다.</li>
</ul>
<h2 id="함수의-구조와-문법">함수의 구조와 문법</h2>
<ul>
<li>함수의 구조는 다음과 같다.</li>
</ul>
<p><img src="/images/swift-loop-function-2.png" alt="swift-loop-function"></p>
<ul>
<li>함수의 문법은 다음과 같습니다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">fName</span><span class="token punctuation">(</span>paramName<span class="token punctuation">:</span>type<span class="token punctuation">)</span> <span class="token operator">-></span> type 
</span><span class="code-line"><span class="token punctuation">{</span>
</span><span class="code-line">	<span class="token comment">//실행될 명령어 작성 return 반환값</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<h2 id="스위프트-함수-예제">스위프트 함수 예제</h2>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token comment">// 덧셈</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">add</span><span class="token punctuation">(</span>num1<span class="token punctuation">:</span><span class="token class-name">Int</span><span class="token punctuation">,</span> num2<span class="token punctuation">:</span><span class="token class-name">Int</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Int</span>
</span><span class="code-line"><span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">return</span> num1 <span class="token operator">+</span> num2
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token function">print</span><span class="token punctuation">(</span><span class="token function">add</span><span class="token punctuation">(</span>num1<span class="token punctuation">:</span><span class="token number">2</span><span class="token punctuation">,</span> num2<span class="token punctuation">:</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line">    
</span><span class="code-line">    
</span><span class="code-line"><span class="token comment">// 나눗셈</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">divide</span><span class="token punctuation">(</span>num1<span class="token punctuation">:</span><span class="token class-name">Int</span><span class="token punctuation">,</span> num2<span class="token punctuation">:</span><span class="token class-name">Int</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">String</span>
</span><span class="code-line"><span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">if</span> num2 <span class="token operator">==</span> <span class="token number">0</span>
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">return</span> <span class="token string-literal"><span class="token string">"num2에 0이외의 값을 넣어주세요"</span></span>
</span><span class="code-line">    <span class="token punctuation">}</span> <span class="token keyword">else</span>
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token keyword">return</span> <span class="token string-literal"><span class="token string">"</span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">num1 <span class="token operator">/</span> num2</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string">"</span></span>
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token function">print</span><span class="token punctuation">(</span><span class="token function">divide</span><span class="token punctuation">(</span>num1<span class="token punctuation">:</span><span class="token number">10</span><span class="token punctuation">,</span> num2<span class="token punctuation">:</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token function">print</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line">    
</span><span class="code-line">    
</span><span class="code-line"><span class="token comment">//Square &#x26; Rectangle &#x26; Cube</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">sagac</span><span class="token punctuation">(</span>what<span class="token punctuation">:</span><span class="token class-name">String</span><span class="token punctuation">,</span> width<span class="token punctuation">:</span> <span class="token class-name">Int</span><span class="token punctuation">,</span> height<span class="token punctuation">:</span> <span class="token class-name">Int</span> <span class="token operator">=</span> <span class="token number">2</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Int</span>
</span><span class="code-line"><span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> returnValue<span class="token punctuation">:</span><span class="token class-name">Int</span> <span class="token operator">=</span> <span class="token number">0</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">if</span> what <span class="token operator">==</span> <span class="token string-literal"><span class="token string">"square"</span></span>
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">        returnValue <span class="token operator">=</span> width <span class="token operator">*</span> width
</span><span class="code-line">        <span class="token keyword">return</span> returnValue
</span><span class="code-line">    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> what <span class="token operator">==</span> <span class="token string-literal"><span class="token string">"rectangle"</span></span>
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">        returnValue <span class="token operator">=</span> width <span class="token operator">*</span> height
</span><span class="code-line">        <span class="token keyword">return</span> returnValue
</span><span class="code-line">    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> what <span class="token operator">==</span> <span class="token string-literal"><span class="token string">"cube"</span></span>
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">        returnValue <span class="token operator">=</span> width <span class="token operator">*</span> width <span class="token operator">*</span> width
</span><span class="code-line">        <span class="token keyword">return</span> returnValue
</span><span class="code-line">    <span class="token punctuation">}</span> <span class="token keyword">else</span>
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"try another shape"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token keyword">return</span> returnValue
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token function">print</span><span class="token punctuation">(</span><span class="token function">sagac</span><span class="token punctuation">(</span>what<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"cube"</span></span><span class="token punctuation">,</span> width<span class="token punctuation">:</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line">    
</span><span class="code-line">    
</span><span class="code-line"><span class="token comment">///Circular Cylineder &#x26; Sphere &#x26; Cone</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token keyword">func</span> <span class="token function-definition function">cirhecone</span><span class="token punctuation">(</span>what<span class="token punctuation">:</span> <span class="token class-name">String</span><span class="token punctuation">,</span> r<span class="token punctuation">:</span> <span class="token class-name">Double</span><span class="token punctuation">,</span> h<span class="token punctuation">:</span> <span class="token class-name">Double</span> <span class="token operator">=</span> <span class="token number">2.0</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">Double</span>
</span><span class="code-line"><span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> returnValue<span class="token punctuation">:</span><span class="token class-name">Double</span> <span class="token operator">=</span> <span class="token number">0</span>
</span><span class="code-line">    
</span><span class="code-line">    <span class="token keyword">if</span> what <span class="token operator">==</span> <span class="token string-literal"><span class="token string">"circular"</span></span>
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">        returnValue <span class="token operator">=</span> <span class="token number">3.141592</span> <span class="token operator">*</span> r <span class="token operator">*</span> r <span class="token operator">*</span> h
</span><span class="code-line">        <span class="token keyword">return</span> returnValue
</span><span class="code-line">    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> what <span class="token operator">==</span> <span class="token string-literal"><span class="token string">"sphere"</span></span>
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">        returnValue <span class="token operator">=</span> <span class="token number">3.141592</span> <span class="token operator">*</span> <span class="token punctuation">(</span><span class="token number">4</span><span class="token operator">/</span><span class="token number">3</span><span class="token punctuation">)</span> <span class="token operator">*</span> r <span class="token operator">*</span> r <span class="token operator">*</span> r
</span><span class="code-line">        <span class="token keyword">return</span> returnValue
</span><span class="code-line">    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> what <span class="token operator">==</span> <span class="token string-literal"><span class="token string">"cone"</span></span>
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">        returnValue <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token number">1</span><span class="token operator">/</span><span class="token number">3</span><span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token number">3.141592</span> <span class="token operator">*</span> r <span class="token operator">*</span> r <span class="token operator">*</span> h
</span><span class="code-line">        <span class="token keyword">return</span> returnValue
</span><span class="code-line">    <span class="token punctuation">}</span> <span class="token keyword">else</span>
</span><span class="code-line">    <span class="token punctuation">{</span>
</span><span class="code-line">        <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"try another shape"</span></span><span class="token punctuation">)</span>
</span><span class="code-line">        <span class="token keyword">return</span> returnValue
</span><span class="code-line">    <span class="token punctuation">}</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token function">print</span><span class="token punctuation">(</span><span class="token function">cirhecone</span><span class="token punctuation">(</span>what<span class="token punctuation">:</span> <span class="token string-literal"><span class="token string">"sphere"</span></span><span class="token punctuation">,</span> r<span class="token punctuation">:</span> <span class="token number">4</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
</span></code></pre>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swift-variable-if-else</guid>
      <title>Swift 변수와 if문</title>
      <description>Swift 프로그래밍 언어의 변수와 조건문에 대해 알아봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/swift-variable-if-else</link>
      <pubDate>Fri, 18 Aug 2017 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li><a href="/blog/swift-language/">스위프트 언어 자체</a>에 대해 알아본 데에 이어,</li>
<li>이번 글에서는 스위프트 프로그래밍 언어의 변수와 조건문에 대해 알아보려고 한다.</li>
</ul>
<h2 id="변수란">변수란</h2>
<ul>
<li>스위프트의 변수란 프로그램에서 데이터를 저장하는 공간을 의미한다.</li>
<li>변수는 이름, 형, 메모리 주소, 값, 영역 등으로 특성을 구분 지어 볼 수 있다.</li>
<li>이름은 말 그대로 변수를 구분하기 위해 사용되는 '이름'이다.</li>
<li>형은 타입이라고도 하는데, 데이터의 자료형을 의한다.</li>
<li>값은 변수에 들어가는 데이터를 의미한다.</li>
<li>영역은 변수가 사용 가능한 범위를 의미한다.</li>
</ul>
<h2 id="변수-문법">변수 문법</h2>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">var</span> name<span class="token punctuation">:</span> <span class="token keyword">Type</span> <span class="token operator">=</span> value
</span></code></pre>
<ul>
<li>위 코드에서 var은 변수를 선언하기 위한 키워드이고,</li>
<li>name은 변수명으로써 개발자가 원하는 이름을 임의로 설정할 수 있다.</li>
<li>Type은 변수의 자료형으로 뒤에서 더 자세히 다룰 것이다.</li>
<li>value는 변수에 대입되는 값이다.</li>
</ul>
<h2 id="변수-이름-규칙">변수 이름 규칙</h2>
<ul>
<li>개발자들이 좋은 변수 이름을 짓는 것이 가장 어렵다는 농담을 할 정도로 변수 이름은 중요하다.</li>
<li>변수 이름을 짓는 데에는 규칙이 있다.</li>
<li>우선, 변수의 이름으로 시스템 예약어를 사용할 수 없다.</li>
<li>숫자는 변수의 이름으로 시작될 수 없다.</li>
<li>하지만, 숫자는 변수의 이름에 포함될 수는 있다.</li>
<li>즉, example1은 변수의 이름으로 사용이 가능하지만, 1example은 변수 이름으로 사용할 수 없다.</li>
<li>변수의 이름에는 공백이 포함될 수 없다.</li>
<li>마지막으로 관습적으로 변수 이름은 소문자로 시작되지만 단어를 구분 짓기 위해서는 대문자를 사용한다.</li>
<li>예를 들면, lowerCamelCase 같은 변수 이름이 있다.</li>
</ul>
<h2 id="변수-선언과-할당">변수 선언과 할당</h2>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">var</span> x<span class="token punctuation">:</span> <span class="token class-name">Int</span>
</span></code></pre>
<ul>
<li>위 변수 문법에서 봤듯이 변수는 var이라는 키워드를 통해 선언이 된다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">var</span> x<span class="token punctuation">:</span> <span class="token class-name">Int</span> <span class="token operator">=</span> <span class="token number">3</span>
</span></code></pre>
<ul>
<li>그리고 변수의 값 할당은 대입 연사자인 = 을 통해 할당된다.</li>
</ul>
<h2 id="자료형">자료형</h2>
<ul>
<li>변수의 자료형에는 정수 Int, 실수 Double, 문자열 String, 불리언 Bool을 비롯해서 여럿 있다.</li>
<li>하지만 이 4가지가 가장 대표적이고 많이 쓰인다.</li>
<li>정수 자료형 Int는 정수형 데이터가 사용되는데, +와 -를 포함한 정수 데이터가 사용된다.</li>
<li>불리언 Bool은 true(참), false(거짓) 단 두 가지 값을 갖는 자료형이다.</li>
<li>Double은 실수형 데이터인데, 64비트의 부동소수점을 사용해서 소수점 15자리까지 표현이 가능하다.</li>
<li>String은 문자열이라고도 부르는데, 유니코드로 이뤄져 있고 쌍 따옴표를("") 붙여 문자를 표현한다.</li>
</ul>
<h2 id="변수-vs-상수">변수 vs 상수</h2>
<ul>
<li>사실 변수와 상수의 차이점은 이름에서 그대로 나타난다.</li>
<li>변수는 변할 수 있는 값이고 상수는 변할 수 없는 값이다.</li>
<li>변수는 var 키워드를 통해 선언되고, 상수는 let 키워드를 통해 선언된다.</li>
<li>아래는 번수의 예시이다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">var</span> gender<span class="token punctuation">:</span><span class="token class-name">String</span> <span class="token operator">=</span> <span class="token string-literal"><span class="token string">"boy"</span></span>
</span><span class="code-line"><span class="token keyword">var</span> familyNumber<span class="token punctuation">:</span><span class="token class-name">Int</span> <span class="token operator">=</span> <span class="token number">4</span>
</span><span class="code-line"><span class="token keyword">var</span> hasPet<span class="token punctuation">:</span><span class="token class-name">Bool</span> <span class="token operator">=</span> <span class="token boolean">false</span>
</span><span class="code-line"><span class="token keyword">var</span> speed<span class="token punctuation">:</span><span class="token class-name">Double</span> <span class="token operator">=</span> <span class="token number">11.5</span>
</span></code></pre>
<h2 id="산술-연산자">산술 연산자</h2>
<ul>
<li>+, -, *, /, % 를 산술 연산자라고 한다.</li>
<li>+는 더하기, -는 빼기, *는 곱하기, /는 나누기, %는 나머지를 뜻한다.</li>
</ul>
<h2 id="비교-연산자">비교 연산자</h2>
<ul>
<li>비교 연산자에는 <code>==</code>, <code>>=</code>, <code>&#x3C;=</code>, <code>></code>, <code>&#x3C;</code>등이 있다.</li>
<li><code>==</code>은 같다라는 의미이고, <code>>=</code> 는 크거나 같다, <code>&#x3C;=</code> 는 작거나 같다, <code>></code>는 크다, <code>&#x3C;</code>는 작다이다.</li>
</ul>
<h2 id="논리-연산자">논리 연산자</h2>
<ul>
<li>논리 연산자에는 <code>&#x26;&#x26;</code>, <code>||</code>, <code>!</code> 가 있는데</li>
<li><code>&#x26;&#x26;</code>는 교집합의 의미 즉, 두 조건 다 true 여야 true 값이 반환된다.</li>
<li><code>||</code>는 합집합의 의미로 둘 중 하나가 true 이면 true 값이 반환된다.</li>
<li><code>!</code>는 무조건 반대의 값을 반환된다.</li>
</ul>
<h2 id="조건문">조건문</h2>
<p><img src="/images/swift-variable-if-else-1.png" alt="swift-variable-if-else"></p>
<ul>
<li>조건문은 어떠한 값이 특정 조건에 해당 할 때만 선택적으로 코드를 실행시켜주는데,</li>
<li>대표적으로 if-else 문과 switch-case 문이 있다.</li>
<li>if-else 문의 문법은 다음과 같다.</li>
</ul>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token keyword">if</span> 조건 <span class="token punctuation">{</span>
</span><span class="code-line">	<span class="token comment">//조건이 만족되면 실행</span>
</span><span class="code-line"><span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">	<span class="token comment">//조건이 만족되지 않으면 실행</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span></code></pre>
<ul>
<li>switch-case 문은 스위프트에서 워낙 강력하게 구현되어 있어서 나중에 더 자세히 알아보도록 하겠다.</li>
</ul>
<h2 id="조건문-예시">조건문 예시</h2>
<pre class="language-swift"><code class="language-swift code-highlight"><span class="code-line"><span class="token comment">// 실습 짝수 홀수</span>
</span><span class="code-line"><span class="token keyword">let</span> num<span class="token punctuation">:</span><span class="token class-name">Int</span> <span class="token operator">=</span> <span class="token number">10</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token keyword">var</span> isEvenNumber<span class="token punctuation">:</span><span class="token class-name">Bool</span> 
</span><span class="code-line">    
</span><span class="code-line"><span class="token keyword">if</span> num<span class="token operator">%</span><span class="token number">2</span> <span class="token operator">==</span> <span class="token number">0</span> <span class="token punctuation">{</span>
</span><span class="code-line">    isEvenNumber <span class="token operator">=</span> <span class="token boolean">true</span>    
</span><span class="code-line"><span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">    isEvenNumber <span class="token operator">=</span> <span class="token boolean">false</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token function">print</span><span class="token punctuation">(</span>isEvenNumber<span class="token punctuation">)</span>
</span><span class="code-line">
</span><span class="code-line"><span class="token comment">// 실습 절대값    </span>
</span><span class="code-line"><span class="token keyword">var</span> testNum<span class="token punctuation">:</span><span class="token class-name">Int</span> <span class="token operator">=</span> <span class="token operator">-</span><span class="token number">10</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token keyword">if</span> testNum <span class="token operator">></span> <span class="token number">0</span> <span class="token punctuation">{</span>
</span><span class="code-line">    testNum <span class="token operator">=</span> testNum <span class="token operator">*</span> <span class="token number">1</span>
</span><span class="code-line"><span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">    testNum <span class="token operator">=</span> testNum <span class="token operator">*</span> <span class="token operator">-</span><span class="token number">1</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token function">print</span><span class="token punctuation">(</span>testNum<span class="token punctuation">)</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token comment">// 실습 나눗셈</span>
</span><span class="code-line"><span class="token keyword">var</span> number <span class="token operator">=</span> <span class="token number">10</span>
</span><span class="code-line"><span class="token keyword">var</span> divider <span class="token operator">=</span> <span class="token number">2</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token keyword">if</span> divider <span class="token operator">==</span> <span class="token number">0</span> <span class="token punctuation">{</span>
</span><span class="code-line">  <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"divider의 값을 0이 아닌 값으로 바꿔주세요."</span></span><span class="token punctuation">)</span>  
</span><span class="code-line"><span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
</span><span class="code-line">    <span class="token keyword">var</span> resultNum<span class="token punctuation">:</span><span class="token class-name">Int</span> <span class="token operator">=</span> number <span class="token operator">/</span> divider
</span><span class="code-line">    <span class="token function">print</span><span class="token punctuation">(</span><span class="token string-literal"><span class="token string">"나눈값은 </span><span class="token interpolation-punctuation punctuation">\(</span><span class="token interpolation">resultNum</span><span class="token interpolation-punctuation punctuation">)</span><span class="token string"> 입니다."</span></span><span class="token punctuation">)</span>
</span><span class="code-line"><span class="token punctuation">}</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token comment">// 실습 뺄셈</span>
</span><span class="code-line"><span class="token keyword">var</span> minusNum1<span class="token punctuation">:</span><span class="token class-name">Int</span> <span class="token operator">=</span> <span class="token number">3</span>
</span><span class="code-line"><span class="token keyword">var</span> minusNum2<span class="token punctuation">:</span><span class="token class-name">Int</span> <span class="token operator">=</span> <span class="token number">5</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token keyword">var</span> temp<span class="token punctuation">:</span><span class="token class-name">Int</span>
</span><span class="code-line">    
</span><span class="code-line"><span class="token keyword">if</span> minusNum1 <span class="token operator">&#x3C;</span> minusNum2 <span class="token punctuation">{</span>
</span><span class="code-line">    temp <span class="token operator">=</span> minusNum2
</span><span class="code-line">    minusNum2 <span class="token operator">=</span> minusNum1
</span><span class="code-line">    minusNum1 <span class="token operator">=</span> temp  
</span><span class="code-line"><span class="token punctuation">}</span> 
</span><span class="code-line">    
</span><span class="code-line"><span class="token function">print</span><span class="token punctuation">(</span>minusNum1 <span class="token operator">-</span> minusNum2<span class="token punctuation">)</span>
</span></code></pre>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/swift-language</guid>
      <title>Swift 언어 소개</title>
      <description>Swift 언어 대해 소개해봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/swift-language</link>
      <pubDate>Thu, 17 Aug 2017 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<ul>
<li>프로그래밍 언어, 스위프트를 이해하기 전에, 컴퓨터에 대한 기본적인 이해를 해보자.</li>
</ul>
<h2 id="컴퓨터란-무엇일까">컴퓨터란 무엇일까?</h2>
<ul>
<li>컴퓨터는 어떠한 데이터를 처리해서 사용자가 원하는 정보를 제공해주는 기기이다.</li>
</ul>
<p><img src="/images/swift-language-1.png" alt="swift-and-computer"></p>
<h2 id="컴퓨터-시스템이란">컴퓨터 시스템이란?</h2>
<ul>
<li>컴퓨터는 하드웨어와 소프트웨어로 나눠 볼 수 있다.</li>
</ul>
<p><img src="/images/swift-language-2.png" alt="swift-and-computer"></p>
<h2 id="하드웨어란">하드웨어란?</h2>
<ul>
<li>다시 하드웨어는 메인보드, 파워, CPU, RAM, HDD, 그래픽카드, ODD 등으로 나눠 볼 수 있다.</li>
<li>메인보드는 컴퓨터의 모든 부품을 연결해주는 회로 같은 역할을 한다.</li>
<li>파워는 전원을 공급해주는 역할을 한다.</li>
<li>CPU 컴퓨터의 두뇌 같은 역할을 하고, 중앙 처리 장치라고 부르기도 한다.</li>
<li>컴퓨터의 주요 기능인 연산 처리 작업이 여기서 이뤄진다고 할 수 있다.</li>
<li>RAM은 기억장치 중 하나로써 CPU가 연산 처리를 할 때 값을 임시로 저장하는 역할을 한다.</li>
<li>단, RAM에는 전기가 공급될 때만 저장을 할 수가 있어 전원이 꺼지면 저장된 값이 사라진다.</li>
<li>그래서 HDD라는 또 다른 기억장치가 존재하는 것이다.</li>
<li>HDD에는 전원 없이도 저장을 할 수가 있어서 어떠한 값을 영구적으로 저장할 수 있다.</li>
<li>요즘은 HDD 대신 성능이 좋은 SSD를 사용하기도 한다.</li>
</ul>
<h2 id="소프트웨어란">소프트웨어란?</h2>
<ul>
<li>다시 소프트웨어는 시스템 소프트웨어와 응용 소프트웨어로 나눠볼 수 있다.</li>
<li>운영체제는 시스템 소프트웨어로써 하드웨어와 응용 소프트웨어를 관리한다.</li>
<li>응용 소프트웨어는 응용 프로그램 또는 앱이라는 이름으로 더 많이 들어봤을 것이다.</li>
<li>운영체제에서 실행되는 모든 소프트웨어를 의미한다.</li>
</ul>
<h2 id="프로그램-vs-프로세스">프로그램 vs 프로세스</h2>
<ul>
<li>둘 다 자주 들어본 단어일 것이다.</li>
<li>두 단어는 비슷하면서도 미묘한 차이가 있다.</li>
<li>프로그램은 저장 장치에 저장된 명령어 집합을 의미하는 것이고,</li>
<li>프로세스는 램에서 실행 중인 프로그램을 의미하는 것이다.</li>
</ul>
<h2 id="프로그래밍과-프로그래밍-언어">프로그래밍과 프로그래밍 언어</h2>
<ul>
<li>프로그래밍이란 위에서 다룬 프로그램을 만드는 행위이다.</li>
<li>프로그래밍 언어는 프로그램을 만들기 위해 사용되는 언어체계를 뜻한다.</li>
<li>프로그래밍 언어에는 저급 언어와 고급 언어가 있다.</li>
<li>저급 언어에는 기계어와 어셈블리어가 있다.</li>
<li>기계어는 0과 1로만 이뤄진 언어이고</li>
<li>어셈블리어는 기호로 나타낸 언어로 기계어보다 인간이 더 쉽게 작성할 수 있다.</li>
<li>저급 언어는 하드웨어가 바로 인식할 수 있기 때문에 속도가 빠르지만,</li>
<li>인간이 프로그래밍 하기 어렵다는 단점이 있다.</li>
<li>우리가 일반적으로 알고 있는 프로그래밍 언어가 고급 언어이다.</li>
<li>인간 즉, 개발자가 쉽게 개발하고 작성할 수 있도록 만들어진 언어이다.</li>
<li>결국, 개발자가 고급 언어로 프로그래밍을 하고</li>
<li>컴파일러를 통해 기계어로 변환해서 컴퓨터 하드웨어가 인식하게 되는 것이다.</li>
</ul>
<h2 id="스위프트">스위프트</h2>
<p><img src="/images/swift-language-3.jpg" alt="swift-and-computer"></p>
<ul>
<li>스위프트는 애플이 자사의 제품을 위해 개발한 프로그래밍 언어이다.</li>
<li>기존에 사용하던 프로그래밍 언어인 오브젝티브 C와 공존하기 위해 개발되었다.</li>
<li>하지만 점점 스위프트가 오브젝티브 C를 대체해가는 추세이다.</li>
<li>스위프트는 자연어에 근접한 문법 체계 갖고 있고,</li>
<li>스크립트 언어의 특성을 갖고 있는 등 매우 강력하면서도 유연하다는 특징이 있다.</li>
<li>스위프트는 진입 장벽이 높았던 오브젝티브 C와는 달리, 개발자가 조금 더 쉽게 접근할 수 있도록 개발되었다.</li>
<li>또한, 스위프트를 오픈소스로 공개함에 따라 앱 개발 외의 목적으로도 사용할 수 있다.</li>
</ul>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/apple-music-download-data-save</guid>
      <title>애플뮤직 다운로드 하고 데이터 절약하기</title>
      <description>애플뮤직 사용법에 대한 심플한 팁을 알아보고자 합니다</description>
      <link>https://www.hohyeonmoon.com/blog/apple-music-download-data-save</link>
      <pubDate>Tue, 11 Jul 2017 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>이번 글에서는 <strong>애플뮤직 사용법에 대한 심플한 팁</strong>을 알아보고자 합니다. 애플뮤직은 애플에서 제공하는 음악 서비스인데요. 아무래도 국내 통신사와는 아무런 관계가 없다 보니.</p>
<p>스트리밍 서비스 이용 시에 혜택이 없고, 그러다 보니 애플뮤직을 스트리밍만으로 이용하기에는 데이터가 부담됩니다. 그래서 이번 글에서는 <strong>애플뮤직 음원 다운로드를 통해 데이터를 절약하는 방법</strong>을 알아보겠습니다.</p>
<h2 id="애플뮤직-다운로드-하는-방법">애플뮤직 다운로드 하는 방법</h2>
<p><img src="/images/apple-music-download-data-save-1.png" alt="apple-music-download-data-save"></p>
<p>일단 애플뮤직 스트리밍 서비스로 인하여 데이터가 소비되는 것을 막기 위해서는 설정 > 음악 > 셀룰러 데이터를 꺼야 합니다.</p>
<p><img src="/images/apple-music-download-data-save-2.png" alt="apple-music-download-data-save"></p>
<p>설정이 완료되었으면, 애플뮤직에서 다운로드하고 싶은 음악을 검색합니다. 음악 추가 버튼을 눌러주고, 보관함에 추가됩니다.</p>
<p><img src="/images/apple-music-download-data-save-3.png" alt="apple-music-download-data-save"></p>
<p>완전히 다운로드하기 위해서는 한 가지 작업을 더 해줘야 하는데요. 지금까지 한 것은 클라우드 보관함에만 추가한 것입니다. 그래서 구름 표시 아이콘을 눌러서 기기에 다운로드를 해줘야 합니다.</p>
<p>이렇게 해서 애플뮤직 음원을 다운로드하는 방법에 대해서 알아봤는데요. <strong>다운로드를 통해 음악을 감상하면, 기기의 용량은 차지하지만 데이터를 사용하지 않아도 된다는 장점</strong>이 있습니다. 하지만 애플뮤직 음원에는 DRM 잠금이 적용되어 있어, 다운로드를 해도 다른 기기로 옮길 수 없다는 단점이 있는데요. 대신 클라우드를 통해 기기 간 이동을 시킬 수 있습니다.</p>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/macbook-wallpaper-change</guid>
      <title>맥북 배경화면 변경하는 방법</title>
      <description>맥북 배경화면을 바꾸는 방법에 대해 살펴봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/macbook-wallpaper-change</link>
      <pubDate>Sat, 08 Jul 2017 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>이번 글에서는 <strong>맥북 배경화면을 바꾸는 방법</strong>에 대해 살펴보도록 하겠습니다. 현재 판매되고 있는 맥은 맥북에어, 맥북프로, 맥 스튜디오 등이 있는데요. 사실상 macOS 운영체제를 사용하는 맥이라면 배경화면 바꾸는 방법이 모두 동일합니다.</p>
<h2 id="맥북-배경화면-바꾸기">맥북 배경화면 바꾸기</h2>
<p><img src="/images/macbook-wallpaper-change-1.png" alt="macbook-wallpaper-change"></p>
<p>우선 배경화면으로 지정할 사진이 필요하겠습니다. 맥북 고화질 배경화면을 준비하거나, 맥 배경화면 다운로드를 하면 됩니다. 사진을 구하기 힘들다면, 애플 기본 배경화면을 사용하셔도 됩니다.</p>
<p><img src="/images/macbook-wallpaper-change-2.png" alt="macbook-wallpaper-change"></p>
<p>맥북 왼쪽 위의 <strong>애플 마크 → 시스템 환경설정 → 데스크탑 및 화면 보호기</strong>를 순서대로 선택해서 들어갑니다. 아니면, 조금 더 간단하게 <strong>바탕화면에서 우클릭 → 데스크탑 배경 변경</strong>으로 들어갑니다.</p>
<p><img src="/images/macbook-wallpaper-change-3.png" alt="macbook-wallpaper-change"></p>
<p>들어갔으면, 원하는 배경화면을 저장해둔 폴더 위치를 추가하고, 사진을 선택합니다.</p>
<p><img src="/images/macbook-wallpaper-change-5.png" alt="macbook-wallpaper-change"></p>
<p>macOS Ventura부터는 UI가 위 사진과 같이 변경되었습니다.</p>
<h2 id="배경화면-추천-및-다운로드">배경화면 추천 및 다운로드</h2>
<p><img src="/images/macbook-wallpaper-change-4.jpg" alt="macbook-wallpaper-change"></p>
<p>애플 기본 배경화면은 조금 따분하고 딱히 만족스러운 사진도 구하기 힘들다면, 요즘 특정 맥에서만 사용 할 수 있는 배경화면을 추천해드리겠습니다.</p>
<ul>
<li><a href="https://d.pr/i/n4Hc1R">맥 스튜디오 배경화면 다운로드</a></li>
<li><a href="https://d.pr/i/BZLDVU">M1 Max 맥북프로 스그 배경화면 다운로드</a></li>
<li><a href="https://d.pr/i/SzKLQq">M1 Max 맥북프로 실버 배경화면 다운로드</a></li>
<li><a href="https://d.pr/i/w2YFOh">몬터레이 배경화면 다운로드</a></li>
<li><a href="https://d.pr/i/UuNIvo">빅서 배경화면 다운로드</a></li>
<li><a href="https://d.pr/WFszBa">아이맥 프로 배경화면 다운로드</a></li>
<li><a href="https://d.pr/Vu5uhW">하이 시에라 배경화면 다운로드</a></li>
</ul>]]></content:encoded>
    </item>
    <item>
      <guid isPermaLink="true">https://www.hohyeonmoon.com/blog/apple-airpods-unboxing-review</guid>
      <title>애플 에어팟 개봉기 및 리뷰</title>
      <description>애플 에어팟을 2번째로 개봉해봅니다</description>
      <link>https://www.hohyeonmoon.com/blog/apple-airpods-unboxing-review</link>
      <pubDate>Fri, 16 Jun 2017 12:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<p>사실 에어팟을 사용하기 시작한지는 꽤 되었습니다. 그러나 처음 에어팟을 구매했을 때는 허겁지겁 개봉하느라 개봉기를 진행하지 못해버렸습니다. 그래서 에어팟 후기를 위해 하나 더 구매했는데요. 그런데 이번에는 정말 입이 쩍 벌어지도록 오래 걸리더군요. 역시 육주팟이었습니다. 예상 배송기간이 역시나 소문대로 6주였습니다. 에어팟의 뜨거운 인기를 새삼 느낄 수 있었는데요. 실제로는 6주보다 적은 시간 안에 배송되기는 했습니다. 더 이상 긴말 말고 에어팟 개봉 및 후기를 남깁니다.</p>
<p><img src="/images/apple-airpods-review-1.jpg" alt="apple-airpods-unboxing"></p>
<h2 id="기본-정보">기본 정보</h2>
<p>아이폰 에어팟의 가격은 비싼 편입니다. 무려 21.9만 원인데요. 이제 그러려니 합니다. 에어팟은 정말 A부터 Z까지 잘 빠졌는데요. 박스 패키징부터 에어팟 유닛, 충전 케이스까지 애플다운 심플함을 갖고 있습니다. 그러나 정작 에어팟을 착용하면 모습이 이상하다는 말이 많았었죠.</p>
<p>색상은 흰색 하나뿐이지만, 해외에서는 다른 색상에 대한 요구가 많아 블랙 하우징을 특히 많이 하더군요. 에어팟의 구성품은 에어팟 본체, 충전 케이스, 라이트닝 케이블 이렇게 세 가지입니다. 에어팟은 1회 충전하면 음악을 5시간 들을 수 있고, 충전 케이스까지 사용하면 음악을 24시간 들을 수 있다고 합니다.</p>
<h2 id="하이라이트-정보">하이라이트 정보</h2>
<p>에어팟은 뭐든지 자동으로 되는데요. 전원 관리, 연결성 모두 자동으로 됩니다. 에어팟 충전 케이스의 뚜껑을 열고 아이폰 가까이로 가져가면, 에어팟 연결 화면이 아이폰에 나타납니다. 이렇게 한 번 페어링 된 에어팟은 아이클라우드에 등록된 모든 기기에 연결됩니다. 한편, 아이폰을 제외한 다른 기기에서 페어링을 하기 위해서는 에어팟 충전 케이스 뒷면에 있는 버튼을 누르면 됩니다.</p>
<p>2개의 에어팟 유닛 중 1개의 유닛만 따로 사용하는 것이 가능합니다. 그래서 한 쪽만 잃어버리면 다른 한 쪽만 다시 구매해 원래대로 사용할 수도 있습니다. 에어팟으로 시리 조작도 가능한데요. 에어팟을 두 번 톡톡 쳐주면 시리가 실행되고, 에어팟에는 마이크가 탑재되어 있어 그대로 이용하면 됩니다. 시리를 이용해 음량 조절이 가능하기는 했지만, 그 외에는 음량 조절하기가 어려워서 아쉬웠습니다.</p>
<h2 id="간단-사용기">간단 사용기</h2>
<p>에어팟은 블루투스 이어폰이라고 느껴질 만큼 음질이 나쁜 편이 아니었습니다. 이어팟과 비교했을 때도 좋은 편이었습니다. 하지만 음악에 빠질 수 있을 만큼의 음질은 아니었고, 배터리 수명이 긴 편이긴 하지만 매번 충전해줘야 하는 불편함이 있었습니다.</p>
<p>그러나 에어팟의 최대 장점과 초점은 간편함입니다. 완전한 무선 이어폰인 에어팟은 상당히 편리했고, 간편했습니다. 또한, 가볍게 음악을 감상할 때는 부족함을 느낄 수 없었습니다. 즉, 에어팟은 음감 용이라기보다는 간편하게 음악을 듣는데 초점을 맞춘듯합니다.</p>
<h2 id="주관적-리뷰">주관적 리뷰</h2>
<p>여기서부터 에어팟에 대한 주관적인 느낌을 말해보고자 합니다. 자체적인 디자인은 역시 애플답게 좋습니다. 착용했을 때의 비주얼이 문제인 것인데요. 직접 착용도 해보고, 다른 분도 착용해본 결과. 연령이 좀 있으신 분들한테는 약간 어색해 보이지만, 그렇지 않은 분들에게는 기기 덕후 느낌이 약간 난다는 것 외에는 생각보다 괜찮았습니다.</p>
<p>에어팟 후기에 배터리와 음질을 빼놓을 수 없겠죠.</p>
<p>에어팟 배터리 수명과 음질은 훌륭하지만 완벽하지는 않았습니다. 배터리는 에어팟 배터리 케이스와 함께라면 충분히 오래가고도 남았지만. 배터리 케이스를 소지하고 다니는 것이 약간 불편했습니다. 음질은 현존하는 블루투스 이어폰 중 최고 수준이라고 생각하지만, 여전히 비슷한 가격대 유선 이어폰의 음질에 비하면 아쉬웠습니다.</p>
<p>하지만 에어팟은 이어폰 본연의 기능보다도 훌륭한 점이 많이 있습니다. 에어팟을 귀에 직접 착용하고 운동을 해봤는데요. 빠질 것 같은 심리적 불안감은 있었지만, 실제로 에어팟 빠짐이 있거나 그러지는 않았습니다.</p>
<p>그 외에도 아이폰과의 매끄러운 에어팟 연결 기능, 에어팟 한쪽 사용 기능 등이 상당히 큰 만족감을 주었습니다. 또, 에어팟 음량 크기 및 아이폰과 연결되는 에어팟 거리 등도 훌륭했습니다.</p>
<p>에어팟 후기, 이 정도면 충분히 설명되었을 거라 생각하는데요. 에어팟 구입을 고민한다면, 구입하는 것을 추천드립니다. 직접 사용해봐야 더 많은 것을 느낄 수 있는 제품이기도 하고, 지금 주문해도 6주를 기다려야 하기 때문이죠.</p>]]></content:encoded>
    </item>
  </channel>
</rss>