<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>malrang-malrang.log</title>
        <link>https://velog.io/</link>
        <description>my brain is malrang</description>
        <lastBuildDate>Sun, 03 Apr 2022 06:53:30 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>malrang-malrang.log</title>
            <url>https://images.velog.io/images/malrang-malrang/profile/3e7098ce-b72e-4196-815a-0263673d30da/social.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. malrang-malrang.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/malrang-malrang" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[객체 지향의 사실과 오해]]></title>
            <link>https://velog.io/@malrang-malrang/%EA%B0%9D%EC%B2%B4-%EC%A7%80%ED%96%A5%EC%9D%98-%EC%82%AC%EC%8B%A4%EA%B3%BC-%EC%98%A4%ED%95%B4</link>
            <guid>https://velog.io/@malrang-malrang/%EA%B0%9D%EC%B2%B4-%EC%A7%80%ED%96%A5%EC%9D%98-%EC%82%AC%EC%8B%A4%EA%B3%BC-%EC%98%A4%ED%95%B4</guid>
            <pubDate>Sun, 03 Apr 2022 06:53:30 GMT</pubDate>
            <description><![CDATA[<p>열심히 읽어보자..</p>
<p><img src="https://media.vlpt.us/images/malrang-malrang/post/3cb11f9e-cdea-4944-b507-e23351b09cb2/KakaoTalk_Image_2022-04-03-15-52-30.jpeg" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Formatter,  Number Formatter]]></title>
            <link>https://velog.io/@malrang-malrang/Formatter-Number-Formatter</link>
            <guid>https://velog.io/@malrang-malrang/Formatter-Number-Formatter</guid>
            <pubDate>Sat, 02 Apr 2022 12:09:26 GMT</pubDate>
            <description><![CDATA[<h1 id="formatter-number-formatter">Formatter, Number Formatter</h1>
<h2 id="formatter">Formatter</h2>
<p>값을 다양한 텍스트 값으로 변환해 줄 수있는 추상 타입</p>
<p>Foundation 에서 지원하는 Formatter 는 다음과 같다.</p>
<ol>
<li>ByteCountFormatter</li>
<li>DateFormatter</li>
<li>DateComponentsFormatter</li>
<li>DateIntervalFormatter</li>
<li>MeasurementFormatter</li>
<li>NumberFormatter</li>
<li>PersonNameComponentsFormatter</li>
</ol>
<p>custom 하여 formatter 를 만들어 사용할수도 있다!</p>
<h2 id="number-formatter">Number Formatter</h2>
<p>Number Formatter 는 Formatter 를 상속 받는 추상 타입!
<code>class NumberFormatter : Formatter</code></p>
<p>숫자들의 값이 큰 경우 콤마를 사용하여 구분해주는 경우가 생긴다.</p>
<p>이때 직접 로직을 만들어 사용할수도 있지만 
NumberFormatter 타입을 이용해 숫자형식을 변환할수 있다.</p>
<p>Int 혹은 Double 값을 넣어 String 값으로 반환 받을수 있는데 이때 반환된 값은 설정해둔 옵션에따라 3자리수 부터 콤마를 포함된 값으로 반환하거나, 숫자를 영어로 바꾸어 표기해주거나 옵션이 다양하다.</p>
<p>또 0이아닌 소수 0.1 등 소수부분을 표시하기 위한 옵션도 제공한다.
(소수의 유효자릿수 를 설정하는 옵션도 제공한다!)</p>
<p>옵션이 정말 많으니 공식 문서 사이트를 보고 참고하자!</p>
<p><a href="https://developer.apple.com/documentation/foundation/numberformatter">Number Formatter</a></p>
<h2 id="number-formatter-를-사용해보자">Number Formatter 를 사용해보자</h2>
<p>Number Formatter 를 인스턴스화 하여 생성해준다!</p>
<pre><code class="language-swift">let numberFormatter = NumberFormatter()</code></pre>
<p>사용할때는 생성해둔 numberFormmatter 에 옵션을 설정해준뒤
.string, .number 과 같은 메서드를 사용해
설정해둔 옵션을 거쳐 String? 값으로 반환해준다.</p>
<h3 id="numberstyle숫자를-나타낼-스타일"><strong>numberStyle</strong>(숫자를 나타낼 스타일)</h3>
<p><code>numberStyle</code> 는 숫자를 어떤 스타일로 나타낼것인지 결정하는 프로퍼티</p>
<ol>
<li><p><strong>.decimal</strong></p>
<pre><code class="language-swift">let value: Double = 1234
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .decimal
let result = numberFormatter.string(for: value)
// &quot;1,234&quot;</code></pre>
<p>위의 예시에 사용된 .decimal 은 10 진법 형식으로 표현하도록 해준다.
(Decimal 타입으로 변환되는것 아님)
(로컬에 있는 위치의 10진법에 맞는 표기로 설정해주라는 뜻 이다.)
(나라 마다 .decimal 이 나타내는 표현이 달라진다고 한다.)</p>
</li>
<li><p><strong>.currency</strong></p>
<pre><code class="language-swift">let numberFormatter = NumberFormatter()
let value: Double = 1234
numberFormatter.numberStyle = .currency
let result = numberFormatter.string(for: value)
// &quot;$1,234.00&quot;</code></pre>
</li>
<li><p><strong>.percent</strong></p>
<pre><code class="language-swift">let numberFormatter = NumberFormatter()
let value: Double = 1234
numberFormatter.numberStyle = .percent
let result = numberFormatter.string(for: value)
// &quot;1,234&quot;</code></pre>
</li>
</ol>
<h3 id="roundingmode반올림"><strong>roundingMode</strong>(반올림)</h3>
<ol>
<li><strong>.ceilng, .floor</strong>(정수부분 까지 올림, 내림)</li>
</ol>
<p><strong>.ceilng</strong>(정수 부분까지 올림)</p>
<pre><code class="language-swift">let numberFormatter = NumberFormatter()
let value: Double = 1234.3333
numberFormatter.roundingMode = .ceiling
let result = numberFormatter.string(for: value)
// 1235</code></pre>
<p><strong>.floor</strong>(정수 부분까지 내림)</p>
<pre><code class="language-swift">let numberFormatter = NumberFormatter()
let value: Double = 1234.3333
numberFormatter.roundingMode = .floor
let result = numberFormatter.string(for: value)
// 1234</code></pre>
<ol start="2">
<li><strong>.down, .Up</strong>(0을 향해 반올림, 0에서 반올림)</li>
</ol>
<p><strong>.down</strong>(0을 향해 반올림? Round towards zero.)</p>
<pre><code class="language-swift">let numberFormatter = NumberFormatter()
let value: Double = 1234.3333
numberFormatter.roundingMode = .down
let result = numberFormatter.string(for: value)
// 1234</code></pre>
<p><strong>.up</strong>(0에서 반올림? Round away from zero.)</p>
<pre><code class="language-swift">let numberFormatter = NumberFormatter()
let value: Double = 1234.3
numberFormatter.roundingMode = .up
let result = numberFormatter.string(for: value)
// 1235</code></pre>
<ol start="3">
<li><strong>.halfUp, halfDown</strong>(반올림, 반내림)</li>
</ol>
<p>두가지의 차이점은 반으로 나누었을때 의 값을가지고 올려줄것인지 내려줄것인지 의 차이가 있다.
쉽게 설명하자면 10 을 중간인 5 를 halfUp을 하게되면 올림을 하게되고
halfDown 을 하게 되면 내림을 하게된다.</p>
<p><strong>.halfUp</strong></p>
<pre><code class="language-swift">let numberFormatter = NumberFormatter()
let value: Double = 1234.5
numberFormatter.roundingMode = .halfUp
let result = numberFormatter.string(for: value)
// 1235</code></pre>
<p><strong>.halfDown</strong></p>
<pre><code class="language-swift">let numberFormatter = NumberFormatter()
let value: Double = 1234.5
numberFormatter.roundingMode = .halfDown
let result = numberFormatter.string(for: value)
// 1234</code></pre>
<ol start="4">
<li><strong>.halfEven</strong>(가장가까운쪽으로 반올림, 중앙일경우 짝수가 되도록 반올림)</li>
</ol>
<p><strong>.halfEven</strong></p>
<pre><code class="language-swift">let numberFormatter = NumberFormatter()
let value: Double = 1234.5
numberFormatter.roundingMode = .halfEven
let result = numberFormatter.string(for: value)
// 1234

let numberFormatter = NumberFormatter()
let value: Double = 1235.5
numberFormatter.roundingMode = .halfEven
let result = numberFormatter.string(for: value)
// 1236</code></pre>
<p>위의 예시를 보면 알수 있듯이 반올림하는 기능이지만 등 거리 일경우 수가 짝수가 될수 있도록 반올림, 반내림 하게 된다.</p>
<h2 id="정수-및-소수-자릿수-구성">정수 및 소수 자릿수 구성</h2>
<ol>
<li>minimumIntegerDigits</li>
</ol>
<ul>
<li>소수점 구분 기호 앞의 최소 자릿수</li>
</ul>
<ol start="2">
<li>maximumIntegerDigits</li>
</ol>
<ul>
<li>소수점 구분 기호 앞의 최대 자릿수</li>
</ul>
<ol start="3">
<li>maximumIntegerDigits</li>
</ol>
<ul>
<li>소수점 구분 기호 뒤의 최소 자릿수</li>
</ul>
<ol start="4">
<li>maximumFractionDigits</li>
</ol>
<ul>
<li>소수점 구분 기호 뒤의 최대 자릿수</li>
</ul>
<h2 id="유효-자릿수-구성">유효 자릿수 구성</h2>
<ol>
<li>usesSignificantDigits</li>
</ol>
<ul>
<li>최대 유효 자릿수를 사용하는지 나타내는 프로퍼티 (Bool값)</li>
</ul>
<ol start="2">
<li>minimumSignificantDigits</li>
</ol>
<ul>
<li>최소 유효 자릿수</li>
</ul>
<ol start="3">
<li>maximumSignificantDigits</li>
</ol>
<ul>
<li>최대 유효 자릿수</li>
</ul>
<p>이외에도 여러가지 옵션들이 많으며 NumberFormatter 은 여러 나라에서 사용되는 앱에서 자주 사용되는것 같다 (국제 통화 를 비교해야 할때?)</p>
<p>다음에또 사용하게된다면 더 깊게 공부해보자..</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[ARC 자동 참조 카운팅 (Automatic Reference Counting)]]></title>
            <link>https://velog.io/@malrang-malrang/ARC-%EC%9E%90%EB%8F%99-%EC%B0%B8%EC%A1%B0-%EC%B9%B4%EC%9A%B4%ED%8C%85-Automatic-Reference-Counting</link>
            <guid>https://velog.io/@malrang-malrang/ARC-%EC%9E%90%EB%8F%99-%EC%B0%B8%EC%A1%B0-%EC%B9%B4%EC%9A%B4%ED%8C%85-Automatic-Reference-Counting</guid>
            <pubDate>Sat, 02 Apr 2022 12:06:12 GMT</pubDate>
            <description><![CDATA[<h1 id="arc-자동-참조-카운팅-automatic-reference-counting">ARC 자동 참조 카운팅 (Automatic Reference Counting)</h1>
<h2 id="arc-자동-참조-카운팅-automatic-reference-counting-1">ARC 자동 참조 카운팅 (Automatic Reference Counting)</h2>
<p>swift는 앱의 메모리 사용량을 관리하기 위해 ARC 를 사용한다.
ARC 는 클래스 인스턴스가 더이상 사용되지 않을때 자동으로 메모리에서 해제 시켜준다.</p>
<p>ARC 는 해당 클래스의 RC(Reference Counting) 를 통해 사용하고있는지 사용되지 않는지 알수있고 이를 통해 자동으로 메모리에서 해제가 가능하게 된다.</p>
<h3 id="클래스의-저장-방식">클래스의 저장 방식</h3>
<p>클래스를 인스턴스화 하게되면 stack 에는 heap 을 가르키는 포인터가 저장된다.</p>
<p>이때 heap 영역을 참조하게 되므로 RC 는 1 이된다.
RC 는 heap 영역에 같이 저장된다.
RC 를 측정하기 위해 메모리를 조금더 사용한다고 할수 있겠다.</p>
<p><img src="https://i.imgur.com/Q8hPSjR.png" alt=""></p>
<p>새로운 상수 point2 를 만들어 point1 을 할당시 아래왜 같은 상황이 발생한다.</p>
<p><img src="https://i.imgur.com/WhMsXGC.png" alt=""></p>
<p>새로운 상수를 만들었기 때문에 stack 에 메모리를 하나더 사용하게 되고 
이미 생성되어있던 heap 영역의 메모리를 참조하기 때문에 heap 영역에 추가되는 것은 없으나 이때 heap 의 RC 는 1 증가 하게 된다.</p>
<p>이때 RC는 2 이다.</p>
<blockquote>
<p>상수 또는 변수에 클래스 인스턴스를 할당할 때 해당 인스턴스에 대한 강한 참조가 생긴다.</p>
</blockquote>
<p>이때 강한 참조(Strong) 는 참조가 유지되는 동안 메모리 할당 해제를 허용하지 않는것을 뜻한다.</p>
<h3 id="클래스-인스턴스-사이의-강한-참조-사이클-strong-reference-cycles-between-class-instances">클래스 인스턴스 사이의 강한 참조 사이클 (Strong Reference Cycles Between Class Instances)</h3>
<p>순환 참조 이녀석...</p>
<p>예시를 보자!</p>
<pre><code class="language-swift">class Person {
    let name: String
    init(name: String) { self.name = name }
    var apartment: Apartment?
    deinit { print(&quot;\(name) is being deinitialized&quot;) }
}

class Apartment {
    let unit: String
    init(unit: String) { self.unit = unit }
    var tenant: Person?
    deinit { print(&quot;Apartment \(unit) is being deinitialized&quot;) }
}</code></pre>
<p>이렇게 두개의 클래스 가 있다.</p>
<pre><code class="language-swift">var john: Person?
var unit4A: Apartment?</code></pre>
<p>얘내를 인스턴스화 하게되면 위의 예시처럼 각각 힙영역에 한놈 스택에는 힙의 주소를 저장할 한놈 씩 저장되게 된다.</p>
<p><img src="https://i.imgur.com/KMR1Iyy.png" alt=""></p>
<p>그런데 여기서 john, unit4A 의 프로퍼티인 apartment, tenant 에 서로를 연결시켜주면 ... 골때리는 상황이 생겨난다.</p>
<pre><code class="language-swift">john = Person(name: &quot;John Appleseed&quot;)
unit4A = Apartment(unit: &quot;4A&quot;)

john!.apartment = unit4A
unit4A!.tenant = john</code></pre>
<p>그림으로 보면 이해가 쉽다!</p>
<p><img src="https://i.imgur.com/OO9kNLY.png" alt=""></p>
<pre><code class="language-swift">john = nil
unit4A = nil</code></pre>
<p>이후 john, unit4A 의 값을 nil 을 넣어주면...
deinit 이 호출 되지 않는다..</p>
<p><img src="https://i.imgur.com/F09NraJ.png" alt=""></p>
<p>위와 같은 골때리는 상황이 생긴다.
서로 heap 영역에서 서로를 참조하는 순환 참조 상태이기때문에 
RC가 0이 되지 않아 메모리에서 해제 되지 않는다.</p>
<p>이런 순환 참조를 해결하는 방법이 weak 와 unowned 를 사용하는 것 이다.</p>
<h3 id="클래스-인스턴스-간의-강한-참조-사이클-해결-resolving-strong-reference-cycles-between-class-instances">클래스 인스턴스 간의 강한 참조 사이클 해결 (Resolving Strong Reference Cycles Between Class Instances)</h3>
<p>위에서 설명한 대로 해결 방법은 2가지 방법이 있다.</p>
<ol>
<li>Weak References(약한참조)</li>
<li>unowned references(미소유 참조)</li>
</ol>
<h3 id="약한-참조-weak-references">약한 참조 (Weak References)</h3>
<p>약한참조 weak 은 말그대로 약한 참조이며 RC 를 증가시키지 않는 방법이다.</p>
<pre><code class="language-swift">class Person {
    let name: String
    init(name: String) { self.name = name }
    var apartment: Apartment?
    deinit { print(&quot;\(name) is being deinitialized&quot;) }
}

class Apartment {
    let unit: String
    init(unit: String) { self.unit = unit }
    weak var tenant: Person?
    deinit { print(&quot;Apartment \(unit) is being deinitialized&quot;) }
}</code></pre>
<p>Apartment 의 프로퍼티인 tenant 에 weak 키워드를 사용하게되면 </p>
<pre><code class="language-swift">john = Person(name: &quot;John Appleseed&quot;)
unit4A = Apartment(unit: &quot;4A&quot;)

john!.apartment = unit4A
unit4A!.tenant = john</code></pre>
<p>아래 와 같이 서로 참조를 하게된다.</p>
<p><img src="https://i.imgur.com/uSwCzk6.png" alt=""></p>
<p>하지만 이때 위의 예시와 달라진점이 있는데 Apartment 가 Person 을 약한 참조 하는것으로 변경되어있는걸 알수 있다.</p>
<p>이후 john 에 nil 을 할당해주면 deinit이 호출되게 된다.</p>
<p><img src="https://i.imgur.com/nuZJQtl.png" alt=""></p>
<p>서로 순환 참조가 일어나지 않으므로 john 의 값이 nil 이되는순간 RC가 0이 되어 메모리에서 해제되게 된다.</p>
<p>이때 아파트에서 tenant 는 john 이었는데 john 이 nil 이되어버렸기 때문에 아파트의 tenant 는 자동적으로 nil 이된다.</p>
<p>ARC 는 참조하는 인스턴스가 해제되면 weak 참조 를 nil 로 바꿔 주는 기능 또한 가지고 있다!</p>
<p><strong>정리해보자</strong></p>
<ol>
<li>weak 키워드를 사용하면 참조중이던 인스턴스가 nil 이될경우 weak 키워드를 사용한 값도 nil 로 변경되므로 항상 nil 값을 포함하는 옵셔널 로 선언되어있어야 한다.</li>
<li>weak 키워드를 사용하면 값이 nil 로 변경될수 있으므로 항상 var 로 선언 되어야 한다.</li>
</ol>
<blockquote>
<p>2개의 인스턴스중 수명이 더짧은 인스턴스에 약한참조를 사용한다.</p>
</blockquote>
<p>설명이 어렵지만 쉽게 말해보자면 </p>
<p>아파트에는 입주자가 있을수도있고 없을수도 있다 그렇기에 옵셔널 값인데
아파트에 입주자가 있다가 입주자가 나갈수도있기 때문에 tenant 에 weak 키워드를 사용한것이다.</p>
<h3 id="미소유-참조-unowned-references">미소유 참조 (Unowned References)</h3>
<p>weak 와 마찬가지로 RC 를 증가시키지 않는다.</p>
<p><strong>weak 와 Unowned 의 차이점이 있다면</strong>
weak 은 2가지의 인스턴스중 수명이 더짧은경우 에 사용한다.
Unowned 은 반대로 다른 인스턴스와 수명이 동일하거나 더긴 경우 Unowned 를 사용한다.</p>
<p>Unowned 은 참조하는 인스턴스가 메모리에서 해제되어도 nil 로 만들어 주지 않는다.</p>
<p>그렇다면 var 일 필요도 옵셔널일 필요도 없겠네?????</p>
<p>쉽게 생각해보자면...1번뷰가 2번뷰를 참조해야하는 상황인데 2번 뷰가 1번뷰 보다 먼저 메모리에서 해제되면 안되는 경우..랄까?</p>
<p>내가 참조하는 상대방이 나보다 먼저 메모리에서 해제되지 않을경우 사용할수 있을것같다.</p>
<p>공식문서의 예제를 봐보자!
은행고객과 고객의 신용카드를 예시로든 예제 이다.</p>
<pre><code class="language-swift">class Customer {
    let name: String
    var card: CreditCard?
    init(name: String) {
        self.name = name
    }
    deinit { print(&quot;\(name) is being deinitialized&quot;) }
}

class CreditCard {
    let number: UInt64
    unowned let customer: Customer
    init(number: UInt64, customer: Customer) {
        self.number = number
        self.customer = customer
    }
    deinit { print(&quot;Card #\(number) is being deinitialized&quot;) }
}</code></pre>
<p>고객은 신용카드가 없을수 있지만 신용 카드는 사용하는 고객이 없으면 안된다!
신용카드는 항상 고객과 연결되어 있어야 한다!</p>
<p>신용카드 입장에서는 고객이라는 값이 항상 있어야 하며 자기자신보다 먼저 메모리 해제가 일어나면 안된다..!</p>
<p>이럴때 unowned 를 사용한다!</p>
<pre><code class="language-swift">var john: Customer?

john = Customer(name: &quot;John Appleseed&quot;)
john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)</code></pre>
<p>현재 참조 상황은 아래와 같다</p>
<p><img src="https://i.imgur.com/NHqieIa.png" alt=""></p>
<p>이후 john 에 nil 을 할당하게 될경우</p>
<pre><code class="language-swift">john = nil
// Prints &quot;John Appleseed is being deinitialized&quot;
// Prints &quot;Card #1234567890123456 is being deinitialized&quot;</code></pre>
<p><img src="https://i.imgur.com/aj4TeZH.png" alt=""></p>
<p>Customer instace 는 john 과 연결이 끊어지게 되고 
RC가 0 이 되면서 메모리에서 해제되게 된다.
왜 RC가 0임? 신용카드가 고객을 참조하고있는데??
위에서 설명했듯이 unowned 키워드를 사용하면 참조를 하고있어도 RC가 증가하지 않는다.</p>
<h2 id="미소유-옵셔널-참조-unowned-optional-references">미소유 옵셔널 참조 (Unowned Optional References)</h2>
<p>Unowned 키워드를 작성했는데 타입이 옵셔널 인경우를 말한다.
위에서 설명은 Unowned 을 사용할때는 자기자신보다 먼저메모리에서 해제되지 않을경우 사용한다고 했는데?? 
그렇기 때문에 Unowned 을 작성한 프로퍼티의 값이 nil 로 변경될일이 없었는데??</p>
<p>이건대체 왜 사용하는것일까..</p>
<p>일단 옵셔널이기때문에 nil 로 변경될수 있다는것을 알고있어야 겠다.
그렇다면 값이 변경될수 있기 때문에 var 로 선언해주어야 겠군..?
자동으로 메모리가 해제될경우 nil 로 변경 되지 않는것만 제외하면 weak 과 같은건가?</p>
<p>예제를 보도록하자!</p>
<p>대학교에서 학과 와 학과에 해당하는 수업에 관한 예제다.</p>
<pre><code class="language-swift">class Department {
    var name: String
    var courses: [Course]
    init(name: String) {
        self.name = name
        self.courses = []
    }
}

class Course {
    var name: String
    unowned var department: Department
    unowned var nextCourse: Course?
    init(name: String, in department: Department) {
        self.name = name
        self.department = department
        self.nextCourse = nil
    }
}</code></pre>
<p>학과는 어떤수업을 해야할지 정해두어야 하기때문에 수업을 배열 컬렉션으로 소유하고 있는 형태다.</p>
<p>수업은 어떤 학과의 수업인지 알고있어야 하며 수업이 사라지기전에 학과가 사라지는 경우는 없으니 학과 프로퍼티는 unowned 키워드를 사용하였다.</p>
<p>하지만 이제 문제가 되는것은 다음수업 이라는 프로퍼티인데 unowned 을 사용했음에도 옵셔널타입이다.</p>
<p>다음 수업이 있을지 없을지 모르기 때문이다.</p>
<pre><code class="language-swift">let department = Department(name: &quot;Horticulture&quot;)

let intro = Course(name: &quot;Survey of Plants&quot;, in: department)
let intermediate = Course(name: &quot;Growing Common Herbs&quot;, in: department)
let advanced = Course(name: &quot;Caring for Tropical Plants&quot;, in: department)

intro.nextCourse = intermediate
intermediate.nextCourse = advanced
department.courses = [intro, intermediate, advanced]</code></pre>
<p>학과는 원예 학과이며 수업 목록은 다음과 같다.</p>
<ol>
<li>식물 조사</li>
<li>허브 재배</li>
<li>열대 식물 돌보기</li>
</ol>
<p>식물조사의 다음 수업은 허브재배
허브재배 다음 수업은 열대 식물 돌보기
열대식물 돌보기의 다음수업은 옵셔널 기본값인 nil 인 상태다.</p>
<p><img src="https://i.imgur.com/YbKjt4f.png" alt=""></p>
<p>학과는 모든 수업을 강하게 참조하고 있는 형태이며
식물조사는 허브재배를 unowned? 형태로 소유하고 있다.</p>
<p>의문점은 다음수업이기때문에 weak 을 사용하는것이 맞지않나? 라는 의문이 든다. 
어떤 수업이 먼저 사라질지 알수 없기때문일까 추측 해본다.</p>
<p>unowned? 보다 weak 을 사용하는게 더 좋지 않을까?
unowned? 이 참조하고 있는 인스턴스가 메모리 해제되게 되면 자동으로 nil 로 변경되지 않아 일일히 어떤 것들을 nil 로 변경해주어야 하는지 찾아서 값을 변경해주어야 할것 같은데..</p>
<p>쉽게 말하면 학과에서 
department.courses 의 Element 중 무언가를 제거하게되면 
해당 Element 가 사용하고있는 unowned 프로퍼티의 값을 nil 로 변경해주어야 한다.</p>
<p>쓰다보니 생각했는데 혹시 모르게 unowned 키워드로 설계 했지만 나중에 먼저 메모리에서 해제될경우를 고려해서 옵셔널을 사용하는것일까??</p>
<p>예시를 생각해 보았다..이런 경우에 사용되지 않을까?
학과가 여러개 있고 수업도 여러개있을때
학과가 어떤 수업을 채택할지 정해지지 않은 경우 를 예시로 들어보자!</p>
<p>학과가 수업을 채택 한 후에는 수업보다 학과가 먼저 사라질일이 없다고 가정할때 unowned? 을 사용할수 있을것 같다.</p>
<p>처음엔 unowned? 프로퍼티의 값을 nil 로 설정한후 
초기화 하게되면 unowned? 프로퍼티에 인스턴스를 할당해준다!
그후로는 학과의 메모리가 먼저 해제될일이 없으니 이와 비슷한 형태로 사용할수 있을것 같다.</p>
<p>쉽게 말해 unowned? 프로퍼티 에 어떤값이 들어갈지 모를때, 하지만 값이 들어가게되면 자기자신보다 먼저 메모리 해제될일이 없을떄 사용하면될것 같다!</p>
<h2 id="참고-문서-및-사이트">참고 문서 및 사이트</h2>
<p><a href="https://zeddios.tistory.com/1213">zedd0200 Blog</a>
<a href="https://bbiguduk.gitbook.io/swift/language-guide-1/automatic-reference-counting">swift공식문서</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[RAM, ROM 그리고 메모리 구조]]></title>
            <link>https://velog.io/@malrang-malrang/RAM-ROM-%EA%B7%B8%EB%A6%AC%EA%B3%A0-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B5%AC%EC%A1%B0</link>
            <guid>https://velog.io/@malrang-malrang/RAM-ROM-%EA%B7%B8%EB%A6%AC%EA%B3%A0-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B5%AC%EC%A1%B0</guid>
            <pubDate>Sat, 02 Apr 2022 11:53:42 GMT</pubDate>
            <description><![CDATA[<h1 id="ram-rom-그리고-메모리-구조">RAM, ROM 그리고 메모리 구조</h1>
<h2 id="ram-rom">RAM, ROM</h2>
<blockquote>
<p><strong>RAM(Random Access Memory)</strong></p>
<ul>
<li>자유롭게 내용을 읽고 쓰고 지울 수 있는 기억장치.</li>
<li>현재 사용 중인 프로그램이나 데이터가 저장됨.</li>
<li>전원이 차단되면 저장된 데이터가 제거되는 휘발성 기억장치.</li>
<li>일반적으로 주기억장치 또는 메모리 라고 한다.</li>
</ul>
</blockquote>
<blockquote>
<p><strong>ROM(Read-only Memory)</strong></p>
<ul>
<li>이름처럼 읽기전용 메모리.</li>
<li>무언가 작성하려면 특수 기기가 필요하고, 삭제나 수정이 불가능한 기억장치.</li>
<li>Rom 은 주기억 장치 보다 변경 가능성이 없는 시스템 소프트웨어를 저장시키는데 이용한다.</li>
</ul>
</blockquote>
<h2 id="메모리-구조">메모리 구조</h2>
<blockquote>
<p><strong>프로그램이 실행되는 과정</strong></p>
<ol>
<li>사용자가 프로그램 실행을 요청한다.</li>
<li>프로그램의 정보를 읽어 메모리(RAM)에 로드(load).</li>
<li>프로그램이 실행되면 운영체제는 메모리(RAM)에 공간을 할당해준다.</li>
<li>CPU 가 기계어로된 코드를 실행한다.</li>
</ol>
</blockquote>
<p><img src="https://i.imgur.com/FMJ2k1i.png" alt=""></p>
<blockquote>
<p><strong>프로그램이 실행되어 RAM에 공간을 할당해줄때 다음과 같이 할당된다.</strong></p>
<ul>
<li>저장되는 순서는 보통 Code(text), Data(GVAR, BSS)가 먼저 할당되고 Heap, Stack 이 할당된다. </li>
</ul>
<p><strong>1. Text(Code)</strong></p>
<ul>
<li>개발자가 작성한 소스 코드가 기계어(0, 1) 형태로 할당되는 공간.</li>
<li>실행할 프로그램의 코드가 Text에 할당된다.</li>
<li>CPU는 Text 영역에 할당된 명령어를 하나씩 처리한다.</li>
</ul>
<p><strong>2. Data(BSS, GVAR)</strong></p>
<ul>
<li>전역변수와 정적(static) 변수가 할당되는 공간.</li>
<li>프로그램 시작과 동시에 할당되고 프로그램이 종료되면 해제 된다.</li>
<li>위의 그림을 보면 알겠지만 초기화 한경우와 초기화 되지 않은 경우를 기준으로 BSS, GVAR 로 나뉘게 된다.</li>
<li>초기화된 데이터는 초기값을 ROM에 할당된다. 하지만 초기화 되지않은 데이터가 ROM에 할당되면 안되기때문에(얘까지 저장하려면 ROM 사이즈가 커야함)초기화 되지 않은 데이터는 RAM에 할당하기 위해 나뉘어진다. </li>
</ul>
<p><strong>3. Heap</strong></p>
<ul>
<li>개발자가 직접 할당,해제 하는 공간</li>
<li>malloc, new 등을 사용해 동적으로 할당되는 변수들이 Heap 에 할당된다.</li>
<li>사용후엔 메모리를 해제 시켜주어야 하며 해제 시키지 않을 경우 memory leak 이 발생한다.(swift 에서는 ARC 가 메모리에서 해제 시켜준다.)</li>
<li>낮은주소 -&gt; 높은 주소로 할당된다.</li>
<li>할당할것이 많아 Stack 영역까지 침범한경우 Heap OverFlow 가 발생.</li>
</ul>
<p><strong>4. Stack</strong></p>
<ul>
<li>함수 호출과 관련있는 지역변수, 매개변수, 리턴값 등이 할당되는 공간.</li>
<li>함수 호출시 할당되며 함수 호출이 완료되면 메모리에서 해제된다.</li>
<li>프로세스가 메모리에 load(로드)될때 stack사이즈가 고정됨.</li>
<li>런타임 시 Stack 사이즈를 변경할수 없다. </li>
<li>컴파일 할때 결정되기 때문에 무한하게 할당할수 없음.</li>
<li>높은주소 -&gt; 낮은주소로 할당된다.</li>
<li>함수를 재귀 호출 하여 Stack영역에 해당 함수의 지역변수, 매게변수들이 게속 할당되면 Heap 영역에 침범하게되어 Stack OverFlow 발생.</li>
</ul>
</blockquote>
<h2 id="heap과-stack-의-장점과-단점">Heap과 Stack 의 장점과 단점</h2>
<blockquote>
<p><strong>Heap 의 장단점</strong></p>
<ul>
<li><strong>장점</strong><ul>
<li>메모리 크기에 대한 제한 없음.</li>
<li>본질적인 범위가 전역이며, 프로그램의 모든 함수에서 액세스 할수있다.</li>
</ul>
</li>
<li><strong>단점</strong><ul>
<li>할당작업, 해제 작업으로 인해 속도 저하.</li>
<li>힙 손상(이중 해제, 해제후 사용 등등)작업으로 인한 속도 저하.</li>
<li>힙 경합(두개 이상의 쓰레드가 동시에 접근하려 할때 lock됨)으로 인해 속도저하.</li>
<li>메모리를 직접 관리해야함, 해제 하지 않으면 메모리 누수(memory leak) 발생.</li>
</ul>
</li>
</ul>
<p><strong>Stack 의 장단점</strong></p>
<ul>
<li><strong>장점</strong><ul>
<li>CPU가 stack 메모리를 효율적으로 구성하기 때문에 속도가 빠르다.
메모리를 직접 해제 해주지 않아도 된다.</li>
</ul>
</li>
<li><strong>단점</strong><ul>
<li>메모리 크기에 대한 제한이 있다.</li>
<li>지역 변수만 액세스 가능하다.</li>
</ul>
</li>
</ul>
</blockquote>
<blockquote>
<p><strong>Heap, Stack 어떤거 사용해야함?</strong></p>
<ul>
<li>데이터의 크기를 모르거나 스택에 저장하기엔 데이터가 너무 크다면 Heap!</li>
<li>이를 제외한 상황이라면 Stack!</li>
</ul>
</blockquote>
<h2 id="참고-문서-및-사이트">참고 문서 및 사이트</h2>
<p><a href="https://babbab2.tistory.com/25">개발자 소들이</a>
<a href="https://kyu9341.github.io/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C/2020/10/04/OS_Process_Structure/">kwon&#39;s Blog</a>
<a href="https://velog.io/@ssionii/%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B5%AC%EC%A1%B0%EB%A5%BC-%EA%B0%84%EB%8B%A8%ED%95%98%EA%B2%8C-%EC%A0%95%EB%A6%AC%ED%95%B4%EB%B3%B4%EC%9E%90">ssionii Velog</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[App's Life Cycle]]></title>
            <link>https://velog.io/@malrang-malrang/Apps-Life-Cycle</link>
            <guid>https://velog.io/@malrang-malrang/Apps-Life-Cycle</guid>
            <pubDate>Thu, 31 Mar 2022 16:09:40 GMT</pubDate>
            <description><![CDATA[<h1 id="apps-life-cycle앱의-수명-주기">App&#39;s Life Cycle(앱의 수명 주기)</h1>
<blockquote>
<p>App의 생명 주기는 App의 실행,종료 및 App의 Foreground,Background 상태에 있을 때 시스템이 발생시키는 event에 의해 App의 상태가 전환되는 일련의 과정을 뜻한다.</p>
</blockquote>
<p><strong>1. Background</strong></p>
<blockquote>
<p>앱이 화면상에서 보여지지 않는 상태
가능한 적은 기능을 수행해야 한다.
화면 밖에 있기때문에 가급적 아무것도 하지 않는것이 좋다.</p>
</blockquote>
<p><strong>2. Foreground</strong></p>
<blockquote>
<p>앱이 화면에 올라와 있는 상태</p>
</blockquote>
<h2 id="app이-실행되면-발생되는-상황">App이 실행되면 발생되는 상황</h2>
<ol>
<li>UIApplication</li>
<li>@UIApplicationMain 또는 @Main 어노테이션이 있는 클래스를 찾아 AppDelegate 객체 생성</li>
<li>Main Event Loop 를 실행(touch, text input등 사용자의 액션을 받는 루프)</li>
</ol>
<h2 id="main-run-loop">Main Run Loop</h2>
<blockquote>
<p>Main Run Loop 는 유저가 일으키는 이벤트들을 처리하는 프로세스다.</p>
<p>UIApplication 객체는 앱이 실행될 때, Main Run Loop를 실행하고 
Main Run Loop 를 View와 관련된 이벤트나 View의 업데이트에 활용 한다.</p>
<p>Main Run Loop 는 View와 관련되어 있기 때문에 Main 스레드 에서 실행 된다.</p>
</blockquote>
<p><img src="https://i.imgur.com/JkfeGQp.png" alt=""></p>
<p><strong>이벤트 처리 순서</strong></p>
<ol>
<li>유저가 이벤트를 발생 시킨다.(터치, 스와이프 등 조작)</li>
<li>시스템을 통해 이벤트가 생성된다.</li>
<li>UIKit 프레임워크를 통해 생성된 port 로 해당 이벤트가 앱으로 전달.</li>
<li>이벤트는 앱 내부에 Queue 형태로 저장된다.</li>
<li>Event Queue 에 있는 이벤트들이 Main Run Loop 에 하나씩 매핑된다.</li>
<li>UIApplication 객체는 어떤 이벤트를 가장 먼저 실행 되어야 하는지 결정한다.</li>
</ol>
<h1 id="appdelegate-와-scenedelegate">AppDelegate 와 SceneDelegate</h1>
<h2 id="ios12-이하의-버젼"><strong>IOS12 이하의 버젼</strong></h2>
<blockquote>
<p>하나의 앱에 하나의 window!</p>
</blockquote>
<p><img src="https://i.imgur.com/AzFfzYj.png" alt=""></p>
<p><strong>AppDelegate 가 두개의 LifeCycle 을 관리한다.</strong></p>
<ul>
<li><ol>
<li>process LifeCycle</li>
</ol>
</li>
<li><ol start="2">
<li>UI LifeCycle </li>
</ol>
</li>
</ul>
<h2 id="ios13-이상의-버젼"><strong>IOS13 이상의 버젼</strong></h2>
<blockquote>
<p>창(window)의 개념이 scene 으로 대체되고 하나의 앱에서 여러개의 scene 을 가질수 있다.</p>
</blockquote>
<p><img src="https://i.imgur.com/3G1jJdn.png" alt=""></p>
<p><strong>AppDelegate 와 SceneDelegate 가 LifeCycle 을 관리 한다</strong></p>
<ul>
<li><strong>AppDelegate</strong><ul>
<li><ol>
<li>Process LifeCycle</li>
</ol>
</li>
<li><ol start="2">
<li>Session LifeCycle</li>
</ol>
</li>
</ul>
</li>
<li><strong>SceneDelegate</strong><ul>
<li><ol>
<li>UI LifeCycle</li>
</ol>
</li>
</ul>
</li>
</ul>
<blockquote>
<p>AppDelegate 의 기능이 SceneDelegate 로 분리되고 AppDelegate 에 Session LifeCycle 이라는 새로운 사이클을 담당하게 된다.</p>
<p>Session LifeCycle 은 Scene 에 대한 정보를 관리한다.</p>
</blockquote>
<h2 id="scene-의-개념이-생긴-이유">Scene 의 개념이 생긴 이유</h2>
<blockquote>
<p>멀티 윈도우 환경을 제공하기 위해 생긴이유가 가장크다.</p>
<p>아이폰은 멀티 윈도우를 제공하지 않지만 아이패드 같은경우 멀티 윈도우 기능을 제공한다. 
기존엔 한개의 앱이 한개의 UI instance 를 갖는 형태였지만 
한개의 앱에서 여러개의 UI instance 들을 갖는 형태를 만들기 위해 Scene 이라는 개념이 생겨 났다.</p>
<p>예를들자면 메모어플, 일정어플 등 아이패드에서 분할 화면으로 작업할때 한화면에서 작업한 내용이 다른화면에서도 반영하고 싶은경우 활용 할 수 있다.</p>
</blockquote>
<h3 id="멀티-윈도우란">멀티 윈도우란?</h3>
<blockquote>
<p>한개의 앱에서 여러개의 window(UI instance) 를 가질수있는 것을 뜻함.
크롬의 새창 버튼과 같은 것. 앱은 하나지만 보여지는것은 각기 다른 2개의 화면을 볼수있음.</p>
</blockquote>
<h1 id="scenedelegateswift-파일">SceneDelegate.swift 파일</h1>
<blockquote>
<p>각 Scene 의 라이프 사이클(UI LifeCycle)을 관리한다.</p>
</blockquote>
<h2 id="uiscenedelegate">UISceneDelegate</h2>
<pre><code class="language-swift">@MainActor protocol UISceneDelegate</code></pre>
<p><strong>scene의 라이프 사이클</strong></p>
<ol>
<li>scene()</li>
</ol>
<ul>
<li>scene 이 앱에 추가될때 호출됨</li>
</ul>
<ol start="2">
<li>sceneDidDisconnect()</li>
</ol>
<ul>
<li>scene 의 연결이 해제될때 호출됨</li>
</ul>
<ol start="3">
<li>sceneDidBecomeActive()</li>
</ol>
<ul>
<li>scene 이 활성화 되었을때 호출됨</li>
</ul>
<ol start="4">
<li>sceneWillResignActive()</li>
</ol>
<ul>
<li>scene 이 활성상태를 멈출때 호출됨</li>
</ul>
<ol start="5">
<li>sceneWillEnterForeground()</li>
</ol>
<ul>
<li>scene 이 실행되어 사용자에게 표시될때 호출됨</li>
</ul>
<ol start="6">
<li>sceneDidEnterBackground() </li>
</ol>
<ul>
<li>scene 이 백그라운드에서 실행중이며 더이상 화면에 표시되지 않을때 호출됨</li>
</ul>
<h1 id="appdelegateswift-파일">AppDelegate.swift 파일</h1>
<ol>
<li>앱의 중요한 데이터 초기화</li>
<li>앱의 scene 환경설정</li>
<li>앱밖에서 발생한 알림(배터리 부족, 다운로드 완료 등)에 대응</li>
<li>특정한 scene, view, viewController에 한정하지 않고 앱자체 타겟 이벤트에 대응</li>
<li>푸시알림 서비스 같은 실행시 요구되는 서비스 등록</li>
</ol>
<h2 id="uiapplicationdelegate">UIApplicationDelegate</h2>
<pre><code class="language-swift">@MainActor protocol UIApplicationDelegate</code></pre>
<h2 id="respond-to-app-based-life-cycle-events앱-라이프사이클-기반-이벤트-처리ios12-이하-버젼">Respond to App-Based Life-Cycle Events(앱 라이프사이클 기반 이벤트 처리)(IOS12 이하 버젼)</h2>
<p><img src="https://i.imgur.com/sQYYM7y.png" alt=""></p>
<p><strong>1. Not Running</strong></p>
<ul>
<li>앱이 실행되지 않았거나, 완전히 종료되어 동작하지 않는 상태</li>
</ul>
<p><strong>2. Inactive</strong></p>
<ul>
<li>앱 시작시 앱의 데이터 구조와 UI를 초기화 함.</li>
</ul>
<p><strong>3. Active</strong></p>
<ul>
<li>앱이 실행중이고 이벤트를 받을수 있는 상태.</li>
<li>Foreground 의 일반적인 상태.</li>
</ul>
<p><strong>4. Active -&gt; Inactive</strong></p>
<ul>
<li>Foreground Active 상태를 벗어나면 데이터를 저장하고 앱의 동작을 멈춘다.</li>
</ul>
<p><strong>5. Background</strong></p>
<ul>
<li>앱 사용중 다른앱을 실행하거나 홈 화면 으로 나갔을떄 의 상태.</li>
<li>Background 에서 동작하는 코드를 추가하면 Suspended 상태로 넘어가지 않고 백그라운드 상태를 유지함.</li>
<li>처음부터 Background 상태로 실행되는 앱은 Inactive 대신Background 상태로 진입.(음악 실행후 화면 에서 나가도 음악이 재생되는 상태)</li>
</ul>
<p><strong>6. Suspended</strong></p>
<ul>
<li>앱이 Background 상태에서 추가적인 작업을 하지 않으면 Suspended 상태로 진입.</li>
<li>앱을 다시 실행할 경우 빠른 실행을 위해 메모리에는 올라가 있음.</li>
<li>메모리가 부족해지면 IOS 는 Suspended 상태의 앱들을 메모리에서 해제함.</li>
</ul>
<h2 id="respond-to-scene-based-life-cycle-events화면-라이프사이클-기반-이벤트-처리ios13-이상-버젼">Respond to Scene-Based Life-Cycle Events(화면 라이프사이클 기반 이벤트 처리)(IOS13 이상 버젼)</h2>
<p><img src="https://i.imgur.com/uSaJQXp.png" alt=""></p>
<p><strong>1. Unattached</strong></p>
<ul>
<li>사용자나 시스템이 앱에 대해서 새로운 씬을 요청하면 UIkit이 장면을 앱에 연결할 때 장면의 초기 UI를 구성하고 장면에 필요한 데이터를 로드 한다.</li>
<li>사용자가 Scene을 요청하면 Foreground 로 이동한다.</li>
<li>시스템이 Scene을 요청하면 Background 로 이동한다.</li>
</ul>
<p><strong>2. Foreground Inactive</strong></p>
<ul>
<li>Foreground가 Active 되기전 잠깐 거치는 단계</li>
<li>ACtive 상태로 전환할때 UI를 구성하고 사용자와 상호 작용할 준비를한다.</li>
<li>앱이 실행중인 상태지만 이벤트를 받지 않는다.</li>
<li>알림 같은 특정 알림창이 화면을 덮어 앱이 event를 받지 못하는 상태</li>
</ul>
<p><strong>3. Foreground Active</strong></p>
<ul>
<li>앱이 실행중이고 이벤트를 받을수 있는 상태.</li>
<li>Foreground 의 일반적인 상태.</li>
</ul>
<p><strong>4. Foreground Active -&gt; Foreground Inactive</strong></p>
<ul>
<li>Foreground Active 상태를 벗어나면 데이터를 저장하고 앱의 동작을 멈춘다.</li>
</ul>
<p><strong>5. Background</strong></p>
<ul>
<li><p>앱 사용중 다른앱을 실행하거나 홈 화면 으로 나갔을떄 의 상태.</p>
</li>
<li><p>Background 에서 동작하는 코드를 추가하면 Suspended 상태로 넘어가지 않고 백그라운드 상태를 유지함.</p>
</li>
<li><p>처음부터 Background 상태로 실행되는 앱은 Inactive 대신Background 상태로 진입.(음악 실행후 화면 에서 나가도 음악이 재생되는 상태)</p>
</li>
<li><p>예정작업? 백그라운드에서 언어타치드 로 가능 이유?</p>
</li>
<li><p>백그라운드 기능중에 예정 작업 같은 기능이있는데 대강 어느정도 시간이지나면 이거를 해라 저거를 해라 지정할수 있음</p>
</li>
</ul>
<p><strong>6. Suspended</strong></p>
<ul>
<li>앱이 Background 상태에서 추가적인 작업을 하지 않으면 Suspended 상태로 진입.</li>
<li>앱을 다시 실행할 경우 빠른 실행을 위해 메모리에는 올라가 있음.</li>
<li>메모리가 부족해지면 IOS 는 Suspended 상태의 앱들을 메모리에서 해제함.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[SOLID 원칙이란?]]></title>
            <link>https://velog.io/@malrang-malrang/SOLID-%EC%9B%90%EC%B9%99%EC%9D%B4%EB%9E%80</link>
            <guid>https://velog.io/@malrang-malrang/SOLID-%EC%9B%90%EC%B9%99%EC%9D%B4%EB%9E%80</guid>
            <pubDate>Sun, 20 Mar 2022 12:46:13 GMT</pubDate>
            <description><![CDATA[<h2 id="객체-지향-프로그래밍이란-oop">객체 지향 프로그래밍이란 (OOP)</h2>
<p>작은 문제를 해결 할수할 수 있는 객체를 만들고
이 객체들을 조합하여 큰 문제를 해결하게 하는 방식이다.</p>
<p>객체지향 설계를 하면 코드의 재사용, 유지보수 의 용이성 등을 장점으로 가져갈수 있다.</p>
<p>코드는 유연하고 확장할 수 있고 유지보수가 용이하고 재사용할 수 있어야 한다.
이러한 OOP 방식을 준수하기 위해 만들어 진것이 SOLID 원칙이다.</p>
<h2 id="solid-원칙">SOLID 원칙</h2>
<p>컴퓨터 프로그래밍에서 SOLID 원칙 이란 
프로그래머가 시간이 지나도 유지 보수 와 확장이 쉬운 시스템을 만들고자 할 때 이원칙들을 함께 적용할 수 있다.</p>
<ul>
<li>S(SRP)<ul>
<li>단일 책임 원칙</li>
<li>한 클래스는 하나의 책임만 가져야 한다.</li>
</ul>
</li>
<li>O(OCP)<ul>
<li>개방-폐쇄 원칙</li>
<li>소프트웨어 요소는 확장에는 열려 있으나 변경에는 닫혀 있어야 한다.</li>
</ul>
</li>
<li>L(LSP)<ul>
<li>리스코프 치환 원칙</li>
<li>프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다.</li>
</ul>
</li>
<li>I(ISP)<ul>
<li>인터페이스 분리 원칙</li>
<li>특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 낫다</li>
</ul>
</li>
<li>D(DIP)<ul>
<li>의존관계 역전 원칙</li>
<li>프로그래머는 추상화에 의존해야지 구체화에 의존하면 안된다.</li>
<li>의존성 주입은 이 원칙을 따르는 방법 중 하나이다.</li>
</ul>
</li>
</ul>
<h3 id="srpsingle-responsibility-principle-단일-책임의-원칙">SRP(Single-Responsibility Principle) 단일 책임의 원칙</h3>
<blockquote>
<p>소프트웨어 요소(클래스, 모듈, 함수 등)는 응집도 있는 하나의 책임을 갖는다.
클래스를 변경해야 하는 이유는 단지 응집도여야 한다.</p>
</blockquote>
<pre><code class="language-swift">class ShoppingMall {

    func ShoppingMallSales() -&gt; Int? {
        let sales = coffeeShop.coffeeShopSales() + clothingStore.clothingStoreSales() +
        restaurant.restaurantSales()

        return sales
    }

    func coffeeShopSales() -&gt; Int {
        return 0
    }

    func clothingStoreSales() -&gt; Int {
        return 0
    }

    func restaurantSales() -&gt; Int {
        return 0
    }
}</code></pre>
<p>위의 예시로 보게되면 ShppingMall 에는 여러가지 가게들이 입점 해있는 상태이다
쇼핑몰은 입점해있는 모든 가게의 매출을 더해 집계할수 있는 기능을 가지고 있다.
지금은 예시로서 내부 구현을 하지 않은상태이지만 구현하게된다면 각각 해야하는 일들이 많아지게되고
ShoppingMall 의 Class 또한 덩치가 매우 커지게 된다.</p>
<p>이때 SRP 를 지키도록 하나의 클래스가 하나의 책임을 갖도록 하려면 기능들을 분리해주어야한다.</p>
<pre><code class="language-swift">class ShoppingMall {
    let coffeeShop = CoffeeShop()
    let clothingStore = ClothingStore()
    let restaurant = Restaurant()

    func ShoppingMallSales() -&gt; Int? {
        let sales = coffeeShop.coffeeShopSales() + clothingStore.clothingStoreSales() +
        restaurant.restaurantSales()

        return sales
    }
}

class CoffeeShop {
    func coffeeShopSales() -&gt; Int {
        return 0
    }
}

class ClothingStore {
    func clothingStoreSales() -&gt; Int {
        return 0
    }
}

class Restaurant {
    func restaurantSales() -&gt; Int {
        return 0
    }
}
</code></pre>
<p>이렇게 각각의 책임을 하위 클래스에게 넘겨주게 되면 각각의 클래스를 테스트 하기 쉬워지게 된다.</p>
<h3 id="ocpopen-close-principle-개방-폐쇄-원칙">OCP(Open-Close Principle) 개방-폐쇄 원칙</h3>
<blockquote>
<p>소프트웨어 요소는 확장 가능 하도록 열려있고, 변경에는 닫혀 있어야 한다.
확장을 할때는 기존의 코드를 최대한 건드리지 않고 확장하자.
새 기능을 추가 할 때 변경하지 말고 새 클래스나 함수를 만들어라.</p>
</blockquote>
<p>확장할때는 최대한 기존의 코드를 수정하지 않고 기능을 추가할수있도록 해야한다!</p>
<p>추상화 를 활용해 해결할수 있다.(예를 들면 protocol)</p>
<pre><code class="language-swift">class Fruits {
    let 딸기 = &quot;딸기&quot;
    let 바나나 = &quot;바나나&quot;
}

class FruitStore {
    var 과일들: [Fruits] = [Fruits(), Fruits()]
}</code></pre>
<p>위의 코드를 보면 과일들 이라는 프로퍼티 내부에는 Fruit 타입만 저장될수있다. 
지금은 과일의 종류가 딸기, 바나나 2개 밖에 없지만 과일의 종류를 더 추가하기 위해서는 Fruit 내부에 새로운 과일의 프로퍼티를 만들어 주어야한다.
이는 OCP 원칙에 위배되는 행위이다.</p>
<p>이를 해결하고자 procotocol 을 활용해 해결할수 있다.</p>
<pre><code class="language-swift">protocol Fruits {}

class 딸기: Fruits {
    let name = &quot;딸기&quot;
}

class 바나나: Fruits {
    let name = &quot;바나나&quot;
}

class 두리안: Fruits {
    let name = &quot;두리안&quot;
}

class FruitStore {
    var 과일들: [Fruits] = [딸기(), 바나나(), 두리안()]
}</code></pre>
<p>위 처럼 과일들이 Fruits 프로토콜을 채택하는 형태고 만들게되면 
과일들 프로퍼티는 [Fruit] 즉 Fruits 프로토콜을 채택하는 녀석이라면 누구든 저장할수 있는 형태가 된다. </p>
<p>1번 예시와 다른점이 있다면 새로운 과일을 추가시킬때 Fruits 프로토콜을 채택만 하면 되기 때문에 기존에 작성해둔 코드를 수정하지 않아도 과일의 종류를 추가시킬수 있게 된다.</p>
<h3 id="lspliskov-substitution-principle-리스코프-치환-원칙">LSP(Liskov-Substitution Principle) 리스코프 치환 원칙</h3>
<blockquote>
<p>서브타입은 (상속받은) 기본 타입으로 대체 가능 해야 한다.
자식 클래스는 부모 클래스 동작(의미)를 바꾸지 않는다.</p>
</blockquote>
<p>서브클래스(자식클래스)는 부모의 역할을 온전히 다 사용할수 있어야 한다.
부모 클래스의 기능을 제한하면 안된다라고 이해할수 있겠다.</p>
<p>class 의 overriding 을 사용하게되면 리스코프 치환원칙을 위배할수있다.</p>
<p>아래의 예시는 직사각형과 정사각형의 예시이다.
정사각형은 직사각형 에 포함된다 할수있다.
그렇기에 정사각형이 직사각형을 상속 받았을때에 일어나는 일이다.</p>
<pre><code class="language-swift">class Rectangle {
    var width = 10
    var height = 5
}

class Square: Rectangle {
    override var height: Int {
        didSet {
            height = width
        }
    }
}</code></pre>
<p>직사각형의 경우 높이와 길이가 다를수 있지만 정사각형의 경우 길이와 높이가 같아야한다. 이를 해결하기 위해 override 하여 재정의 해주었지만 이러한 경우 부모의 역활을 자식에서 대신하지못하는 상황이 발생된다.</p>
<p>이를 해결하기위해 protocol 을 활용하여 해결할수 있다.</p>
<pre><code class="language-swift">protocol Shape {
    var width: Int { get }
    var height: Int { get }
}

class Rectangle: Shape{
    var width = 10
    var height = 5
}

class Square: Shape {
    var width: Int = 5
    var height: Int = 5
}</code></pre>
<p>위의 예시처럼 Rectangle, Square 모두 Shape(모양) protocol 을 채택하게되면 프로토콜 내부의 프로퍼티 값(구현부)은 해당 프로토콜을 채택하는 하위 클래스에서 구현하도록 하면 LSP 의 원칙에 어긋나지 않는 프로그램을 설계할수 있게 된다.</p>
<p>이때 둘다 공통으로 가지고 있어야할 기능이 있다면 protocol 의 기본구현을 이용해 프로토콜을 채택한 하위 객체는 기본구현된 기능을 사용할수 있게된다.
(마치 상속처럼 사용할수 있게되며, struct 에서도 활용 가능하다 프로토콜 짱짱맨, 이를 이용하면 다중 상속처럼 사용도 가능하다..!)</p>
<h3 id="ispinterface-segregation-principle-인터페이스-분리-원칙">ISP(Interface-Segregation Principle) 인터페이스 분리 원칙</h3>
<blockquote>
<p>인터페이스를 작게 분리 유지해야 한다.
클라이언트 객체는 사용하지 않는 메소드에 의존하면 안된다.</p>
</blockquote>
<p>불필요한 인터페이스 요소들을 포함 시키지 말아라.</p>
<p><strong>protocol 예시</strong></p>
<pre><code class="language-swift">protocol Gesture {
    func click()
    func doubleClick()
}</code></pre>
<p>위와 같은 프로토콜을 만들었다 사용할때에는 위의 프로토콜을 채택하여 사용하면 click, doubleClick 기능을 구현하여 사용할수 있게된다.</p>
<p>하지만 이때 click 기능만 필요하다면 어떤가?
doubleClick 는 깡통으로 만들어둬야하나???</p>
<pre><code class="language-swift">class Button: Gesture {
    func click() {
        print(&quot;클릭!&quot;)
    }

    func doubleClick() {}
}</code></pre>
<p>이러한 경우가 생길수 있기에 해당 기능들을 나누어 구현해주는 방식으로 구성해야한다. 위의 상황은 ISP 를 위반하는 인터페이스 라고 할수 있겠다.</p>
<pre><code class="language-swift">protocol click {
    func click()
}

protocol DoubleClick {
    func doubleClick()
}

class Button: click {
    func click() {
        print(&quot;클릭!&quot;)
    }
}</code></pre>
<p>이렇게 나누어진 프로토콜중 필요한 프로토콜만 채택하게되면 원하는 기능만 구현하여 사용할수 있게된다.</p>
<p><strong>class 예시</strong></p>
<pre><code class="language-swift">class Malrang {
    let name = &quot;malrnag&quot;
    var age = &quot;29&quot;
    var hairStyle = &quot;장발&quot;

    func printProfile(profile: Malrang) {
    }
}</code></pre>
<p>나의 정보를 포함하고 있는 Malrang 이라는 클래스가 있다.
printProfile 메서드는 나의 정보를 출력해주는 기능이다.
이때 사실 나이와 이름 은 알아야할 정보지만 헤어스타일은 굳이..출력하고 싶지않다. 
그렇다면 매개변수로 Malrang 타입을 받아 모든 정보를 받아올 필요가 있을까?</p>
<p>이런 상황에서도 protocol 을 활용함으로써 printProfile 가 필요로 하는 정보만 전달해줄수 있도록 할수있다.</p>
<pre><code class="language-swift">protocol Profile {
    var name: String { get }
    var age: Int { get  }
}

class Malrang: Profile {
    let name = &quot;malrnag&quot;
    var age = 29
    var hairStyle = &quot;장발&quot;

    func printProfile(profile: Profile) {
    }
}</code></pre>
<p>printProfile 의 매개변수에는 Profile 을 채택하는 것들로만 들어올수 있게 된다.</p>
<h3 id="dipdependency-inversion-principle-의존관계-역전-원칙">DIP(Dependency-Inversion Principle) 의존관계 역전 원칙</h3>
<blockquote>
<p>상위 레벨 모듈은 하위 레벨에 의존하면 안된다.(둘 다 추상화된 인터페이스에 의존해야 한다 추상화는 구체화에 의존하면 안되고, 구체화는 추상화에 의존하면 안된다.) 
-ex 프로토콜 델리게이트 패턴 사용 하여 해결가능!</p>
</blockquote>
<p>추상화는 위의 예시들에서 본 것 처럼 protocol 을 이용하는것 이것을 추상화에 의존했다 라고 할수 있겠다.</p>
<p>예시를 보도록 하자! 
과일가게(FruitStore)class, 과일가게의 사장(JuiceMaker)class 가 있다고 가정해보자.</p>
<pre><code class="language-swift">class FruitStore {
    var fruitList = [&quot;딸기&quot;, &quot;바나나&quot;, &quot;두리안&quot;]
}

class JuiceMaker {
    let fruitStore = FruitStore()

    func printFruitList() {
        print(fruitStore.fruitList)
    }
}</code></pre>
<p>위의 예시는 과일가게 사장이 과일가게의 인스턴스를 내부적으로 생성해 사용하게된다.</p>
<p>여기서 JuiceMaker 는 상위레벨, FruitStore는 하위레벨 인데 printFruitList 메서드를 사용하는 경우 JuiceMaker가 FruitStore를 의존하게 된다. </p>
<p>이러한 상활일때도 추상화 를 통해 상위레벨이 하위레벨을 의존하지 않게 바꿀수 있겠다.</p>
<pre><code class="language-swift">protocol Fruits {
    var fruits: [String] { get }
    func fruitList()
}

class FruitStore: Fruits {
    var fruits = [&quot;딸기&quot;, &quot;바나나&quot;, &quot;두리안&quot;]

    func fruitList() {
        print(fruits)
    }
}

class JuiceMaker {
    let fruitList: Fruits

    init(fruitList: Fruits) {
        self.fruitList = fruitList
    }

    func printFruitList() {
        fruitList.fruitList()
    }
}

var 과일가게 = FruitStore()
var 과일가게사장 = JuiceMaker(fruitList: 과일가게)
과일가게사장.printFruitList()</code></pre>
<p>위의 예시를 보게 되면 추상화(프로토콜)를 통해 서로가 프로토콜을 의존하도록 수정한예시 이다.</p>
<p>Fruits 라는 프로토콜을 정의하고 프로토콜 내부에 과일들이 저장된 fruits 프로퍼티와 과일들의 목록을 출력하는 기능fruitList 를 채택한 객체에서 구현하도록 하였다.</p>
<p>FruitStore 가 Fruits 프로토콜을 채택하고 내부를 구현해두었다.
JuiceMaker 는 FruitStore 를 소유하는 형태가 아닌 프로토콜을 채택하는 녀석을 저장할수있는 fruitList 라는 프로퍼티를 만들어 이를 활용하는 형태로 변경하였다.
fruitList 는 Fruits 를 채택하는 애들만 저장할수 있기 떄문에 
fruitList 는 Fruits 에 정의된 프로퍼티, 기능들을 사용할수 있게된다.</p>
<p>이렇게 fruitList가 FruitStore 를 의존하는 형태가 아닌 둘다 Fruits(프로토콜) 을 의존하는 형태로 수정함으로써 각각의 객체를 테스트할때도 수월해지며 fruitList 사용이 용이해진다.</p>
<h2 id="solid-원칙을-지키려-노력하자">SOLID 원칙을 지키려 노력하자</h2>
<p>SOLID 를 매번 모두 지킬수는 없지만 지키려 노력하게 되면 코드의 질을 향상시키고 재사용 과 유지보수가 수월해져 더 효율적인 코드를 작성할수 있게 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[defer]]></title>
            <link>https://velog.io/@malrang-malrang/defer</link>
            <guid>https://velog.io/@malrang-malrang/defer</guid>
            <pubDate>Thu, 17 Mar 2022 11:27:15 GMT</pubDate>
            <description><![CDATA[<h2 id="defer">defer</h2>
<h3 id="defer-란-무엇인가">defer 란 무엇인가?</h3>
<p>defer 란 사전적 정의로는 연기하다, 지연되다, 미루다 이다.</p>
<p><img src="https://images.velog.io/images/malrang-malrang/post/7773f615-7e4c-4335-a9bb-f180dbd17fa0/%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-17%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%208.33.04.png" alt=""></p>
<p>함수 안에서 주로 사용되며 작성된 위치와 관계없이 함수종료 직전에 실행 된다.</p>
<p>defer 내부에 작성된 코드들이 함수 끝나기 직전에 행 해진다는 뜻이다.</p>
<h3 id="defer-사용-방법">defer 사용 방법</h3>
<p><img src="https://images.velog.io/images/malrang-malrang/post/363a0964-cb4e-41a1-95c7-1a60b5dfba78/%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%202021-02-22%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%2010.40.00.png" alt=""></p>
<p>어렵지 않다 defer 키워드를 사용하고 중괄호를 열어 내부를 작성하고 중괄호를 닫으면 완성이다!</p>
<h3 id="예시를-보도록-하자">예시를 보도록 하자</h3>
<pre><code class="language-swift">func f() {
    defer { print(&quot;First defer&quot;) }
    print(&quot;End of function&quot;)
}
f()
// Prints &quot;End of function&quot;
// Prints &quot;First defer&quot;</code></pre>
<p>기존 함수의 사이클이라면 함수f를 호출하게되면 
&quot;First defer&quot;
&quot;Second defer&quot;
End of function&quot;
순으로 출력되어야 할것인데 defer 를 사용했기 때문에 순서가 바뀌게되었다.</p>
<p>이것 외에도 다른 특징이 있다.</p>
<p>defer 는 여러번 호출이 가능하며 중첩도 가능하다.</p>
<p>stack 과 같은 방식으로 저장된다고 생각하면 이해가 좀 더 편하다.</p>
<pre><code class="language-swift">func f() {
    defer { print(&quot;First defer&quot;) }
    defer { print(&quot;Second defer&quot;) }
    print(&quot;End of function&quot;)
}
f()
// Prints &quot;End of function&quot;
// Prints &quot;Second defer&quot;
// Prints &quot;First defer&quot;</code></pre>
<p>마지막에 defer 가 가장 먼저 실행 된다.
처음 defer 가 가장 마지막에 실행 된다.</p>
<p>중첩에서도 위와 같다.
가장 바깥쪽에 있는 defer 가 가장 먼저 실행되고
가장 안쪽에 있는 defer 가 마지막에 실행된다.</p>
<pre><code class="language-swift">func f() {
    defer {
        defer {
            print(&quot;First defer&quot;)
        }
        print(&quot;Second defer&quot;)
    }
}
f()
// Prints &quot;Second defer&quot;
// Prints &quot;First defer&quot;</code></pre>
<p>함수 내부에서 defer 구문이 실행되기전에 함수가 종료되면 defer 구문은 실행되지 않는다.</p>
<pre><code class="language-swift">func f() {
    print(&quot;End of function&quot;)
    return
    defer { print(&quot;First defer&quot;) }
    defer { print(&quot;Second defer&quot;) }
}
f()
// Prints &quot;End of function&quot;</code></pre>
<p>반환값이 있는 함수에서의 사용
defer 를 사용하면 return 이후에 defer 구문을 실행하게된다.</p>
<pre><code class="language-swift">func f() -&gt; String? {
    var malrang: String? = &quot;malrang&quot;
    defer {
        malrang = nil
    }
    return malrang
}
print(f())
// &quot;malrang&quot;</code></pre>
<p>분명 함수내부에서 malrang 에 nil 을 넣어줬는데
return 반환 값은 &quot;malrang&quot; 이다
defer 구문은 return 이후에 실행되는것을 알수있다!</p>
]]></description>
        </item>
    </channel>
</rss>