<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>mo_nireu.log</title>
        <link>https://velog.io/</link>
        <description>iOS, Swift Dev</description>
        <lastBuildDate>Tue, 14 Jun 2022 07:31:28 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>mo_nireu.log</title>
            <url>https://images.velog.io/images/mo_nireu/profile/694ec1e0-c411-4134-8aaa-477525c00ed9/social.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. mo_nireu.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/mo_nireu" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[WWDC2022] Swift Concurrency를 통한 Data Race 방지하기(1) - Task isolation]]></title>
            <link>https://velog.io/@mo_nireu/WWDC2022-Swift-Concurrency%EB%A5%BC-%ED%86%B5%ED%95%9C-Data-Race-%EB%B0%A9%EC%A7%80%ED%95%98%EA%B8%B01-Task-isolation</link>
            <guid>https://velog.io/@mo_nireu/WWDC2022-Swift-Concurrency%EB%A5%BC-%ED%86%B5%ED%95%9C-Data-Race-%EB%B0%A9%EC%A7%80%ED%95%98%EA%B8%B01-Task-isolation</guid>
            <pubDate>Tue, 14 Jun 2022 07:31:28 GMT</pubDate>
            <description><![CDATA[<h1 id="원문">원문</h1>
<p><a href="https://developer.apple.com/videos/play/wwdc2022/110351/">[WWDC2022]Eliminate data races using Swift Concurrency</a></p>
<h1 id="task에-대하여">Task에 대하여</h1>
<p>일단 설명을 위해서 concurrency한 환경을 &#39;바다&#39;로 비유하고,
Task를 &#39;배&#39;로 표현한다.</p>
<p>Task는 특정 작업을 시작부터 끝까지 수행하며 다음과 같은 특징을 지닌다.</p>
<ul>
<li>순차적 (Sequential)</li>
<li>비동기적 (Asynchronous)</li>
<li>독립적 (Self-contained)</li>
</ul>
<p>이 Task라는 배는 독립적이며 자체 리소스를 가지고 있으므로 다른 배들과 독립적으로 작동한다. 
따라서 서로의 독립적인 배들은 서로 아무런 영향을 주지 않기 때문에 이론적으로는 Data Race에서 안전하다.</p>
<p>하지만, 실제 작업 환경에서는 이 배들간의 커뮤니케이션이 이루어진다.
여기서는 이 커뮤니케이션을 배들끼리 물건을 주고 받는 것으로 비유한다.</p>
<h2 id="예시">예시</h2>
<p>물건에는 아래와 같이 두가지 종류가 있음.</p>
<ul>
<li>파인애플(Structure)</li>
<li>닭(Class)</li>
</ul>
<p>각각의 코드는 다음과 같다.</p>
<pre><code class="language-swift">// 파인애플 코드

enum Ripeness {
    case hard
    case perfect
    case mushy(daysPast: Int)
}

struct Pineapple {
    var weight: Double
    var ripeness: Ripeness

    mutating func ripen() async {...}
    mutating func slice() -&gt; Int { ... }
}</code></pre>
<pre><code class="language-swift">// 닭 코드

final class Chicken {
    let name: String
    var currentHunger: HungerLevel

    func feed() { ... }
    func play() { ... }
    func produce() -&gt; Egg { ... }
}
</code></pre>
<p>자, 우선 한배에서 다른배로 파인애플을 전달한다고 가정한다.
여기서 파인애플은 <code>Structure</code>이며 <code>Value Type</code>이다.
복사본이라는 뜻이며
값만 같을 뿐 동일한 인스턴스를 참조하는 것은 아니다.</p>
<p>따라서 각각의 배에서 파인애플을 <code>slice()</code> 및 <code>ripen()</code> 하더라도 각각의 배에는 영향을 주지 않는다.</p>
<p>즉, <strong>value type은 data race에 상대적으로 안전하며</strong>
Swift가 Value Type을 선호해왔던 이유이다.</p>
<p>그렇다면 닭을 전달하는 경우에는 어떠할까?
닭은 <code>Class</code>이며 <code>Reference Type</code>이다.
두 배가 같은 인스턴스를 참조한다. 
즉, 독립적이지 않다.</p>
<p>따라서 각각의 배에서 <code>feed()</code> 및 <code>play()</code>를 수행할 경우
Data Race가 발생할 수 있다.
이를 해결하기 위해서는 무엇을 해야할까?</p>
<h1 id="sendable">Sendable</h1>
<h2 id="sendable에-대하여">Sendable에 대하여</h2>
<p>우선 다음과 같은 판단 기준이 필요하다.</p>
<ul>
<li>파인애플은 배 사이 에서 공유하는 것이 안전하지만, 닭은 공유할 수 없음을 알 수 있는 방법</li>
<li>닭이 실수 로 한 보트에서 다른 보트 로 전달되지 않도록 Swift 컴파일러에서 검사</li>
</ul>
<p>위의 역할을 수행하는 것이 바로
<code>Sendable</code> Protocol이다.</p>
<blockquote>
<p><code>Sendable</code> (protocol)
복사를 통해서 동시성(concurrency) 도메인 간에 안전하게 값을 전달할 수 있는 타입.
A type whose values can safely be passed across concurrency domains by copying.</p>
</blockquote>
<p>파인애플(structure)은 Value Type이기 때문에 <code>Sendable</code>을 따르지만,
닭(class)는 동기화 되지않은(unsynchronized) Reference Type이기 때문에 <code>Sendable</code>을 따를 수 없다.</p>
<h2 id="task간의-sendable-검사">Task간의 Sendable 검사</h2>
<p><code>Sendable</code> protocol을 사용하면 데이터가 격리 도메인(Isolation Domain)에서 공유되는 위치를 설명할 수 있다.
예를 들어 아래와 같은 코드가 있다.</p>
<pre><code class="language-swift">let petAdoption = Task {
    let chickens = await hatchNewFlock()
    return chickens.randomElement()!
}
let pet = await petAdoption.value</code></pre>
<p><code>Task</code>에서 <code>Chicken</code>을 반환하려고 하지만, 치킨은 <code>Sendable</code>하지 않기 때문에 안전하지 않다는 오류가 발생한다.</p>
<blockquote>
<p>Error: type <code>Chicken</code> does not conform to the <code>Sendable</code> protocol</p>
</blockquote>
<p><code>Task</code>가 어떻게 정의되어있는지 살며보면 
아래와 같이 <code>Task</code>의 결과 값인 <code>Success</code>가 <code>Sendable</code>을 채택고 있다.</p>
<pre><code class="language-swift">@frozen struct Task&lt;Success, Failure&gt; where Success : Sendable, Failure : Error</code></pre>
<p>따라서 서로 다른 격리 도메인(Isolated Domain)간에 전달될 <code>Generic Parameter</code> 또한 <code>Sendable</code>을 따라야한다.</p>
<h2 id="sendable-전파">Sendable 전파</h2>
<p>Sendable은 조건부 적합성(conditional conformance)을 통해 <code>Collection</code> 및 <code>Generic Type</code>에 전파될 수 있다.
아래의 코드를 보자</p>
<pre><code class="language-swift">
✅ enum Ripeness: Sendable {
    case hard
    case perfect
    case mushy(daysPast: Int)
}

✅ struct Pineapple: Sendable {
    var weight: Double
    var ripeness: Ripeness
}

✅ struct Crate: Sendable { 
    var pineapples: [Pineapple]
}

❌ struct Coop: Sendable { 
    var flock: [Chicken]
}</code></pre>
<p>우선 <code>enum</code>과 <code>struct</code> 모두 <code>Value Type</code>이기 때문에 <code>Ripeness</code>와 <code>Pinapple</code>모두 <code>Sendable</code>을 채택할 수 있다.
그리고 <code>Crate</code>에서 Collection <code>pinapples</code>은 <code>Senable</code>을 채택하는 <code>Pineapple</code>을 담고 있기 때문에 <code>Sendable</code>이다.</p>
<p>하지만 <code>Coop</code>에 <code>Sendable</code>을 적용시키려하면 에러가 난다.</p>
<blockquote>
<p>Error: stored property <code>flock</code> of <code>Sendable</code> - conforming struct <code>Coop</code> has non-sendable type <code>[Chicken]</code></p>
</blockquote>
<p><code>Chicken</code>은 <code>Sendable</code>타입을 적용하지 않고 있다. 
따라서 <code>Chicken</code>을 담고 있는 Collection <code>flock</code>는 <code>Sendable</code>이 아니며, 
이로 인해서 <code>Coop</code>또한 <code>Sendable</code>을 채택할 수 없다.</p>
<h2 id="reference-type에-sendable-적용하기">Reference Type에 Sendable 적용하기</h2>
<p><code>Class</code>에 <code>Sendable</code>을 적용시키는 것이 불가능한 것은 아니다.
다만, 아래 조건을 만족하는 매우 좁은 상황에서만 <code>Sendable</code>로 만들 수 있다.</p>
<ul>
<li><code>final class</code>이어야함.</li>
<li>변경 불가능한 저장소(immutable storage)만 포함해야함.</li>
</ul>
<pre><code class="language-swift">final class Chicken: Sendable {
    let name: String
    var currentHunger: HungerLevel ❌
}</code></pre>
<p>위의 코드는 아래와 같은 에러를 만든다.</p>
<blockquote>
<p>Error: class <code>Chicken</code> cannot conform to <code>Sendable</code>
Error: stored property <code>currentHunger</code> of <code>Sendable</code> - conforming class <code>Chicken</code> is mutable</p>
</blockquote>
<p><code>currentHunger</code>는 변경 가능하다(mutable).
따라서 <code>Chicken</code>은 <code>Sendable</code>을 채택할 수 없다.</p>
<p>만약 <code>Chicken</code>을 <code>Sendable</code>하게 만들고 싶다면,
현재 상태에서 immutable한 <code>name</code>만을 포함해야한다.</p>
<hr>
<p>사실 <code>lock</code>를 일관적으로 사용하는 방법과 같이
내부적인 동기화 작업을 수행하는 <code>Reference Type</code>을 포함하는 방법이 있기는 하다.</p>
<pre><code class="language-swift">class ConcurrentCache&lt;Key: Hashable &amp; Sendable, Value: Sendable&gt;: @unchecked Sendable {
    var lock: NSLock
    var storage: [Key: Value]
}</code></pre>
<p>이러한 유형은 개념적으로는 <code>Sendable</code> 이지만 Swift가 이에 대해 알 수 있는 방법이 없다.
따라서 컴파일러의 검사를 비활성화 하기 위해서 <code>@unchecked Sendable</code>을 사용한다.
다만, 이 경우에는 <strong>Swift가 Data Race Safety를 보장할 수 없기 때문에 매우 주의</strong>해야한다.</p>
<h2 id="task-생성시-sendable-검사">Task 생성시 Sendable 검사</h2>
<p><code>Task</code>를 생성하는 방법 중에는 
기존의 <code>Task</code>내에서 완전히 새롭고 독립된 새로운 <code>Task</code>를 <code>closure</code>를 통해 생성하는 방법이 있다.</p>
<p>위에서 <code>Task</code>를 배로 비유한것으로 설명하자면
기존의 배에서 조그마한 카약을 띄우는 식이다.</p>
<p>이 경우에는 기존 <code>Task</code>(배)에서 값을 캡처 하여, 새 <code>Task</code>(카약)로 전달할 수 있는데
Data Race가 발생할 수 있으므로 <code>Sendable</code> 검사를 수행한다.</p>
<pre><code class="language-swift">let lily = Chicken(name: &quot;Lily&quot;)
Task.detached {
    lily.feed()
}</code></pre>
<p>위의 코드는 <code>sendable</code>이 아닌 <code>lily</code>를 전달하므로 아래과 같은 에러를 발생시킨다.</p>
<blockquote>
<p>Error: capture of <code>lily</code> with non-sendable type <code>Chicken</code></p>
</blockquote>
<p><code>detached</code> 함수는 아래와 같이 작성되어있다.</p>
<pre><code class="language-swift">struct Task&lt;Success: Sendable, Failure: Error&gt; {
    static func detached(
        priority: TaskPriority? = nil,
        operation: @Sendable @escaping () async throws -&gt; Success
    ) -&gt; Task&lt;Success, Failure&gt;
}</code></pre>
<p><code>operation: @Sendable</code>를 보면 알 수 있듯이
해당 함수 유형이 <code>sendable</code>을 준수하고 있다는 것을 보여준다.</p>
<p>즉, 위에서 오류가 났던 코드는 아래와 같이 작성된 것과 같으며
이를 통해 <code>Sendable closure</code>로 유추되는 것이다.</p>
<pre><code class="language-swift">let lily = Chicken(name: &quot;Lily&quot;)
Task.detached { @Sendable in
    lily.feed()
}</code></pre>
<h1 id="결론">결론</h1>
<blockquote>
<p><code>Sendable</code>을 체크함으로써 <code>Task Isolation</code>을 유지할 수 있다.</p>
</blockquote>
<ul>
<li><code>Task</code>는 격리되어있고, 독립적으로 비동기(asynchronous) 작업들을 수행한다.</li>
<li><code>Sendable</code>은 각 <code>Task</code>들이 격리되어있다는 것을 보장한다.</li>
<li>따라서 값들이 교환되어야 하는 모든 곳에서 <code>Sendable</code>이 사용되어야한다.</li>
</ul>
<h1 id="다음-포스트---actor-isolation">다음 포스트 - Actor Isolation</h1>
<p><code>Task</code>를 격리하는 것은 Data Race를 방지하는 좋은 방법이지만,
다음과 같은 큰 문제가 있다.</p>
<blockquote>
<p>공유된 변경 가능한 데이터(shared mutable data)가 없다면, <code>Task</code>들을 의미있게 사용하기 어렵다.</p>
</blockquote>
<p>따라서 Data Race를 일으키지 않는 작업 간에 데이터를 공유할 수 있는 방법이 필요하다.
여기에 Actor Isolation이 등장한다.
(Actor Isolation 작성예정)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[WWDC2022] What's new in Swift - Concurrency Updates]]></title>
            <link>https://velog.io/@mo_nireu/WWDC2022-Whats-new-in-Swift-Concurrency-Updates</link>
            <guid>https://velog.io/@mo_nireu/WWDC2022-Whats-new-in-Swift-Concurrency-Updates</guid>
            <pubDate>Wed, 08 Jun 2022 01:48:48 GMT</pubDate>
            <description><![CDATA[<h1 id="actor-asyncawait-back-deploy">Actor, Async/Await Back deploy.</h1>
<p>Async/Await등의 Concerrency 기능들을 이제는 더 낮은 버전부터 사용가능.</p>
<ul>
<li>macOS 10.15(catalina)</li>
<li>iOS13</li>
<li>tvOS13</li>
<li>watchOS6</li>
</ul>
<h1 id="data-race-avoidance">Data race avoidance</h1>
<p>Swift는 data race가 발생하여 memory safety하지 않은 지점들을 알려줘왔었고,
작년에는 <code>Actor</code>등을 도입하여 data race를 방지 할 수 있는 방법들을 제공해 왔다.
Swift의 최종목표는 memory safety를 넘어서 thread safety로, 올해에는 작년보다 더 다양한 concerrency 방법들을 제공할 예정이라고 한다.</p>
<p>자세한 내용은 <a href="https://developer.apple.com/videos/play/wwdc2022/110351">Eliminate data races using Swift Concerrency 세션</a> 참조.</p>
<h1 id="distributed-actors">Distributed actors</h1>
<p>분산 시스템을 위한 Distributed Actor가 추가됨.
고립성과 위치 투명성을 통해서 네트워킹등의 우발적 복잡성등을 피하는데 도움을 주는 역할을 한다고 함.</p>
<p>자세한 내용은 <a href="https://developer.apple.com/videos/play/wwdc2022/110356">Meet distributed actors in Swift 세션</a> 참조.</p>
<h1 id="async-algorithms">Async algorithms</h1>
<p>swift5.5에서 제공하는 AsyncSequence를 더 쉽게 처리하기 위한 솔루션으로 새로운 오픈소스 알고리즘 세트를 공개함.
<code>zip()</code>, <code>merge()</code>,<code>debounce()</code>,<code>chunked()</code>등을 제공하며 자세한 내용은 <a href="https://developer.apple.com/videos/play/wwdc2022/110354/">Meet Swift Async Algorithms세션</a> 참조</p>
<h1 id="actor-prioritizationconcurrency-optimization">Actor prioritization(concurrency optimization)</h1>
<p>이제부터 <code>Actor</code>는 <strong>Actor prioritization</strong>을 통해서 우선순위가 높은 작업부터 수행함.</p>
<h1 id="swift-concurrency-instrument">Swift Concurrency Instrument</h1>
<p>일반적으로 concurrency가 앱의 성능에 미치는 영향등을 시각화하기 어려움.
이를 해결할 concurrency 시각화 도구인 Swift Concurrency Instrument가 추가됨.</p>
<p>자세한 내용은 <a href="https://developer.apple.com/videos/play/wwdc2022/110350">Visualize and optimize Swift concurrency세션</a> 참조.</p>
<h1 id="참고자료">참고자료</h1>
<ul>
<li><a href="https://developer.apple.com/videos/play/wwdc2022/110354/">https://developer.apple.com/videos/play/wwdc2022/110354/</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Protocol vs Opaque Type]]></title>
            <link>https://velog.io/@mo_nireu/Protocol-vs-Opaque-Type</link>
            <guid>https://velog.io/@mo_nireu/Protocol-vs-Opaque-Type</guid>
            <pubDate>Wed, 13 Apr 2022 00:48:03 GMT</pubDate>
            <description><![CDATA[<p><a href="https://velog.io/@mo_nireu/Generic-vs-Opaque-Type">이전 포스트(Generic vs Opaque Type)</a>에서 Generic과 Opaque Type의 차이점에 대해서 알아보았는데,
Opaque Type이 Protocol 앞에 <code>some</code>을 붙인 모습이란 것을 알 수 있었을 것이다.
그렇다면 왜 <code>some</code>을 붙이고 이로인해 만들어지는 Protocol과 Opaque Type의 차이점에 대해서 알아보자.</p>
<h1 id="차이점">차이점</h1>
<p>Protocol과 Opaque Type의 가장 큰 차이점은 <strong>Type Identity</strong>의 여부이다.</p>
<ul>
<li>Protocol: Type Identity를 가지지 않는다.</li>
<li>Opaque Type: Type Identity를 가진다.</li>
</ul>
<p>이로 인해서 실제 사용시 다음과 같은 차이가 발생한다.</p>
<h2 id="1-return-value">1. Return Value</h2>
<p>다음과 같은 코드가 있다.</p>
<pre><code class="language-swift">protocol Quadrilateral {
    var width: Float { get set }
    var height: Float { get set }
}

struct Square: Quadrilateral {
    var width: Float
    var height: Float
}

struct Rectangle: Quadrilateral {
    var width: Float
    var height: Float
}

struct InversedRectangle: Quadrilateral {
    var width: Float
    var height: Float

    init(rectangle: Quadrilateral) {
        self.width = rectangle.height
        self.height = rectangle.width
    }
}

func getProtoQuadrilateral&lt;T: Quadrilateral&gt;(_ shape: T) -&gt; Quadrilateral {
    if shape is Square { return shape }
    return InversedRectangle(rectangle: shape)
}

// Error: Function declares an opaque return type, but the return statements in its body do not have matching underlying types
func getOpaqueQuadrilateral&lt;T: Quadrilateral&gt;(_ shape: T) -&gt; some Quadrilateral {
    if shape is Square { return shape }
    return InversedRectangle(rectangle: shape)
}</code></pre>
<p>잠시 코드를 설명하자면,
높이(<code>height</code>)와 너비(<code>width</code>) 변수를 가지는, 사각형을 뜻하는 <code>Quadrilateral</code> Protocol이 존재한다.</p>
<p>그리고 이 Protocol을 준수하는 다음과 같은 세가지 <code>structure</code>가 존재한다.</p>
<ul>
<li><code>Square</code>: 정사각형</li>
<li><code>Rectangle</code>: 직사각형</li>
<li><code>InversedRectangle</code>: 입력받은 <code>Quadrilateral</code>의 높이와 너비를 뒤바꾼 <code>Quadrilateral</code></li>
</ul>
<p>아래에는 두개의 function <code>getProtoQuadrilateral</code>와 <code>getOpaqueQuadrilateral</code>이 있는데,
두 function 모두 <code>Quadrilateral</code>를 parameter로 받아서 <code>Sqaure</code>일 경우 그대로 return하고,
<code>Square</code>이 아닐 경우 해당 <code>Quadrilateral</code>을 뒤집은 <code>InversedRectangle</code>을 return 한다.</p>
<p>이떄 OpaqueType을 return하는 <code>getOpaqueQuadrilateral</code>에서 error가 발생하는 것을 확인 할 수 있는데,
이는 <code>getOpaqueQuadrilateral</code>이 상황에 따라서 <code>Squre</code> 또는 <code>InversedRectangle</code>을 return 할 수 있기 때문이다.</p>
<p>OpaqueType은 Type Identity를 가지고 있고, 이 때문에 함수 return시에 하나의 구체 Type만을 return해야한다.
즉, <code>Quadrilateral</code>을 만족하는 한 가지 Type의 return만 가능한 것이다.</p>
<p>반면, Protocol은 <code>Quadrilateral</code>을 채택하는 모든 Type을 return 할 수 있다.</p>
<blockquote>
<p>요약 
OpaqueType은 하나의 구체 Type만을 return.
Protocol은 모든 Type을 return.</p>
</blockquote>
<h2 id="2-self-및-associatedtype-사용">2. Self 및 associatedType 사용</h2>
<p>위에서 Protocol은 Type Identity를 가지지 않고, Opaque Type은 Type Identity를 가진다고 했다.
Type Identity의 여부는 <code>Self</code> 및 <code>associatedType</code>의 추론 조건중 하나이다.
즉, Type Identity를 가지지 않게 되면 <code>Self</code> 및 <code>associatedType</code>을 추론할 수 없으므로 이를 return 값으로 사용할 수 없다.</p>
<p>아래에서 조금 더 자세히 살펴보자.</p>
<p><code>Equatable</code>의 <code>==</code> Operator는 (Self, Self)를 parameter로 받는다.
<code>Self</code>는 보통 Protocol을 채택하는 어떠한 구체적인 Type과 매칭되지만,
앞서 말했듯이 Protocol은 Type에대한 Identity를 가지고 있지 않으므로 <code>Self</code>를 사용할 수 없다.
즉, protocol은 <code>==</code> Operator을 사용할 수 없다.
<img src="https://velog.velcdn.com/images/mo_nireu/post/0f6ff6d1-5075-4440-a162-6b6f48eca569/image.png" alt=""></p>
<p>다음은 <code>associatedType</code>이 적용된 경우 Protocol을 return 할 수 없는 이유이다.
다음과 같은 코드가 있다.</p>
<pre><code class="language-swift">protocol Container {
    associatedtype dataType
    var dataArray: [dataType] { get set }
}

struct IntContainer: Container {
    var dataArray: [Int] = [1, 2, 3, 4, 5]
}

struct StringContainer: Container {
    var dataArray: [String] = [&quot;One&quot;, &quot;Two&quot;, &quot;Three&quot;, &quot;Four&quot;, &quot;Five&quot;]
}

// Error: Protocol &#39;Container&#39; can only be used as a generic constraint because it has Self or associated type requirements
let containerProto: Container = IntContainer()
// OK
let containerOpaque: some Container = IntContainer()</code></pre>
<p><code>let</code> <code>containerProto</code>는 <code>Container</code> protocol을 값으로 받으려고 하는데,
protocol은 Type Identity가 없으므로 외부에서 <code>associatedType</code>을 추론하기 위한 충분한 정보가 없다.
따라서 protocol을 반환 할 수 없으므로 error가 발생한다.</p>
<p>반면 Opaque Type을 받는 <code>containerOpaque</code>는 Type Identity를 가지고 있으므로 <code>AssociatedType</code>을 추론할 수 있다.
즉, return값으로 사용할 수 있게 된다.</p>
<blockquote>
<p>요약 
associatedType 및 Self를 사용하고자 하는 경우, Opaque Type을 return하여 사용하여야 한다.</p>
</blockquote>
<h1 id="참고자료">참고자료</h1>
<p><a href="https://docs.swift.org/swift-book/LanguageGuide/OpaqueTypes.html">https://docs.swift.org/swift-book/LanguageGuide/OpaqueTypes.html</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Generic vs Opaque Type]]></title>
            <link>https://velog.io/@mo_nireu/Generic-vs-Opaque-Type</link>
            <guid>https://velog.io/@mo_nireu/Generic-vs-Opaque-Type</guid>
            <pubDate>Tue, 12 Apr 2022 02:26:03 GMT</pubDate>
            <description><![CDATA[<h1 id="generic">Generic</h1>
<p>Generic 코드</p>
<pre><code class="language-swift">func max&lt;T&gt;(_ x: T, _ y: T) -&gt; T where T: Comparable { ... }</code></pre>
<p>Gerneric을 사용한 코드에서 Type이 선택되는 때는 언제일까?</p>
<p>다음 함수를 Call한다고 할 때
Caller는 x, y의 Type을 선택하게 된다.
즉, Caller가 Type을 선택하게 된다.</p>
<p>함수가 Call될때 Type이 선택되기 때문에,
함수는 Call되기 전까지 GenericType <code>T</code>가 <code>Comparable</code>을 준수하는 Type이란 것을 제외하고는 아무것도 모른다.
즉, parameter의 Type에 대응하기 위해서, 해당 함수의 구현부는 추상적으로 작성되어야 한다.</p>
<h1 id="opaque-type">Opaque Type</h1>
<p>Opaque Type 코드</p>
<pre><code class="language-swift">struct Square: Shape {
    var size: Int
    func draw() -&gt; String {
        let line = String(repeating: &quot;*&quot;, count: size)
        let result = Array&lt;String&gt;(repeating: line, count: size)
        return result.joined(separator: &quot;\n&quot;)
    }
}

func makeTrapezoid() -&gt; some Shape {
    let top = Triangle(size: 2)
    let middle = Square(size: 2)
    let bottom = FlippedShape(shape: top)
    let trapezoid = JoinedShape(
        top: top,
        bottom: JoinedShape(top: middle, bottom: bottom)
    )
    return trapezoid
}
let trapezoid = makeTrapezoid()
print(trapezoid.draw())</code></pre>
<p>Opaque를 사용한 코드에서 Type이 선택되는 때는 언제일까?</p>
<p>함수의 구현부를 살펴보면
구체적인 Type을 생성한 후에 return하게 된다.
즉, 함수 구현부가 Type을 선택하게 된다.</p>
<p>함수 구현부에서 Type이 선택되기 때문에,
함수의 Caller는 return되는 값이 <code>Shape</code> protocol을 준수한다는 것을 제외하고는 아무것도 모른다.
즉, 함수의 return type에 대응하기 위해서, 해당 함수의 Caller는 추상적으로 작성되어야 한다.</p>
<hr>
<h1 id="정리">정리</h1>
<p>위의 내용들을 정리하면 다음과 같다.</p>
<h2 id="type이-선택되는-곳">Type이 선택되는 곳.</h2>
<ul>
<li>Generic: <strong>함수 호출자</strong>가 Type을 선택.</li>
<li>Opaque: <strong>함수 구현부</strong>가 Type을 선택.</li>
</ul>
<h2 id="추상적으로-작성되어야-하는-곳">추상적으로 작성되어야 하는 곳</h2>
<ul>
<li>Generic: <strong>함수 구현부</strong>.</li>
<li>Opaque: <strong>함수 호출자</strong>.</li>
</ul>
<p>혹시 눈치를 챘을 수도 있지만, 
Opaque Type은 Generic과 반대의 성격을 가지고 있는 것을 볼 수 있다.
때문에 Opaque Type을 Reverse Generic이라고도 부른다.</p>
<hr>
<h1 id="참고자료">참고자료</h1>
<p><a href="https://docs.swift.org/swift-book/LanguageGuide/OpaqueTypes.html">https://docs.swift.org/swift-book/LanguageGuide/OpaqueTypes.html</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[이슈: SwiftUI @FocusState 사용시 MemoryLeak 발생.]]></title>
            <link>https://velog.io/@mo_nireu/%EC%9D%B4%EC%8A%88-SwiftUI-FocusState-%EC%82%AC%EC%9A%A9%EC%8B%9C-MemoryLeak-%EB%B0%9C%EC%83%9D</link>
            <guid>https://velog.io/@mo_nireu/%EC%9D%B4%EC%8A%88-SwiftUI-FocusState-%EC%82%AC%EC%9A%A9%EC%8B%9C-MemoryLeak-%EB%B0%9C%EC%83%9D</guid>
            <pubDate>Thu, 31 Mar 2022 09:46:15 GMT</pubDate>
            <description><![CDATA[<h1 id="issue">ISSUE</h1>
<p>SwiftUI를 이용한 프로젝트를 진행하고 있는데 이상한 점을 발견했다.</p>
<p>아래의 예시 코드를 보자.</p>
<pre><code class="language-swift">struct ChildView: View {
    enum FocusedField {
        case firstField
        case secondField
    }
    @State private var firstText = &quot;&quot;
    @State private var secondText = &quot;&quot;
    @FocusState private var focusedField: FocusedField?

    var body: some View {
        TextField(&quot;test&quot;, text: $firstText)
            .focused($focusedField, equals: .firstField)

        TextField(&quot;test&quot;, text: $secondText)
            .focused($focusedField, equals: .secondField)
    }
}</code></pre>
<p>지금 보이는 <code>ChildView</code>는 두개의 <code>TextField</code>를 가지고 있다.
각각의 <code>TextField</code>는 <code>focusedField</code>를 바인딩하여 focused를 관리하도록 되어있다.
이는 <a href="https://developer.apple.com/documentation/swiftui/focusstate">Apple의 공식문서</a>의 내용과 동일하다.</p>
<p><code>ChildView</code>는 <code>ParentView</code>에서 event를 받아 화면에 나타난다.
그 방식이 NavigationLink이던, Sheet이던 아무 상관없다.</p>
<p>문제는 <code>ChildView</code>를 닫아 <code>ParentView</code>로 돌아와도 <strong><code>@FocusState</code>의 잔재로 추정되는 메모리가 남아있다는 것</strong>이다.
몇번이고 <code>ChildView</code>를 열었다가 닫으면 계속해서 누수가 발생한다.
아래 사진은 처음 <code>ChildView</code>를 열고 닫았을 때 발생했던 MemoryLeak이다.
<img src="https://images.velog.io/images/mo_nireu/post/a6e7d5ad-894c-415a-8712-9ff4f822b28a/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-03-31%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%206.32.37.png" alt=""></p>
<p>실제 <code>focusedField</code> 때문인지 확인해보기 위해서 해당 코드들을 지우고 다시 실행해보았다.
결과는 더이상 MemoryLeak가 발생하지 않는다.
<code>focused(_:equals:)</code>를 없애면 해당 문제가 발생하지 않는데, 여기서 발생하는 문제 같다.</p>
<h1 id="해결방법">해결방법</h1>
<p>못찾았다...
아직 내가 이해도나 실력이 부족해서인지, 실제 SwiftUI내에서 발생하는 문제인지 모르겠다...
이와 관련된 내용을 아무리 검색해보아도 나오지 않으니 답답할뿐이다.
그냥 FocusState를 이용하지 말고 ViewModel에 직접 Focus를 구분하는 방식의 로직을 만들어서 View랑 바인딩해야겠다...</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[오류해결: RxSwift Closure Circular Reference]]></title>
            <link>https://velog.io/@mo_nireu/%EC%98%A4%EB%A5%98%ED%95%B4%EA%B2%B0-RxSwift-Closure-Circular-Reference</link>
            <guid>https://velog.io/@mo_nireu/%EC%98%A4%EB%A5%98%ED%95%B4%EA%B2%B0-RxSwift-Closure-Circular-Reference</guid>
            <pubDate>Mon, 27 Dec 2021 04:08:34 GMT</pubDate>
            <description><![CDATA[<h1 id="요약">요약</h1>
<p><code>[weak self]</code>를 활용하여 closure에서의 순환참조를 꼭 해결하자...</p>
<h1 id="발생한-오류">발생한 오류</h1>
<p>RxSwift를 활용한 채팅 앱을 만들고 있었다. 친구목록을 보여주는 <code>FriendListView</code>에서 친구를 선택하면 <code>UINavigationController</code>를 통해서 친구와의 채팅화면을 보여주는 <code>ChatRoomView</code>로 이동을 하게 된다.<em>(<code>FriendListView</code>와 <code>ChatRoomView</code>는 각각의 ViewModel로 Bind되어있다.)</em> 이후 <code>ChatRoomView</code>를 Pop하여 <code>FriendListView</code>로 되돌아 왔는데, Xcode의 Debug Navigator의 메모리 사용량이 그대로이다... 뭔가 이상함을 느껴서 위의 동작을 여러번 수행해봤는데, 아니나 다를까 <code>ChatRoomView</code>의 메모리 해제가 수행되지 않고 있었다...</p>
<h1 id="해결-과정">해결 과정</h1>
<p>처음에는 RxSwift의 <code>DisposeBag</code>에서 Dispose가 일어나지 않는 것이 원인이라 생각했다. <code>DisposeBag</code>의 Dispose를 수행하는 위치에 Log들을 찍어보았지만, 우리의 <code>DisposeBag</code>는 정상적으로 동작하고 있었다.</p>
<p>원인을 찾아야 해결할 수 있다는 생각에 memory leak를 해결하는 방법을 찾다가 Xcode에서 지원하는 여러가지 기능들을 알게 되었다. Debug Memory Graph와 Instruments Profiling의 Leaks가 그것인데, 이와 관련해서는 좀 더 사용을 해보고 나중에 글을 작성해보는 것도 좋겠다.</p>
<p>아무튼, Memory Leak를 통해 점점 쌓여가는 <code>ChatRoomView</code>와 <code>ChatRoomViewModel</code>을 확인해보니 모두 RxSwift Closure의 Strong Reference로 인한 문제였다. 이 부분에서 아차 싶었다. 당연히도 Closure에서의 Circular Reference를 고려했어야 했는데, 전혀 생각지 못한 상태로 앱을 만들고 있었다... 역시 아직 갈길이 멀구나...</p>
<h1 id="해결-방법">해결 방법</h1>
<p>RxSwift의 Closure들이 Self를 Strong하게 물고 있다는 원인이 파악되었으니, 해결하는 방법은 간단했다. <code>[weak self]</code>를 사용하여 weak reference를 적용시켜주면 된다. 너무나 쉽다... 세상에...</p>
<h1 id="추가-자료">추가 자료</h1>
<p><a href="https://velog.io/@haanwave/Article-You-dont-always-need-weak-self">https://velog.io/@haanwave/Article-You-dont-always-need-weak-self</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[오류해결: View간 NavigationBar Title의 크기가 바뀌지 않던 문제]]></title>
            <link>https://velog.io/@mo_nireu/%EC%98%A4%EB%A5%98%ED%95%B4%EA%B2%B0-View%EA%B0%84-NavigationBar-Title%EC%9D%98-%ED%81%AC%EA%B8%B0%EA%B0%80-%EB%B0%94%EB%80%8C%EC%A7%80-%EC%95%8A%EB%8D%98-%EB%AC%B8%EC%A0%9C</link>
            <guid>https://velog.io/@mo_nireu/%EC%98%A4%EB%A5%98%ED%95%B4%EA%B2%B0-View%EA%B0%84-NavigationBar-Title%EC%9D%98-%ED%81%AC%EA%B8%B0%EA%B0%80-%EB%B0%94%EB%80%8C%EC%A7%80-%EC%95%8A%EB%8D%98-%EB%AC%B8%EC%A0%9C</guid>
            <pubDate>Tue, 14 Dec 2021 05:29:47 GMT</pubDate>
            <description><![CDATA[<h1 id="요약">요약</h1>
<p>VC1에서 <code>prefersLargeTitles</code>를 <code>true</code>로 놔둔 상태에서 
VC2의 <code>largeTitleDisplayMode</code>를 <code>.always</code> 또는 <code>.never</code>로 설정하는 것이 답이였다.</p>
<h1 id="발생한-오류">발생한 오류</h1>
<p><code>NavigationController</code>가 Embed된 VC1, 그리고 VC2가 있다고 가정하자.
내가 구현하고 싶었던 것은 VC1에서 VC2로 이동할 때
VC1의 <code>title</code>은 크게, VC2의 <code>title</code>은 작게 설정하는 것이였다.</p>
<p>하지만 여러 시도에도 불구하고 다음과 같은 오류들이 발생했다.</p>
<ul>
<li>VC1과 VC2의 <code>title</code>이 모두 크게 설정됨.</li>
<li>VC1에서 VC2로 이동시 <code>title</code>이 작아지기는 하나, VC1으로 다시 이동하면 VC1은 작은 상태임.</li>
</ul>
<h1 id="문제의-코드">문제의 코드</h1>
<p>나는 <code>title</code>을 VC1의 <code>prefersLargeTitles</code>의 값으로만 제어하려 했다.
따라서 문제의 코드는 다음과 같은 모습을 보였다.
<strong>VC1</strong></p>
<pre><code class="language-swift">override func viewWillAppear(_ animated: Bool) {
    self.navigationController?.navigationBar.prefersLargeTitles = true
        self.navigationController?.navigationBar.sizeToFit()
}

//VC2로의 transition 완료(본코드에는 RxSwift 활용)
transitionToVC2Complete() {
    self.navigationController?.navigationBar.prefersLargeTitles = false
}</code></pre>
<h1 id="해결방법">해결방법</h1>
<p>이 문제를 해결하는 법은 <code>title</code>의 크기를 <code>prefersLargeTitles</code>로 control하는 것이 아닌,
<code>navigationItem</code>의 <code>largeTitleDisplayMode</code>를 사용하는 것이였다.</p>
<p>VC1에서 <code>prefersLargeTitles</code>를 <code>true</code>로 놔둔 상태에서 
VC2의 <code>largeTitleDisplayMode</code>를 <code>.always</code> 또는 <code>.never</code>로 설정하는 것이 답이였다.</p>
<p>즉 다음과 같이 작성해야 정상적으로 작동한다. 세상에...
<strong>VC1</strong></p>
<pre><code class="language-swift">override func viewDidLoad() {
        super.viewDidLoad()
        self.navigationController?.navigationBar.prefersLargeTitles = true
}

override func viewWillAppear(_ animated: Bool) {
        self.navigationController?.navigationBar.sizeToFit()
}</code></pre>
<p><strong>VC2</strong></p>
<pre><code>override func viewDidLoad() {
        super.viewDidLoad()
        self.navigationItem.largeTitleDisplayMode = .never
    }</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[Observable vs Subject]]></title>
            <link>https://velog.io/@mo_nireu/Observable-vs-Subject</link>
            <guid>https://velog.io/@mo_nireu/Observable-vs-Subject</guid>
            <pubDate>Mon, 26 Jul 2021 07:16:08 GMT</pubDate>
            <description><![CDATA[<h1 id="요약">요약</h1>
<table>
<thead>
<tr>
<th>구분</th>
<th>Observable</th>
<th>Subject</th>
</tr>
</thead>
<tbody><tr>
<td>구조</td>
<td>State가 존재하지 않는다.(함수임)</td>
<td>State를 가짐.(Data를 메모리에 저장)</td>
</tr>
<tr>
<td>Observer 별</td>
<td>Observer 마다 따로 코드 실행 (unicast)</td>
<td>모든 Observer에 같은 코드 실행 (multicast)</td>
</tr>
<tr>
<td>역할</td>
<td>Observable 역할만 수행</td>
<td>Observable 및 Observer 역할 수행</td>
</tr>
<tr>
<td>용도</td>
<td>하나의 Observer에 대한 Observable이 필요할 때</td>
<td>1. 잦은 데이터 저장 및 수정</br>2. 여러 Observer가 관찰해야 할 때</br>3. Observer와 Observable의 Proxy역할</td>
</tr>
</tbody></table>
<h1 id="참고자료">참고자료</h1>
<ul>
<li><a href="https://sujinnaljin.medium.com/rxswift-subject-99b401e5d2e5">https://sujinnaljin.medium.com/rxswift-subject-99b401e5d2e5</a></li>
<li><a href="https://ntomios.tistory.com/12">https://ntomios.tistory.com/12</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Associated Type]]></title>
            <link>https://velog.io/@mo_nireu/Associated-Type</link>
            <guid>https://velog.io/@mo_nireu/Associated-Type</guid>
            <pubDate>Sat, 10 Jul 2021 07:53:18 GMT</pubDate>
            <description><![CDATA[<h1 id="요약">요약</h1>
<p><strong>Protocol에서 타입의 견본을 주는(placeholder) Generic 개념.</strong></p>
<h1 id="기본-개념">기본 개념</h1>
<h2 id="placeholder-역할">PlaceHolder 역할</h2>
<blockquote>
<p><strong>An associated type gives a placeholder name to a type that’s used as part of the protocol.</strong> 
associated type은 protocol에 사용되는 타입의 견본(placeholder name)을 주는 역할을 한다.</p>
</blockquote>
<p>Generic에 포함된 개념이다.
한 마디로 protocol을 작성할 때 각각의 property에 적용하는 Generic Type이라고 생각할 수 있다.</p>
<h3 id="예시">예시</h3>
<p>다음과 같은 <code>NumberProtocol</code>이라는 protocol이 있다고 가정하자. 그 안의 <code>thousand</code> property는 1,000의 자리 숫자를 가진다. 그 값은 <code>Int</code>형 일 수도 있고 <code>String</code>형 일 수도 있다. 이를 해결하기 위해서 associated type <code>Number</code>을 설정한다.</p>
<pre><code class="language-swift">protocol NumberProtocol {
    associatedtype Number
    var thousand: Number { get }
}</code></pre>
<p><code>Int</code>형 <code>thousand</code>을 가지는 <code>NumberInt</code> struct는 다음과 같이 만들 수 있다.</p>
<pre><code class="language-swift">struct NumberInt: NumberProtocol {
    var thousand: Int {
        return 1000
    }
}</code></pre>
<p><code>String</code>형 <code>thousand</code>을 가지는 <code>NumberString</code> struct는 다음과 같이 만들 수 있다.</p>
<pre><code class="language-swift">struct NumberString: NumberProtocol {
    var thousand: String {
        return &quot;1000&quot;
    }
}</code></pre>
<hr>
<h2 id="제약-설정">제약 설정</h2>
<p>associated type에는 제약도 설정해 줄 수 있다.</p>
<h3 id="예시-1">예시</h3>
<p>다음과 같이 associated type <code>Number</code>에 <code>Equatable</code> 제약을 설정한다.</p>
<pre><code class="language-swift">protocol NumberProtocol {
    associatedtype Number: Equatable
    var thousand: Number { get }
}</code></pre>
<p>위에서 작성한 <code>Int</code>형과 <code>String</code>형을 가지는 Struct들은 오류가 발생하지 않는다. 기본적으로 Swift의 <code>Int</code>형과 <code>String</code>형 모두 Equatable을 준수하기 때문이다.</p>
<pre><code class="language-swift">struct NumberInt: NumberProtocol {
    var thousand: Int {
        return 1000
    }
}

struct NumberString: NumberProtocol {
    var thousand: String {
        return &quot;1000&quot;
    }
}</code></pre>
<p>하지만 커스텀으로 작성한 <code>NotEquatable</code>class를 제약을 걸어둔 associated type <code>Number</code>에 넣을 경우 Error을 띄우게 된다. <code>NotEquatable</code>은 Equatable을 준수하고 있지 않기 때문이다.
<img src="https://images.velog.io/images/mo_nireu/post/2b7c6b14-7d48-4ade-a140-d8e99ddc911e/image.png" alt=""></p>
<h1 id="참고자료">참고자료</h1>
<ul>
<li><a href="https://docs.swift.org/swift-book/LanguageGuide/Generics.html#//apple_ref/doc/uid/TP40014097-CH26-XID_283">https://docs.swift.org/swift-book/LanguageGuide/Generics.html#//apple_ref/doc/uid/TP40014097-CH26-XID_283</a></li>
<li><a href="https://zeddios.tistory.com/382">https://zeddios.tistory.com/382</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Weak vs Unowned]]></title>
            <link>https://velog.io/@mo_nireu/Weak-vs-Unowned</link>
            <guid>https://velog.io/@mo_nireu/Weak-vs-Unowned</guid>
            <pubDate>Sun, 04 Jul 2021 08:33:44 GMT</pubDate>
            <description><![CDATA[<h1 id="요약">요약</h1>
<p><strong><code>weak</code>(optional) vs <code>unowned</code>(non-optional)</strong></p>
<h1 id="개념">개념</h1>
<p><code>weak</code>와 <code>unowned</code>는 Strong Reference Cycle을 해결하기 위해서 사용한다.
두 방식의 차이는 optional과 non-optional의 차이이다.</p>
<p><code>weak</code>의 경우에는 optional을 사용해야한다. <code>unonwed</code>는 값이 무조건 있다고 가정하고 사용하기 때문에 optional을 채택해서는 안된다.</p>
<p>다음은 <code>weak</code>를 사용한 코드이다.</p>
<pre><code class="language-swift">class Company {
    let name: String
    weak var car: Car?

    init(name: String) {
        self.name = name
        print(&quot;Company Init&quot;)
    }

    deinit { print(&quot;Company Deinit&quot;) }
}

class Car {
    let name: String
    var company: Company?

    init(name: String) {
        self.name = name
        print(&quot;Car Init&quot;)
    }
    deinit { print(&quot;Car Deinit&quot;) }
}


var k8: Car? = .init(name: &quot;k8&quot;)    // Car Init
var kia: Company? = .init(name: &quot;KIA&quot;)    // Company Init

k8?.company = kia
kia?.car = k8

k8 = nil    // Car Deinit
kia?.car    // nil</code></pre>
<p><img src="https://images.velog.io/images/mo_nireu/post/e8a23b38-2d72-4649-b066-b823d233cb03/image.png" alt=""></p>
<p><code>Company(kia)</code>와 <code>Car(k8)</code> 두개의 class가 서로를 property로 가리키고 있는 상태에서, <code>Car</code>을 해제한 후 <code>Company</code>의 property <code>car</code>을 출력해보니 <code>nil</code>이 출력되는 것을 볼 수 있다.</p>
<p><code>weak</code>는 기본적으로 가리키던 instance가 메모리에서 해제될 경우 nil이 할당된다. 따라서 <code>Company(kia)</code>의 property <code>car</code>이 가리키던 <code>Car(k8)</code>이 해제되자 <code>car</code>에는 nil이 할당 된 것이다.</p>
<hr>
<p>그렇다면 위의 코드에 <code>weak</code>를 <code>unowned</code>로 바꾸면 어떻게 될까?</p>
<pre><code class="language-swift">class Company {
    let name: String
    unowned var car: Car?

    init(name: String) {
        self.name = name
        print(&quot;Company Init&quot;)
    }

    deinit { print(&quot;Company Deinit&quot;) }
}

class Car {
    let name: String
    var company: Company?

    init(name: String) {
        self.name = name
        print(&quot;Car Init&quot;)
    }
    deinit { print(&quot;Car Deinit&quot;) }
}


var k8: Car? = .init(name: &quot;k8&quot;)    // Car Init
var kia: Company? = .init(name: &quot;KIA&quot;)    // Company Init

k8?.company = kia
kia?.car = k8

k8 = nil    // Car Deinit
kia?.car    //Error</code></pre>
<p><img src="https://images.velog.io/images/mo_nireu/post/62b036ed-c88f-49c6-838e-b99411f3477d/image.png" alt=""></p>
<p>위와 같이 Error을 띄우게 된다. <code>weak</code>와 달리 <code>unowned</code>는 가리키던 instance가 해제되면 nil을 반환하지 않는다. 대신 해제된 메모리 주소값을 계속해서 들고 있는다. 따라서 이에 접근하려 할 경우, 다음과 같이  Error을 뿜어낸는 것이다.</p>
<p>이러한 이유로 <code>unowned</code>는 non-optional로 설정해야한다. 다음과 같은 코드가 <code>unowned</code>를 바르게 사용하는 코드이다.</p>
<pre><code class="language-swift">class Company {
    let name: String
    unowned let car: Car

    init(name: String, car: Car) {
        self.name = name
        self.car = car
        print(&quot;Company Init&quot;)
    }

    deinit { print(&quot;Company Deinit&quot;) }
}

class Car {
    let name: String
    var company: Company?

    init(name: String) {
        self.name = name
        print(&quot;Car Init&quot;)
    }
    deinit { print(&quot;Car Deinit&quot;) }
}
</code></pre>
<h1 id="참고자료">참고자료</h1>
<p><a href="https://babbab2.tistory.com/27">https://babbab2.tistory.com/27</a>
<a href="http://minsone.github.io/mac/ios/rules-of-weak-and-unowned-in-swift">http://minsone.github.io/mac/ios/rules-of-weak-and-unowned-in-swift</a>
<a href="https://docs.swift.org/swift-book/LanguageGuide/AutomaticReferenceCounting.html">https://docs.swift.org/swift-book/LanguageGuide/AutomaticReferenceCounting.html</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[@discardableResult]]></title>
            <link>https://velog.io/@mo_nireu/discardableResult</link>
            <guid>https://velog.io/@mo_nireu/discardableResult</guid>
            <pubDate>Sat, 03 Jul 2021 09:16:15 GMT</pubDate>
            <description><![CDATA[<h1 id="요약">요약</h1>
<p><strong>어떠한 함수를 사용했지만 반환값을 활용하지 않았을 경우, swift는 경고문을 띄워준다.
이 경고를 제거하기 위해서 <code>@discardableResult</code>를 사용한다.</strong></p>
<h1 id="개념">개념</h1>
<blockquote>
<p><strong>discardable result</strong> 
버릴 수 있는 결과</p>
</blockquote>
<p>다음과 같은 <code>plus</code> 함수가 있다고 가정한다.</p>
<pre><code class="language-swift">func plus(_ n1: Int, _ n2: Int) -&gt; Int {
        return n1 + n2
}</code></pre>
<p><code>plus</code> 함수를 사용하였지만, 반환값 <code>Int</code> 를 활용하지 않았다.</p>
<pre><code class="language-swift">plus(1, 2)</code></pre>
<p>이 경우 Swift는 다음과 같이 경고를 보여준다.
<img src="https://images.velog.io/images/mo_nireu/post/ad887c0a-30fa-413a-8df7-5f07dc18c0ed/image.png" alt=""></p>
<p>해당 경고를 없애기 위해서 <code>@discardableResult</code>를 사용한다.</p>
<h1 id="활용">활용</h1>
<p><code>plus</code> 함수 위에 <code>@discardableResult</code>를 추가한다.</p>
<pre><code class="language-swift">@discardableResult
func plus(_ n1: Int, _ n2: Int) -&gt; Int {
        return n1 + n2
}</code></pre>
<p>경고가 사라진 모습을 볼 수 있다.
<img src="https://images.velog.io/images/mo_nireu/post/88ac0270-36ae-4141-8902-a2cc6b6e192f/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Equatable]]></title>
            <link>https://velog.io/@mo_nireu/Equatable</link>
            <guid>https://velog.io/@mo_nireu/Equatable</guid>
            <pubDate>Sat, 03 Jul 2021 08:19:51 GMT</pubDate>
            <description><![CDATA[<h1 id="요약">요약</h1>
<p><strong>Equatable Protocol을 적용하여 Custom Type끼리의 비교가 가능하다</strong></p>
<h1 id="기본-개념">기본 개념</h1>
<blockquote>
<p><strong>A type that can be compared for value equality.</strong>
값이 동일한지 비교할 수 있는 Type</p>
</blockquote>
<p>Swift 공식 문서에 정의되어있는 Equatable의 개념이다.</p>
<p>Swift 기본 Type들은 대부분 Equatable을 따른다.
Equatable을 따르는 Type들은 같다(<code>==</code>)와 같지 않다(<code>!=</code>) 연산자를 사용할 수 있다.
아래 코드와 같이 말이다.</p>
<pre><code class="language-swift">var c1 = &quot;ABC&quot;
var c2 = &quot;ABC&quot;
var c3 = &quot;XZY&quot;

print(c1 == c2 ? true : false)
// true

print(c1 != c2 ? true : false)
// false

print(c2 == c3 ? true: false)
// false</code></pre>
<h1 id="활용">활용</h1>
<p>기본적으로 Swift에서 Class, Structure, Enum과 같은 CustomType은 서로 비교 불가하다.</p>
<pre><code class="language-swift">class StreetAddress {
    let number: String
    let street: String

    init(_ number: String, _ street: String) {
        self.number = number
        self.street = street
    }
}

print(StreetAddress(&quot;1&quot;, &quot;A&quot;) == StreetAddress(&quot;1&quot;, &quot;A&quot;) ? true : false)
//Error: binary operator &#39;==&#39; cannot be applied to two &#39;StreetAddress&#39; operands</code></pre>
<p>다음과 같이 StreetAddress에 대하여 <code>==</code> 연산자 적용이 불가능하다는 Error가 뜬다.</p>
<p>하지만 이러한 상황에서 Class, Structure, Enum등을 비교하고 싶을 경우, Equatable을 사용하면 된다.</p>
<p>Equatable은 Protocol이다. 
위에서 말했듯이 Equatable을 따르는 Type들은 서로 같은지 비교할 수 있다. 
한마디로 Equatable을 적용할 경우 Class, Structure, Enum 등을 비교할 수 있다.</p>
<pre><code class="language-swift">class StreetAddress: Equatable {
    static func == (lhs: StreetAddress, rhs: StreetAddress) -&gt; Bool {
        return
            lhs.number == rhs.number &amp;&amp;
            lhs.street == rhs.street
    }

    let number: String
    let street: String

    init(_ number: String, _ street: String) {
        self.number = number
        self.street = street
    }
}

print(StreetAddress(&quot;1&quot;, &quot;A&quot;) == StreetAddress(&quot;1&quot;, &quot;A&quot;) ? true : false)
// true
print(StreetAddress(&quot;1&quot;, &quot;A&quot;) != StreetAddress(&quot;1&quot;, &quot;A&quot;) ? true : false)
// false
print(StreetAddress(&quot;1&quot;, &quot;A&quot;) == StreetAddress(&quot;2&quot;, &quot;B&quot;) ? true : false)
// false</code></pre>
<p>Euatable을 적용하고 해당 프로토콜에서 요구하는 <code>static func == (lhs: Self, rhs: Self) -&gt; Bool</code> 을 작성했더니 <code>StreetAddress</code> Class끼리 비교가 가능해졌다.
<code>static func == (lhs: Self, rhs: Self) -&gt; Bool</code> 내부에는 비교할 Type의 모든 Property들이 같은지 확인하여 반환하면 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Class vs Structure]]></title>
            <link>https://velog.io/@mo_nireu/Class-vs-Structure</link>
            <guid>https://velog.io/@mo_nireu/Class-vs-Structure</guid>
            <pubDate>Fri, 14 May 2021 08:49:11 GMT</pubDate>
            <description><![CDATA[<h1 id="class--structure">Class &amp; Structure</h1>
<ul>
<li>Class와 Struct는 swift의 근간을 이루는(객체지향) 매우 중요한 핵심 요소이다.</li>
<li>Class와 Struct는 Member(Property / Method)를 포함한다.<ul>
<li>Property : Struct와 Class 내부에서 정의된 변수나 상수.</li>
<li>Method : Struct와 Class 내부에 정의된 함수.</li>
</ul>
</li>
</ul>
<h2 id="class-vs-structure">Class VS Structure</h2>
<h3 id="공통점">공통점</h3>
<pre><code>* Property 및 메소드 정의
* 서브스크립트 정의
* 초기화 블록 정의
* 확장(extends) 구문
* 프로토콜 구현</code></pre><h3 id="차이점class만-가능한-것들">차이점(Class만 가능한 것들)</h3>
<pre><code>* 상속
* 타입 캐스팅
* 소멸화 구문
* 참조에 의한 전달(Struct는 값에 의한 전달) </code></pre><h3 id="struct-사용-목적">Struct 사용 목적</h3>
<ul>
<li>서로 연관된 몇 개의 기본 데이터 타입 캡술화.</li>
<li>상속이 필요하지 않을때.</li>
<li>데이터 전달 방식이 값에 의한 전달일 경우 더 효율적일 때.</li>
<li>캡슐화된 원본 데이터 보존.</li>
</ul>
<h3 id="값-전달-방식">값 전달 방식</h3>
<ul>
<li>Class : 참조에 의한 전달(Reference Type) </li>
<li>Struct : 값에 의한 전달(Value Type) </li>
</ul>
<h4 id="class---참조에-의한-전달reference-type">Class - 참조에 의한 전달(Reference Type)</h4>
<ul>
<li>한 곳에서 수정할 경우 다른 곳에도 적용된다.</li>
<li>하나의 Class Instance는 오로지 하나의 변수/상수만이 참조할 수 있다.</li>
<li>하나의 Class Instance를 여러 변수나 상수, 또는 함수의 인자값에서 동시에 참조할 수 있다.</li>
</ul>
<pre><code class="language-swift">class VideoMode {
var interlaced = false
var frameRate = 0.0
var name: String?
}

func changeName(v: VideoMode) {
    v.name = &quot;Function Video Instance&quot;
}

let video = VideoMode()
video.name = &quot;Original Video Instance&quot;
print(&quot;video 인스턴스의 name 값은 \(video.name!)입니다.&quot;)
//video 인스턴스의 name 값은 Original Video Instance입니다.

let dvd = video
dvd.name = &quot;DVD Video Instance&quot;
print(&quot;video 인스턴스의 name 값은 \(video.name!)입니다.&quot;)
//video 인스턴스의 name 값은 DVD Video Instance입니다.

changeName(v: video)
print(&quot;video 인스턴스의 name 값은 \(video.name!)입니다.&quot;)
//video 인스턴스의 name 값은 Function Video Instance입니다.</code></pre>
<h5 id="인스턴스-비교">인스턴스 비교</h5>
<ul>
<li>참조 타입이기 때문에 같은 인스턴스 비교하는 연산자 활용<ul>
<li>동일 인스턴스 인지 비교 : ===</li>
<li>동일 인스턴스가 아닌지 비교 : !==</li>
</ul>
</li>
</ul>
<p>동일 인스턴스 참조</p>
<pre><code class="language-swift">class VideoMode {
var interlaced = false
var frameRate = 0.0
var name: String?
}

let video = VideoMode()
let dvd = video

if (video === dvd) {
    print(&quot;video와 DVD는 동일한 인스턴스를 참조하고 있습니다.&quot;)
} else {
    print(&quot;video와 DVD는 서로 다른 인스턴스를 참조하고 있습니다.&quot;)
}

// &quot;video와 DVD는 동일한 인스턴스를 참조하고 있습니다.&quot;</code></pre>
<p>서로 다른 인스턴스 참조</p>
<pre><code class="language-swift">class VideoMode {
var interlaced = false
var frameRate = 0.0
var name: String?
}

let video = VideoMode()
let dvd = VideoMode()

if (video === dvd) {
    print(&quot;video와 DVD는 동일한 인스턴스를 참조하고 있습니다.&quot;)
} else {
    print(&quot;video와 DVD는 서로 다른 인스턴스를 참조하고 있습니다.&quot;)
}

// &quot;video와 DVD는 서로 다른인스턴스를 참조하고 있습니다.&quot;</code></pre>
<h4 id="struct---값에-의한-전달value-type">Struct - 값에 의한 전달(Value Type)</h4>
<ul>
<li>모든 Struct Instance들은 상수나 변수에 할당될 때 복사됨.</li>
<li>따라서 변수에 대입된 기존의 Instance는 서로 독립적이다.</li>
<li>Instance가 상수/변수 중 어느곳에 할당 되는가에 따라 Property값을 변경 여부가 달라진다.<ul>
<li>상수 할당 : Property 변경 불가</li>
<li>변수 할당 : Property 변경 가능</li>
</ul>
</li>
</ul>
<pre><code class="language-swift">struct Resolution {
    var width = 0
    var heigth = 0
}

let hd = Resolution(width: 1920, heigth: 1080)

var cinema = hd
cinema.width = 2048

print(&quot;hd 인스턴스의 width 값은 \(hd.width)입니다.&quot;)
//&quot;hd 인스턴스의 width 값은 1920입니다.\n&quot;

print(&quot;cinema 인스턴스의 width 값은 \(cinema.width)입니다.&quot;)
//&quot;cinema 인스턴스의 width 값은 2048입니다.&quot;</code></pre>
<h2 id="인스턴스instance">인스턴스(Instance)</h2>
<blockquote>
<p>메모리의 공간을 할당 받는 객체</p>
</blockquote>
<ul>
<li>Instance를 생성하여 Property에 접근한다.</li>
<li>dot 문법(.)을 통해 Property에 접근할 수 있다.</li>
</ul>
<h2 id="초기화initialize">초기화(Initialize)</h2>
<ul>
<li>스위프트에서 Optional로 설정되지 않은 모든 Property는 명시적으로 초기화해 주어야 한다.</li>
<li>초기화는 다음 방식으로 수행한다.<ul>
<li>Property를 선언하면서 동시에 초기값을 지정.</li>
<li>초기화 메소드 내에서 Property의 초기값을 지정.</li>
<li>위 두 방법이 불가할 경우 Optional 타입으로 설정.</li>
</ul>
</li>
</ul>
<h3 id="기본-초기화-구문initializer">기본 초기화 구문(Initializer)</h3>
<ul>
<li>Instance만을 생성하는 초기화 구문이다.</li>
<li>어떠한 Property도 초기화하지 않는다.</li>
<li>Class의 경우 모든 Property가 선언과 동시에 초기화되어 있을 경우에만 사용할 수 있다.</li>
</ul>
<pre><code class="language-swift">// 어떠한 인자도 받지 않고 단순히 Resolution 인스턴스만 생성
let defaultRes = Resolution()</code></pre>
<h3 id="멤버-와이즈-초기화-구문memberwise-initializer">멤버 와이즈 초기화 구문(Memberwise Initializer)</h3>
<ul>
<li>Struct는 모든 Property의 값을 인자값으로 입력받아 초기화하는 멤버와이즈 초기화 구문을 제공한다.(Class는 제공하지 않음)</li>
<li>하나의 Property만 초기화하는 구문은 제공하지 않는다.</li>
</ul>
<pre><code class="language-swift">// width와 height를 매개변수로 하여 Resolution 인스턴스 생성
let defaultRes = Resolution(width: 1024, height: 768)</code></pre>
]]></description>
        </item>
    </channel>
</rss>