<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Newon</title>
        <link>https://velog.io/</link>
        <description>나만 고양이 없어</description>
        <lastBuildDate>Tue, 26 Sep 2023 09:43:35 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>Newon</title>
            <url>https://images.velog.io/images/newon-seoul/profile/8665f078-0dbc-44ce-874e-76379f5e35e2/catherine-heath-i4W8OINLI_I-unsplash.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. Newon. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/newon-seoul" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[영어 공부 팁]]></title>
            <link>https://velog.io/@newon-seoul/%EC%98%81%EC%96%B4-%EA%B3%B5%EB%B6%80-%ED%8C%81</link>
            <guid>https://velog.io/@newon-seoul/%EC%98%81%EC%96%B4-%EA%B3%B5%EB%B6%80-%ED%8C%81</guid>
            <pubDate>Tue, 26 Sep 2023 09:43:35 GMT</pubDate>
            <description><![CDATA[<p><a href="https://drive.google.com/file/d/1jt1DvdgnVr8IOjwX3zWfXiLszQeffysE/view?usp=sharing">https://drive.google.com/file/d/1jt1DvdgnVr8IOjwX3zWfXiLszQeffysE/view?usp=sharing</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Combine 을 정리해보았습니다. # 기초편]]></title>
            <link>https://velog.io/@newon-seoul/Combine-%EC%9D%84-%EC%A0%95%EB%A6%AC%ED%95%B4%EB%B3%B4%EC%95%98%EC%8A%B5%EB%8B%88%EB%8B%A4.-%EA%B8%B0%EC%B4%88%ED%8E%B8</link>
            <guid>https://velog.io/@newon-seoul/Combine-%EC%9D%84-%EC%A0%95%EB%A6%AC%ED%95%B4%EB%B3%B4%EC%95%98%EC%8A%B5%EB%8B%88%EB%8B%A4.-%EA%B8%B0%EC%B4%88%ED%8E%B8</guid>
            <pubDate>Wed, 13 Sep 2023 04:12:40 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>이 글은 독자가 Generic Type, URLSession, 클로져와 Callback, 
UIKit 혹은 SwiftUI 의 View LifeCycle 에 대해서 
이미 알고 있음을 전제하고 있습니다.</p>
</blockquote>
<h2 id="combine-이란">Combine 이란?</h2>
<p>Combine 은 앱 내에서 일어나는 <code>이벤트들의 진행 경과</code>들을 <code>선언적으로</code> 코딩할 수 있게끔 도와주는 Apple 의 프레임워크입니다. </p>
<p>어떠한 이벤트를 추적할 때 <code>Delegate 패턴</code> 을 사용하거나, <code>Completion 클로져</code> 를 사용하는 대신 Combine 을 활용해볼 수 있습니다.</p>
<p>이 프레임워크는 Swift API 에 해당하기에
Swift 언어를 사용한다면 <code>UIKit</code> 이나 <code>SwiftUI</code> 둘 다 사용할 수 있습니다.</p>
<blockquote>
<p><em><strong>더 쉽게 말하자면</strong></em>
<code>URLSession.shared.dataTask { }</code> 쓰면 <code>completion()</code> 써야하고
<code>모시깽이 클래스</code> - <code>모시깽이 Delegate</code>  를 적용하는 상황들이</p>
<p>직관적이지 않고, 조금만 복잡해져도 스파게티 코드가 되니 
이걸 간단하게 해결해보자</p>
</blockquote>
<p>라는 취지</p>
<p><img src="https://velog.velcdn.com/images/newon-seoul/post/55f2bb87-a1de-4aed-8b1e-ccd36e24b994/image.gif" alt="Let&#39;s go"></p>
<br/>

<h3 id="combine-개요">Combine 개요</h3>
<p><img src="https://velog.velcdn.com/images/newon-seoul/post/b7093279-23b0-4e7d-8cea-f3791d686589/image.png" alt="Publisher - Subscriber"></p>
<p>Combine 은 결국 
<code>Publisher</code> 라는 이벤트 반응 전송기계
<code>Subscriber</code> 라는 이벤트 수집기계</p>
<p>이 두개를 연결해주는 프레임워크입니다.</p>
<br/>

<p><code>Subscriber</code> 는 <code>Publisher</code> 에게 데이터를 받기만 하는 일방향적 관계이며,
<code>Subscriber</code> 가 <code>Publisher</code> 에게 요청할 수 있는것은 데이터를 달라는 요청만 할 수 있습니다.</p>
<p><code>Publisher</code> 는 <code>Subscriber</code> 에게 데이터를 전달할 때, 바로 전달할 수도 있지만
<code>Operator</code> 를 활용해서, 데이터를 가공해서 줄 수 있습니다.</p>
<p><code>Operator</code> 는 Swift 에서 일상적으로 쓰는 메소드들인
<code>map</code>, <code>flatMap</code>, <code>compactMap</code>, <code>filter</code> 등의 이름을 따서 만든 메소드들로, 이름과 유사한 기능들을 제공합니다. </p>
<blockquote>
<p><em><strong>더 쉽게 말하자면</strong></em>
<code>Publisher</code> 는 데이터를 전송만 담당,
<code>Subscriber</code> 는 데이터 수신만 담당
<code>Operator</code> 는 <code>Publisher</code> 가 데이터 전송할 때, 중간에 수정하는 역할</p>
</blockquote>
<h3 id="subscriber-와-publisher-의-타입">Subscriber 와 Publisher 의 타입</h3>
<p><img src="https://velog.velcdn.com/images/newon-seoul/post/55d5f5d4-29c8-4c3f-a733-6de3db780dc3/image.pdf" alt="Publisher protocol"></p>
<p><img src="https://velog.velcdn.com/images/newon-seoul/post/63a99861-b6e3-46d6-a97a-095b5cdb90ee/image.pdf" alt="Subscriber protocol"></p>
<p><code>Publisher</code> 와 <code>Subscriber</code> 는 
각각 실제 데이터에 해당하는 <code>Output</code> 과 <code>Input</code>,
각각 오류에 해당하는 <code>Failure</code> 과 <code>Failure</code> 를 갖고 있습니다.</p>
<p>서로 연결되어있는 <code>Publisher</code> 와 <code>Subscriber</code> 는
<code>OutPut</code> 과 <code>Input</code> 이 같아야하며, 같은 <code>Failure</code> 를 갖고 있어야 합니다.</p>
<p><img src="https://velog.velcdn.com/images/newon-seoul/post/640ee3ad-7b90-4d4a-ade1-ba0a924f3b2e/image.png" alt=""></p>
<blockquote>
<p><em><strong>더 쉽게 말하자면</strong></em>
<code>Publisher</code> 랑 <code>Subscriber</code> 는 같은 타입이여야해용</p>
</blockquote>
<br/>

<h3 id="publisher-와-subscriber-연결하는-방법">Publisher 와 Subscriber 연결하는 방법</h3>
<p><img src="https://velog.velcdn.com/images/newon-seoul/post/8cf92a11-b0c1-4fea-a618-22185f9a5439/image.png" alt=""></p>
<p>연결은 <code>Publiser</code> 에 <code>Subscriber</code> 를 붙이는 형태로 동작합니다.</p>
<pre><code class="language-swift">SomePublisher
    .sink(receiverCompletion:receiveValue:)`
    .assign(to:on:)

/*
 Publisher 에 sink() 혹은 assign() 을 사용하면
 새로운 Subscriber 를 만들 수 있습니다.
*/
</code></pre>
<p><img src="https://velog.velcdn.com/images/newon-seoul/post/e44fa186-32d8-421f-8bd6-92bc981be3ae/image.png" alt="Sink 사용법"></p>
<br/>

<p><code>Subscriber</code> 는 새로운 <code>Subscriber</code> 를 생성할 수 있습니다.</p>
<pre><code class="language-swift">SomeSubscriber
    .sink(receiverCompletion:receiveValue:)`
    .assign(to:on:)

/*

Subscriber 에 또 sink, 혹은 assign 을 붙여서
새로운 subscriber 를 선언할 수 있다.

*/</code></pre>
<blockquote>
<p><em><strong>더 쉽게 말하자면</strong></em>
<code>Publisher</code> 에 <code>sink()</code> 혹은 <code>assign()</code> 쓰면 
새로운 Subscriber 를 선언할 수 있어요.</p>
</blockquote>
<blockquote>
<p>Class 에는 Observable 프로토콜 (옛날 이름 BindableObject) 을 사용할 수 있는데, 
Class 내부 변수에 @Published 만 붙이면, 자동으로 Publisher 로 만들어요.
<code>@Published var posts = [T]()</code></p>
</blockquote>
<br/>

<h3 id="operators">Operators</h3>
<p><code>Operator</code> 는 <code>Publisher</code> 에 붙여서 사용할 수 있는 메소드입니다.
Publisher 가 뿜어주는 데이터들을 원하는대로 가공할 때 사용합니다.</p>
<pre><code class="language-swift">let sub = NotificationCenter.default
    .publisher(for: NSControl.textDidChangeNotification, object: filterField)
    .map( { ($0.object as! NSTextField).stringValue } )
    .sink(receiveCompletion: { print ($0) },
          receiveValue: { print ($0) })

/*

TextField 의 변화를 감지하는 NotificationCenter 를 만들어서, 
해당 이벤트 (입력 감지) 기반으로 Publisher 를 만들고,
Publisher 가 뿜는 이벤트 기반 데이터 중, 실제 입력값인 String 값만 받도록 Map 해서
sink 를 통해 Subscriber 를 만든 후, 받은 이벤트 상태 (receiveCompletion) 과 값 (receiveValue) 를 출력하는 중 입니다.

*/</code></pre>
<p>Operator 에는 다양한 종류가 있어, 필요에 따라 사용할 수 있습니다.
자주 사용될법한 Operator 들은 다음과 같이 있습니다.</p>
<pre><code class="language-swift">    .map { }
    .flatMap { } // 이벤트가 1회 요청에 여러번 돌아올 때, 해당 값들을 모두 한번에 받습니다. (URLRequest 를 사용하는 시나리오가 대표적)
    .compactMap { } // nil 값은 제외하고 이벤트 값들을 방출합니다.
    .tryMap { } // 에러를 발생시키는 작업을 할 때, 에러가 발생하면 바로 Publisher 를 종료시킵니다.

    .filter { } // 이벤트 값들을 특정 조건에 따라 거릅니다.
    .tryFilter { } // 이벤트 값들을 특정 조건에 따라 거를 때, 에러가 발생하면 바로 Publisher 를 종료시킵니다.

    .setFailureType(to: Error.self) // 해당 에러를 Publisher 가 방출하는 Error 로 바꿉니다. 

    .decode(type: T.self, decoder: JSONDecoder()) // JSON 등의 데이터를 T 자료형으로 디코딩합니다. 실패하면 Publisher 를 종료시킵니다.

    .retry() // Publisher 의 흐름에 따라 내려올 때, 오류가 발생하면 retry의 횟수만큼 처음부터 다시 시도합니다. (URLRequest 를 실패했을 때, 1번 더 시도 하게 하는 등으로 사용할 수 있습니다.)
    .debounce(for: .milliseconds(500), scheduler: RunLoop.main) // 얼마나 자주 이벤트를 요청할 건지 debounce 를 통해 지정할 수 있습니다.

    .eraseToAnyPublisher() // Publisher 의 Operator 들을 거치며 생성된 중첩 상태의 OutPut 들 중 가장 마지막 타입을 기반으로 Publisher 로 1개의 타입으로 만듭니다.
</code></pre>
<br/>

<h3 id="cancellabel">Cancellabel</h3>
<p>Subscriber 를 한번 만들면, 특정 이유에 의해서 종료되지 않는 이상 메모리에 계속해서 남아서 이벤트를 요청하게 됩니다. 이러한 Publisher 들은 필요 없을 때 해제해주지 않으면 메모리 누수로 이어지기 때문에 적절한 시점에서 해제하는 것이 필요합니다.</p>
<p>해제를 하는 방법에는 두가지 방법이 있습니다.</p>
<ul>
<li><code>Subscriber.cancel()</code> 을 호출해서 직접 해제하는 방법</li>
<li><code>Set&lt;AnyCancellabel&gt;()</code> 에 Publisher 들을 모아서 해제하는 방법</li>
</ul>
<h4 id="subscribercancel">Subscriber.cancel()</h4>
<pre><code class="language-swift">let sub = NotificationCenter.default
    .publisher(for: NSControl.textDidChangeNotification, object: filterField)
    .map( { ($0.object as! NSTextField).stringValue } )
    .filter( { $0.unicodeScalars.allSatisfy({CharacterSet.alphanumerics.contains($0)}) } )
    .debounce(for: .milliseconds(500), scheduler: RunLoop.main)
    .receive(on: RunLoop.main)
    .assign(to:\MyViewModel.filterString, on: myViewModel)
    // 어떤 Subscriber

sub?.cancel() // &lt;&lt; 원하는 시점에서 Cancel()</code></pre>
<p><code>Publisher</code> 에서 <code>sink()</code> 혹은 <code>assign()</code> 을 통해 만들어진 <code>Subscriber</code> 들을, 원하는 시점에서 직접 Cancel() 을 호출해서 메모리에서 해제할 수 있습니다.</p>
<p>대표적인 시점은 
<code>UIKit</code> 에서는 <code>viewDidDisapeear()</code>
<code>SwiftUI</code> 에서는 <code>OnDisAppear()</code> 가 될 수 있습니다.</p>
<h4 id="setanycancellabel">Set&lt;AnyCancellabel&gt;()</h4>
<p>Subscriber 들이 다수 존재하고, 특이점이 없는 LifeCycle 을 가진다면 (즉, View가 사라질 때 함께 사라지면 된다면) <code>Set&lt;AnyCancellabel&gt;</code> 를 사용할 수 있습니다.</p>
<pre><code class="language-swift">private var cancellabels = Set&lt;AnyCancellable&gt;() // Subscriber 들을 저장해놓은 Set


let sub = NotificationCenter.default
    .publisher(for: NSControl.textDidChangeNotification, object: filterField)
    .map( { ($0.object as! NSTextField).stringValue } )
    .filter( { $0.unicodeScalars.allSatisfy({CharacterSet.alphanumerics.contains($0)}) } )
    .debounce(for: .milliseconds(500), scheduler: RunLoop.main)
    .receive(on: RunLoop.main)
    .assign(to:\MyViewModel.filterString, on: myViewModel)
    .store(in: &amp;cancellabels) // &lt;&lt; Subscriber 의 마지막에 store() 를 통해 해당 Subscriber 를 Set&lt;Cancellabel&gt; 에 저장한다.


// 이후 Cancellabels 가 사라질 때, 
// Cancellabels 에 저장된 Subscriber 들도 모두 함께 메모리에서 해제됩니다.</code></pre>
<blockquote>
<p><em><strong>더 쉽게 말하자면</strong></em>
<code>Subscriber</code> 는 한번 만들면 메모리 해제해줘야해요.
<code>Subscriber.cancel()</code> 쓰거나, 
<code>Set&lt;AnyCancellabel&gt;</code> - <code>Subscriber.store()</code> 를 통해
메모리에서 해제할 수 있어요.</p>
</blockquote>
<h4 id="읽어주셔서-감사합니당-">읽어주셔서 감사합니당 :)</h4>
<p><img src="https://user-images.githubusercontent.com/80164141/138802009-f777c0cc-d1d1-4cde-8702-9c5e52329e74.gif" alt="북극여우가 눈으로 점프하는 짤"></p>
<h4 id="출처">출처</h4>
<p><a href="https://developer.apple.com/documentation/combine">Combine</a> from Apple
<a href="https://developer.apple.com/videos/play/wwdc2019/721/">Combine in Practice</a> from Apple
<a href="https://medium.com/@puneet.teng/fetch-remote-url-with-urlsession-combine-datataskpublisher-9aa34f98b905">URLSession dataTask Vs Combine dataTaskPublisher</a> from Medium by PTeng</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[MVVM 은 왜 쓰는걸까? by SwiftUI]]></title>
            <link>https://velog.io/@newon-seoul/MVVM-%EB%8F%84%EC%9E%85%EA%B8%B0</link>
            <guid>https://velog.io/@newon-seoul/MVVM-%EB%8F%84%EC%9E%85%EA%B8%B0</guid>
            <pubDate>Mon, 10 Apr 2023 01:32:55 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>주니어 개발자로, SwiftUI 를 통해 MVVM 에 대한 설명 후 SwiftUI 가 MVVM 에 찰떡이라고 느꼈던 주관을 풀어낸 글 입니다.</p>
</blockquote>
<blockquote>
<p>인스턴스는 다양하게 사용할 수 있는 단어이지만, 
여기서는 메모리에 적재되어 실재하는 데이터 덩어리 라는 의미로만 사용됩니다.</p>
</blockquote>
<blockquote>
<p>독자는 SwiftUI 를 통해 UI 를 작성하는 방법을 알고 있으며, 
Modifier 와 Property Wrapper 가 무엇인지 알고 있다고 가정한 글 입니다.</p>
</blockquote>
<p><br/> <br/></p>
<h3 id="디자인패턴이란">디자인패턴이란?</h3>
<p>모바일 개발을 진행하다보면 흔히들 MVC, MVP, MVVM 이라는 디자인 패턴을 보게 된다. 하지만 어떤 글을 보더라도, <code>뭐라카는데?</code> 라는 느낌이 들 것이다. 왜 그럴까?</p>
<p><a href="https://refactoring.guru/design-patterns/what-is-pattern">What&#39;s a design pattern? / Refactoring Guru</a> 에서는 디자인 패턴을 다음과 같이 설명하고 있다.</p>
<blockquote>
</blockquote>
<p>디자인 패턴은 소프트웨어 개발 중 흔하게 발생하는 문제들을 해결할 수 있는 일반론들을 모아 놓은 것이다. 디자인 패턴은 미리 만들어진 청사진과 같아서,  현재 발생하고 있는 설계 (*design) 문제들을 자신의 코드에 맞게 커스터마이징해서 적용하여 사용하는 것이다.</p>
<blockquote>
</blockquote>
<p>따라서 특정 디자인 패턴을 찾았다고 해서, 코드에 복붙을 할 수는 없다. 디자인 패턴은 함수나 라이브러리가 아니라서, 특정 코드 블럭을 복붙한다고 해서 적용할 수 있는 것이 아니기 때문이다.</p>
<blockquote>
</blockquote>
<p>대신 디자인 패턴은 특정 문제를 풀기 위한 넓은 의미로서의 개념과 같다. 디자인 패턴을 사용하되, 세밀하게 현재 코드에 맞도록 적용함으로서 이 개념을 적용할 수 있다.</p>
<p>요약하자면 <code>특정 문제를 해결하기 위한 일반적인 개념</code> 으로 볼 수 있겠다. 
그래서 디자인 패턴은 실제 코드와 실제 문제가 있어야만 적용할 수 있는 것이다.</p>
<p><br/><br/></p>
<h3 id="현재-적용한-mvvm-구조">현재 적용한 MVVM 구조</h3>
<p>그러니까 바로 실제 MVVM 을 그냥 바로 봐보자. <a href="https://namu.wiki/w/%EB%AA%A8%EB%A5%B4%EB%A9%B4%20%EB%A7%9E%EC%95%84%EC%95%BC%EC%A3%A0"><del>원래 모르면 맞아야 한다. ㅎ</del></a></p>
<img src="https://velog.velcdn.com/images/newon-seoul/post/a20ceffe-7a31-4dee-bfca-07cf2e4e97d6/image.png" width="30%" height="30%">

<p>현재 진행하고 있는 프로젝트의 구조이다. 
파란색은 MVVM 의 필수 요소이고, 초록색은 내가 임의로 사용하는 요소이다.</p>
<ul>
<li>Model: 데이터 구조 그 자체</li>
<li>viewModel: 비즈니스 로직 모음집</li>
<li>view: UI 모음집</li>
<li>APIs, Utils: <a href="https://refactoring.guru/design-patterns/singleton">Singleton</a> 을 보장해야 하는 API 이거나, 
서버 등으로부터 복잡하게 데이터를 처리해야하는 API 모음집
API 는 서버, Util 은 로컬
<a href="https://developer.android.com/jetpack/guide?hl=ko#fetch-data">(안드로이드에서 Repository 역할 / 목차: 데이터 가져오기)</a><br/>

</li>
</ul>
<img src="https://t1.daumcdn.net/cfile/tistory/266CBD4856DECEBD05" width="50%" height="50%">


<p><del>예?</del></p>
<hr>
<p>MVVM 디자인 패턴은 구조를 해결하기 위한 문제이다. 
<a href="https://learn.microsoft.com/ko-kr/windows/uwp/data-binding/data-binding-and-mvvm">마이크로소프트</a> 의 MVVM 을 설명을 빌리자면 다음과 같이 이야기할 수 있다. </p>
<blockquote>
</blockquote>
<p>MVVM(Model-View-ViewModel)은 UI 및 비 UI 코드(이하 비즈니스 로직) 를 분리하기 위한 UI 아키텍처 디자인 패턴입니다. </p>
<blockquote>
</blockquote>
<p>MVVM을 사용하여 </p>
<p>1) UI를 선언적으로 정의하여 UI 와 관련된 내용만 깔끔하게 정리할 수 있으며,
2) 비즈니스 로직만 모아놓은 파일을 따로 정리할 수 있으며,
3) UI 와 비즈니스 로직을 거친 데이터를 동기화 상태를 유지할 수 있고,
4) 적절한 명령으로 UI 와 비즈니스 로직을 라우팅하여, 느슨할 결합을 제공할 수 있습니다.</p>
<blockquote>
</blockquote>
<p>*이 내용은 임의로 변형 &amp; 요약한 내용입니다. 원본은 링크에서 확인해주세요.</p>
<p>1번과 2번 항목은 직관적이다.
UI 코드들만 모아서 정리하고 싶고, 비즈니스 로직만 모아서 정리하고 싶다.</p>
<ol>
<li>1번을 실제 구조와 비교해보자. 구조의 사진을 다시 보면 Viwe 안에 폴더를 다시 나눠서 메인 화면, 스플래쉬 화면, 로그인 화면, 등등으로 나누어놓고, <del>펼쳐놓지 않았지만 ㅎ</del> 내부에는 폴더 제목에 해당하는 UI 만 있을 것이라고 쉽게 예상할 수 있다. 실제로 내부에는 UI 와 관련된 내용 + List 등 아이템이 관련된 UI 파일만 있다.</li>
<li>2번을 실제구조와 비교해보자. 
_참고로 Wassup 은 기획에서 나온 UI 컨셉 이름 중 하나이다. _
User 와 관련된 viewModel, Wassup 과 관련된 viewModel, Wassup 에서도 Poster, Video 관련된 viewModel 이 각각 있다. 
각 파일들은 해당 개념, 즉 User / Wassup / Wassup 중에서도 Poster / Wassup 중에서도 Video 와 관련된 비즈니스 로직만 작성했다.</li>
</ol>
<p><br/> <br/></p>
<p>3번과 4번은 의미가 묘하니, 조금 더 살펴보자.</p>
<p>3번, <code>UI</code> 와 <code>비즈니스 로직을 거친 데이터</code> 를 동기화를 한다는 이야기를 풀어보면 <code>비즈니스 로직</code> 은 결국 로직일 뿐, 실제로 <code>UI</code> 에 들어가는 것은 데이터라는 것을 집중하면 쉽게 이해할 수 있다. UI 에서 참여하기 버튼 등을 클릭했을 때, 그것을 <code>특정 비즈니스 로직 (실제로 참여할 수 있는가? 없는가? 등을 해결한 후) 데이터적으로 반응해야 하는데</code> MVVM 은 이를 쉽게 해결할 수 있다는 이야기다.</p>
<p>4번, <code>적절한 명령</code> 으로 <code>UI</code> 와 <code>비즈니스 로직</code> 을 라우팅하여, <code>느슨한 결합</code> 을 제공한다는 이야기를 풀어보면, 얼핏 보면 3번의 내용이 코드적으로 너무 복잡하고, 또 까딱하면 데이터가 서로 엮여서 수정하려면 대규모 리팩토링이 될 것 같은데 MVVM 은 <code>적절한 명령</code> 을 통해 느슨하게 연결해서, 코드가 종속적이지 않고 수정을 쉽게끔 할 수 있다는 이야기이다.</p>
<p>곰곰히 생각해보면 3번과 4번은 하나의 행동, <code>UI</code> 와 <code>데이터</code> 를 연결에 대해서만 이야기 하고 있다. <code>적절한 명령</code> 을 쓰면 <code>UI</code> 와 <code>비즈니스 로직을 처리한 데이터</code> 를 동기화 하면서도 <code>느슨한 결합</code> 을 제공할 수 있다는 것이다.</p>
<br/>

<p>애플은 마이크로소프트만큼 좋은 회사여서 그런지, SwiftUI 역시 <code>적절한 명령</code> 을 가지고 있다. 다음 실제 코드를 살펴보며 3번 내용 먼저 확인해보자.</p>
<img src="https://velog.velcdn.com/images/newon-seoul/post/39cc246b-0b58-4964-b0eb-0e91c1fc4a6c/image.png">

<p><code>@StateObject private var viewModel: UserViewModel</code> 코드는 
UserViewModel 자료형을 가진 변수에, <a href="https://developer.apple.com/documentation/swiftui/stateobject">@StateObject</a> 라는 미리 SwiftUI 가 선언한 속성을 부여하고 있다. </p>
<p><a href="https://developer.apple.com/documentation/swiftui/observedobject">공식문서 가라사대</a>, <code>@StateObject</code> 는 SwiftUI View 의 파라미터에 쓸 수 있는 속성이다. 입력값이 <code>ObservableObject</code>, 관측 가능한 오브젝트, 이며 <code>view</code> 가 <code>ObservableObject</code> 의 속성이 변경될 때 마다 <code>Publish</code>, 출력하기를 바란다면 사용하기를 권장하고 있다. </p>
<blockquote>
<p><code>Publish</code> 가 강조된 이유는 단순히 출력, 출판을 한다는 의미가 아니라 <code>Combine</code> 에서 사용된 <code>Publish</code> 의 개념이기 때문이다.</p>
</blockquote>
<p>이 글에서 <code>Combine</code> 개념은 필요없지만 
궁금하다면 <a href="https://developer.apple.com/videos/play/wwdc2019/722/">Introducing Combine</a> 를 확인하면 알 수 있다.</p>
<p>쉽게말하면 값이 바뀔 때 마다 view 에 적용하고 싶으면 <code>@StateObject</code> 를 붙여서 사용하라고 할 수 있다. 단, 값 또한 관측이 가능해야 한다고 한다. </p>
<p>값의 관측은 viewModel 의 이야기이니, 이미 처리했다라고 생각하고 
우선 UI 에 집중하며 계속해서 코드를 다시 정리해보자.</p>
<pre><code class="language-swift">@StateObject private var viewModel: UserViewModel = UserViewModel() // 선언

var body: some Scene {
    windowGroupd {
        SplashView()
            .environmentObject(viewModel) 
            // 원하는 뷰에 적절한 명령을 통하여
            // 똑같은 인스턴스를 제공해주고 있다.
    }
}</code></pre>
<p>이 코드에서 viewModel 을 초기화하였고, 이를 SplashView 에 <code>.environmentObject()</code> Modifier 를 사용하여 viewModel 을 전달하고 있다. </p>
<p><code>@StateObject</code> 는 <code>ObservableObject</code> 를 선언할 때 사용하며,
<code>@ObservedObject</code> 가 하나의 파일에서, 전달받아서 사용할 때,
<code>@environmentObject</code> 는 인스턴스된 <code>ObservableObject</code> 를 상위뷰로부터 전달받을 때 사용된다.</p>
<h4 id="주석">주석</h4>
<blockquote>
<p><code>@ObservedObject</code> 와 <code>@EnvironmentObject</code> 의 차이는
파라미터로 전달해야 하는가, Modifier 로 전달해야 하는가의 차이라고 생각한다.</p>
</blockquote>
<p>코드로 보자면</p>
<pre><code class="language-swift">struct MyView: View {
    @StateObject private var model = DataModel() // @State 로 선언
&gt;
    var body: some View {
        Text(model.name)
        MySubView(model: model) // @ObervedObject 를 파라미터로 전달
        YourSubView()
            .environmentObject(model: model) 
            // @EnvironmentObject 를 Modifier 로 전달
    }
}
&gt;
struct MySubView: View {
    @ObservedObject var model: DataModel
&gt;
    var body: some View {
        Toggle(&quot;Enabled&quot;, isOn: $model.isEnabled)
    }
}
&gt;
struct YourSubView: View {
    @EnvironmentObject var model: DataModel
&gt;
    var body: some View {
        Toggle(&quot;Enabled&quot;, isOn: $model.isEnabled)
    }
}</code></pre>
<blockquote>
</blockquote>
<p>공식문서에서는 
<code>@ObservedObject - for Subview</code>
<code>@EnvironmentObject - for descendant</code>
로 구분하였는데, 큰 설명은 없기에 취사선택 하면 되는 것 같다.</p>
<blockquote>
</blockquote>
<p>단 선언은 반드시 <code>@StateObject</code> 를 사용하며
외부에서 쓰지 못하도록 <code>private</code> 를 쓸 것을 권장하고 있다.</p>
<blockquote>
</blockquote>
<p>이를 무시하면 내부적으로 SwiftUI 프레임워크의 메모리 관리에 충돌을 일으키고 예상치 못한 결과를 야기한다고 한다.</p>
<p><img src="https://velog.velcdn.com/images/newon-seoul/post/891825f1-2806-476d-9eb6-e9133ef26fbf/image.png" alt=""></p>
<p>전달된 <code>EnvironmentObject</code> 는 다음과 같이 사용할 수 있다.</p>
<h4 id="참고">참고</h4>
<p>_<code>Auth.auth().currentUser?.uid == nil</code> 은 비즈니스 로직이니, viewModel 안에 있어야 하는게 맞고 그에 따라 전달받은 viewModel 내부에서 동기화된 데이터를 처리하는 것이 여태까지의 흐름으로는 맞다.  _</p>
<p>_그럼에도 불구하고 <code>Auth.auth().currentUser?.uid</code> 를 직접 사용한 이유는 해당 속성은 <code>Firebase</code> 라는 라이브러리에서 직접 온 속성이자, 싱글턴 속성이기에 다이렉트로 작성하는 것이 가독성면에서 더 좋다고 판단하여 밖으로 꺼내었다. _</p>
<p>_ 디자인 패턴은 결국 특정 문제를 해결하고자 하는 것이니, 크게 어긋나지 않는 선에서 적절하게 맞추어도 괜찮다고 생각한다. _
<del><em>사실 혼자 하는 프로젝트라서 마음대로 한 것도 없지 않아 있긴 있다. 근데 파이어베이스는 저렇게 빼놓는게 더 직관적이지 않나? ..</em></del></p>
<br/>

<p>정리하자면 UI 에서 <code>적절한 명령</code> 은 <code>@ObservedObject</code> 와 <code>@EnvironmentObject</code> 로, 인스턴스 여부에 따라 취사선택하여 <code>비즈니스 로직을 처리한 데이터</code> 를 <code>UI</code> 에 동기화 할 수 있다. </p>
<br/>

<p>이제 4번 내용을 <code>viewModel</code> 과 함께 살펴보자.
<code>UI</code> 의 <code>적절한 명령</code> 인 <code>@ObservedObject</code> 를 살펴볼 때, 이 입력값은 관측 가능한 오브젝트이어야 하며, 이는 <code>viewModel</code> 이 내부에서 처리를 해주어야 한다.</p>
<p>이 내용을 실제 코드와 함께 살펴보자.</p>
<p><img src="https://velog.velcdn.com/images/newon-seoul/post/8d60e969-e5f9-40ca-ad16-e356165303dc/image.png" alt=""></p>
<p><code>UserViewModel</code> 이라는 <code>class</code> 는 <code>ObservableObject</code> 프로토콜을 따르면서, <code>viewModel</code> 이라는 이름의 <code>class</code> 가 <code>관측 가능한 오브젝트가 될 수 있도록</code> 해주고 있다.</p>
<p><code>관측 가능한 오브젝트</code> 가 된 <code>viewModel</code> 은 비즈니스 로직을 잔뜩 담고 있다. 크게 <code>@Published 변수</code> 와 이를 변경하는 함수들로 구분할 수 있다.
<code>login()</code>, <code>signUp()</code> 등의 유저와 관련된 함수들은 내부에서 각각 자신이 담당하는 <code>@Published 변수</code> 를 변경하는 내용을 담고 있다. </p>
<p><em>함수 내용은 공개 불가능합니다.</em> </p>
<p>놀랍게도 4번의 내용은 이렇게 끝이다. 그저 클래스가 <code>ObservableObject</code> 프로토콜을 따르며 (이 프로토콜은 바라는 내용도 없다!), 입력값에 따라 view 가 반응하기를 원하는 변수 앞에 <code>@Published</code> 를 붙임으로써 <code>UI</code> 와 <code>비즈니스 로직을 처리한 데이터</code> 를 라우팅하고 있다. </p>
<p><code>느슨한 결합</code> 은 어떨까?
지금의 MVVM 구조를 통해 비즈니스 로직 내부에서도 서로 연관된 내용이 아니면 풀려있으며, 비즈니스 로직도 개발자가 원하는 크기와 단위, 개념으로 나눌 수 있게 된다. 이미 현재 적용한 MVVM 구조에서 살펴보았듯 User 와 Wassup 의 비즈니스 로직이 분리되어 있고, Wassup 내부에서 사용되는 Poster 와 Video 도 필요에 따라 분리되어 있는 것을 볼 수 있다. </p>
<p><code>viewModel</code> 에게 <code>ObervableObject</code> 와 <code>@Published</code> 라는 <code>적절한 명령</code> 을 통해 UI 와 비즈니스 로직을 연결한 것이다.</p>
<br/>

<p>그러면 현재 구조에서 사용되었던 <code>Model</code> 은 언제 쓰일까?</p>
<pre><code class="language-swift">class UserModel: ObservableObject {
    @Published var user: UserModel = UserModel()
    ...
}

struct UserModel {
   .....
}</code></pre>
<p>바로 <code>유저</code> 와 같이 큰 개념을 담아야 하는 변수의 커스텀한 자료형을 만들 때 사용된다. User 에는 프로필 사진, 이름 등 다양한 정보가 들어가야 하는데 이를 일일히 <code>@Pubslih</code> 를 사용하기보다 필요한 데이터만 모아서 깔끔하게 정리하고, 이후 초기화가 필요할 때도 <code>Model</code> 만 불러서 초기화할 수 있게 되었다.</p>
<hr>
<h3 id="무엇을-해결할-수-있었는가-주관적-내용">무엇을 해결할 수 있었는가? (주관적 내용)</h3>
<p>위에서 MVVM 의 설명을 이렇게 설명하였다.</p>
<blockquote>
</blockquote>
<p>MVVM(Model-View-ViewModel)은 UI 및 비 UI 코드(이하 비즈니스 로직) 를 분리하기 위한 UI 아키텍처 디자인 패턴입니다.</p>
<blockquote>
</blockquote>
<p>MVVM을 사용하여</p>
<p>1) UI를 선언적으로 정의하여 UI 와 관련된 내용만 깔끔하게 정리할 수 있으며,
2) 비즈니스 로직만 모아놓은 파일을 따로 정리할 수 있으며,
3) UI 와 비즈니스 로직을 거친 데이터를 동기화 상태를 유지할 수 있고,
4) 적절한 명령으로 UI 와 비즈니스 로직을 라우팅하여, 느슨할 결합을 제공할 수 있습니다.</p>
<blockquote>
</blockquote>
<p>*이 내용은 임의로 변형 &amp; 요약한 내용입니다. 원본은 <a href="https://learn.microsoft.com/ko-kr/windows/uwp/data-binding/data-binding-and-mvvm">링크</a>에서 확인해주세요.</p>
<p>이제 이걸 다시 정리해보자면 
<code>MVVM</code> 디자인 패턴은 <code>결국 코드를 어떻게 정리하면 이해하기 쉬울까?</code> 에 대한 답변 중 하나라고 말할 수 있다. </p>
<p>하나의 파일에 <code>UI</code> 와 <code>비즈니스 로직</code> 을 몽땅 함께 담아버리면
나와 신만이 아는 코드에서 신만이 아는 코드가 될 수도 있고,
그렇다고 어설프게 나누면 뭐가 무엇이였는지 까먹어서 마찬가지로 신만이 아는 코드가 될 수도 있다.</p>
<p><code>MVVM</code> 디자인 패턴은 코드를  <code>UI</code> 와 <code>비즈니스 로직</code> 으로 크게 나누고,
이 두개를 <code>적절한 명령</code> 을 통해 <code>동기화</code> 및 <code>느슨한 결합</code> 이라는 이점을 제공해주고 있다.</p>
<p><img src="https://blog.kakaocdn.net/dn/cCoGT9/btq85lwmiP7/5ngW7yRoetZx37HlslaZz1/img.gif" alt=""></p>
<p>기나긴 글을 지나 MVVM 구조에 대해서 이야기를 나누어보았다. 
이제는 실제 사례에서 어떤 점이 편하게 작용할 수 있었는지만 간편하게 살펴보자 :)</p>
<br/>

<p>첫번째. UI 와 비즈니스 로직 코드가 분리되었기에, 테스트 하기 쉬워졌다.
UI 를 먼저 작업하여 원하는 만큼 Preview 로 확인하고, 이후 비즈니스 로직을 넣어볼 수 있게 되어 개발할 때 API 호출 횟수 등에 신경쓰지 않고 미리 다 확인해 볼 수 있게 된 것이다. 이 이점은 다른 개발자와 함께 할 때 더욱 크게 다가오는데, 연결할 API 가 준비 안되어 있으면 다른 UI 작업을 하면 되고, UI 를 분업할 때도 어느 파트를 맡을 지 더욱 직관적으로 정리할 수 있게 된다.</p>
<p>두번째. MVVM 구조에 <code>SwiftUI</code> 에 <code>적절한 명령</code> 을 섞으니 마음이 편안한 선언형 프로그래밍이 가능해졌다. 이름, 개념 단위로 파일명을 작성하니 구조만 보더라도 무엇을 담당하는 파일인지 쉽게 알 수 있게되고, 무엇보다 재활용성이 높아졌다. 
반복적으로 나오는 UI 혹은 두번 이상 쓰이는 비즈니스 로직들을 호출만으로 처리할 수 있게 되니 그 자체만으로 생산성 자체가 높아졌다.</p>
<p>세번째. 더욱 복잡한 구조를 설계할 수 있게 되었다.</p>
<img src="https://velog.velcdn.com/images/newon-seoul/post/fb754dc0-901f-4b14-b8fc-e0a8f81741a6/image.png" width="50%" height="50%">


<p>이처럼 복잡한 화면을 처리해야할 때, 
비즈니스 로직을 담당하는 <code>viewModel</code> 자체가 <code>느슨한 결합</code> 상태이니 핸들링이 쉬워졌다. 무엇보다도 위의 화면처럼 여러 리스트가 있을 때, 리스트 아이템에게도 viewModel 을 만들어줌으로써 코드들을 분리하여 관리할 수 있었고, 또 손 쉽게 리스트에게 데이터를 전달해줄 수 있었다.</p>
<p><img src="https://velog.velcdn.com/images/newon-seoul/post/f565d97a-28ff-4122-8b3e-fba6e6a63f82/image.png" alt=""></p>
<p>응용하면 이런 내용도 해결할 수 있게 되었다.</p>
<p><img src="https://velog.velcdn.com/images/newon-seoul/post/3488f3af-9c34-47f7-8648-789cbd906a82/image.gif" alt=""></p>
<p>해당 내용은 리스트를 생성하고 삭제해야하는 상황으로, </p>
<ol>
<li>리스트 아이템의 내용이 바로바로 반영될 것.</li>
<li>삭제가 가능해야할 것.</li>
</ol>
<p>이라는 문제를 해결해야 했던 상황이였다.</p>
<p>문제는 <code>리스트를 위한 viewModel</code>, <code>리스트 아이템을 위한 viewModel</code> 로 구분하다보니 리스트를 삭제하기 꽤나 번거로운 상황이였다. </p>
<p>UI 코드 상으로는 리스트의 아이템을 표시할 때 아이템의 viewModel 만 사용하게 되는데, 막상 삭제할때는 UI 는 아이템 뷰에 있고, 메소드는 부모가 필요한 상황이라는 아이러니한 조건이었다.
이때 <code>아이템의 viewModel</code> 를 초기화할 때, <code>리스트 그 자체의 접근을 위한 viewModel</code> 을 <code>parent</code> 로 함께 보내주어 직관적으로 아이템이 부모를 호출하여 스스로를 삭제할 수 있게 된 것이다.</p>
<p><img src="https://velog.velcdn.com/images/newon-seoul/post/017ed723-4d9a-4a53-a1d8-157f6a3fe52c/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/newon-seoul/post/25cff33a-4a08-4a3f-a7f5-8bbeee1b5577/image.png" alt=""></p>
<h3 id="결론">결론</h3>
<p><code>MVVM</code> 구조를 <code>SwiftUI</code> 와 함께 알아보았다.
<code>MVVM</code> 이 <code>View(UI)</code> - <code>ViewModel(비즈니스 로직)</code> - <code>Model</code> 의 축약어일 뿐이므로, 지금의 MVVM 구조가 진리도 아니고 개발자마다, 문제마다 다른 <code>MVVM</code> 구조를 가질 수 있다.</p>
<p>또<code>적절한 방법</code> 이라는 워딩을 사용하였지만, 이는 마이크로소프트가 제시할 때의 이야기이고, 애플과 SwiftUI 가 직접 MVVM 을 지원한다고 명시한 것은 아니다. </p>
<blockquote>
<p><code>MVVM</code> 이라는 단어는 애플 공식문서에서 공식적으로 언급이 된 적이 없다고 한다. 
<a href="https://gist.github.com/unnnyong/439555659aa04bbbf78b2fcae9de7661">SwiftUI에서 MVVM 사용을 멈추자&quot;라고 생각이 들었던 이유</a></p>
</blockquote>
<p>그럼에도 불구하고, 이번 구조는 <code>MVVM</code> 이 이루고자 했던 가장 큰 틀
: UI 와 비즈니스 로직을 구분하는 아키텍처 패턴
를 따랐다고 생각한다.</p>
<br/>

<p>선언형 UI 를 사용하는 개발자가 늘어나면서 <code>MVVM</code> 이 꼭 필요한가? 에 대해서도 많은 논의가 있는 것으로 알고 있다. </p>
<p>개인적으로도 안드로이드의 <code>Jetpack compose</code> 를 사용할때는 워낙 자유롭기도 하고, <code>by remember { }</code>, <code>LaunchedEffect</code> 등의 코드를 UI 단에서 사용해야 하다보니 이렇게까지 비즈니스 로직을 UI 에서 섞을거라면  MVVM 을 왜 써야하지? 라는 의문도 있었다.</p>
<p>하지만 SwiftUI 를 기준으로는 </p>
<ul>
<li>UI 내부에서 비즈니스 로직을 처리하기 까다롭다는 점 </li>
<li>버튼이나 onAppear{} 등을 사용하지 않으면 body 내에서는 모든 코드가 View 프로토콜을 따라야 한다.</li>
</ul>
<ul>
<li>Combine 을 비롯한 다수의 비즈니스 로직을 viewModel 이라는 레이어를 만들면 한 곳에서 직관적으로 풀 수 있다는 점 </li>
</ul>
<ul>
<li>PropertyWrapper 를 활용해서 Model 과 View 가 직접적으로 연결될 수 있다고 하더라도, <code>MVC</code> 패턴처럼 모델이 직접 상태를 관리할 것이 아니라면, 결국 누군가는 상태를 관리하고 관련된 메소드를 품고 있어야 한다는 점(<a href="https://haruair.github.io/flux/docs/overview.html">Flux 패턴 등</a>)</li>
</ul>
<p>와 같은 문제를 속 시원하게 까지는 아니지만, 해결한다는 점에서 여전히 괜찮은 옵션 중 하나라고 생각이 든다.</p>
<h4 id="출처">출처</h4>
<p><a href="https://refactoring.guru/design-patterns/what-is-pattern">What&#39;s a design pattern?</a> from Refactoring Guru
<a href="https://learn.microsoft.com/ko-kr/windows/uwp/data-binding/data-binding-and-mvvm">데이터 바인딩 및 MVVM</a> from 마이크로소프트
<a href="https://developer.apple.com/documentation/swiftui/stateobject">@StateObject</a>, <a href="https://developer.apple.com/documentation/swiftui/observedobject">@ObservedObject</a>, <a href="https://developer.apple.com/videos/play/wwdc2019/722/">Introducing Combine</a>  등의 공식문서 
from Apple</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Swift-Language Guide 5.7 / Structures and Classes (야매 번역 + 정리)]]></title>
            <link>https://velog.io/@newon-seoul/Swift-Language-Guide-5.7-Structures-and-Classes-%ED%95%9C%EA%B5%AD%EC%96%B4-%EB%B2%88%EC%97%AD</link>
            <guid>https://velog.io/@newon-seoul/Swift-Language-Guide-5.7-Structures-and-Classes-%ED%95%9C%EA%B5%AD%EC%96%B4-%EB%B2%88%EC%97%AD</guid>
            <pubDate>Thu, 11 Aug 2022 15:15:04 GMT</pubDate>
            <description><![CDATA[<h3 id="초록">초록</h3>
<p><code>구조체(struct)</code>와 <code>클래스(class)</code>는 범용적인 목적을 위해, 프로그래머의 코드를 유연하게 블록처럼 구성하는 것을 의미합니다. 프로그래머는 <code>속성(properties)</code> 과 <code>메소드(methods)</code> 기존에 사용했던 문법과 동일하게 <code>변수, 상수, 함수</code> 문법을 사용하여 구조체나 클래스 내부에 정의할 수 있습니다.</p>
<p>다른 프로그래밍 언어들과 달리, 스위프트는 구조체와 클래스를 위해 별도의 인터페이스나 구현을 위한 별도의 파일을 요구하지 않습니다. 스위프트에서는 프로그래머가 구조체나 클래스를 하나의 파일 안에 정의하고나면 다른 코드에서도 사용할 수 있게끔 자동으로 외부 인터페이스를 만들어 제공해줍니다.</p>
<br/>

<p><em>Note</em> : 클래스의 인스턴스를 통상 <code>오브젝트(object)</code> 로 칭합니다. 하지만 스위프트의 구조체와 클래스는 조금 더 기능적인 면모 <em>( much closer in functionality )</em> 가 부각되며, 이번 챕터 역시 클래스나 구조체의 인스턴스에 적용하는 기능들을 묘사할 예정입니다. 이에 따라 <code>instance</code> 라는 용어도 사용할 것 입니다.</p>
<hr>
<p>블로그장 : 사견으로, 오브젝트와 인스턴스의 차이를 굳이 묘사하자면 (물론 말이 굉장히 많겠지만) 오브젝트를 객체, 즉 설계도로 보고 인스턴스를 객체에 데이터를 넣어서 메모리로 적재한 것으로 이해하고 있습니다. 다만 이런 구분 자체를 굳이 엄격하게 지을 필요는 없다고 생각되며, 구분 행위가 기능보다는 철학적인 면모를 더 내포한다고 생각합니다. 앞으로 나오는 인스턴스는 <code>구분지을 수 있는 하나의 종류</code> 혹은 <code>메모리에 적재된 데이터 묶음</code> 를 혼용해서 사용하는 것으로 이해하고 <del>야매</del> 번역하였음을 미리 알려드립니다. 관련된 <a href="https://stackoverflow.com/questions/2885385/what-is-the-difference-between-an-instance-and-an-object">StackOverFlow</a> 를 첨부합니다.</p>
<p><img src="https://velog.velcdn.com/images/newon-seoul/post/9dba2f99-543e-4f84-92d9-77d16d10e733/image.png" alt="">* 볼드체만 해석 : 인스턴스와 클래스, 그리고 오브젝트는 같은 의미이며 종종 상호교환적으로 사용됩니다.</p>
<hr>
<h3 id="구조체와-클래스-비교하기-comparing-structures-and-classes">구조체와 클래스 비교하기 (Comparing Structures and Classes)</h3>
<p>스위프트에서 구조체와 클래스는 유사한 부분이 많습니다.</p>
<ul>
<li>속성을 정의하여 값을 저장할 수 있습니다.</li>
<li>메소드를 정의하여 함수를 제공할 수 있습니다.</li>
<li>서브스크립트를 정의하여 서브스크립트 문법으로 
구조체나 클래스의 값에 접근할 수 있습니다.  <em>ex: array[1]</em></li>
<li>초기화(initializers) 를 정의하여 초기화 상태를 설정할 수 있습니다.</li>
<li>기본 구현을 넘어 구조체나 클래스의 기능(함수) 를 확장할 수 있습니다.</li>
<li>프로토콜을 준수하여 특정한 표준 함수를 제공하도록 할 수 있습니다.</li>
</ul>
<br/>

<p>클래스는 구조체는 할 수 없는 추가적인 능력들을 갖고 있습니다.</p>
<ul>
<li>상속이 가능하여, 하나의 클래스의 특징들을 다른 클래스로 상속할 수 있습니다.</li>
<li>타입 캐스팅이 가능하여, 프로그래머가 런타임 때 클래스 인스턴스의 자료형을 확인하고 해석할 수 있습니다.</li>
<li>초기화해제 <code>Deinitializers</code> 가 가능하여 인스턴스된 클래스 내 할당된 리소스를 메모리로부터 해제할 수 있습니다. </li>
<li>참조 카운트 <code>Reference counting</code> 으로 클래스 인스턴스에 하나 이상의 참조를 허용합니다.</li>
</ul>
<p>클래스가 추가적인 기능들로 지원하게 되면서 복잡도에 대한 비용이 증가하게 되었습니다. </p>
<p><code>구조체는 사용이 간단하기에 구조체를 사용하는 것을 권하며 클래스는 클래스의 사용이 적절하거나 필수적일 때만 사용할 것을 권합니다.</code> 이는 프로그래머가 구조체나 열거형으로 커스텀 데이터 자료형을 정의하기를 추천드리는 것 입니다. 
<a href="https://developer.apple.com/documentation/swift/choosing-between-structures-and-classes">구조체와 클래스 중 하나를 선택하기</a></p>
<hr>
<h4 id="블로그장--클래스와-구조체의-선택에-대한-주석">블로그장 : 클래스와 구조체의 선택에 대한 주석</h4>
<p>클래스는 복사 시 주소를 참조하므로, 복사된 곳에서 클래스 속성의 변경이 원본에도 영향을 미치게 되어 전체적인 구조가 복잡해지게 됩니다. </p>
<pre><code class="language-swift">class Cat {
    eye: String
}

var cheese = Cat(eye: &quot;Gold&quot;)
var black = a
black.eye = &quot;Black&quot;

print(cheese.eye, black.eye)
// 출력 : Black, Black</code></pre>
<p>반면 구조체는 복사 시 값만 전달할 뿐, 복사된 곳과 원본 사이에 연결성은 하나도 없습니다.</p>
<pre><code class="language-swift">struct Cat {
    eye: String
}

var cheese = Cat(eye: &quot;Gold&quot;)
var black = a
black.eye = &quot;Black&quot;

print(cheese.eye, black.eye)
// 출력 : Gold, Black</code></pre>
<p>이를 쉽게 표현하기로는, 
구조체는 복사본에게 원본을 사진을 인화하여 새롭게 준 것이고
클래스는 복사본에게 컴퓨터 내 사진 폴더 접속권을 준 것이라고 할 수 있습니다.</p>
<p>구조체는 인화한 사진을 주었으므로, 복사본에 낙서를 해도 영향을 안 받는 반면
클래스는 접속권을 준 사진 폴더 접속권을 주었기에, 사진에 낙서하거나 삭제하면 영향을 받습니다. <a href="https://www.udemy.com/course/ios-13-app-development-bootcamp/">Angela iOS 부트캠프 강의 (유데미)</a></p>
<br/>

<p>또한 이외에도, 메모리에서 클래스의 저장공간은 <code>힙</code> 인데 반해 구조체의 저장공간은 <code>스택</code>이 됩니다. 스택에서의 저장은 가장 마지막 데이터의 위에 바로 저장하면 되므로 저장 속도가 굉장히 빠르지만, 힙에서의 저장은 동적으로 메모리의 빈 공간을 찾아서 저장해야 하므로 힙을 전체 탐색 -&gt; 데이터 저장이라는 하나의 단계가 더 포함됩니다. </p>
<p>즉, 구조체는 저장 시 메모리의 빈 공간 탐색 없이 찾아도 되지만
클래스는 저장 시 메모리의 빈 공간을 탐색 후 저장해야 하므로 
속도면에서 더 느릴 수 밖에 없습니다.</p>
<p>메모리 해제에도 스택은 사용이 끝나면 자연스럽게 해제되는 반면, 
클래스는 클래스를 참조하고 있는 인스턴스들이 모두 해제되어야 클래스도 해제되므로
속도, 안정성 면에서 더욱 불안전 할 수 밖에 없습니다.</p>
<p>그렇기에 스위프트에서는 매우 적합한 사례거나 반드시 필요한 사례가 아니라면 구조체를 사용하는 것을 권고하는 것입니다. <a href="https://www.inflearn.com/course/%EC%8A%A4%EC%9C%84%ED%94%84%ED%8A%B8-%EB%AC%B8%EB%B2%95-%EB%A7%88%EC%8A%A4%ED%84%B0-%EC%8A%A4%EC%BF%A8">앨런 Swift문법 마스터 스쿨</a></p>
<br/>

<p>애플의 문서 <a href="https://developer.apple.com/documentation/swift/choosing-between-structures-and-classes">구조체와 클래스 중 하나를 선택하기</a> 에서 구조체의 사용을 
<code>&quot;Using structures makes it easier to reason about a portion of your code without needing to consider the whole state of your app.&quot;</code> 로 표현한 것도, 이와 유사한 의미입니다. </p>
<p>구조체는 스택에 저장되는 인스턴스이자 값 타입 이므로, 구조체가 다른 구조체에 영향을 주지 않는 반면 클래스는 다른 클래스에 영향을 주기 때문에 평범한 종류의 데이터, <code>common kinds of data</code> 라면 구조체를 사용하는 것을 권하는 것 입니다. </p>
<p>애플에서 언급하는 클래스를 사용해야 하는 경우는</p>
<ul>
<li>Object C 로 작성된 API 를 사용해서 데이터를 관리해야 하는 경우,
API 가 상속받을 클래스를 요구하는 경우가 많으므로 클래스 사용 권장</li>
</ul>
<ul>
<li>메모리 관점에서 두 인스턴스가 동일한 지 확인해야 하는 경우,
즉 파일 관리, 네트워크, 하드웨어 기능 사용 등의 경우 클래스 사용 권장,
대표적인 예시로 사운드와 관련된 <code>AVFoundation</code> 의 <code>AVAudioPlayer</code> 로,
사운드를 담당하는 객체가 사운드를 할당받을 때 마다 새로운 인스턴스를
생성해버리면 오디오가 겹쳐서 들리게 됩니다.</li>
</ul>
<hr>
<h4 id="정의-문법-definition-syntax">정의 문법 (Definition Syntax)</h4>
<p>구조체와 클래스는 정의하는 문법이 비슷합니다. &#39;</p>
<pre><code class="language-swift">struct SomeStructure {
    // 구조체 정의
}
class SomeClass {
    // 클래스 정의
}


// 실제 예시

struct Resolution {
    var width = 0
    var height = 0
}

class VideoMode {
    var resolution = Resolution()
    var interlaced = false
    var frameRate = 0.0
    var name: String?
}</code></pre>
<p><em>Note</em> : 프로그래머가 새로운 구조체나 클래스를 정의한다는 것은, 새로운 스위프트 자료형을 정의하는 것과 같습니다. </p>
<p>따라서 파스칼 케이스에 따라 대문자로 시작하고, 단어단위로 대문자를 붙여서 사용함으로써 기존의 스위프트 자료형들 (String, Int, Bool ...) 과 이름짓는 방식을 맞추는 것을 권해드립니다. </p>
<p>또한 속성이나 메소드에는 카멜 케이스에 따라 소문자로 시작하고, 단어단위로 대문자를 붙여서 자료형과 구분하는 것을 권합니다. </p>
<br/>

<p>이때 속성들에는 기본값을 주거나, 안 줄 수도 있으며 
기본값을 주지 않은 속성들은 초기화 시 반드시 값을 지정해야 합니다.
이때 자료형을 옵셔널로 지정하면 초기화 시 자동으로 <code>nil</code> 값이 적용됩니다.</p>
<br/>

<h4 id="구조체와-클래스-인스턴스-structure-and-class-instances">구조체와 클래스 인스턴스 (Structure and Class Instances)</h4>
<p>상단의 예시로 든 , <code>Resolution</code> 구조체와 <code>VideoMode</code> 클래스는 각각 <code>Resolution</code> 과 <code>VideoMode</code> 가 어떤 모습이어야 하는지 설명한 것에 불과합니다. 실제 모습으로 적용하고, 데이터로써 사용하려면 구조체나 클래스의 인스턴스를 만들어야 합니다.</p>
<p>구조체나 클래스를 인스턴스하는 문법은 다음과 같습니다.</p>
<pre><code class="language-swift">let someResolution = Resolution()
let someVideoMode = VideoMode()</code></pre>
<p>구조체와 클래스는 <code>구조체()</code>, <code>클래스()</code> 형태로 인스턴스할 수 있으며, 자세한 사항은 <a href="https://docs.swift.org/swift-book/LanguageGuide/Initialization.html">Initialization</a> 에서 다룹니다.</p>
<h4 id="속성에-접근하기-accessing-properties">속성에 접근하기 (Accessing Properties)</h4>
<p>인스턴스된 클래스나 구조체 바로 뒤에 <code>.</code> 을 사용하므로써 속성에 접근할 수 있습니다. 이때 속성이 또 다른 구조체나 클래스라면 다시 한번 <code>.</code> 를 사용하므로써 속성에 재접근할 수도 있습니다.</p>
<pre><code class="language-swift">print(&quot;어떤 해상도의 넓이는 \(someResolution.width)&quot;)
// 출력: &quot;어떤 해상도의 넓이는 0&quot;

print(&quot;어떤 비디오의 넓이는 \(someVideoMode.resolution.width)&quot;)
// 출력: &quot;어떤 비디오의 넓이는 is 0&quot;

someVideoMode.resolution.width = 1280
print(&quot;어떤 비디오의 넓이는 이제 \(someVideoMode.resolution.width)&quot;)
// 출력: &quot;어떤 비디오의 넓이는 이제 1280&quot;</code></pre>
<h4 id="구조체-자료형의-똑똑한-속성-초기화-memberwise-initializers-for-structure-type">구조체 자료형의 똑똑한 속성 초기화 (Memberwise Initializers for Structure Type)</h4>
<p>구조체는 클래스와 달리 구조체 내 초기화에 대한 내용이 안 적혀있다면 자동으로 <code>memberwise initializer</code> 를 생성합니다. 자세한 사항은 <a href="https://docs.swift.org/swift-book/LanguageGuide/Initialization.html">Initialization</a> 에서 다룹니다.</p>
<h3 id="구조체와-열거형은-값-타입이다-structures-and-enumerations-are-value-types">구조체와 열거형은 값 타입이다. (Structures and Enumerations Are Value Types)</h3>
<p><code>값 타입 (Value type)</code> 은 변수나 상수에 할당하거나 함수에 인자로 전달될 때 그 값을 복사해서 주는 자료형을 의미한다.</p>
<p>사실 이전의 장들에서 당신은 여러번 값 타입들을 사용해왔습니다. 스위프트의 정수, 소수와 같은 숫자, Boolean, 스트링, 배열, 딕셔너리 등등은 모두 값 타입이고, 컴파일 뒷단에서는 구조체로써 적용되고 있습니다.</p>
<p>스위프트에서 모든 구조체와 열거형은 값타입입니다. 이 뜻은 어떤 자료형이나 열거형들을 인스턴스하고, 다른 코드에 전달할 때 언제나 그 값들을 복사해서 주는 것을 의미합니다.</p>
<br/>

<p><em>Note</em> : 표준 라이브러리로 정의되어 있는 배열, 딕셔너리, 스트링과 같은 컬렉션들은 복사를 위한 비용(cost) 를 줄이기 위해 최적화가 적용되어 있습니다. 이 컬렉션들은 바로 복사본을 만드는 것이 아니라, 각각의 원소들에 대해 동일한 메모리(인스턴스) 를 공유합니다. 이때 컬렉션 복사본들 중 하나가 수정된다면 모든 원소들이 수정 바로 전에 새롭게 값을 복사하고, 새롭게 메모리에 적재됩니다. 이 작업은 코드 상으로 항상 복사 이전에 수행됩니다. </p>
<pre><code class="language-swift">let hd = Resolutioin(width: 1920, height: 1080)
let cinema = hd</code></pre>
<p>위의 예시 코드에서 <code>Resolution</code> 는 구조체이므로 즉시 복사본 인스턴스가 만들어지고, 이렇게 만들어진 새로운 복사본이 <code>cinema</code> 에 할당됩니다. 비록 <code>hd</code> 와 <code>cinema</code> 가 똑같은 width, 똑같은 height 를 가졌더라도 컴퓨터 내부적으로 둘은 완벽하게 다른 인스턴스입니다. </p>
<p>이 예시를 통해 확인할 수 있습니다.</p>
<pre><code class="language-swift">cinema.width = 2048

print(&quot;시네마는 이제 \(cinema.width) 픽셀입니다.&quot;)
// 출력 : &quot;시네마는 이제 2048 픽셀입니다.&quot;

print(&quot;hd 는 아직 \(hd.width) 픽셀입니다.&quot;)
// 출력 : &quot;hd 는 아직 1920 픽셀입니다.&quot;</code></pre>
<p>도식화하면 이와 같습니다.</p>
<p><img src="https://velog.velcdn.com/images/newon-seoul/post/92920785-2314-49f9-b93e-cfce5bb8d1a9/image.png" alt=""></p>
<p><code>cinema</code> 가 <code>hd</code> 값을 할당받았기 때문에, <code>hd</code> 는 자신과 동일한 값을 가진 새로운 인스턴스를 생성하여 <code>cinema</code> 에게 할당하였습니다. 이렇게 생성된 <code>hd</code> 와 <code>cinema</code> 는 같은 값을 가진 것 처럼 보여도, 서로 다른 인스턴스이기때문에 <code>cinema</code> 에서 값 변경이 <code>hd</code> 에 영향을 미치지 않는 것 입니다.</p>
<br/>

<p>열거형에서의 예시입니다.</p>
<pre><code class="language-swift">enum CompassPoint {
    case north, south, east, west
    mutating func turnNorth() {
        self = .north
    }
}
var currentDirection = CompassPoint.west
let rememberedDirection = currentDirection
currentDirection.turnNorth()

print(&quot;현재 방향은 \(currentDirection)&quot;)
print(&quot;기억하고 있는 방향은 \(rememberedDirection)&quot;)
// 출력 : &quot;현재 방향은 north&quot;
// 출력 : &quot;기억하고 있는 방향은 west&quot;</code></pre>
<br/>

<h3 id="클래스는-참조타입이다-classes-are-reference-types">클래스는 참조타입이다. (Classes Are Reference Types)</h3>
<p>참조타입은 변수나 상수에 할당되거나, 혹은 함수에 전달될 때 <code>복사되지 않습니다</code>. 복사 대신 현재 존재하는 인스턴스의 주소가 할당되거나, 전달됩니다.</p>
<pre><code class="language-swift">let tenEighty = VideoMode()
tenEighty.resolution = hd
tenEighty.interlaced = true
tenEighty.name = &quot;1080i&quot;
tenEighty.frameRate = 25.0


let alsoTenEighty = tenEighty
alsoTenEighty.frameRate = 30.0

print(tenEighty.frameRate)
print(alsoTenEighty.frameRate)

// 출력 : 30
// 출력 : 30</code></pre>
<p>클래스는 참조타입이기 때문에, <code>tenEighty</code> 와 <code>alsoTenEighty</code> 는 사싱 같은 <code>VideoMode</code> 인스턴스를 참조하고 있습니다. 결과적으로, 둘은 다른 이름으로 불리는 하나의 인스턴스가 되었으며, 이를 표현하면 다음과 같습니다.</p>
<p><img src="https://velog.velcdn.com/images/newon-seoul/post/22b1ebe2-e832-4b4c-9663-92bde72ac923/image.png" alt=""></p>
<p>이때문에, 프로그래머는 <code>tenEighty</code> 를 사용할 때마다 <code>alsoTenEighty</code> 를 고려해서 사용해야 합니다. 이와 반대로, 값 타입은 소스 파일 내 다른 값들과 상호작용이 막혀있기 때문에, 더 쉽게 사용할 수 있게 됩니다. </p>
<p>한편 <code>tenEighty</code> 와 <code>alsoTenEighty</code> 가 <code>let</code> 으로 선언되었음에도, 그 속성을 바꿀 수 있는 것도 주목해야 합니다. <code>tenEighty</code> 와 <code>alsoTenEighty</code> 가 상수로 저장하고 있는 것은 <code>VideoMode</code> 의 인스턴스, 그 자체가 아니라 VideMode 의 <code>주소</code> 를 저장하고 있는 것 입니다. 한편 VideoMode 의 속성은 <code>let</code> 이 아니므로, 이를 변경할 수 있게 되는 것 입니다.</p>
<br/>

<h3 id="식별-연산자-identity-operators">식별 연산자 (Identity Operators)</h3>
<p>클래스는 참조 타입이기 때문에, 다수의 상수와 변수가 하나의 클래스 인스턴스를 참조하는 것이 가능합니다. (구조체와 열겨형은 불가능합니다. 왜냐하면 구조체와 열거형은 언제나 새로운 인스턴스를 만들어서 할당하기 때문입니다.)</p>
<p>때때로 두 상수나 변수가 동일한 클래스 인스턴스를 참조하는지 확인하는 것이 유용할 때가 있는데, 이를 지원하기 위해 스위프트에서는 다음과 같은 연산자를 사용할 수 있습니다.</p>
<ul>
<li>동일함, <code>===</code></li>
<li>동일하지 않음, <code>!==</code></li>
</ul>
<p>동일함은 두 상수나 변수가 동일한 클래스 인스턴스를 참조하고 있다는 것을 의미합니다. 여기서 동일이란 자료형의 제작자에 의해 두 인스턴스가 동일하거나, 동등한 값을 갖고 있음을 의미합니다.</p>
<br/>

<h3 id="포인터-pointers">포인터 (Pointers)</h3>
<p>만약 당신이 C, C++, 혹은 Objective-C 경험이 있다면 이 언어들이 메모리의 주소를 언급하는 <code>pointers</code> 라는 개념을 사용하는 것을 알고 계실겁니다. </p>
<p>스위프트의 참조타입의 인스턴스를 갖고있는 상수나 변수는 C 의 포인터 개념과 유사하나, 그 상수나 변수 자체가 포인터임을 의미하진 않으며, 참조를 만들기 위해 <code>*</code> 작성을 필요로 하지 않습니다. </p>
<p>대신 이 참조들은 스위프트의 여느 다른 상수나 변수처럼 정의됩니다. 표준 라이브러리는 포인터와 버퍼 타입을 제공하고 있으며, 직접 포인터로 상호작용 해야한다면 <a href="https://developer.apple.com/documentation/swift/manual-memory-management">Manual Memory Management</a> 에서 확인할 수 있습니다. </p>
<hr>
<h4 id="참고">참고</h4>
<p><a href="https://stackoverflow.com/questions/2885385/what-is-the-difference-between-an-instance-and-an-object">StackOverFlow - What is the difference between an Instance and an Object?</a></p>
<p><a href="https://www.udemy.com/course/ios-13-app-development-bootcamp/">Angela iOS 부트캠프 강의 (유데미) : Advanced Swift Programming - Classes, Inheritance &amp; Advanced Optionals</a></p>
<p><a href="https://www.inflearn.com/course/%EC%8A%A4%EC%9C%84%ED%94%84%ED%8A%B8-%EB%AC%B8%EB%B2%95-%EB%A7%88%EC%8A%A4%ED%84%B0-%EC%8A%A4%EC%BF%A8">앨런 Swift문법 마스터 스쿨 : 클래스(Class)와 구조체(Struct)</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Swift-Language Guide 5.7 / Enumeration (야매 번역 + 정리)]]></title>
            <link>https://velog.io/@newon-seoul/Swift-Language-Guide-5.7-Enumeration-%EC%95%BC%EB%A7%A4%EB%B2%88%EC%97%AD-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@newon-seoul/Swift-Language-Guide-5.7-Enumeration-%EC%95%BC%EB%A7%A4%EB%B2%88%EC%97%AD-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Thu, 04 Aug 2022 08:21:34 GMT</pubDate>
            <description><![CDATA[<h3 id="초록">초록</h3>
<p>열거형 (Enumeration) 은 관련이 있는 값들을 하나로 묶은 타입(자료형) 으로, 코드 상에서 개발자가 만든 자료형을 안전하게 사용할 수 있게 해줍니다.</p>
<p>열거형의 케이스들은 특정 데이터들을 담는 기능이 포함되어 있습니다. 이때 특정 데이터들은 어떠한 자료형이라도 케이스들이 저장할 수 있으며, 케이스 별로 서로 다른 데이터들을 포함할 수도 있습니다.</p>
<p>Swift 에서 열거형은 일급객체입니다. 열거형들은 클래스에서 지원하는 다양한 기능들을 지원하는데 연산 속성(computed properties) 를 통해 열거형의 현재 값에 대한 추가적인 정보를 제공하거나, 열거형에 속한 값을 함수로 제공하기 위해 메소드를 인스턴스하는 기능등이 포함됩니다.</p>
<blockquote>
<p>일급객체 (First - Class)
: 스위프트에서 일급객체란 </p>
</blockquote>
<ul>
<li>상수(let)나 변수(var) 에 저장될 수 있습니다.</li>
<li>다른 함수에 인자로써 전달할 수 있습니다.</li>
<li>다른 함수의 리턴값으로 반환할 수 있습니다.<blockquote>
</blockquote>
3개의 특징을 지닌 type 을 의미합니다. <a href="https://cocoacasts.com/swift-fundamentals-what-are-first-class-functions-in-swift">출처</a></li>
</ul>
<br/>

<h3 id="열거형-문법-enumeration-syntax">열거형 문법 (Enumeration Syntax)</h3>
<p>열거형은 <code>enum</code> 키워드를 사용하여 정의하고, 그 내부에 내용을 작성할 수 있습니다.<br>이때 내부의 내용이 여러개라면 쉼표를 통해 구분할 수도 있습니다.  </p>
<pre><code class="language-swift">enum CompassPoint {
    case north
    case south
    case east
    case west
}

enum Planet {
    case mercury, venus, earth, mars, jupiter, 
    saturn, uranus, neptune
}</code></pre>
<br/>

<p><em>Note</em>: 
다른 언어들과 달리, 스위프트의 열거형은 정수값을 기본적으로 선언하지 않습니다. </p>
<p><code>CompassPoint</code> 의 예시를 보면 C 언어와 달리 <code>north</code>, <code>south</code>, <code>east</code>, <code>west</code> 는 각각 <code>0</code>, <code>1</code>, <code>2</code>, <code>3</code>  으로 <strong>암시되지 않습니다.</strong> 그 대신, 열거형의 케이스들은 그 자체로써 자료형으로 정의됩니다.</p>
<br/>

<p>각각의 열거형들은 새로운 자료형을 정의하는 것과 같습니다. 따라서 스위프트의 다른 자료형들처럼 대문자로 시작합니다. 열거형의 자료형은 단수형으로 지음으로써 이름 그 자체로써 이해하기 쉽도록 작성하는 것이 좋습니다.</p>
<p>어떤 변수가 한번 열거형으로 선언된다면 해당 변수는 새로운 값을 받을 때,
암시적으로 이전에 사용했던 열거형으로 선언될 것을 알 수 있습니다.
그렇기에 <code>.case</code> 의 형태로 짧게 표현하는 것도 가능합니다.</p>
<pre><code class="language-swift">var directionToHead = CompoassPoint.west
directionToHead = .east</code></pre>
<h3 id="switch-구문에서-열거형의-값-사용하기-matching-enumeration-values-with-a-switch-statement">Switch 구문에서 열거형의 값 사용하기 (Matching Enumeration Values with a Switch Statement)</h3>
<p>각각의 열거형 값들을 switch 구문에서 사용할 수도 있습니다.
<a href="https://velog.io/@newon-seoul/Swift-Language-Guide-5.7-Control-Flow-c22v2cft#switch">Control Flow</a> 에서 언급하였듯, switch 구문은 반드시 모든 상황을 고려해야만 합니다.</p>
<p>이때 열거형을 사용하면, 열거형의 모든 케이스들에 각각 상황을 설정하였다면 <code>default</code> 구문을 사용하지 않아도 컴파일에서 오류가 발생하지 않습니다. 모든 상황을 고려했기 때문입니다. 반대로 열거형의 하나의 케이스라도 설정하지 않았다면 컴파일에서는 오류 구문을 발생시킵니다.</p>
<pre><code class="language-swift">enum CompassPoint {
    case north
    case south
    case east
    case west
}

let directionToHead = CompassPoint.east

switch directionToHead {
case .north: 
    print(&quot;북쪽엔 다양한 행성들이 있어요!&quot;) 
case .south: 
    print(&quot;펭귄 조심하세요 ~&quot;) 
case .east: 
    print(&quot;태양이 떠오르는 방향이라네&quot;) 
case .west: 
    print(&quot;하늘이 푸르른 곳이라네&quot;) 
}

switch directionToHead {
case .north:
    print(&quot;북쪽엔 다양한 행성들이 있어요!&quot;)
default:
    print(&quot;동, 서, 남에는 다른 것들이 있죠!&quot;)
}</code></pre>
<br/>

<h3 id="열거형-케이스들을-순회하여-사용하기-iterating-over-enumeration-cases">열거형 케이스들을 순회하여 사용하기 (Iterating over Enumeration Cases)</h3>
<p>때때로 열거형들은 컬렉션처럼 순회하며 사용하는 것이 유용할 경우가 있습니다. 이때 열거형 뒤에 <code>: CaseIterable</code> 을 붙임으로써 얼거형을 컬렉션처럼 사용할 수 있습니다. 스위프트는 해당 열거형의 <code>allCases</code> 속성을 통해 해당 컬렉션들을 순회하며 보여주게 됩니다.</p>
<pre><code class="language-swift">enum Beverage: CaseIterable {
    case coffe, tea, juice
}

let numberOfChoices = BeverageAllcases.count
print(numberOfChoices)

for beverage in Beverage.allCases {
    print(beverage)
}

// 3
// coffee
// tea
// juice</code></pre>
<p><code>: CaseIterable</code> 은 프로토콜입니다. 
프로토콜에 대한 정보는 <a href="https://docs.swift.org/swift-book/LanguageGuide/Enumerations.html">이곳</a>에서 확인할 수 있습니다.</p>
<br/>

<h3 id="연관값-associated-values">연관값 (Associated Values)</h3>
<p>열거형의 케이스 값들에 특정한 데이터들을 함께 저장하는 것이 유용할 때가 있습니다. 이때 저장되는 데이터들을 <em>연관값(associated value)</em> 이라고 합니다.</p>
<p>스위프트 열거형에서 연관값은 어떠한 자료형의 값이라도 저장할 수 있으며, 하나의 열거형에서 연관값들의 자료형이 케이스마다 다르더라도 상관없습니다.</p>
<br/>

<p>바코드를 통해 예시를 들 수 있습니다.
물품 추적 관리 시스템이 물건들을 관리할 때, 2개 종류의 바코드를 사용한다고 가정해봅니다. </p>
<p>첫번째 종류는 UPC 형식으로, 0 - 9 까지의 숫자를 사용하는 바코드입니다. 각 바코드들은 1자리의 시스템 숫자, 공장 번호 5자리 숫자, 물품 번호 5자리 숫자, 마지막으로 옳게 스캔되었는지 확인하는 1자리의 확인 숫자가 일렬로 늘어져있는 형태입니다.</p>
<p><img src="https://velog.velcdn.com/images/newon-seoul/post/688636b7-e6a7-4a86-b91d-c983500c010e/image.jpeg" alt="바코드 UPC 이미지"></p>
<br/>

<p>두번째 종류는 QR 코드 방식으로 ISO 8859-1 방식의 문자를 2953 자까지 저장할 수 있는 형태입니다.</p>
<p><img src="https://velog.velcdn.com/images/newon-seoul/post/6e9291d0-7866-4c37-b3ae-cafcbc129a78/image.jpeg" alt="바코드 QR 이미지"></p>
<br/>

<p>이런 경우 바코드 열거형을 생성한 후 UPC 형태는 4개의 정수를 가진 튜플로 지정하고, QR 코드는 길이 자유의 스트링으로 지정하는 것이 편리합니다.</p>
<p>코드로 표현하면 다음과 같아집니다.</p>
<pre><code class="language-swift">enum Barcode {
    case upc(Int, Int, Int, Int)
    case qrCode(String)
}

var productBarcode = Barcode.upc(8, 85909, 51226, 3)
productBarcode = .qrCode(&quot;ABCDEFGHIJKLMNOPQRSTUWXYZ&quot;)</code></pre>
<p>이때 하나의 변수인 <code>productBarcode</code> 가 
<code>.upc</code> 일 때는 4개의 정수로 이루어진 튜플로,
<code>.qrCode</code> 일 때는 스트링으로 이루어진 것을 확인할 수 있으며
자유롭게 변형이 가능한 것을 확인할 수 있습니다.</p>
<p>다만 이때, 하나의 변수가 <code>upc</code> 와 <code>qrCode</code> 두 가지 방식 모두를 포함할 수는 없습니다. 변수는 초기화되는 단 한번의 순간에, 하나만 저장할 수 있기 때문입니다.</p>
<br/>

<p>위의 열거형에서 연관값들은 <code>let</code>, <code>var</code> 의 형태와 함께 각각 그 이름을 설정해줄 수 있습니다. 
연관값들이 모두 <code>let</code> 이나 <code>var</code> 로 통일된다면 해당 선언은 case 바로 옆으로 빼서 사용할 수도 있습니다.</p>
<pre><code class="language-swift">switch productBarcode {
    case .upc(let numberSystem, let manufacturer, let product, let check):
        print(&quot;UPC: \(numberSystem), \(manufacturer), \(product), \(check).&quot;)
    case .qrCode(let productCode):
        print(&quot;QR code: \(productCode).&quot;)
}

switch productBarcode {
    case let .upc(numberSystem, manufacturer, product, check):
        print(&quot;UPC: \(numberSystem), \(manufacturer), \(product), \(check).&quot;)
    case let .qrCode(productCode):
        print(&quot;QR code: \(productCode).&quot;)
}</code></pre>
<p>위의 예시는 <code>switch</code> 에서 사용하였지만, enum 선언에서도 동일하게 사용할 수 있습니다.</p>
<br/>

<h3 id="원시값raw-values">원시값(Raw Values)</h3>
<p>열거형 케이스들은 기본 값을 통해 사전에 값을 가질 수 있으며, 이때 사용되는 값들은 모두 동일한 자료형이어야 합니다. 그리고 이것을 원시값 이라고 지칭합니다.</p>
<pre><code class="language-swift">enum ASCIIControlCharacter: Character {
    case tab = &quot;\t&quot;
    case lineFeed - &quot;\n&quot;
    case carriageReturn - &quot;\r&quot;
}</code></pre>
<p>위의 예시는 아스키 컨트롤 문자들을 좀 더 사용하기 쉽도록 문자로 기본값을 설정한 열거형입니다. </p>
<p>이처럼 원시값은 문자열, 문자, 혹은 정수형이나 부동 소수점으로 정할 수 있습니다. 각 원시값들은 하나의 열거형내에서 고유해야합니다.</p>
<p><em>Note</em>:
연관값과 원시값은 다른 용도로 사용됩니다.
원시값은 같은 열거형이면 언제나 같은 케이스를 지칭하지만,</p>
<p>연관값은 같은 열거형이여도 다른 케이스를 지칭할 수 있으며, 
사실 케이스를 설명할 뿐 케이스를 지칭하지도 않습니다. </p>
<h4 id="암시적-원시값-할당-implicitly-assigned-raw-values">암시적 원시값 할당 (Implicitly Assigned Raw Values)</h4>
<p>열거형을 정수나 스트링등의 원시값으로 설정할 때, 모든 케이스마다 일일히 값을 설정할 필요 없습니다. 하나만 설정하면, 스위프트가 알아서 값을 할당해줍니다.</p>
<pre><code class="language-swift">enum Planet: Int {
    case mercuy = 1, venus, earth, mars, jupiter ...
}</code></pre>
<p>위의 예시의 경우 mercury 가 1이므로, venus 부터 2, 3, 4 로 증가하며 원시값이 할당됩니다. 한편 특정 값을 설정하지 않고, <code>: Int</code> 를 사용하면 0부터 원시값이 할당됩니다.</p>
<p>원시값을 스트링으로 지정한다면, 각 케이스들의 이름이 원시값으로 할당됩니다.</p>
<h4 id="원시값으로-초기화하기-initializing-from-a-raw-value">원시값으로 초기화하기 (Initializing from a Raw Value)</h4>
<p>열거형을 원시값과 함께 정의하면, 
변수를 선언할 때 열거형의 파라미터로 원시값을 넣어서 초기화할 수 있습니다.
(이때 파라미터의 이름은 <code>rawValue</code> 입니다.)</p>
<pre><code class="language-swift">let possiblePlanet = Plaent(rawValue: 7)</code></pre>
<p>이때 원시값을 제공하더라도, 해당 원시값이 열거형에 존재하는지 확신할 수 없기 때문에 원시값을 활용한 초기화는 옵셔널 타입으로 반환됩니다.</p>
<h4 id="재귀-열거형-recursive-enumerations">재귀 열거형 (Recursive Enumerations)</h4>
<p>재귀 열거형은 열거형에서 자기 자신을 다시 호출하는 형태를 의미합니다.</p>
<pre><code class="language-swift">enum ArithmeticExpression {
    case number(Int)
    indirect case addition(ArithmeticExpression, ArithmeticExpression)
    indirect case multiplecation(ArithmeticExpression, ArithmeticExpression)
}</code></pre>
<p>(5 + 4) * 2 를 열거형을 통해 표현하고 싶을 때,</p>
<pre><code class="language-swift">let five = ArithmeticExpression.number(5)
let four = ArithmeticExpression.number(4)
let sum = ArithmeticExpression.addition(five, four)

let two = ArithmeticExpression.number(2)
let product = ArithmeticExpression.addition(sum, two)

func evaluate(_ expression: ArithmeticExpression) -&gt; Int {
    switch expression {
    case let .number(value):
        return value
    case let .addition(left, right):
        return evaluate(left) + evaluate(right)
    case let .multiplecation(left, right):
        return evaluate(left) * evaluate(right)
    }
}

print(evaluate(product))
// 18</code></pre>
<p>처럼 사용할 수 있습니다.
<del>..이걸? 굳이?</del></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Swift-Language Guide 5.7 / Functions (야매 번역 + 정리)]]></title>
            <link>https://velog.io/@newon-seoul/Swift-Language-Guide-5.7-Functions-%ED%95%9C%EA%B5%AD%EC%96%B4</link>
            <guid>https://velog.io/@newon-seoul/Swift-Language-Guide-5.7-Functions-%ED%95%9C%EA%B5%AD%EC%96%B4</guid>
            <pubDate>Sun, 10 Jul 2022 16:07:34 GMT</pubDate>
            <description><![CDATA[<h3 id="초록">초록</h3>
<p>함수는 특정한 업무를 수행하기 위해 모아놓은 코드 뭉치라고 할 수 있습니다.
함수를 사용하는 것은 <em>&quot;call&quot;(호출)</em> 이라고 표현하며 필요할 때 호출할 수 있습니다.</p>
<p>Swift 의 함수는 매개변수(parameters) 에 이름을 사용하지 않을 수 있으며, 기본 값을 지정해줄 수도 있는 등 다양한 편의를 제공합니다.</p>
<p>한편 모든 Swift 의 함수들은 자료형을 가지며, 매개변수 자료형과 반환값(Return) 자료형을 포함하고 있습니다. 함수의 자료형들은 다른 자료형과 마찬가지로 자유롭게 사용할 수 있으며, 함수 내에서 함수를 호출 하는 등의 기능도 제공하고 있습니다.</p>
<h3 id="defining-and-calling-functions함수-정의와-함수-호출">Defining and Calling Functions(함수 정의와 함수 호출)</h3>
<p>함수를 정의할 때, 함수에는 <strong>이름</strong>이 필요합니다. 
또한 함수가 입력값 <em><strong>- 매개변수(파라미터) -</strong></em> 을 받거나, 함수가 종료될 때 반환할 값 <em><strong>- 리턴 값(return)-</strong></em> 을 받는다면 추가적으로 함수를 정의할 때 함께 정의해야 합니다.</p>
<p>모든 함수는 함수의 이름을 가지고 있으며, 보통 그 이름은 함수가 수행할 내용을 묘사하도록 작성합니다. 함수를 사용하고 싶다면, 함수의 이름과 함수가 받는 입력값 (매개변수) 를 작성함으로써 <em><strong>호출</strong></em> 할 수 있습니다. </p>
<p>예시는 다음과 같습니다.</p>
<pre><code class="language-swift">func greet(person: String) -&gt; String {
    let greeting = &quot;안녕, &quot; + person + &quot;!&quot;
    return greeting
}

print(greet(person: &quot;안나&quot;))
// Prints &quot;안녕, 안나!&quot;
print(greet(person: &quot;브라이언&quot;))
// Prints &quot;안녕, 브라이언!&quot;</code></pre>
<p><code>greet(person:)</code> 함수를 호출하기 위해, 함수의 <strong><em>이름</em></strong> 을 적고, <code>person:</code> 인자 라벨 뒤에 String 값을 전달한 코드를 위에서 확인할 수 있습니다.</p>
<p><em>Note</em> : <code>print(_:separator:terminator:)</code> 역시 함수인데, 
첫번째 인자 (== 매개변수) 에 별 다른  라벨이 붙지 않은 것을 확인할 수 있습니다. 
또한 2 번째, 3 번째인자들은 <code>Optional</code> 인 것을 확인할 수 있는데, 이 두 인자는 기본 값 <em>default Value</em> 를 갖기 때문입니다.
이와 같은 함수의 문법들은 하단에서 설명합니다.</p>
<br/>

<h3 id="function-parameters-and-return-values-함수의-매개변수와-반환-값">Function Parameters and Return Values (함수의 매개변수와 반환 값)</h3>
<p>Swift 에서 함수의 매개변수와 반환값은 굉장히 자유롭게 사용할 수 있습니다. </p>
<h4 id="function-without-parameters-매개변수-없는-함수">Function without Parameters (매개변수 없는 함수)</h4>
<pre><code class="language-swift">func sayHelloWorld() -&gt; String {
    return &quot;hello, world&quot;
}
print(sayHelloWorld())
// Prints &quot;hello, world&quot;</code></pre>
<h4 id="function-with-multiple-parameters-매개변수가-여러개인-함수">Function with Multiple Parameters (매개변수가 여러개인 함수)</h4>
<pre><code class="language-swift">func greet(person: String) -&gt; String {
    let greeting = &quot;안녕, &quot; + person + &quot;!&quot;
    return greeting
}

func greetAgain(person: String) -&gt; String {
    return &quot;다시 한번 안녕,&quot; + person + &quot;!&quot;
}

func greet(person: String, alreadyGreeted: Bool) -&gt; String {
    if alreadyGreeted {
        return greetAgain(person: person)
    } else {
        return greet(person: person)
    }
}
print(greet(person: &quot;팀&quot;, alreadyGreeted: true))
// Prints &quot;다시 한번 안녕, 팀!&quot;</code></pre>
<p><code>person</code> 과 <code>alreadyGreeted</code> 라는 2개의 매개변수를 받고서,
<code>if</code> 문에서 <code>alreadyGreeted</code> 매개변수를 통해 분기문을 만들고, 
상황에 따라 각기 다른 함수를 호출하는 모습을 확인할 수 있다.</p>
<h4 id="functions-without-return-values리턴값이-없는-함수">Functions without Return Values(리턴값이 없는 함수)</h4>
<pre><code class="language-swift">func greet(person: String) {
    print(&quot;안녕, \(person)!&quot;)
}
greet(person: &quot;데이브&quot;)
// Prints &quot;안녕, 데이브!&quot;</code></pre>
<p>함수 정의에서 반환 화살표 <code>-&gt;</code> 를 통해 반환 값을 명시하지 않아서,
함수 호출에도 불구하고 함수 자체의 반환값은 없다.</p>
<p>혹은 함수의 리턴값을 의도적으로 무시할 수도 있다.</p>
<pre><code class="language-swift">func printAndCount(string: String) -&gt; Int {
    print(string)
    return string.count
}
func printWithoutCounting(string: String) {
    let _ = printAndCount(string: string)
}
printAndCount(string: &quot;hello, world&quot;)
// 출력: &quot;hello, world&quot; 이며, 반환값은 12이다.
printWithoutCounting(string: &quot;hello, world&quot;)
// 출력: &quot;hello, world&quot; 이며, 아무런 값도 반환하지 않는다.</code></pre>
<p><em>Note</em>: 함수의 리턴값은 무시될 수 있지만, 함수가 리턴을 정의했다면 함수는 <strong><em>반드시</em></strong> 특정 자료형을 리턴해야한다. 리턴이 정의된 함수가 리턴을 하지 않으면 컴파일 에러가 발생한다.</p>
<h4 id="functions-with-multiple-return-values여러개의-리턴값이-있는-함수">Functions with Multiple Return Values(여러개의 리턴값이 있는 함수)</h4>
<p>함수는 여러개의 리턴 값을 하나로 뭉쳐서 리턴할 수 있다.</p>
<pre><code class="language-swift">func minMax(array: [Int]) -&gt; (min: Int, max: Int) {
    var currentMin = array[0]
    var currentMax = array[0]
    for value in array[1..&lt;array.count] {
        if value &lt; currentMin {
            currentMin = value
        } else if value &gt; currentMax {
            currentMax = value
        }
    }
    return (currentMin, currentMax)
}

let bounds = minMax(array: [8, -6, 2, 109, 3, 71])
print(&quot;최소는 \(bounds.min) 이고, 최대는 \(bounds.max) 이다.&quot;)
// 출력: &quot;최소는 -6 이고, 최대는 109 이다.&quot;</code></pre>
<p>이때 bounds 가 <code>tuple</code> 형태의 리턴값을 받았음에도, 
별다른 이름, <code>min</code>, <code>max</code>, 을 지정하지 않았는데 출력에서는 사용할 수 있는 이유는
함수가 리턴할 때 이미 튜플들의 이름을 정의했기 때문이다.</p>
<h4 id="optional-tuple-return-types-튜플-리턴값-옵셔널-처리">Optional Tuple Return Types (튜플 리턴값 옵셔널 처리)</h4>
<p>만약 리턴 값이 튜플 자료형인데, 튜플 자체가 <code>nil</code> (없음) 에 해당할 수 있다면 tuple 전체에 <code>?</code> 를 붙임으로써 <code>optional</code> 타입으로 반환할 수 있다.</p>
<pre><code class="language-swift">func minMax(array: [Int]) -&gt; (min: Int, max: Int)? {
    if array.isEmpty { return nil }
    var currentMin = array[0]
    var currentMax = array[0]
    for value in array[1..&lt;array.count] {
        if value &lt; currentMin {
            currentMin = value
        } else if value &gt; currentMax {
            currentMax = value
        }
    }
    return (currentMin, currentMax)
}</code></pre>
<p>이때 만약 튜플 이상의 자료를 리턴하고 싶다면 <code>(Int, String, Int)</code> 형태로 계속해서 붙여서 사용할 수 있으며, <code>Optional</code> 역시 동일하게 적용된다.</p>
<p><em>Note</em>: <code>(Int?, Int?)</code> 와 <code>(Int, Int)?</code> 는 다르다. 전자는 각각의 값이 <code>nil</code> 일 수 있다면, 후자는 튜플 전체 자체가 <code>nil</code> 일 수 있음을 명시한 것이다.</p>
<h4 id="functions-with-an-implicit-return-함수의-암시적-리턴">Functions With an Implicit Return (함수의 암시적 리턴)</h4>
<p>만약 함수가 리턴값이 있는데, 함수가 1줄이라면 암시적으로 그 1줄의 내용이 리턴된다.</p>
<pre><code class="language-swift">func greeting(for person: String) -&gt; String {
    &quot;안녕, &quot; + person + &quot;!&quot;
}
print(greeting(for: &quot;데이브&quot;))
// Prints &quot;안녕, 데이브!&quot;

func anotherGreeting(for person: String) -&gt; String {
    return &quot;또 한번 안녕, &quot; + person + &quot;!&quot;
}
print(anotherGreeting(for: &quot;데이브&quot;))
// Prints &quot;또 한번 안녕, 데이브!&quot;</code></pre>
<p><a href="https://docs.swift.org/swift-book/LanguageGuide/Properties.html#ID608">Shorthand Getter Declaration</a> 에서 프로퍼티의 get 을 통한 암시적 반한을 확인할 수 있다.</p>
<p><em>Note</em>: 함수가 리턴값이 없는데 암시적 리턴을 사용할 수는 없다.</p>
<br/>

<h3 id="function-argument-labels-and-parameter-names함수의-인자-라벨과-파라미터-이름들">Function Argument Labels and Parameter Names(함수의 인자 라벨과 파라미터 이름들)</h3>
<p>각 함수의 파라미터는 <code>인자 라벨</code> 과 <code>파라미터 이름</code> 을 동시에 갖고 있다. 
라벨은 함수를 호출할 때 사용되며, 파라미터는 함수 내에서 사용할 때 사용한다.
기본적으로 인자 라벨과 파라미터는 동일한 이름을 갖는다.</p>
<h4 id="specifying-argument-labels-인자-라벨-특정하기">Specifying Argument Labels (인자 라벨 특정하기)</h4>
<p>다음과 같은 방법으로 인자 라벨을 특정할 수 있다.</p>
<pre><code class="language-swift">func someFunction(argumentLabel parameterName: String) {
    // 함수 내에서, 파라미터 이름은 parameterName 이 된다.
    // 함수 호출 시, 인자 라벨은 argumentLabel 이 된다.
    print(parameterName)
}
someFunction(argumentLabel: &quot;그라데이션&quot;)

// 출력 : 그라데이션</code></pre>
<p>응용은 다음과 같이 할 수 있다.</p>
<pre><code class="language-swift">func greet(person: String, from hometown: String) -&gt; String {
    return &quot;안녕 \(person)!  \(hometown)에서 널 만나니 기뻐!&quot;
}
print(greet(person: &quot;빌&quot;, from: &quot;쿠퍼티노&quot;))
// Prints &quot;안녕 빌!  쿠퍼티노에서 널 만나니 기뻐!&quot;</code></pre>
<h4 id="omitting-argument-labels-인자-라벨-생략">Omitting Argument Labels (인자 라벨 생략)</h4>
<p>만약 라벨이 필요 없다면 <code>_</code> 을 사용해서 생략할 수 있습니다.</p>
<pre><code class="language-swift">func someFunction(_ firstParameterName: Int, secondParameterName: Int) {
    // 함수 내에서 firstParameterName 과 secondParameterName 은 호출될 때 받은 1과 2를 지칭합니다.
}
someFunction(1, secondParameterName: 2)</code></pre>
<h4 id="default-parameter-values-파라미터-기본값">Default Parameter Values (파라미터 기본값)</h4>
<p>파라미터 자료형 다음에 그 값을 할당해줌으로써, 함수의 어떤 파라미터든 기본값을 정의해줄 수 있습니다.</p>
<pre><code class="language-swift">func someFunction(parameterWithoutDefault: Int, parameterWithDefault: Int = 12) {
    // someFunction 을 호출할 때, 2번째 인자를 생략하면
    // 자동적으로 12가 할당되서 사용됩니다.
}
someFunction(parameterWithoutDefault: 3, parameterWithDefault: 6) // parameterWithDefault 의 값은 6으로 새롭게 할당됩니다.
someFunction(parameterWithoutDefault: 4) // parameterWithDefault 의 값이 기본값인 12로 할당됩니다.</code></pre>
<h4 id="variadic-parameters-가변-파라미터">Variadic Parameters (가변 파라미터)</h4>
<p>가변 파라미터는 특정 값을 0개부터 다양한 값을 받을 수 있습니다.
가변 파라미터는 상수 배열로 할당됩니다.</p>
<pre><code class="language-swift">func arithmeticMean(_ numbers: Double...) -&gt; Double {
    var total: Double = 0
    for number in numbers {
        total += number
    }
    return total / Double(numbers.count)
}
arithmeticMean(1, 2, 3, 4, 5)
// 5개의 평균인 3이 반환된다.
arithmeticMean(3, 8.25, 18.75)
// 3개의 평균인 10이 반환된다.</code></pre>
<h4 id="in-out-parameters-인-아웃-파라미터">In-Out Parameters (인 아웃 파라미터)</h4>
<p>함수의 매개변수들은 기본적으로 상수입니다. 함수 내에서 매개변수를 변경하려고 시도하면 컴파일 단계에서 에러를 발생시킵니다. 이는 파라미터를 실수로 변화시키지 못하도록 미연에 방지하는 역할을 합니다. </p>
<p>만약 함수내에서 파라미터의 값을 변경하고 싶으며, 이 변경이 원본 값에도 영향을 미치도록 하고 싶다면 파라미터를 <code>in-out</code> 파라미터로 정의할 수 있습니다.</p>
<p>파라미터 앞에 <code>in-out</code> 파라미터를 정의하여 사용할 수 있습니다. 함수 내에서 <code>in-out</code> 파라미터가 변경되면 함수에서 변경과 함께 원본 값 역시 변경됩니다. </p>
<p><code>in-out</code> 파라미터는 반드시 변수, <code>var</code> 만 전달할 수 이습니다. <code>in-out</code> 파라미터에는 상수나 리터럴 값을 전달할 수 없는데, 상수나 리터럴은 수정이 불가능하기 때문입니다. </p>
<p>인자로 전달할때는 <code>&amp;</code> 를 붙여서 전달하며, 함수 내에서 이 변수가 수정될 수 있다는 의미를 가집니다.</p>
<p>예시입니다.</p>
<pre><code class="language-swift">func swapTwoInts(_ a: inout Int, _ b: inout Int) {
    let temporaryA = a
    a = b
    b = temporaryA
}

var someInt = 3
var anotherInt = 107
swapTwoInts(&amp;someInt, &amp;anotherInt)
print(&quot;someInt는 \(someInt) 이며, anotherInt는 이제 \(anotherInt) 입니다.&quot;)
// Prints &quot;someInt는 이제 107 이며, anotherInt는 이제 now 3&quot;</code></pre>
<p><em>Note</em>: <code>in-out</code> 파라미터는 함수가 리턴하는 것과 다릅니다. 상단의 예시에서 <code>swapTwoInts</code> 는 리턴값이 없음에도 someInt 와 anotherInt 가 변경된 것을 확인할 수 있습니다. <code>in-out</code> 파라미터는 함수 안에서 함수 밖에 영향을 미치는 대안적인 방법으로 생각해볼 수 있습니다.</p>
<br/>

<h3 id="function-types-함수의-자료형">Function Types (함수의 자료형)</h3>
<p>모든 함수는 특정한 함수의 자료형이 존재하며, 파라미터 자료형과 리턴 자료형으로 구성되어 있습니다.</p>
<p>예시입니다.</p>
<pre><code class="language-swift">func addTwoInts(_ a: Int, _ b: Int) -&gt; Int {
    return a + b
}
func multiplyTwoInts(_ a: Int, _ b: Int) -&gt; Int {
    return a * b
}</code></pre>
<p>위의 함수는 다음과 같이 해석할 수 있습니다.
&quot;함수는 2개의 파라미터를 받는데, 둘 다 Int guddlrh, Int 자료형의 값을 반환하는구만&quot;</p>
<br/>

<p>다른 예시입니다.</p>
<pre><code class="language-swift">func printHelloWorld() {
    print(&quot;hello, world&quot;)
}</code></pre>
<p>위의 함수는 다음과 같이 해석할 수 있습니다
&quot;함수는 파라미터가 없고, Void 를 리턴하는구만&quot;</p>
<h3 id="nested-functions-중첩-함수들">Nested Functions (중첩 함수들)</h3>
<p>함수는 함수내에서도 다른 함수를 호출할 수 있습니다. <em>(블로거: 물론 자기 자신도요 ! )</em> </p>
<pre><code class="language-swift">func chooseStepFunction(backward: Bool) -&gt; (Int) -&gt; Int {
    func stepForward(input: Int) -&gt; Int { return input + 1 }
    func stepBackward(input: Int) -&gt; Int { return input - 1 }
    return backward ? stepBackward : stepForward
}
var currentValue = -4
let moveNearerToZero = chooseStepFunction(backward: currentValue &gt; 0)
// moveNearerToZero 는 이제 stepForward 와 중첩되어 호출됩니다.

while currentValue != 0 {
    print(&quot;\(currentValue)... &quot;)
    currentValue = moveNearerToZero(currentValue)
}
print(&quot;zero!&quot;)
// -4...
// -3...
// -2...
// -1...
// zero!</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Swift-Language Guide 5.7 / Control Flow (야매 번역 + 정리)]]></title>
            <link>https://velog.io/@newon-seoul/Swift-Language-Guide-5.7-Control-Flow-c22v2cft</link>
            <guid>https://velog.io/@newon-seoul/Swift-Language-Guide-5.7-Control-Flow-c22v2cft</guid>
            <pubDate>Thu, 07 Jul 2022 17:16:03 GMT</pubDate>
            <description><![CDATA[<h3 id="초록">초록</h3>
<p>Swift 는 다양한 제어 흐름을 제공합니다. 제어 흐름에는 <code>for-in</code>, <code>while</code>, <code>if</code>, <code>guard</code>, <code>switch</code> 등과 이를 조절하는 <code>break</code>, <code>continue</code> 등이 있습니다.</p>
<h3 id="for-in-loops-for-in-반복">For-In Loops (For-in 반복)</h3>
<p><code>For-in</code> 반복 구문은 배열이나 특정 범위의 숫자, 혹은 문자열 내 캐릭터를 반복하는데 사용됩니다. </p>
<pre><code class="language-swift">let names = [&quot;안나&quot;, &quot;알렉스&quot;, &quot;브라이언&quot;, &quot;잭&quot;]
for name in names {
    print(&quot;안녕, \(name)!&quot;)
}
// 안녕, 안나!
// 안녕, 알렉스!
// 안녕, 브라이언!
// 안녕, 잭!</code></pre>
<p><code>For-in</code> 구문은 딕셔너리 역시 반복하여 접근할 수 있습니다. 딕셔너리의 원소들은 (key, value) 튜플로 반환되므로, (key, value) 를 <code>for-in</code> 반복 구문에 지정함으로써 이를 응용하여 사용할 수 있습니다. 단, 딕셔너리는 그 자체로 비정렬 컬렉션(Collection) 이기 때문에, <code>for-in</code> 반복 구문의 순서가 언제나 일정하지는 않습니다.</p>
<pre><code class="language-swift">let numberOfLegs = [&quot;거미&quot;: 8, &quot;개미&quot;: 6, &quot;고양이&quot;: 4]
for (animalName, legCount) in numberOfLegs {
    print(&quot;\(animalName)는 \(legCount)개의 다리가 있어요.&quot;)
}
// 고양이는 4개의 다리가 있어요.
// 개미는 6개의 다리가 있어요.
// 거미는 8개의 다리가 있어요.</code></pre>
<p><code>for-in</code> 구문을 통해 숫자 범위를 반복할 수도 있습니다.
이때 범위를 닫힌 범위로 사용하고 싶다면 <code>..&lt;</code> , <code>..&gt;</code> 를 사용할 수 있으며
열림 범위로 사용하고 싶다면 <code>...</code> 를 사용할 수 있습니다.</p>
<pre><code class="language-swift">for index in 1...5 {
    print(&quot;\(index) 곱하기 5 는 \(index * 5)&quot;)
}

// 1 * 5 는 5
// 2 * 5 는 10
// 3 * 5 는 15
// 4 * 5 는 20
// 5 * 5 는 25

let minutes = 60
for tickMark in 0..&lt;minutes {
    print(tickMark, terminator: &quot; &quot;)
}
// 1 2 3 4 ..... 59</code></pre>
<p><code>for-in</code> 구문에서 사용되는 반복 지정자 (index) 는 <code>for-in</code> 구문 내에서 정의하여 사용할 수 있으며, <code>let</code> 키워드 없이도 상수로써 선언됩니다.
반복 지정자가 필요없다면 <code>_</code> 를 사용하여 무시할 수도 있습니다.</p>
<pre><code class="language-swift">let base = 3
let power = 10
var answer = 1
for _ in 1...power {
    answer *= base
}
print(&quot;\(base)의 \(power)제곱은 \(answer)&quot;)
// Prints &quot;3의 10제곱은 59049&quot;</code></pre>
<p><code>for-in</code> 구문에서 반복 연산자에 특정 조건을 붙이고 싶다면 <code>stride(from:to:by:)</code> 혹은 <code>stirde(from:through:by:)</code> 를 사용할 수 있습니다. </p>
<pre><code class="language-swift">let minutes = 60
let minuteInterval = 5
for tickMark in stride(from: 0, to: minutes, by: minuteInterval) {
    // 5분 단위로 반복하되, to 이전까지만 반복
    // (0, 5, 10, 15 ... 45, 50, 55)
}</code></pre>
<pre><code class="language-swift">let hours = 12
let hourInterval = 3
for tickMark in stride(from: 3, through: hours, by: hourInterval) {
    // 3 단위로 증가하며, through 를 포함해서 반복
    // (3, 6, 9, 12)
}</code></pre>
<h3 id="while">While</h3>
<p><code>while</code> 반복문은 조건이 성립될 때 까지 구문을 반복으로, 다음과 같은 일반적인 형태를 갖습니다.</p>
<p><img src="https://velog.velcdn.com/images/newon-seoul/post/ae2b6ebe-1ea0-42d5-a014-99a128e4a765/image.jpg" alt="while 의 일반적인 구문 형태 / while 조건 { 반복할 내용 }"></p>
<blockquote>
<p>Swift Language Guide - Control Flow - While 에서
주사위 놀이를 들어 while 을 설명하는데, 이는 생략하였습니다. 
<a href="https://docs.swift.org/swift-book/LanguageGuide/ControlFlow.html">확인하기</a></p>
</blockquote>
<p><code>while</code> 은 <code>repeat-while</code> 형태로도 사용할 수 있습니다.
일반적인 형태는 다음과 같습니다.
<img src="https://velog.velcdn.com/images/newon-seoul/post/753a431f-f791-4e78-9895-6bb1a2a18b45/image.jpg" alt=""></p>
<h3 id="conditional-statements조건-구문">Conditional Statements(조건 구문)</h3>
<p>Swift 는 <code>if</code> 와 <code>switch</code> 2개의 조건 구문을 제공합니다. 
<code>if</code> 문은 상대적으로 짧은 구문에, 
<code>switch</code> 문은 상대적으로 길거나 복잡한 구문에 적합합니다.</p>
<h4 id="if">if</h4>
<p><code>if</code> 구문은 주어진 조건이 참인 경우에만 실행되는, 분기를 만드는 조건문입니다.</p>
<pre><code class="language-swift">var temperature = -5
if temperature &lt;= 0 {
    print(&quot;밖이 매우 춥네요. 목도리를 입는게 어떨까요?&quot;)
}
// 출력: &quot;밖이 매우 춥네요. 목도리를 입는게 어떨까요?&quot;</code></pre>
<p><code>if</code> 구문 후 <code>else</code> 를 붙여서 다른 분기에 대한 실행구문을 설정할 수 있습니다. 이때 <code>else</code> 구문은 선택사항입니다.</p>
<pre><code class="language-swift">var temperature = 10
if temperature &lt;= 0 {
    print(&quot;밖이 매우 춥네요. 목도리를 입는게 어떨까요?&quot;)
} else {
    print(&quot;밖이 춥진 않네요. 티셔츠 입어요.&quot;
}
// 출력: &quot;밖이 춥진 않네요. 티셔츠 입어요.&quot;</code></pre>
<p><code>if</code> 구문에서 여러개의 분기가 필요하다면 다음과 같이 사용할 수도 있습니다.</p>
<pre><code class="language-swift">var temperature = 35
if temperature &lt;= 0 {
    print(&quot;밖이 매우 춥네요. 목도리를 입는게 어떨까요?&quot;)
} else if temperature &gt;= 30 {
    print(&quot;밖이 진짜 더워요. 자외선 차단제를 잊지마세요.&quot;)
} else {
    print(&quot;밖이 춥진 않네요. 티셔츠 입어요.&quot;
}
// 출력: &quot;밖이 진짜 더워요. 자외선 차단제를 잊지마세요.&quot;</code></pre>
<h3 id="switch">Switch</h3>
<p><code>switch</code> 구문은 특정 값이 여러개의 조건 중에서 참이 될 수 있는지 고려할 때 사용됩니다. 이때 특정 적합한 조건이 성립되면 해당 조건의 코드를 실행합니다. 
<code>switch</code> 는 여러개의 상황을 고려해야 할 때 <code>if</code> 구문 대신 사용할 수 있습니다.
<img src="https://velog.velcdn.com/images/newon-seoul/post/a209e2ad-ed31-4106-bdc5-28bff7d06b94/image.png" alt="switch 구문 - switch 조건 { case 값 : {} case 값: {} case 값: {} default: {} 형태이다."></p>
<p><code>switch</code> 구문의 <code>case</code> 들은 <code>value</code> 가 성립할 가능성이 있는 구문들입니다. 만약 <code>value</code> 가 <code>case</code> 에 해당하면 그 구문에 해당하는 코드를 실행하게 됩니다. 
한편 <code>switch</code> 는 반드시 해당 value 가 가질 수 있는 모든 상황을 고려해야하며, <code>default</code> 를 통해 case 에 해당하지 않는 값들에 대한 내용을 정의할 수 있습니다.</p>
<p>다음과 같은 예시를 들 수 있습니다.</p>
<pre><code class="language-swift">let someCharacter: Character = &quot;z&quot;
switch someCharacter {
case &quot;a&quot;:
    print(&quot;알파벳 첫번째 글자&quot;)
case &quot;z&quot;:
    print(&quot;알파벳 마지막 글자&quot;)
default:
    print(&quot;알파벳들 중 하나&quot;)
}
// 출력: &quot;알파벳 마지막 글자&quot;</code></pre>
<h3 id="no-implicit-fallthrough암시적으로-내려가지-않음">No Implicit Fallthrough(암시적으로 내려가지 않음)</h3>
<p><code>switch</code> 구문은 특정 case 가 성립되었을 때 해당 구문을 실행한 후 그 다음으로 <strong><em>내려가지 않습니다.</em></strong> 대신 처음으로 case 가 성립된다면 구문 실행 후 즉시 <code>switch</code> 구문에서 빠져나오게 됩니다. 이를 통해 <code>switch</code> 는 더욱 안정적이고 직관적인 사용을 제공합니다.</p>
<p>한편 <code>switch</code> 의 case 는 빈 구문으로 설정할 수 없습니다.
다음과 같은 예시를 들 수 있습니다.</p>
<pre><code class="language-swift">let anotherCharacter: Character = &quot;a&quot;
switch anotherCharacter {
case &quot;a&quot;: // 불가능, 케이스가 비어있다.
case &quot;A&quot;:
    print(&quot;The letter A&quot;)
default:
    print(&quot;Not the letter A&quot;)
}
// case &quot;a&quot; 가 빈 구문이므로 compile 에러를 발생시킨다.</code></pre>
<p><code>switch</code> 의 case 에서 여러개의 값을 확인해야 한다면 다음과 같이 활용할 수 있습니다. 이때 여러줄에 걸쳐서도 사용할 수 있습니다.</p>
<pre><code class="language-swift">let anotherCharacter: Character = &quot;a&quot;
switch anotherCharacter {
case &quot;a&quot;, &quot;A&quot;:
    print(&quot;A 알파벳&quot;)
default:
    print(&quot;A 알파벳이 아님&quot;)
}
// Prints &quot;A 알파벳&quot;</code></pre>
<h4 id="interval-matching범위로-확인">Interval Matching(범위로 확인)</h4>
<p><code>switch</code> 구문에서 case 는 범위로도 활용할 수 있습니다.</p>
<pre><code class="language-swift">let approximateCount = 62
let countedThings = &quot;moons orbiting Saturn&quot;
let naturalCount: String
switch approximateCount {
case 0:
    naturalCount = &quot;no&quot;
case 1..&lt;5:
    naturalCount = &quot;a few&quot;
case 5..&lt;12:
    naturalCount = &quot;several&quot;
case 12..&lt;100:
    naturalCount = &quot;dozens of&quot;
case 100..&lt;1000:
    naturalCount = &quot;hundreds of&quot;
default:
    naturalCount = &quot;many&quot;
}
print(&quot;There are \(naturalCount) \(countedThings).&quot;)
// Prints &quot;There are dozens of moons orbiting Saturn.&quot;</code></pre>
<h4 id="tuples">Tuples</h4>
<p><code>switch</code> 구문에서 tuple 을 활용할 수도 있습니다. 이때 특정 튜플의 원소를 비교하고 싶지 않다면 <code>_</code> 를 사용할 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/newon-seoul/post/7b330971-1d13-47b2-8ecd-d745ea5175d4/image.png" alt=""></p>
<pre><code class="language-swift">let somePoint = (1, 1)
switch somePoint {
case (0, 0):
    print(&quot;\(somePoint) 는 원점에 있습니다.&quot;)
case (_, 0):
    print(&quot;\(somePoint) 는 x 축에 있습니다.&quot;)
case (0, _):
    print(&quot;\(somePoint) 는 y 축에 있습니다.&quot;)
case (-2...2, -2...2):
    print(&quot;\(somePoint) 는 박스 안에 있습니다.&quot;)
default:
    print(&quot;\(somePoint) 는 박스 밖에 있습니다.&quot;)
}
// Prints &quot;(1, 1) 는 박스 안에 있습니다.&quot;</code></pre>
<p>이때 No Implicit Fallthrough 에서 확인하였듯, 상단의 case 가 먼저 성립되면 하단의 case 들은 실행도 되지 않고 무시됩니다.</p>
<br/>

<p>tuple 에서 특정 튜플 원소를 변수로 사용하고 싶다면 다음과 같이 사용할 수 있습니다.</p>
<pre><code class="language-swift">let anotherPoint = (2, 0)
switch anotherPoint {
case (let x, 0):
    print(&quot; \(x) 값을 가지며 x 축에 있음.&quot;)
case (0, let y):
    print(&quot; \(y) 값을 가지며 y축에 있음.&quot;)
case let (x, y):
    print(&quot;(\(x), \(y)) 값을 가지며 x,y 축 안 어딘가에 있음.&quot;)
}
// Prints &quot;2 값을 가지며 x 축에 있음.&quot;</code></pre>
<p>이때 이 <code>switch</code> 구문은 <code>default</code> 가 없음에도 마지막 case 인 <code>let (x, y)</code> 가 모든 상황을 포괄하기 때문입니다.</p>
<h4 id="where">Where</h4>
<p><code>switch</code> 구문의 case 는 <code>where</code> 를 활용하여 특정 조건을 더할 수 있습니다.</p>
<pre><code class="language-swift">let yetAnotherPoint = (1, -1)
switch yetAnotherPoint {
case let (x, y) where x == y:
    print(&quot;(\(x), \(y)) 는 x == y 선에 있습니다.&quot;)
case let (x, y) where x == -y:
    print(&quot;(\(x), \(y)) 는 x == -y 선에 있습니다.&quot;)
case let (x, y):
    print(&quot;(\(x), \(y)) 는 무작위 선에 있습니다.&quot;)
}
// Prints &quot;(1, -1) 는 x == -y 선에 있습니다.&quot;</code></pre>
<h4 id="compound-cases-복합-케이스">Compound Cases (복합 케이스)</h4>
<p><code>switch</code> 구문에서 복합 상황은 다음과 같이 표현할 수 있습니다.</p>
<pre><code class="language-swift">let someCharacter: Character = &quot;e&quot;
switch someCharacter {
case &quot;a&quot;, &quot;e&quot;, &quot;i&quot;, &quot;o&quot;, &quot;u&quot;:
    print(&quot;\(someCharacter) 는 모음이다.&quot;)
case &quot;b&quot;, &quot;c&quot;, &quot;d&quot;, &quot;f&quot;, &quot;g&quot;, &quot;h&quot;, &quot;j&quot;, &quot;k&quot;, &quot;l&quot;, &quot;m&quot;,
     &quot;n&quot;, &quot;p&quot;, &quot;q&quot;, &quot;r&quot;, &quot;s&quot;, &quot;t&quot;, &quot;v&quot;, &quot;w&quot;, &quot;x&quot;, &quot;y&quot;, &quot;z&quot;:
    print(&quot;\(someCharacter) 는 자음이다.&quot;)
default:
    print(&quot;\(someCharacter) 는 자음도, 모음도 아니다.&quot;)
}
// Prints &quot;e 는 모음이다.&quot;</code></pre>
<p>복합 상황에서도 특정 원소에 이름을 선언할 수 있습니다.</p>
<pre><code class="language-swift">let stillAnotherPoint = (9, 0)
switch stillAnotherPoint {
case (let distance, 0), (0, let distance):
    print(&quot;축에 있으며, 원점으로부터 \(distance) 멀다.&quot;)
default:
    print(&quot;축에 있지 않다.&quot;)
}
// Prints &quot;축에 있으며, 원점으로부터 9 멀다.&quot;</code></pre>
<br/>

<h3 id="control-transfer-statements-생략-구문">Control Transfer Statements (생략 구문)</h3>
<p>생략에는 다음과 같은 키워드들을 사용할 수 있습니다.</p>
<ul>
<li>continue</li>
<li>break</li>
<li>fallthrough</li>
<li>return</li>
<li>throw</li>
</ul>
<p><code>continue</code> 는 반복 구문에서 사용할 수 있으며 
<code>continue</code> 밑의 구문을 실행하지 않고 다음 반복을 진행합니다.</p>
<pre><code class="language-swift">let puzzleInput = &quot;great minds think alike&quot;
var puzzleOutput = &quot;&quot;
let charactersToRemove: [Character] = [&quot;a&quot;, &quot;e&quot;, &quot;i&quot;, &quot;o&quot;, &quot;u&quot;, &quot; &quot;]
for character in puzzleInput {
    if charactersToRemove.contains(character) {
        continue
    }
    puzzleOutput.append(character)
}
print(puzzleOutput)
// Prints &quot;grtmndsthnklk&quot;</code></pre>
<p><code>break</code> 는 반복 구문에서 사용할 수 있으며
반복구문을 빠져나옵니다.</p>
<p><code>fallthrough</code> 는 switch 구문에서 사용되며,
case 에서 사용 시 계속해서 다음 case 를 찾아서 실행하게 됩니다.</p>
<pre><code class="language-swift">let integerToDescribe = 5
var description = &quot;숫자 \(integerToDescribe) 는&quot;
switch integerToDescribe {
case 2, 3, 5, 7, 11, 13, 17, 19:
    description += &quot; 소수이며,&quot;
    fallthrough
default:
    description += &quot; 자연수이다.&quot;
}
print(description)
// Prints &quot;숫자 5 는 소수이며, 자연수이다.&quot;</code></pre>
<h4 id="labeled-statements라벨-구문">Labeled Statements(라벨 구문)</h4>
<p>중첩 구문을 사용하면 복잡한 조건 구문도 설계할 수 있습니다. 단 이때 <code>continue</code>, <code>break</code> 등을 사용하려면 불필요한 코드를 추가하게 될 수 있는데 이를 <code>label</code> 을 붙임으로써 해결할 수 있습니다.</p>
<pre><code class="language-swift">gameLoop: while square != finalSquare {
    diceRoll += 1
    if diceRoll == 7 { diceRoll = 1 }
    switch square + diceRoll {
    case finalSquare:
        // diceRoll will move us to the final square, so the game is over
        break gameLoop
    case let newSquare where newSquare &gt; finalSquare:
        // diceRoll will move us beyond the final square, so roll again
        continue gameLoop
    default:
        // this is a valid move, so find out its effect
        square += diceRoll
        square += board[square]
    }
}
print(&quot;Game over!&quot;)</code></pre>
<h4 id="early-exit">Early Exit</h4>
<p><code>guard let</code> 을 활용하여 필요하지 않은 정보가 조건에 맞지 않는 구문이 왔을 때 해당 함수를 빠르게 빠져나올 수 있습니다.</p>
<pre><code class="language-swift">func greet(person: [String: String]) {
    guard let name = person[&quot;name&quot;] else {
        return
    }

    print(&quot;안녕 \(name)!&quot;)

    guard let location = person[&quot;location&quot;] else {
        print(&quot;오늘 너가 가는 길의 날씨가 좋았으면 좋겠다.&quot;)
        return
    }

    print(&quot;오늘 너가 가는 \(location) 날씨가 좋았으면 좋겠다.&quot;)
}

greet(person: [&quot;name&quot;: &quot;존&quot;])
// Prints &quot;안녕 존!&quot;
// Prints &quot;오늘 너가 가는 길의 날씨가 좋았으면 좋겠다.&quot;
greet(person: [&quot;name&quot;: &quot;제인&quot;, &quot;location&quot;: &quot;쿠퍼티노&quot;])
// Prints &quot;안녕 제인!&quot;
// Prints &quot;오늘 너가 가는 쿠퍼티노 날씨가 좋았으면 좋겠다.&quot;</code></pre>
<h3 id="checking-api-availability">Checking API Availability</h3>
<p>Swift 는 API 를 활용할 수 있는지 확인할 수 있는 기능을 내장하고 있으며, 이를 통해 사용할 수 없는 API 를 호출하지 않게 할 수 있습니다.</p>
<p><code>if</code> 혹은 <code>guard</code> 구문과 함께 사용하여 다음과 같이 활용할 수 있습니다.</p>
<pre><code class="language-swift">if #available(iOS 10, macOS 10.12, *) {
    // Use iOS 10 APIs on iOS, and use macOS 10.12 APIs on macOS
} else {
    // Fall back to earlier iOS and macOS APIs
}

@available(macOS 10.12, *)
struct ColorPreference {
    var bestColor = &quot;blue&quot;
}

// ------------------------------

func chooseBestColor() -&gt; String {
    guard #available(macOS 10.12, *) else {
        return &quot;gray&quot;
    }
    let colors = ColorPreference()
    return colors.bestColor
}

// ------------------------------

if #available(iOS 10, *) {
} else {
    // Fallback code
}

if #unavailable(iOS 10) {
    // Fallback code
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Swift:자료구조] LinkedList 2편 : LinkedList 에 노드 삭제하기]]></title>
            <link>https://velog.io/@newon-seoul/Swift%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-LinkedList-2%ED%8E%B8-LinkedList-%EC%97%90-%EB%85%B8%EB%93%9C-%EC%82%AD%EC%A0%9C%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@newon-seoul/Swift%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-LinkedList-2%ED%8E%B8-LinkedList-%EC%97%90-%EB%85%B8%EB%93%9C-%EC%82%AD%EC%A0%9C%ED%95%98%EA%B8%B0</guid>
            <pubDate>Thu, 07 Jul 2022 13:00:55 GMT</pubDate>
            <description><![CDATA[<h3 id="linkedlist---노드-삭제하기">LinkedList - 노드 삭제하기</h3>
<p>노드 추가와 마찬가지로 3개의 방법으로 노드를 추가할 수 있습니다. </p>
<ol>
<li>pop : 링크드리스트 내 가장 첫번째 노드를 삭제합니다.</li>
<li>removeLast: 링크드리스트 내 가장 마지막 노드를 삭제합니다.</li>
<li>remove(at:) : 특정 인덱스의 노드를 삭제합니다.</li>
</ol>
<h4 id="pop">pop</h4>
<pre><code class="language-swift">struct LinkedList&lt;T&gt; {
    ...
    mutating func pop() -&gt; T? {
        defer {
            head = head?.next
            if isEmpty{
                tail = nil
            }
        }
        return head?.value
    }
}
// 출력 예제
var list = LinkedList&lt;Int&gt;()
list.push(3)
list.push(2)
list.push(1)

print(&quot;pop 이전의 링크드리스트 : \(list)&quot;)
let poppedValue = list.pop()
print(&quot;pop 이후의 링크드리스트 : \(list&quot;)
print(&quot;pop 한 값 : &quot; + String(poppedValue))

// pop 이전의 링크드리스트 : 1 -&gt; 2 -&gt; 3
// pop 이후의 링크드리스트 : 2 -&gt; 3
// pop 한 값 : Optional(1)</code></pre>
<p><code>pop</code> 는 링크드리스트의 <code>head</code> 를 삭제하고 리턴하며,
head.next 를 새로운 <code>head</code> 로 설정하는 메소드입니다.</p>
<p>이때 리턴되는 값은 nil 일 수 있기에 (비어있는 링크드리스트를 pop 하는 경우) optional 값으로 주어지게 됩니다.</p>
<blockquote>
<p>TMI
특기할 점이 2가지 입니다.</p>
</blockquote>
<p>첫번째로 <code>defer</code> 의 사용입니다. <code>defer</code> 키워드는 의도적으로 <code>return</code> 바로 전에 실행하도록, 실행 순서를 가장 뒤로 설정하는 키워드입니다. 
만약 <code>defer</code> 키워드를 사용하지 않는다면, 
기존의 값, 즉 삭제되는 값인 head?.value 를 담을 변수가 필요하게 됩니다. 하지만 <code>defer</code> 를 통해서 <code>return</code> 이후에 head = head?.next 를 할당하므로 오직 리턴만을 위해 새로운 변수를 인스턴스할 필요가 없어지게 됩니다.
* 리턴 뒤에 어떻게 함수가 작동하냐구요 ?
<a href="https://kor45cw.tistory.com/269">이렇다고 하네요. 감사합니다 :)</a></p>
<blockquote>
<p>두번째는 메모리 정리에 관한 내용입니다.
<code>pop</code> 메소드를 자세히보면 기존의 head Node 에 대해서는 nil 을 선언도 안하고, 바로 함수를 빠져나가는 것을 확인할 수 있습니다. 
그러면 메모리는 계속해서 예전 head Node 를 계속해서 갖고 있을까요? </p>
</blockquote>
<p>Swift 의 ARC(Auto Reference Calculator) 는 특정 객체가 메모리를 참조하는지 확인해주는 기능이 있습니다. 이때 특정 객체를 그 누구도 참조하지 않는다면 자동으로 메모리를 정리해주게 됩니다. </p>
<blockquote>
</blockquote>
<p>head Node 의 경우가 이에 해당됩니다. 
기존의 LinkedList struct 에서 head 변수를 head?.next 로 변경하게 되면, 기존의 head 는 그 누구도 참조하지 않게 됩니다. 곧 참조 카운트가 0 이 되며, 참조 카운트가 0 인 객체는 함수 종료 시 ARC 가 자동으로 정리해줍니다.</p>
<br/>

<h4 id="removelast">removeLast</h4>
<p><code>removeLast</code> 메소드는 <code>tail</code> 을 삭제하고, <code>tail</code> 앞의 노드를 <code>tail</code> 로 만드는 메소드입니다. 말로는 간단하지만, 사실 여기에는 맹점이 하나 있습니다.</p>
<p>Node 에는 next 만 있고, prev(이전) 가 없기때문에 무슨 노드가 <code>tail</code> 의 앞의 노드인지 알 수 없습니다. 즉, 링크드리스트를 처음부터 끝까지 돌면서 <code>tail</code> 의 앞 노드가 어떤 노드인지 알아내야 합니다.</p>
<pre><code class="language-swift">struct LinkedList&lt;T&gt; {
    ...
    mutating func removeLast() -&gt; T? {
        guard let head = head else {
            return nil   // 1️⃣
        }

        guard head.next != nil else {
            return pop() // 2️⃣
        }

        // 3️⃣
        var prev = head
        var current = head

        while let next = current.next {
            prev = current
            current = next
        }

        // 4️⃣
        prev.next = nil
        tail = prev
        return current.value
    }
}

// 출력 예제
var list = LinkedList&lt;Int&gt;()
list.push(3)
list.push(2)
list.push(1)

print(&quot;removeLast 이전 링크드리스트 : \(list)&quot;)

let removedValue = list.removeLast()
print(&quot;removeLast 이후 링크드리스트 : \(list)&quot;)
print(&quot;removeLast 값 : &quot; + String(removedValue)

// removeLast 이전 링크드리스트 : 1 -&gt; 2 -&gt; 3
// removeLast 이후 링크드리스트 : 1 -&gt; 2
// removeLast 값 : optional(3)</code></pre>
<ol>
<li>만약 <code>head</code> 가 nil 이였다면, nil 을 리턴해줍니다.</li>
<li>만약 <code>head</code> 의 next 가 없다면, 즉 <code>head</code> == <code>tail</code> 인 상황이라면 <code>pop</code> 과 동일하므로 <code>pop</code> 을 리턴합니다.</li>
<li>위의 두 상황이 아니라면, <code>tail</code> 이전의 노드가 어떤 노드인지 찾기 위해 <code>while</code> 로 탐색합니다.</li>
<li><code>tail</code> 이전의 노드를 찾았다면 해당 노드의 next 를 없애고, <code>tail</code> 을 해당 노드로 바꾼 후 이전 <code>tail</code> 을 리턴합니다.</li>
</ol>
<br/>

<h4 id="removeafter">remove(after:)</h4>
<p><code>remove(after:)</code> 메소드는 특정 노드의 next 를 삭제하는 메소드입니다. 이때 next 의 next 를 특정 노드와 연결해주게 됩니다.
<del>굳이</del></p>
<p><img src="https://velog.velcdn.com/images/newon-seoul/post/a32aadb3-61af-4df7-9bf2-378c3083a528/image.jpg" alt=""></p>
<p>링크드리스트가 <code>1 -&gt; 2 -&gt; 3</code> 이였지만, 
remove(after:1) 을 통해 <code>1 -&gt; 3</code> 으로 바꾼 모습입니다.
물론 연결 안해줄 수도 있습니다.</p>
<pre><code class="language-swift">struct LinkedList&lt;T&gt; {
    ...
    mutating func remove(after node: Node&lt;T&gt;) -&gt; T? {
        defer {
            if node.next === tail {
                tail = node
            }
            node.next = node.next?.next // ⭐️
        }
        return node.next?.value
    }    
}

// 출력 예제
var list = LinkedList&lt;Int&gt;()
list.push(3)
list.push(2)
list.push(1)

print(&quot;remove(after:0) 이전 링크드리스트 : \(list)&quot;)
let removedValue remove(after: node)

print(&quot;remove(after:0)&quot; 이후 링크드리스트 : \(list)&quot;)
print(&quot;삭제된 노드값 : &quot; + String(removedValue))
// remove(after:0) 이전 링크드리스트 : 1 -&gt; 2 -&gt; 3
// remove(after:0)&quot; 이후 링크드리스트 : 1 -&gt; 3
// &quot;삭제된 노드값 : Optional(2)&quot;</code></pre>
<p><code>pop</code> 과 같은 이유, 리턴을 위해 새로운 값을 인스턴하지 않기 위해서 <code>defer</code> 를 사용했으며 </p>
<p>만약 삭제되는 node 가 <code>tail</code> 이였다면 <code>tail</code> 을 노드로 설정해주고, 아니라면 <code>1 -&gt; 3</code> 과 같이 다음 다음 노드를 next 로 설정해주고 있습니다.</p>
<br/>

<h4 id="각-삭제-메소드들의-시간복잡도-분석">각 삭제 메소드들의 시간복잡도 분석</h4>
<p><img src="https://velog.velcdn.com/images/newon-seoul/post/be1bddd7-e017-495b-92f4-c82dff6dd9ab/image.jpg" alt="링크드 리스트 삭제 메소드들의 시간복잡도"></p>
<p>추가 메소드와 마찬가지입니다. 모든 메소드들이 O(1) 로, 단 한번에 노드를 추가할 수 있음을 확인할 수 있습니다 !</p>
<p>단, <code>removeLast</code> 는 removeLast 의 prev 를 찾기 위해서 O(LinkedList.count) 만큼의 시간복잡도를 추가적으로 갖게 됩니다. </p>
<br/>
<br/>

<hr>
<p>다음편에서 완전 TMI
LinkedList 를 Collection 에 넣기 위해 Protocol 을 준수해보자네 ! </p>
<p>빠이네 ~ !!
<img src="https://velog.velcdn.com/images/newon-seoul/post/e0b9cb8f-5e81-4dcb-803b-8d16743b2196/image.jpg" alt=""></p>
<hr>
<h4 id="참조">참조</h4>
<p><a href="https://www.raywenderlich.com/books/data-structures-algorithms-in-swift/v4.0/chapters/4-stacks">Data Structures &amp; Algorithms in Swift - fourth Edition</a>
<a href="https://ko.wikipedia.org/wiki/%EC%97%B0%EA%B2%B0_%EB%A6%AC%EC%8A%A4%ED%8A%B8">위키백과 - 연결 리스트</a>
<a href="https://www.advancedswift.com/when-to-use-defer-in-swift/">The Swift Defer Keyword</a>
<a href="https://kor45cw.tistory.com/269">Swift 에서 &quot;defer&quot;란 무엇인가</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Swift:자료구조] LinkedList 1편 : Node 와 LinkedList 에 추가하기]]></title>
            <link>https://velog.io/@newon-seoul/Swift%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-LinkedList-1%ED%8E%B8-Node-%EC%99%80-LinkedList-%EC%97%90-%EC%B6%94%EA%B0%80%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@newon-seoul/Swift%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-LinkedList-1%ED%8E%B8-Node-%EC%99%80-LinkedList-%EC%97%90-%EC%B6%94%EA%B0%80%ED%95%98%EA%B8%B0</guid>
            <pubDate>Thu, 07 Jul 2022 12:59:46 GMT</pubDate>
            <description><![CDATA[<h3 id="linkedlist-란">LinkedList 란?</h3>
<p>링크드리스트는 특정 값들을 일렬로, 그것도 단방향으로 저장하는 형태의 자료구조를 의미합니다. </p>
<p><img src="https://velog.velcdn.com/images/newon-seoul/post/c6ce8edc-4195-4e98-a923-b1286159cfbb/image.png" alt=""></p>
<p>이때 링크드리스트가 담고 있는 값의 형태를 <code>노드(node)</code> 라고 표현합니다.
<code>노드</code>는 <code>값</code> 과 <code>다음 노드의 메모리 주소</code> 를 갖고 있습니다. 
만약 다음 노드가 없다면 메모리주소에는 <code>nil</code> 을 할당합니다. 
이는 해당 노드가 링크드리스트의 마지막임을 뜻하기도 합니다.</p>
<p>상단의 그림에서 노드는 총 3개로, 편의상 왼쪽부터 노드 1,2,3 으로 부른다면</p>
<ul>
<li>노드 1 : 12 값과 노드 2의 메모리주소를 가진 노드</li>
<li>노드 2 : 99 값과 노드 3의 메모리주소를 가진 노드</li>
<li>노드 3 : 37 값과 다음 메모리 주소가 없는 노드</li>
</ul>
<p>로 구분할 수 있습니다. 
노드의 값은 중복될 수 있지만, 메모리주소는 당연히 중복될 수 없습니다. 
메모리 내 같은 공간에 2개의 정보를 동시에 담을 순 없으니까요 :)
<del>하지만 양자 컴퓨터가 나온다면 어떨까?</del> <del>양.자.컴.퓨.터</del> </p>
<br/>

<h3 id="노드-구현">노드 구현</h3>
<p>링크드리스트를 구현하기 이전에, 링크드리스트에 포함될 노드를 먼저 구현해보겠습니다.</p>
<pre><code class="language-swift">class Node&lt;T&gt; {
    var value: T
    var next: Node?

    init(value: T, next: Node? = nil) {
        self.value = value
        self.next = next
    }
}

// 밑의 코드는 print 시 편의를 위해 사용 
// 출처 : raywenderlich node
extension Node: CustomStringConvertible {
    var description: String {
        guard let next = next else {
            return &quot;\(value)&quot;
        }
        return &quot;\(value) -&gt; &quot; + String(describing: next) + &quot; &quot;
    }
}

let node1 = Node(value:1)
let node2 = Node(value:2)
let node3 = Node(value:3)

node1.next = node2
node2.next = node3

print(node1)

// 출력
1 -&gt; 2 -&gt; 3</code></pre>
<p>노드를 구현한 <code>class</code> 를 확인해보겠습니다.</p>
<p>우선 <code>struct</code> 가 아닌 <code>class</code> 로 구현되어 모든 노드들이 <code>참조 타입</code> 이 되도록 설정되었습니다. 이는 <code>next</code> 가 다음 노드의 메모리 주소를 참조한다는 것으로 이어집니다.</p>
<p><code>class</code> 내부는 간단하게 되어있습니다. 제네릭타입으로 어떤 형태든 값을 받을 수 있는 <code>var value: T</code> 와 다음 노드를 저장할  <code>next</code>, 그리고 생성 시 초기화를 위한 <code>init</code> 이 있습니다.</p>
<p><em>* 여기서 T는 제네릭 타입으로, 어떤 자료형이든 초기에 받는 
그 자료형을 이 변수의 자료형으로 사용하겠다 라는 의미입니다. 
Int 를 주면 앞으로는 Int, String 을 주면 String, 
자신이 생성한 구조체를 주면 그 구조체가 됩니다. 
T 는 임의의 명칭으로, 자유롭게 바꿔서도 쓸 수 있습니다.</em></p>
<p>이후 하단에서 <code>node1</code>, <code>node2</code>, <code>node3</code> 을 생성하고 
각각 1,2,3 이라는 값을 준 후, 1의 next 를 2, 2의 next를 3으로 주고 
출력을 했더니</p>
<p>쨔잔 1 -&gt; 2 -&gt; 3 이라는 굉장히 직관적인 결과가 나왔습니다.
노드는 이와 같이 값과 다음 노드의 메모리주소를 갖는 <code>class</code> 입니다.</p>
<br/>



<p>만약 <code>struct</code> 로 <code>class</code> 를 구현하면 어떻게 될까요?
그렇다면 <code>Hashable, Equtable</code> 프로토콜을 준수하도록 하고, 이후 메소드에서도 계속해서 값이 아닌 참조를 하도록 강제해야 합니다.</p>
<p>왜냐하면 <code>struct</code> 는 생성 및 할당 시 새로운 인스턴스를 생성, 즉 매번 새롭게 메모리에 적재되는 <code>값 타입</code> 인 반면 <code>class</code> 는 할당을 하더라도 그 주소가 할당되는 <code>참조 타입</code> 이기 때문입니다. 자세한 내용은 값 타입과 참조 타입을 확인해주세요.</p>
<br/>

<hr>
<h3 id="linkedlist-구현">LinkedList 구현</h3>
<pre><code class="language-swift">struct LinkedList&lt;T&gt; {
    var head: Node&lt;T&gt;?
    var tail: Node&lt;T&gt;?

    init() { }

    var isEmpty: Bool {
        head == nil
    }
}

// 밑의 코드는 print 시 편의를 위해 사용 
// 출처 : raywenderlich node
extension LinkedList: CustomStringConvertible {
    var description: String{
        return &quot;Empty list&quot;
    }
    return String(describing: head)
}</code></pre>
<p>Linked List 구조체를 만들어보았습니다. 
<code>Node&lt;T&gt;?</code> 를 받는 2개의 변수 <code>head</code> 와 <code>tail</code> 이 있고,
head 가 nil 이면 이 링크드리스트는 비어있다 라고 표현하고 있네요.</p>
<p><img src="https://velog.velcdn.com/images/newon-seoul/post/a504ccfa-67ba-404a-890f-9dc9e423992a/image.png" alt="">
위의 그림을 다시 가져와서 살펴보면
<code>head</code> 는 링크드리스트의 가장 첫번째 노드를 의미합니다. 
<code>tail</code> 은 next 가 없는 노드, 즉 링크드리스트의 가장 마지막 노드를 의미합니다.</p>
<p>만약 <code>head</code> 의 next 가 없다면 <code>head</code> 는 <code>tail</code> 이기도 한거죠!</p>
<p>LinkedList 를 구현해보았지만, 무언가가 많이 부족합니다.
아직까지는 LinkedList 에 노드를 추가할수도, 삭제할수도 없기 때문입니다.</p>
<p>앞으로 push, append, insert 메소드를 구현해서 노드를 추가해보고
pop, removeLast, remove(after:) 메소드를 구현해서 노드를 삭제해보겠습니다.</p>
<p><del>많냐</del></p>
<h3 id="linkedlist---노드-추가하기">LinkedList - 노드 추가하기</h3>
<p>LinkedList 에는 3개의 방법으로 노드를 추가할 수 있습니다. </p>
<ol>
<li>push : 링크드리스트의 가장 앞에 node 를 추가합니다.</li>
<li>append : 링크드리스트의 가장 맨 뒤에 node 를 추가합니다.</li>
<li>insert(after:) : 링크드리스트 내 특정 노드 뒤에 노드를 추가합니다.</li>
</ol>
<h4 id="push">push</h4>
<pre><code class="language-swift">struct LinkedList&lt;T&gt; {
    ...
    mutating func push(_ value: T) {
        head = Node(value: value, next: head)
        if tail == nil {
            tail = head
        }
    }
}

// 출력 예제
var list = LinkedList&lt;Int&gt;()
list.push(3)
list.push(2)
list.push(1)

print(list)
// 1 -&gt; 2 -&gt; 3</code></pre>
<p><code>push</code> 메소드는 추가하고자 하는 값을 알려주면
그 값을 지닌 <code>Node</code> 를 만들어서 head 로 선언해주고, 
동시에 이전의 head 는 next 로 선언해줍니다. </p>
<p>이때 만약 <code>tail</code> 이 <code>nil</code> 이였다면 (== 처음 노드를 넣는다면)
<code>tail</code> 을 <code>head</code> 로 지정합니다. </p>
<h4 id="append">append</h4>
<pre><code class="language-swift">struct LinkedList&lt;T&gt; {
    ...
    mutating func append(_ value: T) {
        guard !isEmpty else {       // 1️⃣
            push(value)
            return
        }

        tail!.next = Node(value: T) // 2️⃣
        tail = tail!.next           // 3️⃣
    }
}

// 출력 예제
var list = LinkedList&lt;Int&gt;()
list.append(1)
list.append(2)
list.append(3)

print(list)
// 1 -&gt; 2 -&gt; 3</code></pre>
<p><code>append</code> 메소드는 추가하고자 하는 값을 알려주면
링크드리스트의 가장 마지막에 해당 노드를 만들어 추가해줍니다.</p>
<p>이때 로직은 3단계로 나누어집니다.</p>
<ol>
<li>만약 LinkedList 가 비어있다면, 이는 <code>push</code> 와 동일하기에 <code>push</code> 에 값을 넘겨주고 종료합니다.</li>
<li>LinkedList 가 비어있지 않다면, <code>tail</code> 의 next 에 
전달받은 값으로 <code>Node</code> 를 생성하고 next 로 지정합니다.</li>
<li><code>tail</code> 을 <code>tail!.next</code> 로 설정합니다. 
이때 tail 은 반드시 존재하니 <code>!</code> 로 옵셔널을 해제해줍니다. </li>
</ol>
<h4 id="insertafter">insert(after:)</h4>
<p><code>insert</code> 는 해당 링크드리스트의 특정 노드 뒤에 새로운 노드를 추가하는 메소드입니다. </p>
<p>단, 바로 작성하기에는 문제가 하나 있는데
왜냐하면 지금 우리는 특정 노드가 몇번째에 있는지 알 수 없기 때문입니다.</p>
<p>노드들은 중복된 값을 가질 수 있고, 한편 LinkedList 는 <code>[]</code> 를 통해서 접근할 수 도 없으니 우선 해당 노드가 몇번째 노드인지 먼저 찾는 메소드부터 작성하고서, 그 후에 원하는 값을 노드로 추가해줄 수 있게됩니다.</p>
<pre><code class="language-swift">struct LinkedList&lt;T&gt; {
    ...
    func find(at index: Int) -&gt; Node&lt;T&gt;? {
        // 1️⃣
        var currentNode = head
        var currentIndex = 0

        // 2️⃣
        while currentNode != nil &amp;&amp; currentIndex &lt; index {
            currentNode = currentNode!.next
            currentIndex += 1
        }
        return currentNode
    }
</code></pre>
<p><code>find(at:)</code> 메소드는 찾고자하는 노드의 인덱스를 주면
해당 인덱스에 해당하는 노드를 찾는 메소드입니다.
<del>그것이 메소드니까..?</del></p>
<ol>
<li>현재노드와 현재 인덱스를 변수로 선언하고, 각각 head 와 0 을 줍니다.</li>
<li>현재노드 변수는 계속해서 다음 노드를, 현재 인덱스는 계속해서 1을 더해가며 <code>해당 인덱스를 찾거나</code>, <code>tail 다음(nil)에 도달할 때 까지</code> 인덱스에 해당하는 노드를 찾습니다.</li>
<li>원했던 노드를 리턴합니다.</li>
</ol>
<br/>

<p>이제 <code>find</code> 를 통해 <code>insert(at:)</code> 을 구현해보겠습니다.</p>
<pre><code class="language-swift">struct LinkedList&lt;T&gt; {
    ...
    // 1️⃣
    @discardableResult
    mutating func insert(_ value: T, after node: Node&lt;T&gt;) -&gt; Node&lt;T&gt; {
        // 2️⃣
        guard tail !== node else {
            append(value)
            return tail!
        }

        // 3️⃣
        node.next = Node(value: value, next: node.next)
        return node.next!
    }

}

// 출력 예제
var list = LinkedList&lt;Int&gt;()
list.push(3)
list.push(2)
list.push(1)

print(&quot;insert 이전의 링크드리스트 : \(list)&quot;)
var middleNode = list.node(at: 1)!
for _ in 1 ... 4 {
    middleNode = list.insert(-1, after: middleNode)
}
print(&quot;insert 이후의 링크드리스트 : \(list)&quot;)

// insert 이전의 링크드리스트 : 1 -&gt; 2 -&gt; 3
// insert 이후의 링크드리스트 : 1 -&gt; 2 -&gt; -1 -&gt; -1 -&gt; -1 -&gt; -1 -&gt; 3
</code></pre>
<ol>
<li>@discardableResult 는 해당 함수의 리턴값이 사용되지 않더라도, Swift 컴파일러가 경고해줄 필요는 없다라는 의미입니다.
insert 후에 해당 결과값이 필요할 수도 있지만, 안 필요한 경우가 더 많기 때문에 <del>눈뽕</del> 경고창을 해당 띄우지 않도록 설정해줍니다.</li>
<li>만약 특정 노드가 링크드리스트의 <code>tail</code> 이였다면, 이는 <code>append</code> 와 동일한 메소드가 됩니다. append 에 값을 넘겨주고 종료합니다.</li>
<li>append 에서 했던 코드와 유사합니다.
해당 노드의 next 에 새로운 노드를 만듦과 동시에 새로운 노드의 next 는 기존 노드의 next 로 설정해줍니다.</li>
</ol>
<p>3번의 경우 한 줄의 코드가 2개의 행동,
<code>특정 노드의 next 를 내가 준 값의 새로운 노드로 설정</code> 과
<code>내가 준 값의 새로운 노드의 next 는 특정 노드의 원래 next</code> 로 설정!</p>
<p>이 한번에 진행되어 헷갈릴 수 있지만 위와 같은 내용으로 
<code>insert(after:)</code> 메소드를 만들 수 있습니다.</p>
<br/>

<h4 id="각-추가-메소드들의-시간복잡도-분석">각 추가 메소드들의 시간복잡도 분석</h4>
<p><img src="https://velog.velcdn.com/images/newon-seoul/post/ae308505-0df5-42cb-8f2f-3679289e92de/image.jpg" alt="linkedList 각 메소드들 시간 복잡도 분석"></p>
<p>모든 메소드들이 O(1) 로, 단 한번에 노드를 추가할 수 있음을 확인할 수 있습니다 !</p>
<p>왜일까요 ?</p>
<p>다른 노드들을 밀거나, 미루거나의 행동 없이 
<code>head</code>, <code>tail</code> 혹은 <code>next</code> 만 재설정해주면 되기 때문입니다.</p>
<p>단, <code>insert(after:)</code> 를 위해서 특정 노드가 몇번째 노드인지 확인하는 행동에는 o(index) 만큼의 시간이 걸린다는 걸 확인할 수 있습니다.</p>
<br/>
<br/>


<hr>
<p>그럼 다음 편에서 삭제를 알아보자네 ! 
빠이네 !</p>
<p><img src="https://velog.velcdn.com/images/newon-seoul/post/a8a45876-2f25-4930-a03a-b7e42977a75c/image.jpg" alt=""></p>
<hr>
<h4 id="참고">참고</h4>
<p><a href="https://www.raywenderlich.com/books/data-structures-algorithms-in-swift/v4.0/chapters/4-stacks">Data Structures &amp; Algorithms in Swift - fourth Edition</a>
<a href="https://ko.wikipedia.org/wiki/%EC%97%B0%EA%B2%B0_%EB%A6%AC%EC%8A%A4%ED%8A%B8">위키백과</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Swift:자료구조] Stack 와 struct]]></title>
            <link>https://velog.io/@newon-seoul/Swift%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-Stack-%EC%99%80-struct</link>
            <guid>https://velog.io/@newon-seoul/Swift%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-Stack-%EC%99%80-struct</guid>
            <pubDate>Tue, 05 Jul 2022 12:22:37 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>들어가기 전에 !!
나는 stack 이 어떤 것인지 알고, Swift 로 어떻게 쓰는지만 알고 싶다.</p>
</blockquote>
<p>: 그냥 배열 쓰세용 :)</p>
<pre><code class="language-swift">var stack = [T]() // T 에는 원하는 자료형 - Int, String ...
stack.append()  // push
stack.popLast   // pop
stack.isEmpty   // isEmpty
stack.last      // peek</code></pre>
<hr>
<h3 id="stack-정의">Stack 정의</h3>
<p>Stack 자료구조는 자료를 쌓듯이 저장하고, 사용할때도 가장 뒤에 있는 자료 먼저 꺼내서 사용하는 형태를 지칭합니다. </p>
<p><img src="https://velog.velcdn.com/images/newon-seoul/post/1b0e987d-90d0-43c4-a386-7105603f3256/image.gif" alt=""></p>
<p>좀 더 편하게 말하자면, 프링글스 같은 자료구조 입니다.
넣을 때는 아래에서부터 차곡차곡 과자를 쌓았겠지만, 
먹을 때는 위에서부터 차근차근 먹게 되는 구조. </p>
<p><em>Stack</em> 입니다. <del>쏟아서 먹지만 않는다면</del></p>
<p><img src="https://velog.velcdn.com/images/newon-seoul/post/02b6b089-b548-4c79-aebd-bf4ed1a6906a/image.jpeg" alt=""></p>
<p>이때 과자_(자료)_를 넣는 행위를 <code>push</code>, 과자를 꺼내는 행위를 <code>pop</code> 이라고 합니다.</p>
<p>이러한 자료구조의 장점은 사용하고자 하는 용도가 명백할 때, 
즉 <code>자료를 차곡차곡 쌓아서 위에서 부터 쓰겠다.</code> 를 지킨다면 언제나 시간복잡도를 O(1) 을 지킬 수 있기 때문에 굉장히 빠른 자료구조가 됩니다. </p>
<p>왜냐구요? 항상 맨 뒤에다가 넣으면 되고, 맨 뒤에 있는 것만 빼서 쓰면 되거든요 !! </p>
<blockquote>
<p>단, 이때 이미 쌓여있는 자료 중 어떤 것이 몇번째에 있지 라든가,
 &quot;뒤에 있는 것만 활용하겠다&quot; 라는 취지를 어기게 되면 시간복잡도는 단숨에 확 늘어나게 됩니다.</p>
<p>왜냐구요? 프링글스를 뒤적뒤적 하면서 정확히 밑에서부터 42번째 있는 프링글스를 찾아가며 먹고 싶진 않잖아요 !!</p>
</blockquote>
<hr>
<h3 id="stack-의-메소드들">Stack 의 메소드들</h3>
<ul>
<li>push : 자료를 넣는 메소드에요.</li>
<li>pop : 자료를 꺼내는 메소드에요.</li>
<li>peek : 가장 뒷단, 혹은 상단에 있는 자료를 확인하는 메소드에요.</li>
<li>isEmpty: 스택이 비어있는지 확인할 메소드에요.</li>
</ul>
<hr>
<h3 id="stack---swift">Stack - Swift</h3>
<pre><code class="language-swift">struct Stack&lt;T&gt; {
    var storage = [T]()
    init(_ elements: [T]) {
        storage = elements
    }

    mutating func push(_ element: T) {
        storage.append(element)
    }
    mutating func pop() -&gt; T? {
        storage.popLast()
    }

    func peek() -&gt; T? {
        storage.last
    }
    var isEmpty : Bool {
        storage.isEmpty
    }
}

var stack = Stack&lt;Int&gt;([1,2,3,4,5])
</code></pre>
<br/>

<p>앞으로 자료구조는 모두 struct 를 활용하여 구조체 형태로 만들게 될 것 입니다. 사실 Stack 은 가장 상단에서 언급하였듯, 배열을 활용해서 사용해도 되긴 하지만 struct 활용이 처음인만큼 어떤 내용들이 있는지 살펴보겠습니다.</p>
<br/>

<ul>
<li><code>struct</code> : 구조체를 정의하는 문법입니다. 해당 문법을 통해 사용자는 복잡한 형태를 하나의 자료형처럼 사용할 수 있게 됩니다. 이때 struct 는 <code>값 타입</code> 으로, 새로 생성될 때 마다 새로운 객체가 인스턴스 됩니다. </li>
</ul>
<pre><code class="language-swift">struct Coordinate&lt;Int&gt; {
   var y: Int
   var x: Int
}

var a = A&lt;Coordinate&gt;(y: 0, x: 0)
var b = a
b.y = 1; b.x = 1
print(a)
print(b)

// 출력 :
// Coordinate(y: 0, x : 0)
// Coordinate(y: 1, x : 1)
// 즉, 값 타입은 생성될 때 마다 새롭게 메모리에 적재되기에 (인스턴스 되기에)
// 새롭게 생성된 두 값 타입은 서로에게 영향을 미치지 않으며
// 구조체 struct 는 언제나 값 타입이다.</code></pre>
<br/>

<ul>
<li><code>Stack&lt;T&gt;</code>: 이름인 Stack 과 자료형을 지칭하는 <code>T</code> 입니다. 이때 <code>T</code> 는 <code>제네릭 타입</code>이라고 지칭되며, 어떠한 자료형이든 입력을 받아주겠다 라는 의미로 사용됩니다. 한번 입력되고 나면 해당 함수 내에서는 처음에 입력된 자료형으로만 통일되어 사용할 수 있습니다. <a href="https://docs.swift.org/swift-book/LanguageGuide/Generics.html">제네릭 타입에 대해서 더 궁금하면 여기를 참고해보세요.</a></li>
</ul>
<br/>

<ul>
<li><code>var storage = [T]()</code>, <code>init(...) { ... }</code> : struct 를 통해 호출할 변수, 프로퍼티와 struct 를 처음 생성할 때 지시할 내용을 <code>init</code> 함수를 통해 지정할 수 있습니다. 
여기서는 제네릭 타입 T 를 통해 프로퍼티인 배열 storage 를 생성하고, init 함수에서는 T 타입의 배열을 storage 에 넣는 것을 확인할 수 있습니다.</li>
</ul>
<br/>

<ul>
<li><code>mutating func ... ()</code> : 
struct 는 <em>-좀 더 정확히는 값 타입의 프로퍼티들은-</em> 
기본적으로 내부의 값을 임의로 바꿀 수 없게 되어있습니다. 따라서 일반적인 func 함수를 호출해서 내부의 프로퍼티를 변경하려고 하면 &quot;할 수 없어 !&quot; 라고 컴파일러가 호되게 야단칩니다. 그래서 <code>mutating</code> 키워드를 활용하여 <code>아니? 나 이거 바꿀건데</code> 라고 컴파일러에게 요청할 수 있게됩니다.
여기서는 <code>mutating func pop</code>, <code>mutating func push</code> 를 통해 내부의 프로퍼티인 <code>var storage</code> 의 값을 원하는대로 바꾸고 있네요.</li>
</ul>
<br/>

<ul>
<li><code>func peek() ...</code> : 상단의 <code>mutating func</code> 와 달리 mutating 이 없는 peek 는 이름 그대로, 가장 상단의 값을 확인만 할 뿐이니 mutating 이 필요가 없는 모습을 확인할 수 있습니다.</li>
</ul>
<br/>

<ul>
<li><code>var isEmpty : Bool { }</code> : 연산 프로퍼티라고 불리는 변수입니다. 특징은 특정 값을 저장하지 않고, 다른 값을 읽어들여서 확인하거나, 수정하는 형태로 사용되는 프로퍼티입니다. 읽어들이는 행위를 <code>GET</code>, 특정 데이터를 수정하는 행위를 <code>SET</code> 이라고 합니다.
여기서는 <code>GET</code> 의 형태로만 사용되어, <code>storage</code> 가 비어있는지만 확인하고 있네요. </li>
</ul>
<br/>

<hr>
<h3 id="그래서-stack-은-어떻게-쓰면-되는건데">그래서 Stack 은 어떻게 쓰면 되는건데</h3>
<p>정말 복잡했던 <code>struct</code> 설명이 애석하게도, 자세히 살펴보면 결국 Swift 의 기본 제공 Collection 인 배열의 메소드만 활용하고 있는 것을 확인할 수 있어요. 따라서 각각의 내용들은 이렇게 바꿔서 사용하는게 <del>정신건강</del> 편리할 것 같습니다.</p>
<pre><code class="language-swift">var stack = [T]() 
: 원하는 자료형으로 stack 을 선언, 
struct Stack&lt;T&gt;{
    var storage = [T]()
    init (_elements: [T]) {
        storage = elements
    }

    ...
}
를 stack = [T]() 로 한번에 정리


stack.append()
: mutating func push(_ element: T) { 
    storage.append(element)
} 를 push 를 통해 정리


stack.popLast
: mutating func pop() -&gt; T? {
    storage.popLast
} 를 통해 pop 을 정리


stack.last
:func peek() -&gt; T? {
    storage.last
} 를 통해 last 를 정리


stack.isEmpty
: var isEmpty : Bool {
    storage.isEmpty
  } 를 통해 isEmpty 를 정리</code></pre>
<p>요약은 상단처럼 볼 수 있습니다.</p>
<pre><code class="language-swift">var stack = [T]() // T 에는 원하는 자료형 - Int, String ...
stack.append()  // push
stack.popLast   // pop
stack.isEmpty   // isEmpty
stack.last      // peek</code></pre>
<hr>
<h3 id="그래서-stack-이-알고리즘-푸는데-어디에-쓰여요">그래서 Stack 이 알고리즘 푸는데 어디에 쓰여요</h3>
<p>데이터가 언제나 순서대로 온다는 점을 착안해서 이런 문제들이 출제되고 있어요.
<a href="https://www.acmicpc.net/problem/3986">백준 - 좋은 단어</a>
<a href="https://www.acmicpc.net/problem/9935">백준 - 문자열 폭발</a>
<a href="https://school.programmers.co.kr/learn/courses/30/lessons/64061">프로그래머스 - 크레인 인형뽑기 게임</a></p>
<p>관통하는 주제로는 &quot;순서대로 오는 무언가를, 특정 조건에 따라 구분할 수 있는가?&quot; 가 될 것 같네요 !!</p>
<br/>

<p>한편 Stack 은 Stack 그 자체로 쓰이기 보다는 CS 관점에서 볼 때 재귀함수와 DFS 의 기본 구조라서, 이를 활용한 문제들이 더 많이 나오게 됩니다.</p>
<p><del>ㅎㅎ.. 코틀린버전으로 쓴 게 있는데 확인해주면 ㅈ..ㅈ..좋아합니다! 언어 상관없이 이해되게 썻다고 하네요!</del> <a href="https://velog.io/@newon-seoul/%EB%AC%B8%EA%B3%BC%EC%83%9D%EC%9D%B4-%EC%A0%81%EC%96%B4%EB%B3%B4%EB%8A%94-%EB%B0%B1%ED%8A%B8%EB%9E%98%ED%82%B9-%EC%9E%AC%EA%B7%80%EC%99%80-DFS-%EB%A5%BC-%EA%B3%81%EB%93%A4%EC%9D%B8">문과생이 적어보는 백트래킹 재귀와 DFS 를 곁들인</a></p>
<br/>

<p>그럼 빠이네라네 ~ 
<img src="https://velog.velcdn.com/images/newon-seoul/post/9d54821e-ef07-4287-a084-9c1a79aaaee8/image.jpg" alt=""></p>
<hr>
<h4 id="참고">참고</h4>
<p><a href="https://www.raywenderlich.com/books/data-structures-algorithms-in-swift/v4.0/chapters/4-stacks">Data Structures &amp; Algorithms in Swift - fourth Edition</a>
<a href="https://docs.swift.org/swift-book/LanguageGuide/TheBasics.html">Swift Language Guide 5.7</a>
<a href="https://www.boostcourse.org/mo122/joinLectures/38564">부스트코스 - iOS 프로그래밍을 위한 스위프트 기초</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Swift:알고리즘] 날짜로 요일 알기]]></title>
            <link>https://velog.io/@newon-seoul/Swift%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%82%A0%EC%A7%9C%EB%A1%9C-%EC%9A%94%EC%9D%BC-%EC%95%8C%EA%B8%B0</link>
            <guid>https://velog.io/@newon-seoul/Swift%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%82%A0%EC%A7%9C%EB%A1%9C-%EC%9A%94%EC%9D%BC-%EC%95%8C%EA%B8%B0</guid>
            <pubDate>Sat, 02 Jul 2022 12:24:20 GMT</pubDate>
            <description><![CDATA[<p>특정 년도의 1월 1일의 요일이 언제인지 알 때
다음과 같이 언제가 어떤 날인지 알 수 있다.</p>
<pre><code class="language-swift">import Foundation

let monthList = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] // 월별 일자
let weekOfDay = [&quot;SUN&quot;, &quot;MON&quot;, &quot;TUE&quot;, &quot;WED&quot;, &quot;THU&quot;, &quot;FRI&quot;, &quot;SAT&quot;] // 1월 1일의 요일을 가장 맨 앞에 둔다.
var week = &quot;&quot;

let input = readLine()!.split(separator: &quot; &quot;).map{ Int(String($0))! }
var (month, day) = (input[0], input[1])

var totalDay = 0
for i in 0 ..&lt; month - 1 {
    totalDay += monthList[i]
}
totalDay += day - 1
week = weekOfDay[totalDay % 7]

while week != &quot;SUN&quot; {
    totalDay -= 1
    week = weekOfDay[totalDay % 7]

    day -= 1
    if day &lt;= 0 {
        month -= 1
        day = monthList[month - 1]
    }
}

print(&quot;\(week), \(month) 월 \(day) 일&quot;)</code></pre>
<p>언젠가 다시 필요할 수도 있을 것 같아서 ..</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Swift-Language Guide 5.7 / Collection Types (야매 번역 + 정리)]]></title>
            <link>https://velog.io/@newon-seoul/Swift-Language-Guide-5.7-Collection-Types</link>
            <guid>https://velog.io/@newon-seoul/Swift-Language-Guide-5.7-Collection-Types</guid>
            <pubDate>Wed, 29 Jun 2022 06:45:52 GMT</pubDate>
            <description><![CDATA[<h3 id="초록">초록</h3>
<p>Swift 는 3개의 주요 컬렉션 (Collection) 자료형 <code>Array</code>, <code>Set</code>, <code>Dictionaries</code> 을 제공합니다. <code>Array</code> 는 값을 지니는 정렬된 컬렉션이며, <code>Set</code> 과 <code>Dictionaries</code> 는 비정렬 컬렉션으로, 각각 고유의 값을 지니거나 <code>Key-Value</code> 로 이루어진 컬렉션입니다. </p>
<p><img src="https://velog.velcdn.com/images/newon-seoul/post/7fef652d-ca7f-4e99-ada7-8f0d2830a4d0/image.png" alt=""></p>
<p>Swift 에서 각 컬렉션들은 지닐 수 있는 자료형이 명백하게 정의되기에, 사용자는 잘못된 형태의 값을 컬렉션에 넣을 수 없게 됩니다. 또한 각각의 컬렉션은 컬랙션 내에서 동일한 자료형만 반복될 것임을 확신할 수 있게 됩니다.</p>
<h3 id="mutability-of-collections컬렉션-변경-가능-여부">Mutability of Collections(컬렉션 변경 가능 여부)</h3>
<p><code>Array</code>, <code>Set</code>, <code>Dictionaries</code> 를 만들 때 변수(<em>variable</em>)로 만들게 되면 해당 컬렉션은 변경 및 수정이 가능하게 되며, 이와 반대로 상수(<em>constant</em>)로 만들게되면 초기화를 할 때를 제외하면 변경 및 수정이 불가능하게 됩니다.</p>
<h3 id="arrays-배열">Arrays (배열)</h3>
<p><code>array</code> 는 같은 자료형으로 정렬된 목록의 값들을 저장하는 컬렉션입니다. </p>
<p><em>Note</em>: Swift 의 배열은 Foundation 프레임워크의 NSArray class 와 연결되어 있습니다. Array 를 Foundation 과 Cocoa 를 통해 사용하고 싶다면 <a href="https://developer.apple.com/documentation/swift/array#2846730">Bridging Between Array and NSArray</a> 를 참고해주세요. </p>
<h4 id="array-type-shorthand-syntax-array-자료형-줄임-문법">Array Type Shorthand Syntax (Array 자료형 줄임 문법)</h4>
<p>Swift Array 자료형은 <code>Array&lt;Element&gt;</code> 의 형태로 정의됩니다. 이때 짧게 사용하는 방법으로 <code>[Element]</code> 를 통해 사용할 수 있습니다. 두 형태는 기능적으로 동일하며, 이하 Swift Language Guide 에서는 줄임 표현을 사용할 것 입니다.</p>
<h4 id="creating-an-empty-array">Creating an Empty Array</h4>
<p>빈 배열은 타음과 같이 만들 수 있습니다.</p>
<pre><code class="language-swift">var someInts: [Int] = []
print(&quot;someInts 는 [Int] 자료형으로 \(someInts.count) 개수 만큼 원소를 갖고 있습니다.&quot;)
// &quot;someInts 는 [Int] 자료형으로 0 개수 만큼 갖고 원소를 갖고 있습니다.&quot;</code></pre>
<p>배열이 variable 에 Int 자료형으로 선언되었으므로 다음과 같이 사용할 수 있습니다.</p>
<pre><code class="language-swift">someInts.append(3)
// someInts 는 이제 Int 자료형의 원소를 1개 갖고 있습니다.
someInts = []
// someInts 는 이제 빈 배열이지만, 여전히 [Int] 형입니다.</code></pre>
<h4 id="creating-an-array-with-a-default-value-초기값으로-배열-만들기">Creating an Array with a Default Value (초기값으로 배열 만들기)</h4>
<p>Swift 의 배열 자료형은 초기화 시 특정 사이즈에 동일한 값을 넣어서 초기화 하는 방법을 제공합니다.</p>
<pre><code class="language-swift">var threeDoubles = Array(repeating: 0.0, count: 3)
//threeDoubles 는 [Double] 자료형에 [0.0, 0.0, 0.0] 입니다.

// 번역 : 이런 형태도 가능합니다.
var threeDoubles = [Double](repeating: 0.0, count: 3)
// threeDoubles 는 [Double] 자료형에 [0.0, 0.0, 0.0] 입니다.</code></pre>
<h4 id="creating-an-array-by-adding-two-arrays-together-두-배열을-합쳐-하나의-배열-만들기">Creating an Array by Adding Two Arrays Together (두 배열을 합쳐 하나의 배열 만들기)</h4>
<p>동일한 두 자료형의 배열을 <code>+</code> 연산자를 통해서 두 배열이 합쳐진 새로운 배열을 생성할 수 있습니다.</p>
<pre><code class="language-swift">var anotherThreeDoubles = Array(repeating: 2.5, count: 3)
var sixDoubles = threeDoubles + anotherThreeDoubles
// sixDoubles 는 [Double] 자료형이며, [0.0, 0.0, 0.0, 2.5, 2.5, 2.5,] 입니다.</code></pre>
<h4 id="creating-an-array-with-an-array-literal리터럴을-통해-배열-만들기">Creating an Array with an Array Literal(리터럴을 통해 배열 만들기)</h4>
<p>리터럴을 통해서도 배열을 만들 수 있습니다. <code>[]</code> 안에 원하는 원소를 넣고, <code>,</code> 로 구분할 수 있습니다.</p>
<pre><code class="language-swift">var shoppingList: [String] = [&quot;Eggs&quot;, &quot;Milk&quot;]
// shoppingList 는 [String] 자료형에 Eggs 와 Milk 를 담고 있습니다.</code></pre>
<p>이때 원소를 하나의 자료형으로 통일하면 배열의 자료형은 원소의 자료형으로 자동캐스팅이 됩니다.</p>
<pre><code class="language-swift">var shoppingList = [&quot;Eggs&quot;, &quot;Milk&quot;]
// shoppingList 는 [String] 자료형에 Eggs 와 Milk 를 담고 있습니다.</code></pre>
<h4 id="accessing-and-modifying-an-array배열-접근과-배열-수정">Accessing and Modifying an Array(배열 접근과 배열 수정)</h4>
<p>배열의 메소드와 프로퍼티, 인덱스 문법을 통해 배열에 접근하거나 수정할 수 있습니다.</p>
<p>배열의 개수는 <code>count</code> 프로퍼티를 사용할 수 있습니다.</p>
<pre><code class="language-swift">print(&quot;shoppingList 는 \(shoppingList.count)개의 원소를 갖고 있습니다.&quot;)
// 출력 : shoppingList 는 2개의 원소를 갖고 있습니다.</code></pre>
<p>배열이 빈 값인지 확인하고 싶다면 <code>isEmpty</code> 프로퍼티를 사용할 수 있습니다. <code>isEmpty</code> 는 <code>count == 0</code> 과 동일합니다. </p>
<pre><code class="language-swift">if shoppingList.isEmpty{
    print(&quot;쇼핑리스트는 비어있습니다.&quot;)
} else {
    print(&quot;쇼핑 리스트는 비어있지 않습니다.&quot;)
}
// 출력 : 쇼핑 리스트는 비어있지 않습니다.</code></pre>
<p>배열에 원소를 추가하고 싶다면 <code>append(_:)</code> 메소드를 사용할 수 있습니다.
* 번역 : 메소드나 함수에서 매개변수 앞에 <code>_</code> 가 있으면 호출할 때 매개변수 라벨을 생략할 수 있습니다.</p>
<pre><code class="language-swift">shoppingList.append(&quot;Flour&quot;)
// shoppingList 는 이제 3개의 아이템이 되었고, 팬케이크를 구울 것 같네요 :)</code></pre>
<p>혹은 이런 방법으로도 배열에 원소를 추가할 수 있습니다.</p>
<pre><code class="language-swift">shoppingList += [&quot;Baking Powder&quot;]
// 쇼핑리스트는 이제 4개의 아이템을 갖고 있습니다.
shoppingList += [&quot;Chocolate Spread&quot;, &quot;Cheese&quot;, &quot;Butter&quot;]
// 쇼핑리스트는 이제 7개의 아이템을 갖고 있습니다.</code></pre>
<p>인덱스 문법을 활용하여 배열 안의 값을 확인하거나, 새로운 값을 할당할 수도 있습니다.</p>
<pre><code class="language-swift">var firstItem = shoppingList[0]
shoppingList[0] = &quot;Six eggs&quot;

// firstItem 은 Eggs 가 되고,
// shoppingList[0] 는 &quot;Six eggs&quot; 가 됩니다.
// 번역 : 이때, 배열은 &quot;값 타입&quot; 이기 때문에, firstItem 이 Six eggs 로 변경되지 않습니다. </code></pre>
<p>인덱스 문법을 활용할때는 사용하고자 하는 인덱스가 배열의 범위안에 있는지 확인하여야 합니다. 만약 배열에 포함되어 있지 않은 인덱스를 사용하면 런타임 에러가 발생할 것 입니다.</p>
<p>한편 다음과 같이 인덱스 문법을 활용하여 특정 범위의 배열에 접근하거나 수정할 수도 있습니다. 이때 배열은 배열 리터럴의 크기로 조정하여 기존의 값에 합쳐지게 됩니다.</p>
<pre><code class="language-swift">shoppingList[4..6] = [&quot;Bananas&quot;, &quot;Apples&quot;]
// shoppingList 는 이제 기존 3개 원소를 2개 원소로 줄여, 
// 6개의 아이템을 갖게 됩니다.</code></pre>
<p>배열 내 특정 인덱스에 삽입을 하고 싶다면 <code>insert(_:at:)</code> 메소드 를 사용할 수 있습니다.</p>
<pre><code class="language-swift">shoppingList.insert(&quot;Maple Syrup&quot;, at 0)
// shoppingList 의 첫번째 원소에 Maple Syrup 이 들어가며 , 총 7개의 원소를 갖게 됩니다.</code></pre>
<p>이와 유사하게 배열 내 특정 인덱스를 삭제하고 싶다면 <code>remove(at:)</code> 메소드를 사용할 수 있습니다. <code>remove</code> 메소드는 삭제한 원소를 리턴하는데, 필요없다면 무시하고 사용할 수 있습니다. </p>
<pre><code class="language-swift">let mapleSyrup = shoppingList.remove(at: 0)</code></pre>
<p><em>Note</em> : 배열의 총 크기는 <code>0</code> ~ <code>count - 1</code> 입니다. 이때 count 가 0 이라면 빈 배열로, 접근할 수 없습니다. 인덱스를 활용한다면 이 점에 유의해서 사용해주세요.</p>
<h4 id="lterating-over-an-array배열-반복하기">Lterating Over an Array(배열 반복하기)</h4>
<p>배열 내 전체 값들을 <code>for-in</code> 반복문을 통해 접근할 수 있습니다.</p>
<pre><code class="language-swift">for item in shoppingList {
    print(item)
}
// Six eggs
// Milk
// Flour
// Baking Powder
// Bananas</code></pre>
<p>반복 시 인덱스가 필요하다면 다음과 같은 형태도 고려해볼 수 있습니다.</p>
<pre><code class="language-swift">for (index, value) in shoppingList.enumerated() {
    print(&quot;Item\(index + 1) : \(value)&quot;)
}
// Item 1: Six eggs
// Item 2: Milk
// Item 3: Flour
// Item 4: Baking Powder
// Item 5: Bananas</code></pre>
<h3 id="sets-세트-궁">Sets (세트 <del>궁</del>)</h3>
<p>세트는 비정렬 컬렉션에 같은 자료형의 값들을 <code>고유</code> 하게 저장하는 컬렉션을 의미합니다. 원소들의 순서가 중요하지 않거나, 원소가 반드시 1개만 존재해야 한다면 <code>set</code> 를 사용할 수 있습니다.</p>
<p><em>Note</em> : Swift 의 set 자료형은 Foundation 의 NSSet class 를 따릅니다. 더 자세한 내용은 <a href="https://developer.apple.com/documentation/swift/set#2845530">Bridging Between Set and NSSet</a> 를 확인해주세요.</p>
<h4 id="hash-values-for-set-types-set-자료형을-위한-해쉬-값">Hash Values for Set Types (Set 자료형을 위한 해쉬 값)</h4>
<p><code>Set</code> 에 저장되는 값들은 반드시 hashable, 즉 각 값들이 hash value 를 지녀 다른 값과 계산할 수 있는 자료형이어야 합니다. *<em>hash value 는 Int 값이며, 동일한 값은 동일한 hash value 를 갖고 있어야합니다. *</em></p>
<p><em>번역</em> : Swift 4.2 이후로부터 hashable 이 적용된 자료형은 컴파일러에서 자체적으로 hash algorithm 이 적용됩니다. 이에 따라 보다 빠른 최적화가 필요하거나 <del>쌉컴덕</del> 이 아니라면 컴파일러에게 맡기고, <strong>아무것도 안하면 됩니다</strong> ! sturct 등은 해당 제네릭 자료형에 Hashable protocol, equatable protocl 을 적용하면 됩니다. <a href="https://www.youtube.com/watch?t=106&amp;v=MKIk8rH1OUQ&amp;feature=youtu.be">참고</a></p>
<p>Swift 내 기본 자료형들 (<em>String, Int, Double, Bool 등</em>) 은 자체적으로 hashable 를 내장하고 있으며 <code>set value</code> 나 <code>dictionary key type</code> 에 사용할 수 있습니다. Enumeration 값 역시 자체적으로 hashable 이 적용됩니다.</p>
<h4 id="set-type-synatx-set-자료형-문법">Set Type Synatx (set 자료형 문법)</h4>
<p>Set 은 <code>Set&lt;Element&gt;</code> 로 정의할 수 있으며, 배열과 달리 짧은 문법은 없습니다.</p>
<h4 id="creating-and-initializing-an-empty-set-빈-set-만들기">Creating and Initializing an Empty Set (빈 set 만들기)</h4>
<pre><code class="language-swift">var letters = Set&lt;Character&gt;()
print(letters 는 Set&lt;Character&gt; 자료형으로, \(letters.count)개의 원소를 갖고 있습니다.)
// letters 는 Set&lt;Character&gt; 자료형으로 0개의 원소를 갖고 있습니다.</code></pre>
<p>한번 Set 을 초기화하면 자료형이 정해지기에 자료형을 언급하지 않아도 됩니다. 다음과 같이 활용할 수 있습니다.</p>
<pre><code class="language-swift">letters.insert(&quot;a&quot;)
letters = []</code></pre>
<h4 id="creating-a-set-with-an-array-literal-리터럴로-set-만들기">Creating a Set with an Array Literal (리터럴로 Set 만들기)</h4>
<p>리터럴을 통해 Set 을 초기화할 수도 있습니다. </p>
<pre><code class="language-swift">var favoriteGeners: Set&lt;String&gt; = [&quot;Rock&quot;, &quot;Classical&quot;, &quot;Hip hop&quot;]
// favoriteGeners 는 3개의 원소로 초기화되었습니다.

// 다음과 같이 짧게 표현할 수도 있습니다.
var favoriteGeners: Set = [&quot;Rock&quot;, &quot;Classical&quot;, &quot;Hip hop&quot;]</code></pre>
<p>한번 선언되면, 해당 Set 는 같은 자료형만 삽입할 수 있게 됩니다.</p>
<h4 id="accessing-and-modifying-a-set-set-에-접근과-수정하기">Accessing and Modifying a Set (Set 에 접근과 수정하기)</h4>
<p>다음 메소드와 프로퍼티를 통해 Set 에 접근하거나 수정할 수 있습니다.</p>
<p>세트의 개수는 <code>count</code> 프로퍼티를 사용할 수 있습니다.</p>
<pre><code class="language-swift">print(&quot;저는 \(favoriteGenres.count)개의 음악 장르를 선호해요.&quot;)
// 출력 : 저는 3개의 음악 장르를 선호해요.</code></pre>
<p>세트가 빈 값인지 확인하고 싶다면 <code>isEmpty</code> 프로퍼티를 사용할 수 있습니다. <code>isEmpty</code> 는 <code>count == 0</code> 과 동일합니다. </p>
<pre><code class="language-swift">if favoriteGenres.isEmpty {
    print(&quot;음악이 있기만 한다면, 난 까탈쟁이는 아니에요.&quot;)
} else {
    print(&quot;전 특정 음악을 선호해요.&quot;)
}
// 출력: &quot;전 특정 음악을 선호해요. &quot;</code></pre>
<p>세트에 원소를 삽입하고 싶다면 <code>insert(_:at:)</code> 메소드 를 사용할 수 있습니다.</p>
<pre><code class="language-swift">favoriteGenres.insert(&quot;Jazz&quot;)
// favoriteGenres 는 이제 4개의 원소를 갖고 있습니다.</code></pre>
<p>이와 유사하게 세트 내 특정 인덱스를 삭제하고 싶다면 <code>remove(at:)</code> 메소드를 사용할 수 있습니다. <code>remove</code> 메소드는 삭제한 원소를 리턴하는데, 필요없다면 무시하고 사용할 수 있습니다. </p>
<pre><code class="language-swift">if let removeGenre = fvoriteGenres.remove(&quot;Rock&quot;) {
    print(&quot;\(removeGenre)? 없앱니다 ~ &quot;)
} els e{
    print(&quot;그런 장르 좋아한 적 없습니다.&quot;)
}
// 출력 : &quot;Rock&quot;? 없앱니다 ~</code></pre>
<p><em><del>너는 록을 좋아하지 않아</del></em></p>
<p><em>Note</em> : 배열의 총 크기는 <code>0</code> ~ <code>count - 1</code> 입니다. 이때 count 가 0 이라면 빈 배열로, 접근할 수 없습니다. 인덱스를 활용한다면 이 점에 유의해서 사용해주세요.</p>
<p>한편 Set 가 특정 원소를 포함하고 있는지 확인하고 싶다면 <code>contains(_:)</code> 메소드를 사용할 수 있습니다.</p>
<pre><code class="language-swift">if favoriteGenres.contains(&quot;Funk&quot;) {
    print(&quot;하하 내 화려한 발재간을 보아라&quot;)
} else {
    print(&quot;너무 시끄럽네 ..&quot;)
}
// 출력 : 너무 시끄럽네 ..</code></pre>
<h4 id="iterating-over-a-set-set-반복하기">Iterating Over a Set (Set 반복하기)</h4>
<p>세트 내 전체 값들을 <code>for-in</code> 반복문을 통해 접근할 수 있습니다.</p>
<pre><code class="language-swift">for genre in favoriteGenres {
    print(&quot;\(genre)&quot;)
}
// Classical
// Jazz
// Hip hop</code></pre>
<p>Swift 의 set 은 특정한 정렬이 없습니다. 혹시 특정한 기준으로 정렬된 set 를 반복하고 싶다면 <code>sorted()</code> 메소드를 활용해보세요. </p>
<pre><code class="language-swift">for genre in favoriteGenres.sorted() {
    print(&quot;\(genre)&quot;)
}
// Classical
// Hip hop
// Jazz</code></pre>
<h3 id="performing-set-operations-set-최적화-수행">Performing Set Operations (Set 최적화 수행)</h3>
<p>Set 자료형은 set 의 구조를 작업하는 효율적인 메소드들을 제공합니다. 합집합, 교집합, 차집합, 대칭차집합 와 같은 내용입니다.</p>
<h4 id="fundamental-set-operations-기본적인-set-작업">Fundamental Set Operations (기본적인 Set 작업)</h4>
<p>다음과 같은 작업을 수행할 수 있습니다.
<img src="https://velog.velcdn.com/images/newon-seoul/post/ed3c686e-a89e-40a9-adbc-a6ec282543d0/image.png" alt=""></p>
<ul>
<li><code>intersection(_:)</code> 메소드를 활용하여 교집합 set 을 얻을 수 있습니다.</li>
<li><code>symmetricDifference(_:)</code> 메소드를 활용하여 대칭차집합 set 을 얻을 수 있습니다.</li>
<li><code>union(_:)</code> 메소드를 활용하여 두 set 을 합칠 수 있습니다.</li>
<li><code>subtracting(_:)</code> 메소드를 활용하여 여집합 set 을 얻을 수 있습니다.</li>
</ul>
<p>코드로 표현하면 다음과 같습니다.</p>
<pre><code class="language-swift">let oddDigits: Set = [1, 3, 5, 7, 9]
let evenDigits: Set = [0, 2, 4, 6, 8]
let singleDigitPrimeNumbers: Set = [2, 3, 5, 7]

oddDigits.union(evenDigits).sorted()
// [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
oddDigits.intersection(evenDigits).sorted()
// []
oddDigits.subtracting(singleDigitPrimeNumbers).sorted()
// [1, 9]
oddDigits.symmetricDifference(singleDigitPrimeNumbers).sorted()
// [1, 2, 9]</code></pre>
<h4 id="set-membership-and-equality-set-의-소속과-동일성">Set Membership and Equality (Set 의 소속과 동일성)</h4>
<p>다음 도표를 통해 Set 의 관계를 살펴볼 수 있습니다. Set a 는 Set b 를 포함하므로 a 는 b 의 상위집합입니다. 한편 b 는 a 의 부분집합이 됩니다. Set c 는 b 와 관련이 없는 별개의 집합이 됩니다.</p>
<p><img src="https://velog.velcdn.com/images/newon-seoul/post/fbc90fe4-dd0d-4a32-846c-641effc20887/image.png" alt=""></p>
<ul>
<li><code>==</code> 연산자를 통해 두 Set 이 모두 동일한 원소들을 포함하는지 확인할 수 있습니다.</li>
<li><code>isSubset(of:)</code> 메소드를 통해 어떤 Set 이 다른 Set 의 부분집합인지 확인할 수 있습니다.</li>
<li><code>isSuperset(of:)</code> 메소드를 통해 어떤 Set 이 다른 Set 의 상위집합인지 확인할 수 있습니다.</li>
<li><code>isStrictSubset(of:)</code> 혹은 <code>isStrictSuperset(of:)</code> 메소드들을 통해 각각이 부분집합, 상위집합이되 동일한 집합이 아닌지 확인할 수 있습니다.</li>
<li><code>isDisjoint(with:)</code> 을 통해 두 Set 가 공통된 원소를 없는지 확인할 수 있습니다.</li>
</ul>
<p>코드로 표현하면 다음과 같습니다.</p>
<pre><code class="language-swift">let houseAnimals: Set = [&quot;🐶&quot;, &quot;🐱&quot;]
let farmAnimals: Set = [&quot;🐮&quot;, &quot;🐔&quot;, &quot;🐑&quot;, &quot;🐶&quot;, &quot;🐱&quot;]
let cityAnimals: Set = [&quot;🐦&quot;, &quot;🐭&quot;]

houseAnimals.isSubset(of: farmAnimals)
// true
farmAnimals.isSuperset(of: houseAnimals)
// true
farmAnimals.isDisjoint(with: cityAnimals)
// true</code></pre>
<h3 id="dictionaries-딕셔너리">Dictionaries (딕셔너리)</h3>
<p>Dictionary 는 키와 값이라는 한 쌍을 기준으로 같은 자료형을 저장하는 비정렬 컬렉션입니다. 각 값들은 고유한 키에 속하게 되며, 이를 통해 딕셔너리 내에 값들을 확인할 수 있게 됩니다. 비정렬 컬렉션이므로, 실제 사전과 같이 특정 값을 찾고 싶다면 키를 통해 확인할 수 있습니다.</p>
<p><em>Note</em>: Swift 의 딕셔너리는 Foundation 의 NSDictionary class 를 따릅니다. 자세한 사항은 <a href="https://developer.apple.com/documentation/swift/dictionary#2846239">Bridging Between Dictionary and NSDictionary</a> 에서 확인할 수 있습니다.</p>
<h4 id="dictionary-ype-shorthand-syntax-딕셔너리-자료형-줄임-표현">Dictionary Ype Shorthand Syntax (딕셔너리 자료형 줄임 표현)</h4>
<p>딕셔너리는 <code>Dictionary&lt;Key, Value&gt;</code> 의 형태로 선언되지만, <code>[Key:Value]</code> 로 짧게 표현할 수도 있습니다. 이때 Key 값은 Hashable protocol 을 따르는 자료형이어야 합니다. </p>
<h4 id="creating-an-empty-dictionary-빈-딕셔너리-만들기">Creating an Empty Dictionary (빈 딕셔너리 만들기)</h4>
<pre><code class="language-swift">var namesOfIntegers: [Int: String] = [:]
// namesOfIntegers 는 빈 [Int:String] 딕셔너리 입니다.</code></pre>
<p>한번 딕셔너리를 초기화하면 자료형이 정해지기에 자료형을 언급하지 않아도 됩니다. 다음과 같이 활용할 수 있습니다.</p>
<pre><code class="language-swift">namesOfIntegers[16] = &quot;sixteen&quot;
// namesOfIntegers 는 이제 1 쌍의 Key-Value 를 갖고 있습니다.
namesOfIntegers = [:]
// naemsOfIntegers 는 빈 딕셔너리입니다.</code></pre>
<h4 id="creating-a-set-with-an-array-literal-리터럴로-set-만들기-1">Creating a Set with an Array Literal (리터럴로 Set 만들기)</h4>
<p>리터럴을 통해 딕셔너리를 초기화할 수도 있습니다. </p>
<pre><code class="language-swift">var airports: [String: String] = [&quot;YYZ&quot;: &quot;Toronto Pearson&quot;, &quot;DUB&quot;: &quot;Dublin&quot;]
// airports 는 2개의 키-쌍 값을 갖고 있습니다.

// 다음과 같이 짧게 표현할 수도 있습니다.
var airports = [&quot;YYZ&quot;: &quot;Toronto Pearson&quot;, &quot;DUB&quot;: &quot;Dublin&quot;]</code></pre>
<p>한번 선언되면, 해당 딕셔너리는 같은 자료형만 삽입할 수 있게 됩니다.</p>
<h4 id="accessing-and-modifying-a-dictionary-딕셔너리에-접근과-수정하기">Accessing and Modifying a Dictionary (딕셔너리에 접근과 수정하기)</h4>
<p>다음 메소드와 프로퍼티를 통해 딕셔너리에 접근하거나 수정할 수 있습니다.</p>
<p>딕셔너리의 개수는 <code>count</code> 프로퍼티를 사용할 수 있습니다.</p>
<pre><code class="language-swift">print(&quot;공항 딕셔너리는 \(airports.count)개의 원소를 갖고 있습니다.&quot;)
// 출력: &quot;공항 딕셔너리는 2개의 원소를 갖고 있습니다.&quot;</code></pre>
<p>딕셔너리가 빈 값인지 확인하고 싶다면 <code>isEmpty</code> 프로퍼티를 사용할 수 있습니다. <code>isEmpty</code> 는 <code>count == 0</code> 과 동일합니다. </p>
<pre><code class="language-swift">if airports.isEmpty {
    print(&quot;공항 노선이 없습니다.&quot;)
} else {
    print(&quot;공항 노선이 있습니다.&quot;)
}
// Prints &quot;공항 노선이 없습니다.&quot;</code></pre>
<p>딕셔너리에 원소를 삽입하고 싶다면 인덱스 문법을 사용할 수 있습니다.</p>
<pre><code class="language-swift">airports[&quot;LHR&quot;] = &quot;London&quot;
// 공항 딕셔너리는 이제 3개의 원소를 갖고 있습니다.</code></pre>
<p>딕셔너리의 원소를 수정하고 싶을때도 인덱스 문법을 사용할 수 있습니다.</p>
<pre><code class="language-swift">airports[&quot;LHR&quot;] = &quot;London Heathrow&quot;
// &quot;LHR&quot; 의 값은 &quot;London Heathrow&quot; 로 변경되었습니다.</code></pre>
<p>인덱스 문법 대신 <code>updateValue(_:forKey:)</code> 메소드를 통해 특정 키의 값을 수정할 수 있습니다. 이때 <code>updateValue(_:forKey:)</code> 메소드는 해당 키가 존재하지 않는다면 <code>nil</code> 을 존재한다면 이전의 <code>value</code> 를 리턴합니다.</p>
<pre><code class="language-swift">if let oldValue = airports.updateValue(&quot;Dublin Airport&quot;, forKey: &quot;DUB&quot;) {
    print(&quot;DUB 키의 이전 값은 \(oldValue) 입니다.&quot;)
}
// 출력: &quot;DUB 키의 이전 값은 Dublin 입니다.&quot;</code></pre>
<p>인덱스 문법 역시 이와 유사한 표현을 사용할 수 있습니다. 단, <code>updateValue(_:forKey:)</code> 메소드와 달리 이전의 값이 있더라도 그 값을 리턴하지 않습니다.</p>
<pre><code class="language-swift">if let airportName = airports[&quot;DUB&quot;] {
    print(&quot;공항 이름은 \(airportName) 입니다.&quot;)
} else {
    print(&quot;해당 공항은 없습니다.&quot;)
}
// Prints &quot;공항 이름은 Dublin Airport 입니다.&quot;
</code></pre>
<p>딕셔너리 내 특정 키를 삭제하고 싶다면 인덱스 문법을 활용하여 특정 키에 nil 을 할당하면 됩니다.</p>
<pre><code class="language-swift">airports[&quot;APL&quot;] = &quot;Apple International&quot;
// &quot;Apple International&quot; 는 실제 공항이 아니므로 삭제합니다.
airports[&quot;APL&quot;] = nil
// APL 은 딕셔너리에서 삭제되었습니다.</code></pre>
<p>이와 유사하게 <code>remove(at:)</code> 메소드를 사용할 수 있습니다. <code>remove</code> 메소드는 삭제한 원소를 리턴하는데, 필요없다면 무시하고 사용할 수 있습니다. </p>
<pre><code class="language-swift">if let removedValue = airports.removeValue(forKey: &quot;DUB&quot;) {
    print(&quot;삭제된 공항의 이름은 \(removedValue) 입니다.&quot;)
} else {
    print(&quot;공항 딕셔너리는 DUB 키에 값을 갖고 있지 않습니다.&quot;)
}
// 출력: &quot;삭제된 공항의 이름은 \(removedValue) 입니다.&quot;</code></pre>
<h4 id="iterating-over-a-dictionary-딕셔너리-반복하기">Iterating Over a Dictionary (딕셔너리 반복하기)</h4>
<p>딕셔너리 내 전체 값들을 <code>for-in</code> 반복문을 통해 접근할 수 있습니다.</p>
<pre><code class="language-swift">for (airportCode, airportName) in airports {
    print(&quot;\(airportCode): \(airportName)&quot;)
}
// LHR: London Heathrow
// YYZ: Toronto Pearson</code></pre>
<p>딕셔너리의 키나 벨류로 반복하고 싶다면 다음과 같이 사용할 수 있습니다.</p>
<pre><code class="language-swift">for airportCode in airports.keys {
    print(&quot;공항 코드: \(airportCode)&quot;)
}
// 공항 코드: LHR
// 공항 코드: YYZ

for airportName in airports.values {
    print(&quot;공항 이름: \(airportName)&quot;)
}
// 공항 이름: London Heathrow
// 공항 이름: Toronto Pearson</code></pre>
<p>혹시 API 에 사용하기 위해 딕셔너리의 키나 벨류가 필요하다면 <code>Array instance</code> 를 활용할 수 있습니다.</p>
<pre><code class="language-swift">let airportCodes = [String](airports.keys)
// airportCodes 는 [&quot;LHR&quot;, &quot;YYZ&quot;]

let airportNames = [String](airports.values)
// airportNames 는 [&quot;London Heathrow&quot;, &quot;Toronto Pearson&quot;]</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Swift-Language Guide 5.7 / Strings and Characters (야매 번역 + 정리)]]></title>
            <link>https://velog.io/@newon-seoul/Swift-Language-Guide-5.7</link>
            <guid>https://velog.io/@newon-seoul/Swift-Language-Guide-5.7</guid>
            <pubDate>Fri, 24 Jun 2022 11:08:54 GMT</pubDate>
            <description><![CDATA[<h3 id="초록">초록</h3>
<p>String 자료형은 Character 의 연속체로서 &quot;hello, world&quot; 나 &quot;albatross&quot; 와 같은 것을 의미합니다. Swift 의 자료형 String 과 Character 는 코드 속의 텍스트를 유니코드와 빠르게 호환할 수 있도록 합니다. </p>
<p><em>Note</em>: Swift 의 String 자료형은 Foundation 내 NSString 와 연결되어 있습니다. Foundation 역시 String 자료형을 표현하기 위해 NSString 를 정의하고 있습니다. 이에 따라, Foundation 을 import 한다면 String 에서 NSSring 메소드들을 별다른 캐스팅 없이 사용할 수 있게 됩니다.</p>
<p>자세한 사항은 <a href="https://developer.apple.com/documentation/swift/string#2919514">Bridging Between String and NSString</a> 을 참고해주세요.</p>
<br/>
<br/>

<h3 id="string-literals-문자열-리터럴">String Literals (문자열 리터럴)</h3>
<p>Swift 에서 문자열 리터럴은 <code>&quot;&quot;</code> 에 감쌓인 캐릭터들의 연속체들입니다. 
다음과 같이 문자열 리터럴을 초기화할 수 있습니다.</p>
<pre><code class="language-swift">let someString = &quot;Some string literal value&quot;</code></pre>
<pre><code>번역 : 리터럴은 데이터 값 그 자체를 의미한다.
예시)  let a = 1 
      a는 변수 / 1은 리터럴 이다.</code></pre><br/>
<br/>

<h3 id="multiline-string-literals-다중-문자열스트링-리터럴">Multiline String Literals (다중 문자열스트링 리터럴)</h3>
<p>필요하다면 다중 문자열 리터럴 - 캐릭터 연속체가 3개의 <code>&quot;</code> 로 감싸인 형태- 를 사용할 수 있습니다.</p>
<pre><code class="language-swift">let quotation = &quot;&quot;&quot;
하얀 토끼는 자신의 안경을 내려놓았다. 그는 &quot;어디서부터 시작하면 될까요,
주인님?&quot; 라고 물어왔다.

&quot;네가 시작한 곳에서 시작해라,&quot; 왕은 장엄하게 답하였다. &quot;그리고 네가 마지막에 다다를 때 까지 가서, 그곳에서 멈추어라.&quot;
&quot;&quot;&quot;

// 번역 : Velog 의 편집기가 &quot;&quot;&quot; &quot;&quot;&quot; 를 인식 못 하고 있지만, 
// 실제 사용 시 전문이 하나의 String 으로 들어가게 됩니다.</code></pre>
<p>이때 가독성을 위해, 백슬래시(\) 를 사용하여 코드 내에서 띄워쓰기를 표현할 수 있습니다.</p>
<p>한편 종결 <code>&quot;&quot;&quot;</code> 에서 공백 문자를 포함하면 다중 문자열 리터럴의 포맷에 들여쓰기를 할 수 있습니다. 이때 들여쓰이는 내용은 코드에만 반영될 뿐, 실제 출력에는 영향을 미치지 않습니다.</p>
<p><img src="https://velog.velcdn.com/images/newon-seoul/post/a7bfd308-85ed-4c7e-8078-6d9fda874f46/image.png" alt="종결 &quot;&quot;&quot;"></p>
<p>상단의 예시에서 종결 <code>&quot;&quot;&quot;</code> 에 4개의 공백문자를 쓰면 <code>&quot;&quot;&quot;</code> <code>&quot;&quot;&quot;</code> 내부의 문자열은 4개의 공백문자를 무시하게 됩니다. 2번째 문단을 보면 4개의 공백문자가 추가로 들어가있는데 이는 반영되어 4개의 공백문자 이후에 문자열이 시작됩니다.</p>
<br/>
<br/>

<h3 id="special-characters-in-string-literals-문자열-리터럴-내-특별한-캐릭터">Special Characters in String Literals (문자열 리터럴 내 특별한 캐릭터)</h3>
<p>문자열 리터럴은 다음과 같은 특별한 캐릭터들을 사용할 수 있습니다.</p>
<ul>
<li>탈출 문자 <code>\</code>,  <code>\0 == null</code>, <code>\\ == 백슬래시</code>, <code>\t == 수평 탭</code>, <code>\n == 한줄 띄기</code>, <code>\r == 리턴</code>, <code>\&quot; == 큰 따옴표</code>, <code>\&#39; == 작은 따옴표</code></li>
<li>임의의 유니코드 스칼라 값, <code>\u{n}</code> 의 형태로 적으며 n 에는 1 ~ 8 의 16진법 숫자가 들어갈 수 있습니다. (유니코드는 <a href="https://docs.swift.org/swift-book/LanguageGuide/StringsAndCharacters.html#ID293">유니코드</a> 에서 다룹니다.)</li>
</ul>
<pre><code class="language-swift">let wiseWords = &quot;\&quot;상상이 지식보다 더 중요하다.\&quot; - 아인슈타인&quot;
// &quot;상상이 지식보다 더 중요하다.&quot; - 아인슈타인
let dollarSign = &quot;\u{24}&quot; // $, 유니코드 스칼라 U+0024
let blackHeart = &quot;\u{2665} // 🖤, 유니코드 스칼라 U+2665
let sparklingHeart = &quot;\u{1F496} // 💖, 유니코드 스칼라 U+1F496</code></pre>
<p>이때 <code>&quot;&quot;&quot;</code> 를 사용한 다중 문자열 리터럴에서 &quot;&quot;&quot; 를 표현하고 싶다면 <code>\&quot;\&quot;\&quot;</code> 형태로 표현해야 합니다.</p>
<br/>
<br/>

<h3 id="extended-string-delimiters-확장-문자열-구분자">Extended String Delimiters (확장 문자열 구분자)</h3>
<p>문자열을 호출할 때 따옴표 양 옆에 문자열을 추가함으로써, 탈출 캐릭터를 <code>\</code> 에서 <code>\추가한 캐릭터</code> 형태로 바꿀 수 있습니다.</p>
<pre><code class="language-swift">#&quot;1번째 줄 \n 2번째줄&quot;#
#&quot;1번째 줄 \#n 2번째줄&quot;#

// 출력 : 1번째 줄 \n 2번째줄
// 출력 : 1번째 줄
//       2번째 줄
</code></pre>
<br/>
<br/>

<h3 id="initializing-an-empty-string-빈-문자열-초기화">Initializing an Empty String (빈 문자열 초기화)</h3>
<p>빈 문자열 값을 생성하거나, 할당하고 싶다면 다음과 같은 방법으로 사용할 수 있습니다.</p>
<pre><code class="language-swift">var emptyString = &quot;&quot;
var anotherEmptyString = String()
// 모두 빈 문자열이자 동일한 값을 지닙니다.</code></pre>
<br/>
<br/>

<h3 id="string-mutability-문자열-호환">String Mutability (문자열 호환)</h3>
<p>특정 문자열을 수정하거나 추가할 수 있으나, <code>var</code> 문자열에만 적용되고 <code>let</code> 문자열은 수정할 수 없습니다.</p>
<pre><code class="language-swift">var variableString = &quot;말&quot;
variableString += &quot;과 마차&quot;
// variableString 은 이제 &quot;말과 마차&quot; 입니다.

let constantString = &quot;하이랜더&quot;
let constantString += &quot;와 또 다른 하이랜더&quot;

// 컴파일 에러가 납니다.
// 번역 : 하이랜더는 머리가 잘리지만 않으면 불사신인 존재끼리
//       영혼의 맞다이를 떠서 살아남는 사람이 상을 받는다는 영화에서 나온 존재</code></pre>
<br/>
<br/>

<h3 id="strings-are-value-types-문자열은-값-타입이다">Strings are Value Types (문자열은 값 타입이다.)</h3>
<p>Swift 의 문자열 자료형은 값 타입입니다. 만약 새로운 문자열 값을 생성하고, 그 문자열이 함수나 메소드 등에 의해서 복사되거나, 변수나 상수에 할당된다면 복사본은 기존의 문자열 자료형에서 생성된, 새로운 문자열입니다. 값 타입은 <a href="https://docs.swift.org/swift-book/LanguageGuide/ClassesAndStructures.html#ID88">이곳</a>에서 더 상세하게 기술되어 있습니다.</p>
<p>Swift 의 복사 전제 문자열 행동은 문자열 값을 전달할 때 정확히 똑같은 값이지만, 어디에서 왔는지 확인할 필요 없는 새로운 값을 갖게 됩니다. 따라서 전달하는 문자열은 수정되지 않음을 확신할 수 있게 됩니다.</p>
<p>화면 뒷단에서 Swift 컴파일러는 문자열 사용의 최적화를 진행하며 오로지 필요할 때만 복사하게끔 합니다. 이에따라 개발자들은 언제나 문자열을 값 타입으로써 훌륭한 성능을 얻을 수 있게 됩니다.</p>
<p><del>근데 백준에서 왜 그렇게 안되는게 많아요</del></p>
<br/>
<br/>

<h3 id="working-with-characters-캐릭터-활용하기">Working with Characters (캐릭터 활용하기)</h3>
<p><code>for-in</code> 과 이터레이팅(반복)을 사용하여 각각의 캐릭터 값을 문자열로부터 얻을 수 있습니다.</p>
<pre><code class="language-swift">for character in &quot;Dog!🐶&quot;{
    print(character)
}
// D
// o
// g
// !
// 🐶</code></pre>
<p>이와 유사하게, 하나의 값만 담고있는 문자열로부터 캐릭터 변수나 상수를 만들 수도 있습니다. </p>
<pre><code class="language-swift">let exclmationMark: Character = &quot;!&quot;</code></pre>
<p>문자열은 캐릭터 배열을 전달하여 만들 수도 있습니다.</p>
<pre><code class="language-swift">let catCharacters: [Character] = [&quot;고&quot;, &quot;양&quot;, &quot;이&quot;, &quot;!&quot;, &quot;🐱&quot;]
let catString = String(catCharacters)
print(catString)

// &quot;고양이!🐱&quot; 가 출력된다.</code></pre>
<br/>
<br/>

<h3 id="concatenating-strings-and-characters-문자열과-캐릭터-연결">Concatenating Strings and Characters (문자열과 캐릭터 연결)</h3>
<p>문자열 값은 덧셈 연산자 <code>+</code> 를 활용하여 새로운 문자열 값으로 만들 수 있습니다.</p>
<pre><code class="language-swift">// 번역 : 그런데 String + Character 은 안됩니다.

var string = &quot;조아 햄 버 거&quot;
var character: Character = &quot;!&quot;
print(string + character)

// 오류 - Character 를 String 으로 바꿀 수 없습니다.
// 이를 위해서 string.append() 를 사용할 수 있습니다.

var string = &quot;조아 햄 버 거&quot;
var character: Character = &quot;!&quot;
string.append(character)
print(string)

// 출력 : 조아 햄 버 거!</code></pre>
<p>다중 문자열 리터럴 <code>&quot;&quot;&quot;</code> 에서 한 줄을 띄우지 않으면 끝난 지점에서 바로 다음 문자열이 붙게 됩니다.</p>
<pre><code class="language-swift">let badStart = &quot;&quot;&quot;
one
two
&quot;&quot;&quot;

let end = &quot;&quot;&quot;
three
&quot;&quot;&quot;
print(badStart + end)
// one
// twoThree

let goodStart = &quot;&quot;&quot;
one
two

&quot;&quot;&quot;
print(goodStart + end)
// one
// two
// three</code></pre>
<br/>
<br/>

<h3 id="string-interpolation문자열-보간">String Interpolation(문자열 보간)</h3>
<p>문자열 보간은 문자열 내에 새로운 문자열 값을 포함하는 방법을 의미합니다.</p>
<pre><code class="language-swift">let multiplier = 3
let message = &quot;\(multiplier) 곱하기 2.5 는 \(Double(multiplier) * 2.5)&quot;

// 출력 3 곱하기 2.5 는 7.5</code></pre>
<p>문자열 보간 때 확장 문자열 구분자를 사용하면 확장 문자열 구분자를 포함하여야 합니다.</p>
<pre><code class="language-swift">let multiplier = 3
let message = #&quot;\#(multiplier) 곱하기 2.5 는 \#(Double(multiplier) * 2.5)&quot;#

// 출력 3 곱하기 2.5 는 7.5</code></pre>
<br/>
<br/>

<h3 id="unicode-유니코드">Unicode (유니코드)</h3>
<p>유니코드는 국제적인 규격으로 다양한 출력 시스템 내에서 인코딩, 표현과 텍스트 출력을 위해 사용됩니다. 유니코드를 통해 개발자는 외부 - 텍스트 파일이나 웹 페이지 등 - 에서 온 다른 언어의 캐릭터 자료형도 규격화된 양식 안에서 표현할 수 있게 되며, 해당 글자들을 읽고 쓸 수 있게 됩니다. 
Swift 의 문자열과 캐릭터는 유니코드 호환 자료형이며 이번 목차에서 설명합니다.</p>
<br/>

<h4 id="unicode-scalar-values-유니코드-스칼라-값">Unicode Scalar Values (유니코드 스칼라 값)</h4>
<p>화면 뒷단에서, Swift 의 네이티브 문자열 자료형은 유니코드 스칼라 값을 통해 만들어집니다. 유니코드 스칼라 값은 21 비트 크기의 숫자 혹은 캐릭터, 수정자를 표현하는 고유한 값입니다. 이를테면 U+0061 은 &quot;LATIN SMALL LETTER A&quot; 인 &quot;a&quot; 를 표현하고, U+1F425 는 &quot;서 있는 병아리&quot; 를 의미합니다.</p>
<pre><code class="language-swift">번역 : 앞으로 나오는 유니코드는 
      한국어 문자뷰어 (한국 맥에서 fn 키를 누르면 나오는 표현) 를 사용합니다.</code></pre>
<br/>

<h4 id="extended-grapheme-clusters확장된-음운-단위체들">Extended Grapheme Clusters(확장된 <a href="https://ko.dict.naver.com/#/entry/koko/f5422a924ba047e884e883054e4da8db">음운</a> 단위체들)</h4>
<p>Swift 내 모든 인스턴스된 캐릭터 자료형들은 하나의 음운을 표현합니다. 확장 음운 단위체는 하나 이상의 유니코드 스칼라들을 합쳐서 만들어진 값이 됩니다.</p>
<p>확장된 음운 단위체들은 복잡한 문자 체계를 하나의 캐릭터 값으로 표현하는데 편리한 기능을 제공합니다. 예를 들어 한국어의 알파벳인 한글은 유니코드의 합쳐진 형태와 분리된 형태로 나누어서 표현할 수 있게 됩니다. Swift 에서는 두 형태 모두 하나의 캐릭터로써 값을 지니게 됩니다.</p>
<pre><code class="language-swift">let precomposed: Character = &quot;\u{D55c}&quot; // 한
let decomposed: Character = &quot;\u{1112}\u{1161}\u{11AB}&quot; // ㅎ, ㅏ, ㄴ

// precompose 는 &quot;한&quot; 이며
// decomposed 역시 &quot;한&quot; 이 된다.</code></pre>
<p>한편 유니코드 스칼라에서 지역 상징 표현은 한 쌍의 캐릭터 값으로 묶어서 해당 국기를 표현할 수 있습니다. </p>
<pre><code class="language-swift">let regionalIndicatorForUS: Character = &quot;\u{1F1FA}\u{1F1F8}&quot;
// regionalIndicatorForUS == 🇺🇸</code></pre>
<br/>
<br/>

<h3 id="counting-characters캐릭터-개수-세기">Counting Characters(캐릭터 개수 세기)</h3>
<p>문자열 값의 캐릭터 갯수를 세기 위해서 문자열 값의 count 프로퍼티를 사용할 수 있습니다.</p>
<pre><code class="language-swift">let unusualMenagerie = &quot;Koala 🐨, Snail 🐌, Penguin 🐧, Dromedary 🐪&quot; 
print(&quot;unusualMenagerie 은 \(unusualMenagerie.count) 캐릭터를 갖고 있습니다.&quot;) 
// Prints &quot;unusualMenagerie 은 40 캐릭터를 갖고 있습니다.&quot;</code></pre>
<p>이때 Swift 는 확장 음운 단위체를 캐릭터에 사용하므로, 문자열 합치기나 수정이 언제나 문자열 캐릭터 갯수에 영향을 미치지 않습니다.</p>
<pre><code class="language-swift">번역 :
한국어의 경우 &quot;한&quot; 으로 표기하든 &quot;ㅎ&quot;,&quot;ㅏ&quot;,&quot;ㄴ&quot; 으로 표기하든
swift 는 1개의 캐릭터로 인식하므로
언제나 문자열 + 문자열이 갯수가 늘어나는 것은 아니라는 것을 말한다.


예시 ) var ha:Character = &quot;\u{1112}\u{1161}&quot; // 하
      var n:Character  = &quot;\u{11AB}&quot;         // ㄴ
      var han = String(ha) + String(n)
      print(&quot;\(han), \(han.count)&quot;)
      // 출력 한, 1</code></pre>
<p><em>Note</em>: 확장 음운 단위체는 다중의 유니코드 스칼라와 합쳐질 수 있습니다.같은 캐릭터라도 다른 표기를 한다면 메모리의 양 역시 달라질 수 있음을 의미합니다. 이때문에 Swift 는 각각의 문자열들이 동일한 메모리를 저장하고 있지 않게 됩니다. 이와 마찬가지 이유로 문자열의 캐릭터 수 또한 반복(iterating)을 통해 해당 문자열의 확장 음운 단위들을 확인해야만 알 수 있게 됩니다. 특별하게 긴 문자열 값들을 다룬다면 갯수 프로퍼티는 반드시 반복(iterate) 를 통해서 전체 문자열 내 유니코드 스칼라를 확인할 것이고, 그에 따라 문자열 내 캐릭터의 갯수를 정한다는 것을 주의하세요. </p>
<p>같은 캐릭터를 포함하더라도 count 프로퍼티를 통해 반환된 캐릭터들의 카운트가 언제나 NSString 의 length 와 같은 값을 갖는 것은 아닙니다. NSString 의 length 는 UTF-16 표현에 의한 16비트 코드 유닛의 갯수를 세는 반면 count 는 확장 음운 단위에 준한 값으로 계산하기 때문입니다.</p>
<br/>
<br/>

<h3 id="accessing-and-modifying-a-string문자열-접근과-수정">Accessing and Modifying a String(문자열 접근과 수정)</h3>
<p>문자열 메소드나 프로퍼티, 서브스크립트 문법을 활용하여 문자열에 접근하거나 수정할 수 있습니다.</p>
<br/>

<h4 id="string-indices문자열-인덱스">String Indices(문자열 인덱스)</h4>
<p>각 문자열 값은 String.Index 라는 인덱스와 연결되어 있습니다. String.Index 는 문자열 내 각 캐릭터들의 자리를 표현합니다.</p>
<p>상단에서 언급되엇듯, 다른 캐릭터들은 다른 메모리의 저장을 요구합니다. 이에 따라 캐릭터의 명확한 자리를 확정하고 싶다면 String 의 시작부터 끝까지 각각의 유니코드 스칼라를 반복해서 확인해야 합니다. 이러한 이유로 스위프트는 정수 값의 인덱스를 제공할 수 없습니다.</p>
<p>startIndex 프로퍼티를 사용하여 문자열의 첫번째 캐릭터에 접근할 수 있습니다. 한편 endIndex 프로퍼티를 사용하여 문자열의 마지막 캐릭터 다음의 값에 접근할 수 있습니다. 이에 따라 endIndex 프로퍼티는 문자열 내 subscript 의 매개변수로 유요한 값을 전달하지 못합니다. 만약 문자열이 비었다면 startIndex 와 endIndex 는 같습니다.</p>
<p>subscript 문법을 활용하여 문자열의 특정 인덱스에 접근할 수 있습니다.</p>
<pre><code class="language-swift">let greeting = &quot;Guten Tag!&quot;
greeting[greeting.startIndex]
// G
greeting[greeting.index(before: greeting.endIndex)]
// !
greeting[greeting.index(after: greeting.startIndex)]
// u
let index = greeting.index(greeting.startIndex, offsetBy: 7)
greeting[index]
// a</code></pre>
<p>만약 문자열의 범위를 벗어나는 인덱스를 조회하려고 하면 문자열 범위는 런타임 에러를 발생시킬 것 입니다.</p>
<pre><code class="language-swift">greeting[greeting.endIndex] // Error
greeting.index(after: greeting.endIndex) // Error</code></pre>
<p>indices 프로퍼티를 활용하여 문자열 내 각각의 캐릭터에 접근할 수 있습니다.</p>
<pre><code class="language-swift">for index in greeting.indices {
    print(&quot;\(greeting[index]) &quot;, terminator: &quot;&quot;)
}
// Prints &quot;G u t e n   T a g ! &quot;</code></pre>
<br/>

<h4 id="inserting-and-removing">Inserting and Removing</h4>
<p>단일 캐릭터를 문자열의 특정 위치에 삽입하고 싶다면 inser(_:at:) 을 사용할 수 있습니다. </p>
<pre><code class="language-swift">var welcome = &quot;hello&quot;
welcome.insert(&quot;!&quot;, at: welcome.endIndex)
// welcome now equals &quot;hello!&quot;

welcome.insert(contentsOf: &quot; there&quot;, at: welcome.index(before: welcome.endIndex))
// welcome now equals &quot;hello there!&quot;</code></pre>
<p>삭제는 다음과 같습니다.</p>
<pre><code class="language-swift">welcome.remove(at: welcome.index(before: welcome.endIndex))
// welcome now equals &quot;hello there&quot;

let range = welcome.index(welcome.endIndex, offsetBy: -6)..&lt;welcome.endIndex
welcome.removeSubrange(range)
// welcome now equals &quot;hello&quot;</code></pre>
<br/>
<br/>

<h3 id="substrings-부분-문자열">Substrings (부분 문자열)</h3>
<p>subscript 나 prefix(_:) 와 같은 메소드를 사용하여 부분 문자열 =을 얻으면, 이 인스턴스된 결과는 문자열 이 아닌 부분 문자열이 됩니다. 부분 문자열 는 Swift 의 문자열과 유사한 자료형으로, 문자열과 같이 사용할 수 있습니다. 다만 문자열과 다르게 짧은 작업을 위해서 사용할 것을 권장합니다. 만약 결과값을 저장하여 긴 시간 동안 사용하고 싶다면 부분 문자열 을 문자열 인스턴스로 바꿔서 저장할 것을 권장합니다.</p>
<pre><code class="language-swift">let greeting = &quot;Hello, world!&quot;
let index = greeting.firstIndex(of: &quot;,&quot;) ?? greeting.endIndex
let beginning = greeting[..&lt;index]
// beginning is &quot;Hello&quot;

// Convert the result to a String for long-term storage.
let newString = String(beginning)</code></pre>
<p>부분 문자열과 문자열의 차이는, 최적화를 위해서 부분 문자열은 원본 문자열의 메모리를 재사용한다는 것 입니다. (문자열 역시 비슷한 최적화를 갖고 있으나, 만약 두 문자열이 같은 메모리를 공유한다면 이는 같은 것으로 간주됩니다.) 이 최적화는 실제로 문자열이나 부분 문자열의 값을 수정하기 전까지는 메모리를 복사하는 비용을 지불하지 않도록 도와줍니다. 그렇기에 부분 문자열을 장 기간 사용하는 것을 지향하게 됩니다. 부분 문자열은 문자열의 저장 공간을 재사용하기 때문에, 전체 문자열이 부분 문자열을 위해 계속해서 메모리상에 존재해야하기 때문입니다.</p>
<p>상단의 예시에서 <code>greeting</code> 은 문자열로, 실제 메모리 상에서 저장되어 있는 값입니다. 한편 <code>beginning</code> 은 <code>greeting</code> 의 부분 문자열이기 때문에 <code>beginning</code> 은 <code>greeting</code> 의 저장 공산을 재 사용하게 됩니다. 이에 반해 <code>newString</code> 은 새로운 문자열을 인스턴스하며 메모리상에 적재되었습니다. 이를 다음과 같이 도식화할 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/newon-seoul/post/28d45271-eed8-4e16-ac22-065610f03401/image.png" alt=""></p>
<p><em>Note</em>: 문자열과 부분 문자열은 모두 StringProtocol 프로토콜을 따릅니다. 이는 문자열과 관련된 메소드나 함수를 사용할 때 StringProtocol 값을 받아들인다는 뜻 입니다. 그렇기에 개발자는 문자열이나 부분 문자열에 StringProtocl 내 함수들을 사용할 수 있습니다.</p>
<br/>
<br/>

<h3 id="comparing-strings">Comparing Strings</h3>
<p>Swift 는 동일, 접두사 동일, 접미사 동일 3개의 텍스트 비교 값을 제공합니다.</p>
<br/>

<h4 id="문자열과-캐릭터-비교">문자열과 캐릭터 비교</h4>
<p>두 문자열 비교는 <code>==</code> 혹은 <code>!=</code> 로 확인할 수 있습니다. 이때, 두 문자열 사이에 확장 음운 단위가 있다면 이는 사람이 일반적으로 받아들이는 언어적 의미에서 동일한지에 대해서 비교합니다. </p>
<pre><code class="language-swift">즉 Unicode 를 활용한 확장 음운이 존재하면, 
두 문자열이 &quot;언어적&quot;으로 같은 지 확인한다는 뜻입니다.

예를 들어 유니코드로 적은 &quot;한&quot; 과 &quot;ㅎ&quot;,&quot;ㅏ&quot;,&quot;ㄴ&quot; 은
동일한 문자열이 되지만
라틴알파벳 &quot;à(`a)&quot; 와 러시아 알파벳 &quot;à(`a)&quot; 는 다르게 인식된다는 뜻입니다.</code></pre>
<br/>

<h4 id="접두사와-접미사-비교">접두사와 접미사 비교</h4>
<p>두 문자열이 특정한 접두사나 접미사를 가지고 있는지 확인하려면 string prefix 혹은 suffix 를 사용할 수 있습니다. 
메소드는 <code>string.hasPrefix(_:)</code>,<code>string.hasSuffix(_:)</code>  으로, 두 메소드 다 문자열 매개변수를 받고 Boolean 값을 리턴합니다.</p>
<p>다음과 같은 예시에서 사용할 수 있습니다.</p>
<pre><code class="language-swift">let romeoAndJuliet = [
    &quot;Act 1 Scene 1: Verona, A public place&quot;,
    &quot;Act 1 Scene 2: Capulet&#39;s mansion&quot;,
    &quot;Act 1 Scene 3: A room in Capulet&#39;s mansion&quot;,
    &quot;Act 1 Scene 4: A street outside Capulet&#39;s mansion&quot;,
    &quot;Act 1 Scene 5: The Great Hall in Capulet&#39;s mansion&quot;,
    &quot;Act 2 Scene 1: Outside Capulet&#39;s mansion&quot;,
    &quot;Act 2 Scene 2: Capulet&#39;s orchard&quot;,
    &quot;Act 2 Scene 3: Outside Friar Lawrence&#39;s cell&quot;,
    &quot;Act 2 Scene 4: A street in Verona&quot;,
    &quot;Act 2 Scene 5: Capulet&#39;s mansion&quot;,
    &quot;Act 2 Scene 6: Friar Lawrence&#39;s cell&quot;
]</code></pre>
<p>위와 같은 본문이 있을 때, prefix 를 활용하여 접두사를 확인할 수 있습니다.</p>
<pre><code class="language-swift">var act1SceneCount = 0
for scene in romeoAndJuliet {
    if scene.hasPrefix(&quot;Act 1 &quot;) {
        act1SceneCount += 1
    }
}
print(&quot;There are \(act1SceneCount) scenes in Act 1&quot;)
// Prints &quot;There are 5 scenes in Act 1&quot;</code></pre>
<p>한편 suffix 를 활용하여 접미사도 확인할 수 있습니다.</p>
<pre><code class="language-swift">var mansionCount = 0
var cellCount = 0
for scene in romeoAndJuliet {
    if scene.hasSuffix(&quot;Capulet&#39;s mansion&quot;) {
        mansionCount += 1
    } else if scene.hasSuffix(&quot;Friar Lawrence&#39;s cell&quot;) {
        cellCount += 1
    }
}
print(&quot;\(mansionCount) mansion scenes; \(cellCount) cell scenes&quot;)
// Prints &quot;6 mansion scenes; 2 cell scenes&quot;</code></pre>
<p>prefix 와 suffix 역시 확장 음운 단위가 있다면, <em>문자열과 캐릭터 비교</em> 에서 처럼 언어의 의미적 단위에서 비교하게 됩니다.</p>
<br/>
<br/>

<h3 id="unicode-representations-of-strings문자열의-유니코드-표현법">Unicode Representations of Strings(문자열의 유니코드 표현법)</h3>
<p>유니코드 문자열을 텍스트 파일에 작성하거나 저장할 때, 문자열 내 유니코드 스칼라들은 유니코드에서 사전 정의된 여러 인코딩 양식 중 하나를 따라 인코딩됩니다. 각 양식은 코드 유닛이라 부르는 작은 덩어리들로 문자열을 인코딩합니다. </p>
<p>양식에는 UTF-8 양식 (문자열을 8 비트 코드 유닛으로 인코딩), UTF-16 양식(문자열을 16 비트 코드 유닛으로 인코딩), UTF-32 양식(문자열을 32 비트 코드 유닛으로 인코딩) 이 있습니다.</p>
<p>Swift 는 문자열의 유니코드 표현법 접근을 위해 여러 방법을 제공합니다. <code>for-in</code> 구문을 활용해서 반복(iterating) 할 수 있으며, 유니코드 확장 음운 단위로서 각 캐릭터 값에 접근할 수 있습니다. 이 프로세스는 상단의 Working with Characters 에서 설명되었습니다.</p>
<p>대체적으로 문자열 값은 3개의 유니코드 컴파일 표현법으로 접근할 수 있습니다.</p>
<ul>
<li>UTF-8 코드 유닛 집합</li>
<li>UTF-16 코드 유닛 집합</li>
<li>21 비트 유니코드 스칼라 값 집합 (값은 UTF-32 인코딩과 동일)</li>
</ul>
<p>각 표현법은 같은 <code>let dogString = &quot;Dog!!&quot;🐶</code> 도 다르게 표현됩니다.</p>
<br/>

<h4 id="utf-8-representationsutf-8-표현법">UTF-8 Representations(UTF-8 표현법)</h4>
<p><img src="https://velog.velcdn.com/images/newon-seoul/post/3aa003a4-bc72-445c-8f4d-da03f1f45abf/image.png" alt=""></p>
<pre><code class="language-swift">for codeUnit in dogString.utf8 {
    print(&quot;\(codeUnit) &quot;, terminator: &quot;&quot;)
}
print(&quot;&quot;)
// Prints &quot;68 111 103 226 128 188 240 159 144 182 &quot;</code></pre>
<p>이때 <code>&quot;D&quot;, &quot;o&quot;, &quot;g&quot;</code> 는 <code>ASCII</code> 코드와 동일한 값입니다.</p>
<br/>

<h4 id="utf-16-representationsutf-16-표현법">UTF-16 Representations(UTF-16 표현법)</h4>
<p><img src="https://velog.velcdn.com/images/newon-seoul/post/82c1fad1-2241-4f8c-a0bb-5b029f285167/image.png" alt=""></p>
<pre><code class="language-swift">for codeUnit in dogString.utf16 {
    print(&quot;\(codeUnit) &quot;, terminator: &quot;&quot;)
}
print(&quot;&quot;)
// Prints &quot;68 111 103 8252 55357 56374 &quot;</code></pre>
<p>마찬가지로  <code>&quot;D&quot;, &quot;o&quot;, &quot;g&quot;</code> 는 <code>ASCII</code> 코드와 동일한 값입니다.</p>
<br/>

<h4 id="unicode-scalar-representation유니코드-스칼라-표현법">Unicode Scalar Representation(유니코드 스칼라 표현법)</h4>
<p><img src="https://velog.velcdn.com/images/newon-seoul/post/97278ca6-23ab-460a-b1e6-b7719e427735/image.png" alt=""></p>
<pre><code class="language-swift">for scalar in dogString.unicodeScalars {
    print(&quot;\(scalar.value) &quot;, terminator: &quot;&quot;)
}
print(&quot;&quot;)
// Prints &quot;68 111 103 8252 128054 &quot;</code></pre>
<p>이때 참고로, 다음과 같은 표현으로 각 scalr 에 접근할 수 있습니다.</p>
<pre><code class="language-swift">for scalar in dogString.unicodeScalars {
    print(&quot;\(scalar) &quot;)
}
// D
// o
// g
// ‼
// 🐶</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Swift-Language Guide 5.7 / Basic Operators (야매 번역 + 정리)]]></title>
            <link>https://velog.io/@newon-seoul/Swift-Language-Guide-5.7-Basic-Operators-%EB%B2%88%EC%97%AD</link>
            <guid>https://velog.io/@newon-seoul/Swift-Language-Guide-5.7-Basic-Operators-%EB%B2%88%EC%97%AD</guid>
            <pubDate>Wed, 22 Jun 2022 17:46:33 GMT</pubDate>
            <description><![CDATA[<h3 id="초록">초록</h3>
<p>연산자는 다음과 같이 값을 확인하거나 변화, 합치기 위해 사용되는 특별한 상징이나 구문을 의미합니다. </p>
<pre><code class="language-swift">let i = 1 + 2
if enteredDoorCode &amp;&amp; passedRetinaScan</code></pre>
<p>Swift 의 연산자들은 비정상적인 결과값을 갖지 않도록 연산의 결과가 오버플로우 하는지를 감지하는데, 오버플로우 행동과 관련된 연산자를 활용하고 싶다면 <a href="https://docs.swift.org/swift-book/LanguageGuide/AdvancedOperators.html#ID37">Overflow Operators</a> 를 확인해주세요.</p>
<p>Swift 는 C 언어에서는 제공되지 않았던 <code>a..&lt;b</code> 나 <code>a...b</code> 와 같은 줄임표현도 제공합니다. 더 많은 연산자들을 확인하고 싶다면 <a href="https://docs.swift.org/swift-book/LanguageGuide/AdvancedOperators.html">Advanced Operators</a> 를 확인해주세요.</p>
<br/>
<br/>

<h3 id="terminology-용어">Terminology (용어)</h3>
<p>연산자는 크게 단항 <em>(unary)</em>, 이항 <em>(binary)</em>, 삼항 <em>(ternary)</em> 으로 구분할 수 있습니다.</p>
<ul>
<li>단항 연산자는 <code>-a</code> 와 같이 1개의 목표 대상을 지닌 연산자를 의미하며, 접두연산자 <code>prefix, 앞에 붙는 연산자, !a</code> 와 접미연산자 <code>postfix, 뒤에 붙는 연산자, a!</code> 로 구분할 수 있습니다.</li>
<li>이항 연산자는 <code>2 + 3</code> 과 같이 2개의 목표 대상을 지닌 연산자를 의미하며 중위 연산자 <em>(infix)</em> 라고도 불립니다.</li>
<li>삼항 연산자는 3개의 목표 대상을 지닌 연산자로, Swift 에서는 딱 1개 , 조건부 연산자 <em>(conditional operator)</em> 만 있습니다.
<code>a ? b : c</code></li>
</ul>
<p>목표 대상은 피연산자 <em>(operand)</em> 로 지칭합니다.
<code>1 + 2</code> 에서 <code>+</code> 는 이항 연산자, 중위 연산자 <em>(infix)</em> 이며 <code>1</code> 과 <code>2</code> 는 피연산자 <em>(operand)</em> 입니다.</p>
<br/>
<br/>

<h3 id="assignment-operator-할당-연산자">Assignment Operator (할당 연산자)</h3>
<p>할당 연산자 <code>(a = b)</code> 는 값을 초기화하거나 새롭게 할당할 때 사용합니다.</p>
<pre><code class="language-swift">let b = 10
var a = 5
a = b
// a 의 값은 이제 10 입니다.</code></pre>
<p>만약 오른쪽의 값이 튜플과 같이 여러개의 값을 갖고 있다면 한번에 나누어서 값을 할당할 수 있습니다.</p>
<pre><code class="language-swift">let (x,y) = (1,2)
// x 는 1 이며, y 는 이제 2 입니다.</code></pre>
<p>C 언어와 다르게 Swift 의 할당연산자 <code>=</code> 는 스스로 값을 리턴하지 않습니다. 따라서 다음과 같은 구문은 사용할 수 없습니다.</p>
<pre><code class="language-swift">if x = y {
   code ....
   code ....
} </code></pre>
<br/>
<br/>

<h3 id="arithmetic-operators-산술연산자">Arithmetic Operators (산술연산자)</h3>
<ul>
<li><p>더하기 <code>+</code> , <code>ex) 1 + 2</code>
더하기는 String 타입에서도 사용할 수 있습니다.
<code>ex) &quot;Hello&quot;, + &quot;World!&quot;</code></p>
</li>
<li><p>빼기 <code>-</code> , <code>ex) 5 - 3</code></p>
</li>
<li><p>곱하기 <code>*</code> , <code>ex) 2 * 3</code></p>
</li>
<li><p>나누기 <code>/</code> , <code>10.0 / 2.5</code></p>
</li>
</ul>
<br/>

<h4 id="나머지-연산자-remainder">나머지 연산자 (remainder)</h4>
<p>나머지 연산자 <code>a % b</code> 는 b 가 a에 근접하도록 최대한의 곱셈을 해준 후, 남은 값을 반환하는 연산자입니다. </p>
<pre><code>다른 언어에서는 나머지 연산자를 &quot;modulo&quot; 연산자로 알려져있습니다, 만 
Swift 의 나머지 연산자는 음의 나머지 값을 반환하므로, 
엄밀히 말해서, &quot;remainder&quot; 연산자라고 부르는 것이 맞습니다.

번역 : 
a = -9, b = 4 일 때, 

% 를 modulo 연산을 하게 되면
4 * 3 을 한 후 남은 3이 나머지 값이 되지만

% 를 remainder 로 계산하게 되면
4 * 2 를 한 후 남은 -1 이 나머지 값이 됩니다.

Swift 는 % 계산을 하면 -1 이 남으므로 
용어는 remainder 가 맞다라고 &quot;엄밀히&quot; 말하고 있습니다.</code></pre><br/>

<h4 id="단항-빼기-연산자-unary-minus-operator">단항 빼기 연산자 (Unary Minus Operator)</h4>
<p>정수는 접두연산 <code>-</code> 를 사용해서 양의 값을 음으로 바꿀 수 있습니다.</p>
<pre><code class="language-swift">let three = 3
let minusThree = -three        // minusThree == -3
let plusThree = -minusThree    // plusThree == 3</code></pre>
<p>이처럼 빼기 <code>-</code> 를 값의 바로 앞에 붙임으로써 해당 값이 연산되기 이전에 값을 바꾸도록 사용할 수 있습니다.</p>
<h4 id="단항-더하기-연산자-unary-plus-operator">단항 더하기 연산자 (Unary Plus Operator)</h4>
<p>더하기도 똑같이 할 수 있습니다. 만 아무런 영향도 미치지 않습니다.</p>
<br/>
<br/>

<h3 id="compound-assignment-operators복합연산자">Compound Assignment Operators(복합연산자)</h3>
<p>C 언어처럼 Swift 는 <code>=</code> 과 다른 연산자를 합친 복합 연산자를 지원합니다.</p>
<pre><code class="language-swift">var a = 1
a += 2</code></pre>
<p><em>Note</em> : 단 복합연산자는 값을 리턴하지 않습니다. 따라서 다음과 같은 구문은 사용할 수 없습니다.</p>
<pre><code class="language-swift">let b = a += 2</code></pre>
<p>Swift standard library 가 제공하는 연산자에 대한 정보를 확인하고 싶으시다면 <a href="https://developer.apple.com/documentation/swift/swift_standard_library/operator_declarations">Operator Declarations</a> 를 확인해주세요.</p>
<br/>
<br/>

<h3 id="comparison-operators비교-연산자">Comparison Operators(비교 연산자)</h3>
<p>Swift 는 다음과 같은 비교 연산을 지원합니다.</p>
<ul>
<li>동일하다 : <code>a == b</code></li>
<li>동일하지 않다 : <code>a != b</code></li>
<li>크다 : <code>a &gt; b</code></li>
<li>작다 : <code>a &lt; b</code></li>
<li>크거나 같다 : <code>a &gt;= b</code></li>
<li>작거나 같다 : <code>a &lt;= b</code></li>
</ul>
<p>비교 연산자는 if 구문에서 자주 사용됩니다. if 구문에 대해 더 알고 싶다면 <a href="https://docs.swift.org/swift-book/LanguageGuide/ControlFlow.html">Control Flow</a> 를 확인해주세요.</p>
<p>비교 연산자는 같은 자료형과 같은 갯수를 가진 튜플<em>(tuple)</em> 에도 사용할 수 있습니다. 튜플을 비교할 때는 왼쪽에서 오른쪽으로, 한번에 한번씩만 비교하며 두 값이 다를 때 까지만 진행됩니다. </p>
<pre><code class="language-swift">(1, &quot;zebra&quot;) &lt; (2, &quot;apple&quot;)
// true, 1이 2보다 작기 때문입니다. zebra 와 apple 은 비교되지 않습니다.

(3, &quot;apple&quot;) &lt; (3, &quot;bird&quot;)
// ture, 3과 3이 같고 apple 이 bird 보다 작기 때문입니다.
// 번역 : String 은 길이가 아닌 서로의 앞 글자부터 아스키코드 값을 비교합니다.

(4, &quot;dog&quot;) == (4, &quot;dog&quot;)
// true, 4과 4가 같고 &quot;dog&quot; 가 &quot;dog&quot; 로 같기 때문입니다. </code></pre>
<p>위의 예시와 같이 비교 연은 왼쪽에서 오른쪽으로 진행되는 것을 확인할 수 있습니다. 첫번째 예시를 보면 &quot;zebra&quot; 와 &quot;apple&quot; 이 비교되지 않는 것을 확인할 수 있는데, 비교 연산이 이미 첫번째로 비교한 <code>1</code> <code>2</code> 비교에서 끝났기 때문입니다. 만약 서로의 첫번째 원소가 같다면 두번째 원소로 이동하여 서로를 비교하게 됩니다.</p>
<p>튜플끼리의 비교는 각 튜플 원소들의 값을 비교할 수 있을 때만 적용할 수 있습니다. 예를 들어 아래의 예시와 같이 (String, Int) 튜플은 비교할 수 있지만 (String, Bool) 은 비교할 수 없습니다. Bool 은 <code>&lt;</code>, <code>&gt;</code>, <code>==</code>로 비교할 수 없기 때문입니다.</p>
<pre><code class="language-swift">(&quot;blue&quot;, -1) &lt; (&quot;purple&quot;, 1)  // 비교 가능하며 true 입니다.
(&quot;blue&quot;, false) &lt; (&quot;purple&quot;, true) // 비교 자체가 불가능합니다.</code></pre>
<p><em>Note</em>: Swift standard library 에서 튜플은 7개 미만의 원소만 비교할 수 있습니다. 7개 이상의 원소를 포함한 튜플을 비교하고 싶다면 직접 비교 연산을 적용시켜야 합니다.</p>
<br/>
<br/>

<h3 id="ternary-conditional-operator-삼항-연산자">Ternary Conditional Operator (삼항 연산자)</h3>
<p>삼항 연산자는 <code>question ? answer1 : answer2</code> , 3 부분으로 이루어진 특별한 연산을 수행합니다. <code>question</code> 이 <code>true</code> 라면 <code>answer1</code> 을, <code>false</code> 라면 <code>answer2</code> 를 리턴합니다. </p>
<p>삼항 연산자는 다음의 줄임 표현입니다.</p>
<pre><code class="language-swift">question? answer1 : answer2

if question {
    answer1
} else {
    answer2
}</code></pre>
<p>침대의 가로길이를 맞추려고 할 때, 침대가 머리맡 선반이 있다면 50을, 없다면 20을 주고 싶은 상황이라면 다음과 같이 코드를 작성할 수 있습니다. </p>
<pre><code class="language-swift">let contentHeight = 40
let hasHeader = true
let rowHeight = contentHeight + (hasHeader ? 50 : 20)

-----------------------------------------------------

let contentHeight = 40
let hasHeader = true
let rowHeight: Int
if hasHeader {
    rowHeight = contentHeight + 50
} else {
    rowHeight = contentHeight + 20
}</code></pre>
<p>삼항연산자는 효율적으로 표현을 줄일 수 있습니다. 하지만 남용하면 지나친 간결성이 코드의 가독성을 저해하므로 여러개의 상황을 결합하여 삼항 연산자를 사용하지 않도록 합니다.</p>
<br/>
<br/>

<h3 id="nil-coalescing-operator닐-병합-연산자">Nil-Coalescing Operator(닐-병합 연산자)</h3>
<p>닐 병합연산자 <code>a ?? b</code> (이하 병합연산자) 는 옵셔널<em>(optional)</em> 을 꺼내 풀어서 값을 갖고 있다면 <em>(a 가 nil 이 아니라면)</em> 그 값을, 값이 nil 이라면 기본 값인 b 를 리턴하는 연산을 의미합니다. 이때 <code>a</code> 는 항상 옵셔널<em>(optional)</em> 자료형이어야 하며, <code>b</code> 는 항상 a 의 자료형과 일치해야 합니다.</p>
<p>병합연산자는 다음의 줄임 표현이라고 할 수 있습니다.</p>
<pre><code class="language-swift">a != nil ? a! b</code></pre>
<p>이 코드는 삼항 연산자를 통해 <code>a!</code> 를 수행하고, 만약 a 의 값이 nil 이라면 b 를 리턴하고 있습니다.</p>
<p><em>Note</em>: 만약 a 가 옵셔널 자료형이 아니라면 b 는 수행되지 않습니다. <a href="https://www.scienceall.com/%EB%8B%A8%EB%9D%BD-short-circuit-%E7%9F%AD%E7%B5%A1/">short-circuited</a> 에 준하는 내용입니다. </p>
<p>병합 연산자의 예시로, 기본색과 유저가 정한 색을 고르는 상황입니다. </p>
<pre><code class="language-swift">let defaultColorName = &quot;red&quot;
var userDefinedColorName: String? // nil 이 기본값입니다.

var colorNameToUse = uerDefinedColorName ?? defaultColorName
// userDefinedColorName 이 nil 이라면 
// colorNameToUse 에는 defaultColorName 이 할당됩니다.</code></pre>
<p><code>userDefinedColorName</code> 변수는 옵셔널 String 으로 정의되어 있기에, 병합연산자를 통해서 값을 정해줄 수 있습니다.</p>
<p>만약 <code>userDefinedColorName</code> 이 nil 이 아니라면 <code>defaultColorName</code> 대신 <code>userDefinedColorName</code> 이 사용됩니다.</p>
<pre><code class="language-swift">userDefinedColorName = &quot;green&quot;
colorNameToUse = userDefinedColorName ?? defaultColorName
// userDefinedColorName 이 nil 이 아니기때문에, colorNameToUse 는 &quot;green&quot; 으로 할당됩니다.</code></pre>
<h3 id="range-operators범위-연산자">Range Operators(범위 연산자)</h3>
<p>Swift 는 범위를 짧게 표현할 수 있는 여러 범위 연산자가 있습니다.</p>
<br/>
<br/>

<h4 id="closed-range-operator닫힌-범위-연산자">Closed Range Operator(닫힌 범위 연산자)</h4>
<p>닫힌 범위 연산자는 <code>(a...b)</code> 로 a 부터 b 까지 범위에 a 와 b 를 모두 함하는 연산을 의미합니다. 이때 <code>a</code> 는 반드시 <code>b</code> 보다 작아야합니다.</p>
<p>닫힌 범위 연산자는 <code>for ... - in ...</code> 반복문처럼 모든 값을 확인하고 싶을 때 유용합니다. </p>
<pre><code class="language-swift">for index in 1...5 {
    print(&quot;\(index) 곱하기 5 는 \(index * 5)&quot;)
}
// 1 곱하기 5 는 5
// 2 곱하기 5 는 10
// 3 곱하기 5 는 15
// 4 곱하기 5 는 20
// 5 곱하기 5 는 25</code></pre>
<p>더 자세한 <code>for-in</code> 반복문은 <a href="https://docs.swift.org/swift-book/LanguageGuide/ControlFlow.html">Control Flow</a> 를 확인해주세요.</p>
<br/>

<h3 id="half-open-range-operator반열림-범위-연산자">Half-Open Range Operator(반열림 범위 연산자)</h3>
<p>반열림 범위 연산자 <code>(a..&lt;b)</code> 는 a 부터 b 까지의 범위 중 b 를 포함하지 않는 연산을 의미합니다. 반열림의 의미는 처음의 값은 포함하지만 마지막을 포함하지 않기 때문입니다. 닫힘 범위 연산자가 그러했듯 <code>a</code> 는 <code>b</code> 보다 작아야합니다. 만약 <code>a</code> 와 <code>b</code> 가 같다면 해당 범위 연산자는 빈 값을 리턴합니다.</p>
<p>반열림 범위 연산자는 특히 0을 기준으로한 배열과 함께 사용할 때 유용합니다.</p>
<pre><code class="language-swift">let names = [&quot;안나&quot;, &quot;알렉스&quot;, &quot;브라이언&quot;, &quot;뉴원&quot;]
let count = names.count
for i in 0..&lt;count {
    print(&quot;사람\(i+1) 은 \(naems[i])라고 불립니다.&quot;)
}
// 사람1 안나라고 불립니다.
// 사람2 알렉스라고 불립니다.
// 사람3 브라이언라고 불립니다.
// 사람4 뉴원라고 불립니다.</code></pre>
<p>위에서 반열림 범위 연산자는 배열이 4개의 원소를 갖고 있지만, <code>0..&lt;count</code> 가 3, 배열의 마지막 인덱스, 까지만 호출하고 있습니다. 배열에 대해 더 자세히 알고 싶다면 <a href="https://docs.swift.org/swift-book/LanguageGuide/CollectionTypes.html#ID107">Arrays</a>를 참고해주세요.</p>
<br/>

<h4 id="one-sided-ranges한방향-범위-연산자">One-Sided Ranges(한방향 범위 연산자)</h4>
<p>닫힌 범위 연산자는 한 방향으로 계속해서 반복하는 형태의 연산자를 가질 수 있습니다. 이를테면 범위는 2부터 배열의 끝까지 가도록 할 수 있습니다. 이때 특정 값을 범위 연산자로부터 꺼내 사용할 수 있게됩니다. 이런 종류의 연산자를 한방향 범위 연산자<em>(One-Sided Ranges)</em> 라고 합니다. 연산자가 한쪽 방향에만 있기 때문에 이러한 이름이 붙게 되었습니다.</p>
<pre><code class="language-swift">for name in names[2...] {
    print(name)
}
// 브라이언
// 뉴원

for name in names[...2] {
    print(name)
}
// 안나
// 알렉스
// 브라이언</code></pre>
<p>반열림 범위 연산자 역시 위와 동일한 맥락에서 사용할 수 있습니다.</p>
<pre><code class="language-swift">for name in names[..&lt;2] {
    print(name)
}
// 안나
// 알렉스</code></pre>
<p>한방향 범위 연산자는 <code>for-in</code> 구문에서만 사용할 수 있는 것이 아닌, 다른 상황에서도 사용할 수 있습니다. 하지만 이때 한방향 범위 연산자는 범위가 정해져있지 않는 연산자에게서 값을 지정할 수 없게됩니다. 범위가 정해져있지 않기에 그 값이 명확하지 않기 때문입니다. </p>
<pre><code class="language-swift">let range = ...5
range.contains(7) // false
range.contains(5) // true
range.contains(-1) // true</code></pre>
<h3 id="logical-operators논리-연산자">Logical Operators(논리 연산자)</h3>
<p>논리 연산자는 Boolean 자료형의 논리 값을 true 나 false 로 수정하거나 병합하는 연산자를 의미합니다. Swift 는 C 언어 바탕의 3개의 논리 연산자를 제공합니다.</p>
<ul>
<li>논리 부정, <em>NOT</em> (!a)</li>
<li>논리곱, <em>AND</em> (a &amp;&amp; b)</li>
<li>논리합, <em>OR</em> (a || b)</li>
</ul>
<br/>
<br/>

<h4 id="not-연산자">NOT 연산자</h4>
<p>NOT 연산자, 부정 연산자 <code>!a</code> 는 Boolean 자료형의 값을 뒤집는 것으로 <code>true</code> 가 <code>false</code> 로, <code>false</code> 가 <code>true</code> 로 전환되는 것을 의미합니다.</p>
<p>부정 연산자는 접미 연산자로, 해당 값이 연산되기 이전에 나타나며 &quot;a 가 아니다 (<em>not a</em>)&quot; 로 읽을 수 있습니다.</p>
<pre><code class="language-swift">let allowedEntry = false
if !allowedEntry {
    print(&quot;ACCESS DENIED&quot;)
}
// &quot;ACCESS DENIED&quot; 가 출력됩니다.</code></pre>
<p>부정 연산자를 활용함으로써 코드의 가독성과 간결성을 유지할 수 있으며, 부정형을 두번 사용하거나 혼란스러운 논리 기재를 피할 수 있습니다.</p>
<br/>

<h4 id="and-연산자">AND 연산자</h4>
<p>AND 연산자, 논리곱 연산자 <code>a &amp;&amp; b</code> 는 두 값이 모두 true 임을 통해 전체 표현또한 <code>true</code> 임을 나타내는 연산자입니다.</p>
<p>만약 두 값이 <code>false</code> 라면 전체 표현 역시 <code>false</code> 가 됩니다. 이때, 사실 첫번째 값이 <code>false</code> 라면 두번째 값은 계산조차 되지 않는데 왜냐하면 이미 전체 표현식은 <code>true</code> 가 될 수 없기 때문입니다.</p>
<pre><code class="language-swift">let enteredDoorCode = true
let passedRetinaScan = false
if enteredDoorCode &amp;&amp; passedRetinaScan {
    print(&quot;Welcome!&quot;)
} else {
    print()&quot;ACCESS DENIED
}
// &quot;ACCESS DENIED&quot; 가 출력됩니다.</code></pre>
<br/>

<h4 id="or-연산자">OR 연산자</h4>
<p>OR 연산자, 논리합 연산자 <code>a || b</code> 는 중위 연산자로 파이프 모양의 Character 가 2개 있는 것으로 만들 수 있습니다. OR 연산자는 둘 중 하나의 값이라도 <code>true</code> 라면 전체 표현 역시 <code>true</code> 임을 나타내는 연산자입니다.</p>
<p>OR 연산자도 AND 연산자와 마찬가지로, 첫번째 값이 <code>true</code> 라면 두번째 값부터는 계산조차 되지 않는데 왜냐하면 이미 전체 표현식은 <code>false</code> 가 될 수 없기 때문입니다.</p>
<pre><code class="language-swift">let hasDoorKey = false
let knowsOverridePassword = true
if hasDoorKey || knowsOverridePassword {
    print(&quot;Welcome!&quot;)
} else {
     print(&quot;ACCESS DENIED&quot;)
}
// &quot;Welcome&quot; 이 출력됩니다.</code></pre>
<br/>

<h4 id="논리-연산자-조합하기">논리 연산자 조합하기</h4>
<p>논리 연산자들을 여러개 사용하여 더욱 길고, 조합된 표현식을 사용할 수도 있습니다.</p>
<pre><code class="language-swift">if enteredDoorCode &amp;&amp; passRetinaScan || hasDoorKey || knowsOverridePassword {
    print(&quot;Welcome!&quot;)
} else {
    print(&quot;ACCESS DENIED&quot;)
}
// &quot;Welcome&quot; 이 출력됩니다.</code></pre>
<p>위의 코드는 길어보이지만 3개의 논리 연산을 진행하고 있습니다.
<code>enteredDoorCode 와 passRetinaScan 가 true 인지</code>, 
<code>hasDoorKey 가 true 인지</code>
<code>knowsOverridePassword 가 true 인지</code> </p>
<p>입니다.</p>
<p><em>Note</em>: Swift 의 논리연산자는 왼쪽이 우선순위에 있습니다. 즉, 다수의 논리 연산자를 사용하더라도, 내부에서 나뉘더라도 왼쪽부터 논리 연산을 진행합니다.</p>
<br/>

<h4 id="괄호를-통해-명백하게-하기-explicit-parentheses">괄호를 통해 명백하게 하기 (Explicit Parentheses)</h4>
<p>위의 코드에서 괄호를 통해 코드를 명백하게 할 수 있습니다.</p>
<pre><code class="language-swift">if (enteredDoorCode &amp;&amp; passRetinaScan) || hasDoorKey || knowsOverridePassword {
    print(&quot;Welcome!&quot;)
} else {
    print(&quot;ACCESS DENIED&quot;)
}
// &quot;Welcome&quot; 이 출력됩니다.</code></pre>
<p>괄호가 연산에 영향을 미치지는 않습니만, 코드의 가독성을 위해 활용할 수 있습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Swift 알고리즘 입력받기]]></title>
            <link>https://velog.io/@newon-seoul/Swift-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%9E%85%EB%A0%A5%EB%B0%9B%EA%B8%B0</link>
            <guid>https://velog.io/@newon-seoul/Swift-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EC%9E%85%EB%A0%A5%EB%B0%9B%EA%B8%B0</guid>
            <pubDate>Mon, 13 Jun 2022 12:43:46 GMT</pubDate>
            <description><![CDATA[<h2 id="입력받기">입력받기</h2>
<h3 id="기본형태">기본형태</h3>
<pre><code class="language-swift">let input = readLine()!
print(input + &quot;, &quot; + &quot;\(type(of: input))&quot;)

// 입력 : 10
// 결과 : 10, String

readLine() 에 ! 를 붙이지 않으면 Optional String 으로 받는다.</code></pre>
<br/>

<h3 id="정수로-입력받기">정수로 입력받기</h3>
<pre><code class="language-swift">let input = Int(readLine()!)!
print(&quot;\(input)&quot; + &quot;, &quot; + &quot;\(type(of: input))&quot;)

// 입력 : 10
// 결과 : 10, Int

readLine()! 으로 받더라도, String 이 Int 로 캐스팅 실패할 수도 있으므로
!를 붙여 그럴 가능성이 없다고 선언한다.</code></pre>
<br/>

<h3 id="끝날-때-까지-계속-입력받기">끝날 때 까지 계속 입력받기</h3>
<pre><code class="language-swift">while let readString = readLine() {
    s += readString
}</code></pre>
<h3 id="문자열을-arraycharacter-으로-받기">문자열을 Array&lt;Character&gt; 으로 받기</h3>
<pre><code class="language-swift">let input = Array(readLine()!)
print(&quot;\(input)&quot; + &quot; &quot; &quot;\(type(of: input))&quot;)

// 입력 : ABABAB
// 결과 : [&quot;A&quot;, &quot;B&quot;, &quot;A&quot;, &quot;B&quot;, &quot;A&quot;, &quot;B&quot;] Array&lt;String&gt;</code></pre>
<br/>

<h3 id="공백문자를-기준으로-띄워서-arraystring-으로-받기">공백문자를 기준으로 띄워서 Array&lt;String&gt; 으로 받기</h3>
<pre><code class="language-swift">import foundation

let input = readLine()!.components(separatedBy: &quot; &quot;)
print(&quot;\(input)&quot; + &quot; &quot; &quot;\(type(of: input))&quot;)

// components 는 foundation Library 에 포함되어있다.
// 입력 : A B A B A B
// 결과 : [&quot;A&quot;, &quot;B&quot;, &quot;A&quot;, &quot;B&quot;, &quot;A&quot;, &quot;B&quot;] Array&lt;String&gt;
</code></pre>
<br/>

<h3 id="공백문자를-기준으로-띄워서-arrayint-으로-받기">공백문자를 기준으로 띄워서 Array&lt;Int&gt; 으로 받기</h3>
<pre><code class="language-swift">let input = readLine()!.split(separator: &quot; &quot;).map{Int($0)!}
print(&quot;\(input)&quot; + &quot;, &quot; + &quot;\(type(of: input))&quot;)

// 입력 : 1 0 1 0 1
// 결과 : [1, 0, 1, 0, 1], Array&lt;Int&gt;</code></pre>
<br/>

<h3 id="한-줄-정수를-arrayint-로-입력받기">한 줄 정수를 Array&lt;Int&gt; 로 입력받기</h3>
<pre><code class="language-swift">let input = Array(readLine()!).map{ Int(String($0))! }
print(&quot;\(input)&quot; + &quot;, &quot; + &quot;\(type(of: input))&quot;)

// String 형변환 후 Int 로 하면 속도가 더 빠르다.
// 이유는 SubString 과 String 의 차이
// 참조 : https://icksw.tistory.com/218

// 입력 : 10101
// 결과 : [1, 0, 1, 0, 1], Array&lt;Int&gt;</code></pre>
<br/>

<h3 id="공백문자를-기준으로-띄워서-이차원배열에-arrayint-로-받기">공백문자를 기준으로 띄워서 이차원배열에 Array&lt;Int&gt; 로 받기</h3>
<pre><code class="language-swift">var input = [[Int]](repeating: [Int](repeating: 0, count: 5), count: 5)
for i in 0...input.count - 1 {
    input[i] = readLine()!.components(separatedBy: &quot; &quot;).map{ Int(String($0))! }
}

print(&quot;\(input)&quot; + &quot;, &quot; + &quot;\(type(of: input))&quot;)

// 입력 : 
0 1 1 1 1
0 1 1 1 1
0 0 0 1 1
1 1 0 0 0
1 1 1 1 0

// 결과 :
[[0, 1, 1, 1, 1], [0, 1, 1, 1, 1], [0, 0, 0, 1, 1], [1, 1, 0, 0, 0], [1, 1, 1, 1, 0]], Array&lt;Array&lt;Int&gt;&gt;</code></pre>
<br/>

<h3 id="공백문자-없이-이차원배열에-arrayint-로-받기">공백문자 없이 이차원배열에 Array&lt;Int&gt; 로 받기</h3>
<pre><code class="language-swift">var input = [[Int]](repeating: [Int](repeating: 0, count: 5), count: 5)
for i in 0...input.count - 1 {
    input[i] = Array(readLine()!.map{Int(String($0))! })
}

print(&quot;\(input)&quot; + &quot;, &quot; + &quot;\(type(of: input))&quot;)

// 입력 :
01111
01111
00011
11000
11110

// 결과 :
[[0, 1, 1, 1, 1], [0, 1, 1, 1, 1], [0, 0, 0, 1, 1], [1, 1, 0, 0, 0], [1, 1, 1, 1, 0]], Array&lt;Array&lt;Int&gt;&gt;</code></pre>
<br/>

<h3 id="공백문자를-기준으로-띄워서-이차원배열에-arraystring-로-받기">공백문자를 기준으로 띄워서 이차원배열에 Array&lt;String&gt; 로 받기</h3>
<pre><code class="language-swift">var input = [[String]](repeating: [String](repeating: &quot;&quot;, count: 5), count: 5)
for i in 0...input.count - 1 {
    input[i] = readLine()!.components(separatedBy: &quot; &quot;)
}

print(&quot;\(input)&quot; + &quot;, &quot; + &quot;\(type(of: input))&quot;)

// 입력 :
A B B B B
A B B B B
A A A B B
B B A A A
B B B B A

// 결과 :
[[&quot;A&quot;, &quot;B&quot;, &quot;B&quot;, &quot;B&quot;, &quot;B&quot;], [&quot;A&quot;, &quot;B&quot;, &quot;B&quot;, &quot;B&quot;, &quot;B&quot;], [&quot;A&quot;, &quot;A&quot;, &quot;A&quot;, &quot;B&quot;, &quot;B&quot;], [&quot;B&quot;, &quot;B&quot;, &quot;A&quot;, &quot;A&quot;, &quot;A&quot;], [&quot;B&quot;, &quot;B&quot;, &quot;B&quot;, &quot;B&quot;, &quot;A&quot;]], Array&lt;Array&lt;String&gt;&gt;</code></pre>
<br/>

<h3 id="공백문자-없이-이차원배열에-arraystring-로-받기">공백문자 없이 이차원배열에 Array&lt;String&gt; 로 받기</h3>
<pre><code class="language-swift">var input = [String](repeating: &quot;&quot;, count: 5)
for i in 0...input.count - 1 {
    input[i] = readLine()!
}

print(&quot;\(input)&quot; + &quot;, &quot; + &quot;\(type(of: input))&quot;)

// 입력 :
ABBBB
ABBBB
AAABB
BBAAA
BBBBA

// 결과 :
[&quot;ABBBB&quot;, &quot;ABBBB&quot;, &quot;AAABB&quot;, &quot;BBAAA&quot;, &quot;BBBBA&quot;], Array&lt;String&gt;

------------------------------

var input = [[String]](repeating: [String](repeating: &quot;&quot;, count: 5), count: 5)
for i in 0...input.count - 1 {
    input[i] = Array(readLine()!.map{ String($0) })
}

print(&quot;\(input)&quot; + &quot;, &quot; + &quot;\(type(of: input))&quot;)

// 입력 :
ABBBB
ABBBB
AAABB
BBAAA
BBBBA

// 결과 :
[[&quot;A&quot;, &quot;B&quot;, &quot;B&quot;, &quot;B&quot;, &quot;B&quot;], [&quot;A&quot;, &quot;B&quot;, &quot;B&quot;, &quot;B&quot;, &quot;B&quot;], [&quot;A&quot;, &quot;A&quot;, &quot;A&quot;, &quot;B&quot;, &quot;B&quot;], [&quot;B&quot;, &quot;B&quot;, &quot;A&quot;, &quot;A&quot;, &quot;A&quot;], [&quot;B&quot;, &quot;B&quot;, &quot;B&quot;, &quot;B&quot;, &quot;A&quot;]], Array&lt;Array&lt;String&gt;&gt;
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준]1654_랜선자르기.Kotlin]]></title>
            <link>https://velog.io/@newon-seoul/%EB%B0%B1%EC%A4%801654%EB%9E%9C%EC%84%A0%EC%9E%90%EB%A5%B4%EA%B8%B0.Kotlin</link>
            <guid>https://velog.io/@newon-seoul/%EB%B0%B1%EC%A4%801654%EB%9E%9C%EC%84%A0%EC%9E%90%EB%A5%B4%EA%B8%B0.Kotlin</guid>
            <pubDate>Fri, 28 Jan 2022 04:29:08 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<p><img src="https://images.velog.io/images/newon-seoul/post/7206cdd3-1de0-41e1-9bbb-72a61179ab89/%EC%8A%A4%ED%81%AC%EB%A6%B0%EC%83%B7%202022-01-28%20%EC%98%A4%ED%9B%84%2012.00.58.png" alt="">
<a href="https://www.acmicpc.net/problem/1654">문제로 이동하기</a></p>
<h3 id="핵심-로직">핵심 로직</h3>
<ul>
<li>이분 탐색으로 인덱스가 아닌 실제 값을 찾기</li>
<li>이분 탐색 중 Upper bound 를 활용하기</li>
</ul>
<h3 id="코드">코드</h3>
<pre><code class="language-Kotlin">lateinit var lanCable: Array&lt;Int&gt;  

fun solve(K: Int, N: Int): Long {  
    var minimumLan:Long = 0  
    var maximumLan:Long = lanCable[lanCable.lastIndex] + 1.toLong()  
    var mid: Long  
    var count:Long  

    while (minimumLan &lt; maximumLan){  
        mid = (maximumLan + minimumLan) / 2  
        count = 0  

        for(i in lanCable.indices){  
            count += (lanCable[i] / mid)  
        }  

        if (count &lt; N)  
            maximumLan = mid  
        else  
            minimumLan = mid + 1  
    }  

    return minimumLan  
}  

fun main() {  
    val br = System.`in`.bufferedReader()  
    val bw = System.`out`.bufferedWriter()  

    val (K, N) = br.readLine().split(&quot; &quot;).map {it.toInt()}

    lanCable = Array(K) { 0 }  

    for (i in lanCable.indices)  
        lanCable[i] = br.readLine().toInt()  

    lanCable.sort()  

    bw.append(&quot;${solve(K, N) - 1}&quot;)  
    bw.flush()  
    bw.close()  
}</code></pre>
<h2 id="풀이">풀이</h2>
<p>랜선 자르기의 핵심은 <code>여러 값들이 주어졌을 때, 문제의 조건을 만족하는 최댓값</code>을 구하는 것이다.</p>
<p>비교를 해야할 여러 값들이 존재하고, 그 값들과 특정 조건이 만족하는 상황을 구하는 것인데 그림으로 표현하자면 다음과 같다.</p>
<br/>


<p><img src="https://images.velog.io/images/newon-seoul/post/01fd0263-d990-430d-ad09-8fbba43986df/IMG_0118.jpg" alt="">
랜선 K (예제 입력 : 4) 개가 각각의 길이로 주어졌을 때, 
각각의 랜선을 잘라서 N (예제 입력 : 11)개로 만들고자 하는데, 
모든 랜선을 균일하게 자른다고 가정했을 때,
가장 길게 자를 수 있는 값은 무엇인가 ?</p>
<p>로 정리할 수 있다.</p>
<p>이때 일반적인 방법을 사용하면 시간초과를 받게 되고, 
이분탐색 중 Upper bound 를 통해 보다 빠르게 찾아낼 수 있다.</p>
<p>원래의 이분탐색 중 Upper bound 는 
중복이 있는 배열에서 중복의 가장 마지막 인덱스 값을 찾기 위해 사용된다.</p>
<pre><code class="language-Kotlin">fun binarySearch(arr: IntArray, target: Int): Int {
    var low = 0
    var high = arr.lastIndex
    var mid: Int

    while (low &lt;= high) {
        mid = (low + high) / 2

        when {
            target &lt; arr[mid] -&gt; high = mid - 1
            target &gt;= arr[mid] -&gt; low = mid + 1
            // 찾고자 하는 값이 중앙값보다 크거나, *같다면(!!)*
            // 시작값(low)를 mid + 1 로 올려서
            // 만족하는 최대 인덱스를 찾는다.
        }
    }
    return low
}
</code></pre>
<br/>

<p>하지만 이것을 조금 비틀어서<br><code>인덱스 대신 실제 값</code> 으로 Upper bound 를 수행하는 것이 포인트다.</p>
<br/>



<pre><code class="language-Kotlin">while (minimumLan &lt; maximumLan){  
    mid = (maximumLan + minimumLan) / 2  
    count = 0  

    for(i in lanCable.indices){  
        count += (lanCable[i] / mid)  
    }  

    if (count &lt; N)  
        maximumLan = mid  
    else  
        minimumLan = mid + 1  
}  

return minimumLan</code></pre>
<blockquote>
<p>여기서 count 는 랜선의 갯수를 세는 변수로, 
  조건에 부합한지 확인하는 변수이다.
  위 코드의 target 역할을 한다.</p>
</blockquote>
<br/>
<br/>

<h3 id="주의사항">주의사항</h3>
<ol>
<li>Int 범위를 넘어갈 수 있음. 
mid 를 구하는 방법이 (max + min ) / 2 이며, 
입력 상, max 와 min 을 합칠 때 Int 를 초과할 수 있으므로
Long 을 써주어야 한다.  <br/>
<br/>


</li>
</ol>
<ol start="2">
<li>max 는 항상 max + 1 이어야 함.
Upper bound 를 통해 찾는 값은
min ~ max 내에서 찾게 된다.
이는 특정 케이스, 최소와 최대가 0일 때 문제가 생긴다.  </li>
</ol>
<pre><code class="language-Kotlin"> min = 0
 max = 0
 mid = (min + max) / 2  // 0

 // min &lt; max 가 아니기에, 
 // 이분탐색이 수행되지 않고 종료된다.</code></pre>
<h2 id="일반화-및-후기">일반화 및 후기</h2>
<p>해당 문제의 로직은 여러 값들 중에서 조건을 만족하는 최댓값을 구할 때 사용할 수 있다.</p>
<p>어려운 개념은 아닌데, 선뜻 손이 안 갔던 문제였다.  </p>
<p><img src="https://images.velog.io/images/newon-seoul/post/05c2050b-2648-41e9-b5ca-67abfddff378/%EC%8A%A4%ED%81%AC%EB%A6%B0%EC%83%B7%202022-01-28%20%EC%98%A4%ED%9B%84%201.08.49.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Kotlin 과 객체 지향 프로그래밍]]></title>
            <link>https://velog.io/@newon-seoul/Kotlin-%EA%B3%BC-OOP%EA%B0%9D%EC%B2%B4-%EC%A7%80%ED%96%A5-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D</link>
            <guid>https://velog.io/@newon-seoul/Kotlin-%EA%B3%BC-OOP%EA%B0%9D%EC%B2%B4-%EC%A7%80%ED%96%A5-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D</guid>
            <pubDate>Fri, 21 Jan 2022 04:21:01 GMT</pubDate>
            <description><![CDATA[<h2 id="컴파일러와-객체-지향-프로그래밍oop">컴파일러와 객체 지향 프로그래밍(OOP)</h2>
<p>객체(Object) 를 지향(Oriented) 하는 프로그래밍은 코딩을 작성할 때 사용할 수 있는 하나의 패러다임, 더 일반적으로는 하나의 글쓰기 장르라고 볼 수 있다. </p>
<p>잠시 객체 지향 프로그래밍을 접어두고, 코딩이 어떻게 동작하는지부터 생각해보자. 어떤 프로그래밍 언어를 쓰더라도 코드는 컴파일러를 거쳐서 수행된다. 사람이 작성한 코드를 기계어로 번역하는 작업이 필요한 것인데, 이때 코드는 위에서부터 아래로 한 줄씩 코드를 읽고, 번역하고, 내용을 수행한다. </p>
<p>화가가 그림을 그려서 파는 작업을 위의 문단의 내용만 갖고서 코드로 표현하면 다음과 같다.</p>
<pre><code class="language-Kotlin">var 화가 지갑 = 0
var 화가가 갖고 있는 그림 = 1

var 손님 지갑 = 20000
var 손님이 갖고 있는 그림 = 0
var 손님은 그림을 갖고 싶다 = true

if (10000 &gt;= 손님 지갑 &amp;&amp; 손님은 그림을 갖고 싶다) {
    손님 지갑 -= 10000
    화가 지갑 += 10000
    손님이 갖고 있는 그림 += 1
    화가가 갖고 있는 그림 -= 1

    손님은 그림을 갖고 싶다 = false
}  </code></pre>
<p>Kotlin 컴파일러는 위에서부터 읽으며 모든 내용을 절차대로 수행할 것이다. 이때, 만약 손님이 1명이 아니라 여러 명이라면 코드는 계속해서 저 코드를 부분적으로 반복하며, 많은 줄을 작성해야할 것이다.</p>
<p><img src="https://memegenerator.net/img/instances/58100671/no-way.jpg" alt=""></p>
<p>그렇다. 굉장히 귀찮은 작업이며, 이것을 해결하기 위해 나온 것이
절차적 프로그래밍과 객체 지향 프로그래밍이다.</p>
<blockquote>
<p>잠깐, 절차적 프로그래밍 ?
절차적 프로그래밍은 함수의 재호출을 이용해 코드를 재활용하는 방법을 의미한다.</p>
<p> 즉, 컴파일러가 위에서부터 아래로 순서대로 읽는 것과는 별개로 (애초에 모든 코드는 절차적이다.) , 함수같은 Procedural 를 재활용하자는 의미에서 Procedural Programming 인 것이다. </p>
</blockquote>
<blockquote>
<p>이 글에서 절차적 프로그래밍은 함수를 통해 코드를 재활용한다는 의미로만 사용하고, 그 이상의 내용은 다루지 않는다.</p>
</blockquote>
<br/>
<br/>

<h2 id="객체-지향-프로그래밍object-oriented-programming">객체 지향 프로그래밍(Object Oriented Programming)</h2>
<p>객체(Object) 를 지향(Oriented) 하는 프로그래밍은 코딩을 작성할 때 사용할 수 있는 하나의 패러다임, 더 일반적으로는 하나의 글쓰기 장르라고 볼 수 있다. </p>
<p>객체를 지향한다고 하니, 객체가 무엇인지 알아보자.<br>여기서 말하는 <code>객체</code> 란 하나로써 존재할 수 있는 무언가를 의미한다. 
사람, 고양이, 우주, 자동차 등이 될 수 있다. </p>
<p>언급된 객체들의 특징은 자신이 <code>주체</code> 가 될 수 있다는 점이다.
고양이는 고양이로서 존재할 수 있고, 우주는 우주로서 존재할 수 있다. 
고양이를 이루는 것 중에는 털이 있지만, 털이 조금 빠진다고 고양이가 고양이가 되진 않는다. 
털이 빠진 고양이가 될 순 있지만.</p>
<p>굉장히 관념적이지만, 여기서 말하는 <code>객체</code> 가 
하나로서 존재할 수 있는 어떤 <code>추상적인 무언가</code> 로 이해했다면 완벽하다.</p>
<p>객체 지향 프로그래밍은 프로그래밍을 짤 때 <code>객체</code> 단위로 코드를 작성하기를 <code>지향</code> 한다는 것이다. </p>
<p><img src="https://lh3.googleusercontent.com/KbLdT9CPvlk5r5GPFq2h9i5JiEYtjXCJUHhc-g7axTN0SzjIXmi4gstBmJTxFM199NzesOXvM_Yeb6XmCtfGq9SF3JBLohZ-VfP8Cvhv1zFdpixZSfYrZbgnl9MeCzaxxy99xi168EpwHkZl4B9ESlUQLir7rFwYtUUI_fFn0eRbVURPyLGhepiunmQXSB_JiJcfgYa_-q2jvqcqatkj3S3EohEEi_rdSUCDpTi8KWG3f00gJ5NBJRPyed6ZULWsrMKnbB7-2A_T9O6i3M7y9kp6tWEq-c5mB2Zd6kQUlBRVDz8s2kU2Axt4LMWLR5DK7h4mtvzdhx_RM7JmX_7yvhCI_fNhbDDlSntyoMmUd9AqVlrmFSGDBLQchVGofJl_15SkMXpTb9xZ9NhPGUsL27DztjQSMyyowI452GWWDnw3P7cN0Tsu478sPQ_rgraQvlin5DJnWWqP77zdG6v9S_z-LmMK7Jh-4aQ_D4q-XoM36IJpXFWKFgcy7F6N641ZGhpXFHOBtnp7Bb0pJW3fM21mgWHuOcTfHxihfgRoONPDBeEiG93OuERNtoD5Zq6ovn1IV4zUFx3duPmpMmiED2MtMsIKa3uGF3WrKw_dIgZFw2_2SfkNkdVXeD0wl8OUwAxEm7HKFLSqHIgwT4n9MnRTyEAxMTymKhtPC9p30ccVfevn3bY-PAviXNHKyfm8jedERxQrT1U-_V-gWH7T17k=w1132-h1063-no?authuser=0" alt=""></p>
<p>고양이라는 하나의 객체에는 성격, 근육, 털, 행동 등등 여러가지 것들이 포함될 수 있다. 어떠한 것들은 있을 수도 있고, 없을 수도 있지만 <code>고양이</code> 라는 객체는 존재하며, </p>
<p>이 같은 생각을 바탕으로 코드를 작성하겠다는 패러다임이 바로 객체 지향 프로그래밍(Object Oriented Programming) 이다.</p>
<br/>


<h2 id="kotlin-과-객체-지향-프로그래밍">Kotlin 과 객체 지향 프로그래밍</h2>
<p>코틀린으로 실제 객체, 고양이를 작성을 해보자.</p>
<p>위에서 언급한 하나로서 존재할 수 있는 <code>객체</code>, 즉 고양이는 <code>Class</code> 로 정의되며, 그 내부의 털, 성격, 근육 등은 <code>변수</code> 혹은 <code>함수</code> 로 정의할 수 있다.</p>
<pre><code class="language-Kotlin">fun main(){
  val cat = Cat()

  println(&quot;눈동자는 ${cat.눈동자}, 털은 ${cat.털}, 성격은 ${cat.성격}&quot;)

  cat.털 = &quot;깎아버리기!&quot;
  cat.눈동자 = &quot;까망색&quot;
  println(&quot;${cat.털}, ${cat.눈동자}&quot;)

  cat.밥과 관련된 행동(true)
}

class Cat(){
   val 눈동자: String = &quot;Blue&quot;
   var 털: String = &quot;너무 많아&quot;
   val 성격: String = &quot;커여워&quot;

   fun 밥과 관련된 행동(밥: Boolean){
      if(!밥){
         println(&quot;냥냥펀치!!&quot;)
      } else {
         println(&quot;와구와구&quot;)
      }
   }
}</code></pre>
<pre><code class="language-Kotlin">결과
눈동자는 Blue, 털은 너무 많아, 성격은 커여워
눈동자는 Blue, 털은 깎아버리기!, 성격은 커여워
와구와구</code></pre>
<ul>
<li>클래스는 다음과 같이 미리 class 를 만들어 놓은 후, 변수로 선언하여 사용할 수 있다. 클래스의 내부 변수 접근은 <code>.</code> 으로 할 수 있다. </li>
</ul>
<ul>
<li>class 로 정의된 변수 중, var 변수는 외부에서도 변경이 가능하지만 val 변수는 변경이 되지 않기 때문에 털은 변하되 눈동자는 변하지 않는다.</li>
</ul>
<ul>
<li>클래스 내부 함수 접근 역시 <code>.</code> 로 할 수 있다.</li>
</ul>
<br/>


<p>한편, 클래스도 매개변수를 받을 수 있다. 같은 내용을 매개변수를 받는 형태로 바꾼다면 다음과 같다.</p>
<pre><code class="language-Kotlin">fun main(){
  val cat = Cat()

  println(&quot;눈동자는 ${cat.눈동자}, 털은 ${cat.털}, 성격은 ${cat.성격}&quot;)

  cat.털 = &quot;깎아버리기!&quot;
  cat.눈동자 = &quot;까망색&quot;
  println(&quot;${cat.털}, ${cat.눈동자}&quot;)

  cat.밥과 관련된 행동(false)
}

class Cat( val 눈동자: String = &quot;Blue&quot;, 
           var 털: String, 
           val 성격: String = &quot;커여워&quot;) 
{
      fun 밥과 관련된 행동(밥: Boolean){
           if(!밥){
              println(&quot;냥냥펀치!!&quot;)
           } else {
              println(&quot;와구와구&quot;)
           }
      }
}</code></pre>
<pre><code class="language-Kotlin">결과
Error --&gt; 매개변수 값을 선언해주세요.
눈동자는 Blue, 털은 깎아버리기!, 성격은 커여워
냥냥펀치!!</code></pre>
<ul>
<li>클래스의 매개변수는 val, var 타입이 올 수 있으며 val 은 변경 불가, var 은 변경 가능이다.</li>
</ul>
<ul>
<li><p>클래스의 매개변수는 Cat 의 눈동자와 같이 기본값을 줄 수도 있고, 털처럼 기본값을 안줄 수도 있다. 기본값을 주지 않은 매개변수는 선언 시 반드시 매개변수값을 넣어주어야 한다. 기본값이 있는 곳에 새로운 매개변수 값을 넣으면 새로운 값으로 덮어쓴다.</p>
<br/>

</li>
</ul>
<p>이렇게 작성된 코드는 반복작업도 굉장히 간편하다. 밥과 관련된 행동을 반복하고 싶다면 다음과 같이, 코드 한 줄이면 반복 작업을 수행할 수 있다.</p>
<pre><code class="language-Kotlin">fun main(){
  val cat = Cat()

  cat.밥과 관련된 행동(false)
  cat.밥과 관련된 행동(true)
  cat.밥과 관련된 행동(true)
  cat.밥과 관련된 행동(true)
}

class Cat( val 눈동자: String = &quot;Blue&quot;, 
           var 털: String, 
           val 성격: String = &quot;커여워&quot;) 
{
      fun 밥과 관련된 행동(밥: Boolean){
           if(!밥){
              println(&quot;냥냥펀치!!&quot;)
           } else {
              println(&quot;와구와구&quot;)
           }
      }
}</code></pre>
<pre><code class="language-Kotlin">결과
냥냥펀치!!
와구와구
와구와구
와구와구</code></pre>
  <br/>


<p>한편 같은 객체이지만, 서로 다른 존재를 부르고 싶을때도 간편하다.</p>
<pre><code class="language-Kotlin">fun main(){
  val catBlue = Cat(&quot;Blue&quot;, &quot;너무많아!&quot;, &quot;도도해!&quot;)
  val catBlack = Cat(&quot;Black&quot;, &quot;조금있어!&quot;)
  val catOdd = Cat(&quot;Odd&quot;, &quot;깍어비리기!!&quot;, &quot;나른해&quot;)

  println(&quot;${catBlue.눈동자}, ${catBlue.털}, ${catBlue.성격}&quot;)
  println(&quot;${catBlack.눈동자}, ${catBlack.털}, ${catBlack.성격}&quot;)
  println(&quot;${catOdd.눈동자}, ${catOdd.털}, ${catOdd.성격}&quot;)
}

class Cat( var 눈동자: String, 
           var 털: String, 
           val 성격: String = &quot;커여워&quot;) 
{
      fun 밥과 관련된 행동(밥: Boolean){
           if(!밥){
              println(&quot;냥냥펀치!!&quot;)
           } else {
              println(&quot;와구와구&quot;)
           }
      }
}</code></pre>
<pre><code class="language-Kotlin">결과
Blue, 너무많아!, &quot;도도해!
Black, 조금있어! 커여워
Odd, 깍어비리기!!, 나른해</code></pre>
<blockquote>
<p>참고로 Class 를 직접 부르면 컴파일러는 </p>
<p><img src="https://w.namu.la/s/d85d3c39fd3b225bc05fd8d64fb4f334200644f7154148283e6dc731e25f9ac20a52aafd3de51e7e88dcb35cf7582cfcea9c9b65e530ec41178ea063f131fcc70d0e3d5932c702d06310796913a7a2e7" alt=""></p>
<p>클래스는 직접 호출하지 않고, 반드시 변수 등에 선언을 하고서 사용해야 한다. 클래스는 수치만 들어간 설계도이기에 설계도를 직접 호출하면 당연히 
실제 사용자는 ? 를 띄울 뿐이다. </p>
</blockquote>
  <br/>
  <br/>

<h3 id="정리">정리</h3>
<p>객체 지향 프로그래밍은 하나의 객체를 관점으로 프로그래밍을 작성하는 것을 의미한다. 반복적인 작업을 피하고, 이해와 효율성을 높이기 위해 사용된다. </p>
<p>Class 는 하나의 객체를 담는 그릇이다. 실제 치수, 내용 등을 포함하고 있지만 기본적으로 설계도이기에 사용 시 다른 변수에 선언을 하고서 사용해야 한다.</p>
<p>모듈화를 통해 코드 전체의 이해와 재사용으로 효율성이 높아진다.
단, 모듈화로 인해 컴파일러는 더 많은 코스트를 요구하여 성능에는 더 안 좋다. 또한 설계 자체에 시간이 오래 걸릴 수 있다.</p>
<p>감사합니다 :)
<img src="https://user-images.githubusercontent.com/80164141/138802009-f777c0cc-d1d1-4cde-8702-9c5e52329e74.gif" alt=""></p>
<blockquote>
<p>참고
Udemy # <a href="https://www.udemy.com/course/kotling-android-jetpack-compose-/">Android Jetpack Compose: The Comprehensive Bootcamp [2022]</a></p>
<p>Blog # <a href="https://st-lab.tistory.com/151">객체 지향 프로그래밍이 뭔가요? (꼬리에 꼬리를 무는 질문 1순위, 그놈의 OOP)</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[문과생이 적어보는 유클리드 호제법 (a.k.a GCD 알고리즘)]]></title>
            <link>https://velog.io/@newon-seoul/%EB%AC%B8%EA%B3%BC%EC%83%9D%EC%9D%B4-%EC%A0%81%EC%96%B4%EB%B3%B4%EB%8A%94-%EC%9C%A0%ED%81%B4%EB%A6%AC%EB%93%9C-%ED%98%B8%EC%A0%9C%EB%B2%95-a.k.a-GCD-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</link>
            <guid>https://velog.io/@newon-seoul/%EB%AC%B8%EA%B3%BC%EC%83%9D%EC%9D%B4-%EC%A0%81%EC%96%B4%EB%B3%B4%EB%8A%94-%EC%9C%A0%ED%81%B4%EB%A6%AC%EB%93%9C-%ED%98%B8%EC%A0%9C%EB%B2%95-a.k.a-GCD-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</guid>
            <pubDate>Tue, 04 Jan 2022 15:37:55 GMT</pubDate>
            <description><![CDATA[<h3 id="유클리드-호제법--나눗셈-알고리즘으로-최대-공약수-구하기">유클리드 호제법 == 나눗셈 알고리즘으로 최대 공약수 구하기</h3>
<p>작성자 : 뉴원 (Newon)<br/><br/>
유클리드 호제법이란 <br/>
두 정수 <code>a, b</code>ﾠﾠ|ﾠﾠ   a 와 b 의 <code>최대공약수 𝒹</code>  ﾠﾠ|ﾠﾠ  a / b 했을 때 나오는 <code>나머지 𝛾</code>  ﾠﾠ|ﾠﾠ  이 있을 때  <br/>
<br/></p>
<blockquote>
<p><code>𝒹 = gcd(a, b) = gcd(b, 𝛾)</code> 가 성립함을 의미한다.
<em>이때 gcd(a, b) 는 a 와 b 사이의 최대공약수를 뜻한다.</em></p>
</blockquote>
<p>이때 <code>𝒹 = gcd(a, b) = gcd(b, 𝛾)</code> 를 확장해서 <code>𝛾´</code>이 <code>b를 𝛾로 나누었을때의 나머지</code>라고 한다면 
<code>𝒹 = gcd(a, b) = gcd(b, 𝛾) = gcd(𝛾, 𝛾´) ...</code> 이 성립하게 된다.
이 성질을 이용해서 알고리즘에서 최대공약수를 구할 때 gcd 를 구하는 함수를 만들고, 이를 for 문이나 재귀함수로 반복해서 푸는 방법이 성립하게 된다.</p>
<p>이를 간단하게 코드로 작성하면 다음과 같이 나타난다. </p>
<pre><code class="language-Kotlin">
fun Gcd(a:Int, b:Int):Int {
    var r = a % b
    if (r == 0)
       return b
    else
       return Gcd(b, r)
}

fun main() {
    val br = System.`in`.bufferedReader()
    val (a,b) = br.readLine().split(&#39; &#39;).map {it.toInt()}

    var gcd = Gcd(a,b)
    println(gcd)                                               // a 와 b 의 최대공약수
    println(a*b/gcd)                                           // a 와 b 의 최소공배수

/* 
*    백준 2609, 최대공약수와 최소공배수 문제이다.
*    코틀린으로 작성되었다.
*/</code></pre>
<h3 id="이게-왜-됨">이게 왜 됨?</h3>
<p>글의 본문이다. 왜 될까? </p>
<center>
<img 
src="https://mblogthumb-phinf.pstatic.net/MjAxODEwMTFfMTYw/MDAxNTM5MjI1OTcxODc5.WnNZInoiz0MY7txOJLbGB_IJ-OGoJfKqDOGxfV_DSi8g.IMZ0kIqROr2lmavgFniMfueg4htsBZj33S5oaaLwUKsg.GIF.pola0216/source.gif?type=w800" width="200" height="200"/>
</center>

<p><strong><em>a, b, 𝛾(= a와 b의 나머지) 에는 무슨 관계가 있길래 gcd(a,b) 와 gcd(b,𝛾) 과 같고, 𝛾가 𝛾의 나머지(𝛾´) 의 최대공약수, gcd(𝛾, 𝛾´)와 같고 <br/>이걸 { ... } 반복해도 성립하게 되는걸까?<br/>
<br/>
이게 왜 되는지 이해해보는 것이 이 글의 목표이다.</em></strong><br/>
<br/></p>
<p>두 정수 <code>a, b</code>가 있고 <code>a &gt; b</code> 이면서, <code>𝒹(최대공약수)</code> 를 지니고 있는 수를 통해 알아보자. ﾠﾠﾠﾠﾠ ﾠﾠﾠﾠﾠ ﾠﾠﾠﾠﾠﾠ<code>대전제 = a 와 b 의 최대공약수 𝒹</code><br/>
우선 우리는 a 와 b 의 최대공약수 𝒹를 알고 있으니, a 와 b 를 다음과 같이 바꿔본다.<br/></p>
<blockquote>
<p><code>a = 𝒹 * ⍺</code><br/>
<code>b = 𝒹 * β</code><br/>
⍺와 β는 𝒹를 곱했을 때 각각 a 와 b 가 나오는 정수
<br/></p>
</blockquote>
<p>그럼 우린 다음과 같이 쓸 수 있다.<br/></p>
<blockquote>
<p><code>a = q * b + 𝛾</code>ﾠﾠﾠﾠﾠﾠﾠﾠﾠﾠﾠﾠﾠﾠﾠﾠﾠﾠﾠ//ﾠﾠq 는 a / b 의 목,ﾠ 𝛾 은 나머지이다.<br/>
<code>𝒹 * ⍺ = q * 𝒹 * β + 𝛾</code>ﾠﾠﾠﾠﾠﾠﾠﾠﾠ//ﾠﾠa  를 𝒹 * ⍺로,ﾠ b 를  𝒹 * β 로 치환했다.ﾠﾠﾠﾠ ﾠﾠﾠﾠﾠﾠﾠﾠﾠﾠﾠﾠﾠﾠﾠ⍺와 β는 조건을 만족하는 임의의 수<br/>
<code>𝛾 = 𝒹 (⍺ - q * β)</code>ﾠﾠﾠﾠﾠﾠﾠﾠﾠﾠﾠﾠﾠ//ﾠﾠ위의  식을  𝛾  과  나머지로  정리하였다.<br/>
<code>𝛾 = 𝒹    *   (⍺ - q * β)</code>ﾠﾠﾠﾠﾠﾠﾠﾠﾠﾠ//ﾠﾠ?!ﾠﾠ 𝛾 ﾠ로 정리하였더니,ﾠ  𝒹  *  (⍺ - q * β) 의 형태이므로,ﾠ 𝛾 의 약수에도 𝒹 가 들어감을 알 수 있다 !! 
<br/>
올, 위와 같이 정리하였더니 우리는 𝛾 의 약수에 a 와 b 의 최대공약수인 𝒹가 있음을 알 수 있었다!! <br/></p>
</blockquote>
<p>그렇다면, <code>𝒹는 b 와 𝛾 의 최대공약수</code>이기도 할까?</p>
<p><em>그렇다, 이것이 이 글의 <code>핵심 주제 ①</code>이다.</em>
<code>𝒹는 a 와 b 와 𝛾의 최대공약수</code>가 참인지 거짓인지 확인하는 것이 오늘 주제의 <code>핵심 주제</code> 중 하나이다.<br><em>미리 스포하자면 핵심 주제는 <code>핵심 주제 ② (crazy_𝛾은 언젠가는 0이 될 수 밖에 없다)</code> 까지 있다.</em></p>
<br/>

<p>우리는 현재 <code>a</code> 와 <code>b</code> 의 <code>최대공약수가 𝒹</code> 라는 것을 알고 있으며 <code>𝛾 에도 𝒹라는 공약수</code>가 들어간다는 것을 안다.  </p>
<p>이때 <strong>𝛾 에게 있어서도 𝒹가 최대공약수가 된다면</strong> 
우리는 <code>a 와 b 와 𝛾 의 최대공약수가 𝒹 로 같다</code>는 것을 알 수 있게 된다 !!</p>
<hr>
<h3 id="𝛾-의-최대공약수가-a와-b의-최대공약수인-𝒹-와-같다는-동화--가능-">𝛾 의 최대공약수가 a와 b의 최대공약수인 𝒹 와 같다는 동화 .. 가능 ?</h3>
<p><img 
src="https://i.ibb.co/6g18SfS/Kakao-Talk-Photo-2021-09-30-20-47-35.gif" width="200" height="200"/></p>
<p>인생은 호락호락하지 않다, 그리고 우리는 𝒹가 𝛾의 최대공약수라고 확신할 수 없다. 
확신할 수 없으니 <strong><em>𝒹 가 𝛾의 최대공약수가 아님</em></strong> 이라고 가정해보자.ﾠ</p>
<p><code>대 가정 = 𝒹 가 𝛾의 최대공약수가 아님</code></p>
<p>𝛾의 최대공약수가 𝒹 가 아니라면, 𝛾 의 최대공약수는 그 어떤 임의의 수 <code>𝒹´</code> 일 것이다.
잠시 정리해서<br/> </p>
<ul>
<li>𝒹 = gcd(a,b) 이고 𝒹´ = gcd(b, 𝛾) 이라면<br/></li>
<li>𝒹´ 는 언제나 𝒹 보다 작아야한다.</li>
</ul>
<p><code>조건 ① = (𝒹 &lt; 𝒹´)</code></p>
<ul>
<li>왜? <code>대 가정</code>에 의해서 𝒹 는 𝛾 의 최대공약수가 아니고, 𝒹´ 가 𝛾 의 최대공약수이어야 하기 때문이다.</li>
</ul>
<p>현재 우리는 <code>대 가정</code>과 <code>조건 ①</code>를 갖고 있다. </p>
<p>그럼, 𝒹´의 관점에서 b 와 𝛾를 다시 써보자.</p>
<blockquote>
<p>b = 𝒹´ * b´ﾠﾠﾠﾠﾠﾠﾠﾠﾠﾠ//ﾠﾠb´은  b = 𝒹´ * b´ 를 만족하는 수<br/>
𝛾 = 𝒹´ * r´ﾠﾠﾠﾠﾠﾠﾠﾠﾠﾠ//ﾠﾠr´은 𝛾 = 𝒹´ * r´를 만족하는 수<br/>
<br/></p>
</blockquote>
<p>이걸 위에서 사용했던 <code>a = q * b + 𝛾</code>ﾠﾠﾠ에 대입해보자. <br/></p>
<blockquote>
<p>a = q * 𝒹´ * b´ﾠ+ 𝒹´ * r´ﾠﾠﾠﾠﾠﾠﾠﾠﾠﾠﾠﾠﾠﾠﾠﾠ// b 와 r 에 𝒹´에서 본 b 와 r 를 넣었다.<br/>
a = 𝒹´ * (q * b´ + r´)ﾠﾠﾠﾠﾠﾠﾠﾠﾠﾠﾠﾠﾠﾠﾠﾠﾠﾠﾠ// 넣어본 김에 깔끔하게 𝒹´로 정리해보았다.<br/>
<br/></p>
</blockquote>
<p>어 ? a 의 공약수에도 𝒹´가 들어간다.
하지만 알다시피, 대전제로 우리는 a 와 b 의 최대공약수 𝒹 라고 하였으며, <br/>
또 따라서 𝒹´는 𝒹 보다 작을 수 밖에 없다 !!
<code>조건 ② = (𝒹´ &lt; 𝒹)</code></p>
<p>? <code>조건 ① = (𝒹 &lt; 𝒹´)</code> 과 <code>조건 ② = (𝒹´ &lt; 𝒹)</code> 이 모순된다. </p>
<p>문과인 나도 안다. <strong>어떠한 정수 𝒹가 𝒹´ 보다 작으면서 클 수는 없다</strong> </p>
<p>그렇다면 잘못된 건 <code>대 가정 = 𝒹 가 𝛾의 최대공약수가 아님</code> !! <br/>
해당 가정의 결론이 거짓이니, 그 가정의 반대는 참 ! 즉 <code>𝒹 는 𝛾의 최대공약수임</code></p>
<p>따라서 우리는 <code>a 와 b 와 𝛾 의 최대공약수가 𝒹로 같다.</code> 는 이야기가 동화인 줄 알았지만<br>사실 팩트기반 실제 사례 기반 수필로써 <code>핵심주제 ① : a 와 b 와 𝛾 의 최대공약수가 𝒹로 같다.</code> 가 True임을 알 수 있었다.</p>
<hr>
<h3 id="ㅇㅋ-근데-왜-a-와-b-와-𝛾-의-최대공약수가-같다고-그걸-저렇게-반복해도-성립하는거임">ㅇㅋ, 근데 왜 a 와 b 와 𝛾 의 최대공약수가 같다고 그걸 저렇게 반복해도 성립하는거임?</h3>
<p>그렇다, 우리가 <code>핵심 주제 ① : a 와 b 와 𝛾 의 최대공약수가 𝒹로 같다.</code> 라는 팩트를 갖고 있어도 
우리는 코틀린 예제로 쓰인 저 코드가 잘 작동하게 되는 이유를 아직 찾지 못했다.</p>
<p><img 
src="https://postfiles.pstatic.net/MjAyMDA2MjZfMTg2/MDAxNTkzMTYzMTAxNzEz.2ZOU95zPr-Yf7OWs9Iy_qCnvEhVKm2dXLkhaBXATNtUg.8ZPKSf1bE8wpKfN1uR3aXVzZv9YIfl6q2aB3cKgeh84g.GIF.c_blub/48C5FAA5-5FDB-421A-95EA-331A34587FA5.gif?type=w966" width="200" height="200"/></p>
<p>코드를 다시 한번 살펴보자</p>
<pre><code class="language-Kotlin">
fun Gcd(a:Int, b:Int):Int {
    var r = a % b
    if (r == 0)
       return b
    else
       return Gcd(b, r)
}
{ ... }</code></pre>
<p>Gcd() 는 나머지 𝛾 이 0이 될 때 모든 연산을 끝내게 된다.
다시 말하면 𝛾 은 유한한 횟수 안에 언젠가 0 된다는 것이다. 
언젠가는 나머지가 0이 된다라는걸 확신하는 듯한 저 표정이 거만하기 짝이 없다. 저게 블러핑인지 아닌지 한번 확인해보자. </p>
<p><code>a / b 의 나머지가 𝛾</code> 이듯, <code>b / 𝛾 의 나머지가 𝛾´</code> 라고 말해보자.</p>
<p><code>핵심 주제 ① = 𝒹 는 a와 b 와 𝛾의 최대공약수임</code> 에 따라서 <code>gcd(a, b) = gcd(b, 𝛾)</code> 이듯 <code>gcd(b, 𝛾) 은 gcd(𝛾, 𝛾´)</code> 이다.</p>
<p>..어 왜?</p>
<p>두 정수 a 와 b 를 다시 한번 살펴보자. (a &gt; b), a 와 b 의 최대공약수를 𝒹 라고 할 때</p>
<blockquote>
<p>a = q * b + 𝛾
gcd(a, b) = gcd(b, 𝛾) 
a 와 b 의 최대공약수 == b 와 𝛾 의 최대공약수</p>
</blockquote>
<p>마찬가지로 이번엔 위의 내용과 상관없이 순수하게 두 정수 b 와 r 을 살펴보자. (b &gt; 𝛾) </p>
<blockquote>
<p>b = q * 𝛾 + 𝛾´
gcd(b, 𝛾) = gcd (𝛾, 𝛾´) 
b 와 𝛾 의 최대공약수 == 𝛾 와 𝛾´의 최대공약수</p>
</blockquote>
<p><code>핵심 주제 ① = a 와 b 와 𝛾 의 최대공약수가 𝒹로 같다.</code>에 따라서 </p>
<ul>
<li>gcd(a,b) == gcd(b,𝛾) 인데</li>
<li>gcd(b,𝛾) == gcd(𝛾, 𝛾´) 이니</li>
<li>gcd(a,b) == gcd(𝛾, 𝛾´) 이다.</li>
</ul>
<p>오, 그렇다면 <code>𝛾´ 과 𝛾´´</code> 사이에도 <code>최대공약수는 𝒹</code> 이고 <code>𝛾´´ 과 𝛾´´´</code> 에도 <code>최대공약수는 𝒹</code> 이고 <code>𝛾´´´ 과 𝛾´´´´</code> 에도 <code>𝒹</code> 이고 <code>{ ... }</code> 에도 <code>𝒹</code>  </p>
<p>무한한 나머지와 그 나머지의 최대공약수는 언제나 a 와 b 의 최대공약수와 같다는 건 알겠지만, 혹시 <code>𝛾´´´´´´{...}</code>가 0이 안되면 어떻게 될까?? </p>
<p><code>𝛾´´´´´´{...}</code> 를 이제부터 <code>crazy_𝛾</code>이라고 불러보자.
나머지를 계속하다보면 언젠가는 우린 <code>crazy_𝛾</code>를 만나게 될텐데, 그때의 식은 다음과 같을 것이다.</p>
<blockquote>
<p>b &gt; 𝛾 &gt; 𝛾&#39; &gt; 𝛾&#39;&#39; &gt; 𝛾&#39;&#39;&#39; ... crazy_r != 0</p>
</blockquote>
<p>우리는 기억해내야 한다, <code>b</code> 와 <code>𝛾</code> 도, 그 어떠한 <code>crazy_𝛾</code> 들도 모두 <code>정수</code> 라는 것을.
즉, <code>crazy_𝛾</code> 이 정수고, 0이 아니라면 <code>less_crazy_𝛾</code>과 <code>crazy_𝛾</code>로 나눠서 <code>more_crazy_𝛾´</code>라는 정수를 만들 수 있으니</p>
<blockquote>
<p>b &gt; 𝛾 &gt; 𝛾&#39; &gt; 𝛾&#39;&#39; &gt; 𝛾&#39;&#39;&#39; ... &gt; less_crazy_𝛾 &gt; crazy_𝛾 &gt; more_crazy_𝛾 &gt; more_crazy_𝛾2 { ... } </p>
</blockquote>
<p>가 성립함을 알 수 있고, 여기서 항상 <code>crazy_𝛾</code>은 <code>crazy_𝛾 &gt; more_crazy_𝛾</code>를 성립하게 된다. 
왜냐하면 <code>more_crazy_𝛾</code>는 <code>crazy_𝛾</code>의 나머지이니까.</p>
<p>정수가 언제나 앞의 숫자보다 작아진다면, 언젠가는 0에 도달하게 된다. 왜냐고? 그것이 정수이니까 (끄덕)</p>
<blockquote>
<p>a &gt; b 일 때, a 와 b 가 정수라면 a 와 b 차이의 최솟값은 1
a &gt; b &gt; b&#39; 는 최소한 1씩 줄어드는 정수이며, 이게 계속해서 반복된다면 언젠가는 0에 도달하게 된다. </p>
</blockquote>
<p>따라서 <code>핵심주제 ② = crazy_𝛾은 언젠가는 0이 될 수 밖에 없다</code> !!</p>
<p><img 
src="https://blog.kakaocdn.net/dn/b7Rey8/btqExZC771a/cZofK59sF1KN00Exlz3sWK/img.gif" width="200" height="200"/></p>
<p>마지막으로 코드를 다시 한번 살펴보면</p>
<pre><code class="language-Kotlin">
fun Gcd(a:Int, b:Int):Int {
    var r = a % b
    if (r == 0)
       return b
    else
       return Gcd(b, r)
}
{ ... }</code></pre>
<p><code>var r</code> 은 재귀함수로 돌아가며 계속해서 <code>𝛾</code>, <code>𝛾´</code>, <code>𝛾´´</code>, <code>𝛾´´´</code> {...} <code>crazy_𝛾</code> 이 된다 하더라도 
<code>핵심주제 ② = crazy_𝛾은 언젠가는 0이 될 수 밖에 없다</code>에 의해서 언젠가는 0이 된다는 걸 할 수 있다.
그렇기 때문에, 위의 코드가 <code>무한히 돌지 않고 유한한 횟수 내에서</code> 나머지가 0인 순간을 찾을 수 있는 것이다.</p>
<hr>
<h3 id="결론">결론</h3>
<p>유클리드 호제법을 통해 우리는 다음과 같이</p>
<ul>
<li><code>핵심주제 ① : a 와 b 와 𝛾 의 최대공약수가 𝒹로 같다.</code></li>
<li><code>핵심주제 ② : crazy_𝛾은 언젠가는 0이 될 수 밖에 없다</code></li>
</ul>
<p>가 성립함을 알 수 있었고, 이에 따라 Gcd(최대공약수)를 구하는, 소위 나머지 알고리즘라는 것이 성립함을 알 수 있었다. </p>
<p>즉 정수 <code>a</code>, <code>b</code>, <code>𝛾</code> 이 있을 때</p>
<pre><code class="language-Kotlin">fun Gcd(a:Int, b:Int):Int {
    var r = a % b
    if (r == 0)
       return b
    else
       return Gcd(b, r)
}</code></pre>
<p>와 같이 <code>a</code> 와 <code>b</code> 를 나눈 나머지 <code>𝛾</code>가 0이 될 때 까지</p>
<ul>
<li><code>a = b</code></li>
<li><code>b = r</code> 
을 반복하다보면 언젠가 최대공약수가 나온다는 것을 알게되었다.</li>
</ul>
<p><em>Gcd 문제 푸는데 이걸 다 알아야 하냐고?</em></p>
<p><img 
src="https://postfiles.pstatic.net/MjAyMDA2MjZfMTg2/MDAxNTkzMTYzMTAxNzEz.2ZOU95zPr-Yf7OWs9Iy_qCnvEhVKm2dXLkhaBXATNtUg.8ZPKSf1bE8wpKfN1uR3aXVzZv9YIfl6q2aB3cKgeh84g.GIF.c_blub/48C5FAA5-5FDB-421A-95EA-331A34587FA5.gif?type=w966" width="200" height="200"/></p>
<p><img 
src="https://storage.googleapis.com/jjalbot-jjals/2018/12/rylg064feE/20171212_5a2ea716c5d24.gif" width="200" height="200"/></p>
<blockquote>
<p>출처
brain from 감자 4호 <br/>
알고리즘 공부하면서 알아본 내용입니다, 오류 • 오타 등 알려주시면 정말 감사하겠습니다 :)</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[문과생이 적어보는 백트래킹 (재귀와 DFS 를 곁들인)]]></title>
            <link>https://velog.io/@newon-seoul/%EB%AC%B8%EA%B3%BC%EC%83%9D%EC%9D%B4-%EC%A0%81%EC%96%B4%EB%B3%B4%EB%8A%94-%EB%B0%B1%ED%8A%B8%EB%9E%98%ED%82%B9-%EC%9E%AC%EA%B7%80%EC%99%80-DFS-%EB%A5%BC-%EA%B3%81%EB%93%A4%EC%9D%B8</link>
            <guid>https://velog.io/@newon-seoul/%EB%AC%B8%EA%B3%BC%EC%83%9D%EC%9D%B4-%EC%A0%81%EC%96%B4%EB%B3%B4%EB%8A%94-%EB%B0%B1%ED%8A%B8%EB%9E%98%ED%82%B9-%EC%9E%AC%EA%B7%80%EC%99%80-DFS-%EB%A5%BC-%EA%B3%81%EB%93%A4%EC%9D%B8</guid>
            <pubDate>Tue, 04 Jan 2022 15:30:02 GMT</pubDate>
            <description><![CDATA[<h1 id="문과생이-적어보는-백트래킹재귀와-dfs-를-곁들인">문과생이 적어보는 백트래킹(재귀와 DFS 를 곁들인)</h1>
<blockquote>
<p>들어가기에 앞서서, 해당 글은 기본적인 문법 (for, while, print, 입력받기, 배열)에 대해서 알고 있음을 전제로 합니다.<br>만약 기본적인 문법을 모르는 상태라면 반복문과 출력, 배열, 입력받기에 대해서 먼저 이해한 후 다시 찾아와주세요. :)  </p>
</blockquote>
<blockquote>
<p>이 글은 백트래킹만 언급하는 것이 아니라 재귀함수부터 백트래킹까지 모든 내용을 차례대로 다룹니다.<br>그 과정에서 약간의 자료구조(Stack), 명령형 프로그래밍과 선언형 프로그래밍의 차이, DFS 를 재귀로 구현하는 이유 등에 대해서 언급합니다.<br>예제에서 C언어와 Kotlin 을 섞어서 사용하고 있지만, 최대한 언어적 특징없이 기본적인 문법만 사용합니다.    </p>
</blockquote>
<blockquote>
<p>글은 작성자가 이해한 흐름에 따라 작성되었으며, 의식의 흐름에 따라 작성되어 존대없이 편한 말로 작성되었습니다.<br>오류 및 오타 지적 감사합니다. :)<br>작성자 : 뉴원(Newon)</p>
</blockquote>
<h3 id="백트래킹-dfs-탐색-중-가지치기-하는-것">백트래킹, DFS 탐색 중 가지치기 하는 것.</h3>
<p><code>백트래킹</code>은 완전 탐색 방법 중 하나인 <code>깊이 우선 탐색(DFS)</code>을 진행하면서 조건을 확인,<br><code>해당 노드가 유망하지 않으면</code> 더 이상 탐색하지 않는 것을 의마한다.  </p>
<p>백트래킹은 일반적으로 재귀의 형태로 작성되며, 크게 다음의 3개 내용을 작성해야한다.   </p>
<ul>
<li>재귀를 진행하는 동안 사용될 깊이(depth)를 매개변수로 넣기</li>
<li>재귀가 종료되는 시점에서 수행해야할 내용</li>
<li>재귀가 진행중이면 가지치기(백트래킹)할 내용</li>
</ul>
<p>여기에 재귀함수를 편하게 돌리고 싶다면 재귀에 필요하지만 변하지 않는 변수들과 재귀에서 사용하는 배열들을 전역변수로 선언하면<br>재귀함수의 매개변수가 깔끔해져서 편하다.  </p>
<p>코드로 확인해보자. <a href="https://www.acmicpc.net/problem/15649">백준 N과 M(1) 문제</a> 를 확인하면<br>1 ~ N 까지의 숫자 중에서 M개를 중복없이 오름차순으로 출력하는 것이 문제이다.  </p>
<p><em>코드는 C언어로 쓰였지만, 코드만의 특징없이 작성되었다.</em></p>
<pre><code class="language-C">// 목표 : 1 ~ N 까지의 숫자에서 M개르 선택하고 중복없이 오름차순으로 출력하기

#include &lt;stdio.h&gt;
#include &lt;stdbool.h&gt;

int arr[10] = {0, };                              // 1부터 N까지이니, 마음편하게 10개의 배열을 선언하였다.
bool isusedArr[10] = {false,};                    // 해당 숫자의 중복 여부를 위해 사용했는지 안했는지를 파악할 같은 크기의 배열을 하나 더 선언했다.
int N;                                            // 재귀에서 사용하지만 그 숫자가 변하지는 않는 변수를 전역변수로 선언하였다.
int M;                                            // 재귀에서 사용하지만 그 숫자가 변하지는 않는 변수를 전역변수로 선언하였다.

void Solve(int k){                                // 재귀함수가 사용되는 동안 사용될 depth 를 여기선 k로 표현하고 있다. 
    if(k == M){                                   // 해당 재귀함수는 k가 계속 증가하며, k == M 일때 멈추는 구조를 가지고 있다.
        for (int i = 0; i &lt; M; i++){              // 종료될 때, 수행해야할 내용은 &quot;출력&quot;이므로, 출력을 하고 있다.
            printf(&quot;%d &quot;, arr[i]);
        }
        printf(&quot;\n&quot;);                             // 엔터를 출력하고 있다.
    return;                                   // 마지막에 수행해야할 내용들을 다 수행했으면 return 으로 함수를 종료한다.
    }

    for (int i = 1; i &lt;= N; i++){                 // 재귀함수가 종료시점이 아니라면 for 문을 통해 재귀를 진행한다.
        if(!isusedArr[i]){                        // 가지치기할 내용을 찾고있다. 이번 같은 경우는 중복을 없애기 위해 다음과 같이 적용하고 있다.
            arr[k] = i;                           // arr[k] 에 i를 사용하고 있다.
            isusedArr[i] = true;                  // 사용하니까, 사용했음을 표시하고 있다.
            Solve(k+1);                           // 여기에서 재귀가 계속 반복되고 있다. k는 자릿수로 계속 증가하다가, k == M일 때 종료돨 것이다.
            isusedArr[i] = false;                 // 다음 DFS 를 위해 다시 사용하지 않았으로 바꿔주고 있다.
        }
    }
}

int main(){
    scanf(&quot;%d %d&quot;, &amp;N, &amp;M);                       // 함수의 시작이다. N과 M을 입력받고 있다.
    Solve(0);                                     // 재귀함수의 시작이다. 0부터 시작하고 있다.
}</code></pre>
<p>코드를 크게크게 확인해보자  </p>
<ul>
<li>Solve 함수는 DFS 함수로 k를 기준으로 진행되고 있다.  </li>
<li>Solve 의 맨 위에선 재귀가 종료될 시점에 출력을 하고 변경없이 return 으로 함수를 종료하고 있다.  </li>
<li>Solve 의 밑 에서는 for 문을 통해 가지치기할 내용을 확인하고 있다.<br><code>if(!isusedArr[i])</code> 를 통해 isusedArr이 0, 즉 사용하지 않은 숫자라면 재귀를 진행하고 있다.<br>세부적으론, <code>arr[k]</code> 에 i를 넣고있고, 해당 i를 사용처리 한 후 다음 재귀로 넘어가고 난 후 비사용으로 바꿔주고 있다.  </li>
</ul>
<p>백트래킹은 위의 구조를 기본 골조로 하며, 조건의 추가 &amp; 삭제, 혹은 해당 depth 의 사용, 미사용 등의 조합으로 사용된다.  </p>
<h2 id="아-그래서-그게-뭔데-ㄹㅇㅋㅋ">아 그래서 그게 뭔데 ㄹㅇㅋㅋ</h2>
<img src="https://user-images.githubusercontent.com/80164141/138657237-2fb8bf1f-2cd5-4a6e-9d84-3bd303c251d5.jpg" width="30%"/>

<p>만약 당신이 위의 글만 보고서 <strong>아 ! 백트래킹이란 저런거구나 ㅎㅎ 이해했어</strong> 라면 이제 뒤로가기를 눌러도 좋다.<br>이제부터 이 글은 철저하게 아무것도 모르는 문과생의, 문과생에 의한, 문과생을 위한 언어로 설명된다.  </p>
<p>우선 우리는 ① <code>재귀함수</code>가 무엇인지 정확하게 알 필요가 있다.<br>그 다음으로 ② <code>DFS 함수</code>에 대해서 알아야 하며,<br>최종적으로 DFS 를 진행할 때 ③ <code>가지치기(백트래킹)</code>을 어떻게 하는 지 알아볼 것이다.<br>  <br/></p>
<hr>
<h3 id="①-재귀함수가-뭔데">① 재귀함수가 뭔데</h3>
<h4 id="가-재귀함수란">가. 재귀함수란?</h4>
<img src="https://media.giphy.com/media/3ov9jQX2Ow4bM5xxuM/giphy.gif" width="30%"/>
<img width="600" alt="스크린샷 2021-10-25 오후 5 47 22" src="https://user-images.githubusercontent.com/80164141/138665281-c20aae33-e2ed-46ed-bd0b-59d95e4f289d.png">

<p>재귀함수란 코드 내에서 자기 자신을 호출하는 함수를 의미한다.<br>내가 나를 부르고, 다시 내가 나를 부르고, 틱X 이나 유튜브숏X에서 자주 보던 그것들이 맞다.  </p>
<p>프로그래밍으로 재귀함수는 다음처럼 쓰인다.  </p>
<pre><code class="language-Kotlin">
fun DFS(N: Int){
    print(&quot;$N &quot;)
    return DFS(N + 1);
}

fun main(){
    DFS(0)
}</code></pre>
<p>위의 코틀린 함수를 확인해보자.  </p>
<p>main 함수에서 <code>DFS라는 함수</code>를, 0을 넣어서 호출하고 있다. <strong><em>함수 이름에는 우선 신경쓰지 말자</em></strong><br><code>DFS 라는 함수</code>가 뭐하는 녀석인지 확인해보면, 우선 이녀석은 <code>N을 매개변수</code>로 받고 있다.<br>이후 print(&quot;$N &quot;) 을 통해서 N과 스페이스바를 출력하고, 종료할 때 자기 자신에 (N+1)을 넣은 것, <code>DFS(N + 1)</code> 을 호출하고 있다.  </p>
<p>그렇다면 이 재귀함수는 어떻게 작동할까?  </p>
<ul>
<li>DFS(0) 호출 - DFS(0)의 내용 수행 - DFS(0 + 1) 호출   </li>
<li>DFS(1) 호출 - DFS(1)의 내용 수행 - DFS(1 + 1) 호출</li>
<li>DFS(2) 호출 - DFS(2)의 내용 수행 - DFS(2 + 1) 호출</li>
<li>무한반복
...  </li>
</ul>
<p>와 같이 반복하게 된다.<br>언제 끝날까? 영원히 끝나지 않는다. 왜냐하면 위의 함수는 자기자신을 호출하곤 있지만, 종료 조건이 없기 때문이다.<br>따라서 위의 컴퓨터의 메모리가 허락할 때 까지 
<code>0 1 2 3 4 5 ... 백만스물하나 ... 백만스물둘...</code><br>을 출력하고 있을 것이다.  </p>
<p><img src="https://user-images.githubusercontent.com/80164141/138710611-7689c33a-2358-419b-afb1-af23b3521219.gif" alt="재귀함수"><br>이 터미널 창을 DFS 함수라고 비유한다면, 다음과 같이 1을 받고 1 출력 종료 -&gt; 2를 받고 2 출력 종료 ... 를 무한반복 중인 것이다.  </p>
<p>위의 재귀함수를 다음과 같이 바꿔보자.</p>
<pre><code class="language-Kotlin">
fun DFS(N: Int){
    if(N == 11)
      return;

    printf(&quot;$N &quot;)
    return DFS(N + 1)
}

fun main(){
    DFS(0)
}</code></pre>
<p>위의 코드와 차이점은 <code>N</code>이 11일 때, 아무것도 하지 않고 그냥 종료가 된다는 것이다.<br>그럼 이 함수는 다음과 같이 작동한다.</p>
<ul>
<li>DFS(0) 호출 - N이 11인지 확인 - 11이 아님 - DFS(0)의 내용 수행 - DFS(0 + 1) 호출</li>
<li>DFS(1) 호출 - N이 11인지 확인 - 11이 아님 - DFS(1)의 내용 수행 - DFS(1 + 1) 호출</li>
<li>DFS(2) 호출 - N이 11인지 확인 - 11이 아님 - DFS(2)의 내용 수행 - DFS(2 + 1) 호출
... </li>
<li>DFS(11) 호출 - N이 11인지 확인 - N이 11임 - 그냥 종료</li>
</ul>
<p>if 문에서 N이 11일 때 종료하라는 내용을 통해서, 해당 재귀함수는 무한반복하지 않고 N이 11일 때 바로 종료하게 된다.<br>따라서 위의 코드는 다음과 같이 출력하고 
<code>0 1 2 3 4 5 6 7 8 9 10</code><br>이후 함수가 종료된다.  </p>
<p>if 문을 통해서 재귀함수가 종료될 조건을 단 것, 이것을 <code>Base Condition</code> 이라고 부른다.  </p>
<p><strong>재귀함수는 매개변수를 통해서 Base Condition 에 점차 다가가도록 설계하는 것이 원칙이다.</strong><br>그래야 재귀함수를 안전하게 종료시킬 수 있기 때문이다.  </p>
<p>매개변수는 Base Condition 에 다가갈수만 있다면 증가해도, 감소해도 상관없지만 일반적으로 감소하도록 설계한다.  </p>
<hr>
<p><img src="https://user-images.githubusercontent.com/80164141/138710611-7689c33a-2358-419b-afb1-af23b3521219.gif" alt="재귀함수">  </p>
<p>이 짤방을 다시 한번 살펴보자, 모든 함수는 return을 기준으로 <code>종료</code>하게 되어있다. 그렇다면 기존에 불려진 함수들은 언제 <code>종료</code>가 될까?  </p>
<p>정답은 <code>호출된 순서의 역순으로 닫힌다</code> 이다. 짤방으로 표현하자면 이렇게 된다.  </p>
<p><img src="https://user-images.githubusercontent.com/80164141/138711835-9b36994d-4091-41b8-a654-e2efa78fea95.gif" alt="재귀함수_완전">  </p>
<p>그래서 코드를 이렇게 짜면, 역순으로 정렬할 수도 있다.   </p>
<pre><code class="language-Kotlin">fun DFS(N: Int){
    if(N == 11){
      return;
    }

    DFS(N + 1)
    print(&quot;$N &quot;)
    return;
}

fun main(){
   DFS(0)
}</code></pre>
<p>위의 코드는 DFS 를 호출한 다음에 N을 print 하고 있다.<br>따라서 <code>N</code> 이 <code>11</code>까지 이른 다음에야 순차대로 종료되며 <code>N이 10일 때</code>, <code>N이 9일 때</code>, <code>8</code>..<code>7</code>..<br>순서대로 출력되고 가장 마지막 == 가장 처음에 호출한 함수가 종료된다.<br><code>출력은 요렇게 나온다. -&gt; 10 9 8 7 6 5 4 3 2 1 0</code>  </p>
<p>이 의미가 이해되었다면 재귀함수란? 에 가장 먼저 나왔던 2개의 짤 중 밑의 짤방이 전부 이해될 것이다.  </p>
<br/>  
<br/>  

<p>이러한 방식을 자료구조 중 <code>Stack</code> 이 적용된 것 이라고 한다. `</p>
<p><img src="https://prmoreira23.github.io/assets/stack-data-structure.gif" alt="스택"></p>
<p>설명에서 push 는 자료 삽입을, pop은 자료를 빼는 것을 의미하며<br>스택 구조가 적용되면 데이터는 언제나 <code>마지막에 넣은 것</code>부터 빼내게 되고, <code>처음에 넣은 것</code> 이 가장 마지막에 나오게 된다.  </p>
<blockquote>
<p>재귀, DFS, 백트래킹이 전부 Stack 이 적용되지만 본 글에서는 이 이상의 Stack 개념은 사용하지 않는다.<br>궁금하거나 필요하다면 Stack 을 찾아보는 것을 추천한다.</p>
</blockquote>
<br/>

<hr>
<p><strong><em>어 음 그런데 말이죠 ..?</em></strong></p>
<img src = "https://c.tenor.com/kZjYjiDPTQEAAAAd/한심좌-khaby00.gif" width="20%"/>  


<p>사실 위의 출력문들은 굳이 재귀로 하지 않고, for 문으로도 쉽게 만들 수 있다.  </p>
<pre><code class="language-Kotlin">for(i in 0..10){
   print(&quot;$i &quot;)
}

// 역순이면 이렇게

for(i in 10 downTo 0){
   print(&quot;$i &quot;)
}</code></pre>
<p>게다가 하나의 함수를 호출하는 것은 단순한 중복문보다 많은 메모리를 요구하며 속도 역시 <em><code>압도적인 힘ㅇ..</code></em> 느리다.<br>이러한 이유에도 불구하고 재귀함수를 쓰는 이유를 알아보자.  </p>
<hr>
<h4 id="나-메모리도-많이-잡아먹고-헷갈리는-재귀함수-왜-씀-feat-선언형-프로그래밍">나. 메모리도 많이 잡아먹고 헷갈리는 재귀함수 왜 씀? (Feat. 선언형 프로그래밍)</h4>
<p>코드란 <code>컴퓨팅 효율적으로만 설계하는 것이 아니라</code><br>이후 <code>타인에 의한</code> 유지 보수를 고려하여 적어야 한다.  </p>
<p><code>즉 누가 보더라도 코드는 쉽게 읽히며, 코드가 수행하는 내용이 직관적이여서 개발자의 작업시간을 줄이는 것</code><br>또한 좋은 코드의 조건 중 하나이다.  </p>
<p>이러한 관점에서 <code>재귀함수</code>는 <code>for 문</code>으로 작성했을 때 보다 월등히 가독성이 높아서, 개발자의 시간을 줄여줄 수 있을 때 사용한다.  </p>
<p>  #</p>
<p>재귀함수가 직관적이라니, 이게 무슨소리일까?  </p>
<p>피보나치의 수열을 예시로 들어보자.<br>수학에서, 피보나치 수(영어: Fibonacci numbers)는 첫째 및 둘째 항이 1이며 그 뒤의 모든 항은 바로 앞 두 항의 합인 수열이다.<br><code>1 1 2 3 5 8 13 21 34 55 ...</code></p>
<p>이걸 For 문과 재귀함수로 구현하면 다음과 같다.  </p>
<pre><code class="language-Kotlin">// for 문으로 작성한 피보나치
fun Fibonacci(N: Int): Int{
   var one = 1
   var two = 1
   var result = 0

   if(N &lt;= 2){
      print(&quot;$one &quot;)
      return;
   }

   for (i in 3..N){
      result = one + two
      one = two
      two = result
   }
   return result
}

// 재귀로 작성한 피보나치
fun Fibonacci(N: Int): Int{
    if(N == 0)
       return 0
    if(N == 1)
       return 1

    return Fibonacci(N - 1) + Fibonacci(N - 2)
}

fun main(){
    print(Fibonacci(10))
}
// 출력은 같은 10이다.</code></pre>
<p>잠시 저 두 함수가 피보나치를 출력한다는 것을 모른채로 비교해보자.  </p>
<p>For 문으로 적힌 함수를 이해하려면 <code>one</code> 이 어떤 변수인지, <code>two</code> 가 어떤 변수인지, <code>result</code> 는 어떤 변수인지<br><code>N</code> 이 왜 2일땐 <code>one</code>만 출력하고 리턴하는지, <code>for문은 왜 3부터 시작하고 그때마다 result 는 one + two 를 받는지</code> 이해하고나야 비로서<br>이 함수가 피보나치 함수임을 이해할 수 있다.  </p>
<p>그에 반면 재귀로 작성된 함수는 간단하다.<br>계산이 어떻게 되는진 모르겠지만 <code>함수(N)</code> 은 <code>함수(N-1)</code> + <code>함수(N-2)</code> 이고,<br>이걸 계속해서 반복하다보면 N 이 0일 땐 0을, N이 1일 땐 1을 리턴하여서 이를 반복한다고 적혀있다.  </p>
<p>더 간단하게는, 내부가 어떻게 돌아가는진 모르겠지만 우린 <code>함수(N) = 함수(N-1) + 함수(N-2)</code> 임을 알 수 있다.  </p>
<p>이것이 재귀함수를 사용했을 때 가독성이 늘어나는 대표적인 사례이다.<br>피보나치 수열은 그나마 2개의 항이 만드는 상황만 이해하면 되었지만, 이보다 더 복잡한 사례가 나온다면 For 문으로 작성된 함수는 더더욱 힘들 것이다.  </p>
<hr>
<p>바로 그런 사례가 있다.<br>재귀함수를 구글링했다면 바로 접해봤을 문제, <strong><em>하노이의 탑</em></strong> 문제이다.  </p>
<p><strong>하노이의 탑</strong> 문제는 <a href="https://ko.khanacademy.org/computing/computer-science/algorithms/towers-of-hanoi/a/towers-of-hanoi">다음</a>과 같다. <a href="https://vidkidz.tistory.com/649">게임</a>  </p>
<p>  <img src="https://upload.wikimedia.org/wikipedia/commons/0/07/Tower_of_Hanoi.jpeg" alt="하노이의 탑"></p>
<p>간략히 요약하면, <code>3개의 대</code>가 있고 <code>크기가 오름차순인 원반들</code>이 있고, 이걸 <code>한번에 하나씩 옮겨서</code> 다른 대로 옮기되,<br><code>큰 원반은 작은 원반 위에 갈 수 없다</code> 는 조건 속에서 수행하라는 것이다.<br>알고리즘 문제로 치환하자면 <code>원반이 움직일 때 마다 어디서 어디로 옮겼는지 출력하고, 최종적으로 몇번 움직였는지 출력하라</code> 정도로 바꿀 수 있겠다.  </p>
<p>For 문으로 도전.. .
도전은 언제나 아름답지만, 이번엔 추천하진 않는다.<br>For 문으로 만들고 싶다면 우선 원반의 갯수만큼 For 문을 만들어야할 것이며, 한번 옮겨질 때 마다 이전의 For 문들은 어떻게 해야하는지,<br>횟수는 어디에서 세야할 지도 막막한데, 원반의 갯수가 N으로 입력받아야 한다면 ..  </p>
<p><img src="https://ac2.namu.la/b3/b3c5dd481cf53631a0e21df5aca56340605fab02b1b0f0177fc74b6c9d05a530.gif" alt="난 죽음을 택하겠다"></p>
<p>여기서 우리는 재귀함수의 진정한 사용이유를 알 수 있다.<br><code>재귀함수의 가장 큰 장점</code>은 For 문과 같은 <code>명령형 프로그래밍</code>이 아니라, <code>선언형 프로그래밍</code>이라는 점에 있다.  </p>
<p>무슨 의미일까?<br>잠시 하노이의 문제는 접어두고, N 팩토리얼을 한번 출력해보자.<br>알다시피, 방법은 For 문과 재귀함수 2개가 있다.  </p>
<p>팩토리얼이란 N을 기준으로 n부터 1까지의 모든 수를 곱한 값이다. <code>(표기는 n!)</code><br>이때 <code>명령형 프로그래밍의 관점</code>에서 10!을 구하려면 다음과 같이 바라보게 된다.</p>
<pre><code class="language-kotlin">var value = 1
for (i in 1..10){
    value *= i
}

----------------
value = 1 * 2
value = (1 * 2) * 3
value = (1 * 2 * 3) * 4
...
value = (1 * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9) * 10</code></pre>
<ul>
<li>value 에 대하여 사용자는 모든 i 항들에 대하여 절차적으로 구하고 나서야 팩토리얼 n을 알게되는 것으로 <code>인식</code>한다.  </li>
</ul>
<p>이를 다시 <code>선언형 프로그래밍 관점</code>에서 바라본다면 다음과 같아진다.</p>
<pre><code class="language-kotlin">fun Factorial(N: Int): Int{    
    if(N == 1) return 1
    return Factorial(N - 1) * N  
}

----------------
N == 10  Factorial(9) * 10
N == 9   Factorial(8) * 9
N == 8   Factorial(7) * 8
...
N == 2   Factorial(1) * 2
N == 1   1</code></pre>
<ul>
<li>재귀함수 Factorial 은 return 값이 재귀함수와 어떤 관계가 있는지 <code>선언</code>만 하였다.  </li>
<li>그 이후 절차에 관련한 것은 return 을 수행하는 컴퓨터에게 <code>맡겨버리고</code> 사용자는 <code>선언</code>에 해당하는 결과값을 갖는 것으로 <code>인식</code>한다.</li>
</ul>
<p>같은 결과값이지만 <code>명령형 프로그래밍의 관점은 사용자가 모든 절차를 인지하고 있음을 전제</code>하는 반면<br><code>선언형 프로그래밍의 관점은 사용자가 결과와 그 나머지의 관계를 선언만</code> 한다는 점에서 차이가 나타난다.  </p>
<p>즉, 재귀함수의 장점 중 하나는 <code>계산에 대한 내용을 컴퓨터에게 맡겨버린다</code>에 있다.<br>이를 하노이에 적용시켜보자.<br><code>문제를 한정시켜서, N개의 원판과 대 A, B, C 가 있을 때 원판들은 최초에 A에 있고, N개의 원판을 C로 옮기는 것을 목표로 한다.</code>  </p>
<p>하노이의 탑 문제의 답을 거꾸로 추적해보면 다음과 같은 특성을 지닌다.</p>
<ul>
<li>가장 마지막의 원판을 제외하고, N - 1 개의 원판들을 B에 옮겨놓는다.</li>
<li>마지막 원판을 C에 갔다 놓는다.</li>
<li>B에 옮겨놨던 원판들을 C에 통째로 옮긴다.  </li>
</ul>
<p>이걸 역순으로 반복하면 우리가 <a href="https://vidkidz.tistory.com/649">게임</a> 에서 진행했던 순서가 된다.  </p>
<pre><code class="language-C">// C로 작성되었다.
// 대의 이름은 각각 A, B, C 이며 N개의 원판이 있는 상황이다. 

#include &lt;stdio.h&gt;

int N;
int count;

void Hanoi(int N, int A, int B, int C){
                                                                     // N 이 0 일때가 Base condition 이지만 이번 경우엔 수행해야할 내용이 없으므로, 적지 않았다.
    if(N &gt; 0){                                                   // N 이 0이 아닌동안, 즉 Base Condition 에 도달하지 않는 동안 수행할 내용이다.
        Hanoi(N-1,A,C,B);                                    // A에 있는 N - 1개 원판들을 C를 이용해서 B로 옮긴다.
        printf(&quot;%d 에서 %d 로 가장 맨 위의 원판 이동\n&quot;, A,C);      // A에 있는 남아있는 원판, 가장 큰 원판을 C로 옮긴다.
        Hanoi(N-1,B,A,C);                                    // B에 있는 N - 1개 원판들을 A를 이용해서 C로 옮긴다.
    }
}

int main(){
    scanf(&quot;%d&quot;, &amp;N);
    Hanoi(N,1,2,3);
}</code></pre>
<p>이 함수에서 개발자는 절차마다 그 값이 무엇인지에 대해서 작성한 코드는 단 1개도 없다.  </p>
<p>개발자는 그저 N - 1 일 때 어떻게 해야하는지 논리적으로 <code>선언</code>만 하였고, 컴퓨터가 대신 <code>계산</code>한 것이다.<br>이것이 재귀함수를 이용하는 이유이다.  </p>
<p>위의 내용이 이해가 안간다면 다음의 영상을 참고하면 좋을 것 같다.<a href="https://www.youtube.com/watch?v=q6RicK1FCUs&amp;t=1s">Tower of Hanoi Problem - Made Easy</a>  </p>
<blockquote>
<p>위의 하노이와 관련된 내용은 참고에 연결된 유튜브 영상의 내용을 요약하여 옮긴 것이다.<br>컴퓨터에 맡겨버린다 라는 의미가 궁금하다면 다음 블로그를 참고해보자. <a href="https://geniusnohkang.tistory.com/28">반복과 재귀 : DFS 문제를 재귀로 구현하면 편리한 이유</a>
<br/>  </p>
</blockquote>
<h5 id="재귀함수편-요약">재귀함수편 요약</h5>
<ol>
<li>재귀함수란 자기 자신을 호출하는 함수이다.  </li>
<li>재귀함수는 매개변수를 통해 Base Condition 에 도달하도록 설계한다.  </li>
<li>모든 재귀함수는 이론적으로 For문이나 While 문으로 구현이 가능하나, 사용자의 편의(가독성)를 위해서 사용된다.  </li>
</ol>
<blockquote>
<p>재귀함수는 다이나믹 프로그래밍에서 다시 한번 쓰이게 된다.  </p>
</blockquote>
<hr>
<h3 id="②-dfs-함수">② DFS 함수</h3>
<p>이제 본론이다. 백트래킹은 뭐길래 DFS와 함께 쓰이는 걸까?<br>한줄 요약하자면 <code>DFS 를 하는 와중에 더 이상 탐색할 필요가 없는걸 쳐내는 행위를 백트래킹</code>이라고 한다.  </p>
<p>DFS(Depth - First - Search) 는 깊이 우선 탐색을 의미한다.<br>어떠한 내용을 <code>완전 탐색(브루트 포스)</code>해야 할 때, 깊이 먼저 탐색하는 것을 의미한다.<br>그리고 우린 이 DFS 를 여태 실컷 살펴보았던 <code>재귀</code>를 통해 구현할 것이다.  </p>
<img src="https://upload.wikimedia.org/wikipedia/commons/7/7f/Depth-First-Search.gif">  

<blockquote>
<p>DFS는 그래프나 트리와 연계되어 사용되지만, 본 글에서는 그래프나 트리의 내용 없이 DFS 그 자체에 대해서만 알아본다.<br>완전 탐색(브루트 포스)라는 개념이 생소하다면 본 글에서는 모든 걸 다 탐색한다 정도로 인지하면 된다.</p>
</blockquote>
<p>DFS는 완전탐색 중 하나이니, 모든걸 탐색해야하는 상황을 가정해보자.  </p>
<p>1부터 6까지의 숫자 중에서 3개를 뽑는 모든 경우의 수를 출력해보고자 한다.<br>여러가지 방법이 있겠지만 우린 다음과 같은 방법을 써보고자 한다.  </p>
<p>  <img src="https://user-images.githubusercontent.com/80164141/138796603-9199937a-948c-41c7-9bc3-9a34ac784fa8.gif" alt="DFS">  </p>
<p>  <em>목표 출력 예제는 다음과 같다.</em></p>
<pre><code>  1 1 1                            |    수행 로직
  1 1 2                            |    ① 3개의 빈칸을 만든다.
  1 1 3                            |    ② 첫번째 자리에 1을 넣어본다.
  1 1 4                            |    ③ 두번째 자리에 1를 넣어본다.
  1 1 5                            |    ④ 세번째 자리에 1을 넣어본다
  1 1 6                            |    ⑤ 세번째 자리에 1을 빼고, 2를 넣어본다.
  1 2 1                            |    ⑥ 6까지 반복하고 나면, 두번째 자리를 2으로 바꾼다.
  1 2 2                            |    ⑦ 세번째 자리를 1부터 채워넣는다.
  ...                              |    ⑧ 6 6 6 가 될때까지 반복한다.  
  6 6 4                            |
  6 6 5                            |
  6 6 6                            |</code></pre><p>  재귀함수로 구성할 것이며, 미리 코드를 보기 전에 고민해보는 것도 좋다.<br>  코드는 다음과 같다.  </p>
<pre><code class="language-C">#include &lt;stdio.h&gt;

int arr[3];                                    // 빈칸을 전역변수로 선언하여 함수가 호출할 때 마다 넣어주는 번거로움을 줄였다.
int N, M;                                      // 문제에선 6개 중 3개이지만, 언제든 입력값에 따라 바꿀 수 있게 N과 M으로 설정했다.
                                               // 여기서는 각각 6과 3으로 직접 하드코딩하지만 밑의 예제는 N과 M으로 넣는다.

void DFS(int depth){                           // 이 재귀함수는 depth 를 기준으로 움직인다. 따라서 Base Condition 도 depth 를 기준으로 작성된다.
     if(depth == 3){                           // depth == 3일 때가 Base Condition 이다.
        for(int i = 0; i &lt; 3; i++){            // 배열에 쌓인 내용을 출력하고 있다.
        printf(&quot;%d &quot;, arr[i]);
    }
    printf(&quot;\n&quot;);
    return;
     }

     for(int i = 1; i &lt;= 6; i++){              // Base Condition 이 아닐때 for문을 돌며 후보군(1 ~ 6)을 찾고 있다.
        arr[depth] = i;                    // 후보군을 찾으면 배열의 빈 칸에 넣고 있다.
        DFS(depth + 1);                    // 다음 깊이로 넘어가고 있다.
     }
}

int main(){
    scanf(&quot;%d %d&quot;, &amp;N, &amp;M);                    // N과 M을 받고 있다.
    DFS(0);                                    // DFS를 0의 깊이부터 선언하고 있다.
}</code></pre>
<p>DFS 재귀함수는 0부터 시작하고 있으며,<br>배열의 인덱스 <code>0 1 2</code> 를 하나의 <code>깊이</code>로 인지하고, 0 -&gt; 1 -&gt; 2의 형태를 취하고 있다.  </p>
<p>따라서 DFS 가 전달받는 depth 는 배열의 왼쪽부터 순서대로 탐색하게 된다.<br>그렇게 DFS 는 1부터 6까지 3개의 숫자를 넣는 방법을 중복을 포함해서 전부 넣고있다.  </p>
<p><img src="https://c.tenor.com/Q1utpA4Y2PYAAAAC/idea-eureka.gif" alt="유레카"><br>이것이 <code>DFS</code> 다.<br><code>깊이</code>를 설정하고, 해당 <code>깊이</code>에 A가 있음을 상정하고, <code>다음 깊이</code>로 가서 해당 깊이에 있을 수 있는 것을 다시 넣고 !!  </p>
<p>하지만 출력문을 보니 좀 불편하다.<br><code>모든걸 깊이대로 탐색</code>하는건 좋은데 <code>중복도 없애고 싶고</code>, <code>오름차순으로 정렬</code>하고 싶은 마음이 들 수도 있다.<br>그걸 수행하는 것이 바로 <code>백트래킹</code>이다.  </p>
<hr>
<h3 id="③-백트래킹">③ 백트래킹</h3>
<p>위의 문제를 다시 한번 바꿔보자.<br>이번에는 1부터 6까지의 숫자 중에서 3개를 뽑되,<br>중복은 허용하지 않으며 오름차순으로 정렬할 것이다.<br>그림으로 표현하자면 다음과 같아진다.  </p>
<img src="https://user-images.githubusercontent.com/80164141/138740819-c6b2e0f1-1eb8-458a-8909-68af4d8ceac9.gif" width="50%"/>


<p>  <em>목표 출력 예제는 다음과 같다.</em></p>
<pre><code>  1 2 3          |      수행로직
  1 2 4          |      3개의 빈칸을 만든다.
  1 2 5          |      첫번째 자리에 1을 넣어본다.
  1 2 6          |      두번째 자리에 2를 넣어본다.
  1 3 4          |      세번째 자리에 3을 넣어본다.
  1 3 5          |      세번째 자리에 3을 빼고, 4를 넣어본다.
  ...            |      6까지 반복하고 나면, 두번째 자리를 3으로 바꾼다.
  3 4 6          |      세번째 자리를 3을 제외한 2~6까지 넣어본다.
  3 5 6          |      4 5 6 가 될때까지 반복한다. 
  4 5 6          |      </code></pre><p>재귀파트에서 살펴보았던 것과 마찬가지로, 이걸 반복문을 통해서 만들수도 있겠지만 제법 많은 고생을 해야한다.<br>우리는 계산에 관한건 컴퓨터에 맡기고 <code>선언</code>으로 구현하고자 한다.<br>또한 조건에 부합하지 않는 것을 이제부터 <code>유망하지 않다</code>라고 표현한다.  </p>
<pre><code class="language-C">#include &lt;stdio.h&gt;

int arr[M];                                    // 빈칸을 전역변수로 선언하여 함수가 호출할 때 마다 넣어주는 번거로움을 줄였다.
int visit[7] = {0, };                          // 마찬가지 이유이다. visit 배열의 용도는 사용한 숫자인지 아닌지를 체크한다. 0 = 미방문, 1 = 방문
int N, M;                                      // 문제에선 6개 중 3개이지만, 언제든 입력값에 따라 바꿀 수 있게 N과 M으로 설정했다.

void DFS(int depth){                           // 이 재귀함수는 depth 를 기준으로 움직인다. 따라서 Base Condition 도 depth 를 기준으로 작성된다.
     if(depth == M){                           // depth == 3일 때가 Base Condition 이다.
        for(int i = 0; i &lt; 3; i++){            // 배열에 쌓인 내용을 출력하고 있다.
        printf(&quot;%d &quot;, arr[i]);
    }
    printf(&quot;\n&quot;);
    return;
     }

     for(int i = 1; i &lt;= N; i++){              // Base Condition 이 아닐때 for문을 돌며 후보군을 찾고 있다.
         if(!visit[i]){                        // 가지치기를 하고 있다, 방문한 곳은 가지 않고 있다.
        arr[depth] = i;                    // 조건에 부합하면 빈 칸에 넣고 있다.
        visit[i] = 1;                      // 가지치기를 위해 조건을 설정하고 있다, 방문한 곳을 방문했다라고 표현하고 있다.
        DFS(depth + 1);                    // 다음 깊이로 넘어가고 있다.
        visit[i] = 0;                      // 다음 단계를 위해 초기화해주고 있다.
     }
     }
}

int main(){
    scanf(&quot;%d %d&quot;, &amp;N, &amp;M);
    DFS(0);
}

//P.s. C언어에서 배열은 변수를 넣어 선언할 수 없어서, stdlib.h 의 동적할당 int* arr = (int*)malloc(sizeof(int) * M)) 을 사용해야하나
//       이해의 편의를 위해서 arr[M]을 넣었다.</code></pre>
<p>가장 상단에서 재귀함수에 필요하되, depth 가 아닌 것들을 전부 전역변수로 선언하였다.    </p>
<p>DFS 재귀함수는 depth 라는 매개변수를 가지고서, Base Condition 에 도달하도록 조정되고 있다.<br>여기서는 depth 가 0부터 1씩 증가하며, Base Condition 이 3일 때 배열에 담긴 내용을 출력하고 종료되도록 설계되었다.  </p>
<p>DFS 재귀함수에서 for문은 Baes Condition 에 도달하지 못했을 때 for 문에 들어가게 된다.<br>for 문에서는 후보군을 찾는 것과 동시에, 후보군을 찾더라도 <code>방문하지 않은 곳</code> 이라는 조건에 부합하지 않으면 <code>유망하지 않으니</code> <code>가지치기</code>하고 있다.<br><code>유망하면</code> 배열에 넣고, 방문처리를 한 후에, 다음 depth + 1 을 한 DFS를 호출함으로써 <code>다음 깊이</code>로 넘어가고 있다.  </p>
<p>하나의 재귀함수가 <code>Base Condition (depth == 3)</code>에 도달하더라도<br>for 문에서 불려졌던 재귀함수들은 아직 종료되지 않았다.<br>DFS를 호출한 그곳으로 다시 돌아가서 방문처리 한 내용을 다시 미방문처리하고 <code>(== 해당 깊이의 끝을 보아서 거슬러 올라가기)</code>,  
for 문에서 다음 후보군을 찾고 다시 가지치기를 진행하고, 배열에 넣고, <code>유망</code>한지 확인하고, 다음 깊이로 넘어가는 작업을 반복하고 있다.<br>또한 for 문은 계속해서 증가하게 되므로, <code>오름차순</code>으로 자연스럽게 정렬이 된다.  </p>
<p>이것이 깊이 우선 탐색에서 사용되는 백트래킹이다.<br>그래프와 트리의 개념없이 설명되었지만 사실 <code>다음 깊이</code>로 상정한 <code>배열</code> 을, 다음 <code>노드</code>로 바꾼다면 같은 맥락이 된다.  </p>
<hr>
<h3 id="결론">결론</h3>
<p><img src="https://c.tenor.com/k0HlwNZW9ZsAAAAC/kindergarden-congratulations.gif" alt="Congratulation"><br><img src="https://media3.giphy.com/media/95P1vO6r7rsk0/giphy.gif" alt="Thank you">  </p>
<br/>  

<p>여기까지 따라와주셔서 감사합니다 :)  </p>
<p>이제 다시 한번 맨 위의 글을 보면 무슨 내용을 말했는지 완벽하게 이해가 갈 것이다.<br>여기까지 읽었다면 백트래킹을 좀 더 체화하기 위해서 <a href="https://www.acmicpc.net/workbook/view/2052">백준의 N과 M 시리즈</a>를 전부 풀어보는 것을 추천한다.<br>설령 내용이 완벽하게 이해가 안 가더라도, 문제를 풀면서 자연스럽게 체화될 것이다.  </p>
<p>그리고 N과 M을 전부 풀었다면, 당신은 그 악명높은 <a href="https://www.acmicpc.net/problem/9663">N-Queen</a> 문제도 풀 수 있는 실력이 된 것이다.<br>화이팅 !  </p>
  <br/>
  <br/>

<p>안뇽 ~ :)<br><br/></p>
<p><img src="https://user-images.githubusercontent.com/80164141/138802009-f777c0cc-d1d1-4cde-8702-9c5e52329e74.gif" alt="북극여우가 눈으로 점프하는 짤"></p>
<h2 id="참고">참고</h2>
<p><a href="https://burning-camp.tistory.com/66">[자료구조] 스택(Stack)이란?</a><br><a href="https://ko.wikipedia.org/wiki/%ED%94%BC%EB%B3%B4%EB%82%98%EC%B9%98_%EC%88%98">피보나치 수열</a><br><a href="https://www.youtube.com/watch?v=WPSeyjX1-4s&amp;t=1502s">6. Recursion and Dictionaries</a><br><a href="https://www.youtube.com/watch?v=q6RicK1FCUs&amp;t=1s">Tower of Hanoi Problem - Made Easy</a><br><a href="https://geniusnohkang.tistory.com/28">반복과 재귀 : DFS 문제를 재귀로 구현하면 편리한 이유</a>  </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[안드로이드 스튜디오 미세먼지 팁 (독자적인 Kotlin 모듈 / Jetpack Compose 함수 분할)]]></title>
            <link>https://velog.io/@newon-seoul/%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4-%EB%AF%B8%EC%84%B8%EB%A8%BC%EC%A7%80-%ED%8C%81-%EB%8F%85%EC%9E%90%EC%A0%81%EC%9D%B8-Kotlin-%EB%AA%A8%EB%93%88-Jetpack-Compose-%ED%95%A8%EC%88%98-%EB%B6%84%ED%95%A0</link>
            <guid>https://velog.io/@newon-seoul/%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-%EC%8A%A4%ED%8A%9C%EB%94%94%EC%98%A4-%EB%AF%B8%EC%84%B8%EB%A8%BC%EC%A7%80-%ED%8C%81-%EB%8F%85%EC%9E%90%EC%A0%81%EC%9D%B8-Kotlin-%EB%AA%A8%EB%93%88-Jetpack-Compose-%ED%95%A8%EC%88%98-%EB%B6%84%ED%95%A0</guid>
            <pubDate>Tue, 04 Jan 2022 15:20:11 GMT</pubDate>
            <description><![CDATA[<h3 id="안드로이드-스튜디오-내부에서-독자적인-kotlin-모듈-만들기">안드로이드 스튜디오 내부에서 독자적인 Kotlin 모듈 만들기</h3>
<ol>
<li><p>안드로이드 스튜디오 좌측 App 에 오른쪽 버튼
 New -&gt; Module 을 클릭한다.
<img src="https://user-images.githubusercontent.com/80164141/148077461-6094185c-e132-42c9-baf7-2334a64318b9.JPG" alt="Kotlin 모듈 1"></p>
</li>
<li><p>Application / Library name 에 Kotlin Module 이름 생성
<img src="https://user-images.githubusercontent.com/80164141/148077471-0eb4f103-22cd-4b90-af1d-3e5c8f6747b9.jpg" alt="Kotlin 모듈 2"></p>
<blockquote>
<p>Module name 에는 문법을 위한 이름이 설정된다. </p>
</blockquote>
</li>
<li><p>[설정한 이름]의 새로운 모듈 내부에, java 파일 내부에서 원하는 코틀린을 실행한다.
<img src="https://user-images.githubusercontent.com/80164141/148077473-c5abaa6a-2dc7-4f3a-9856-9cce5d2a3c46.jpg" alt="Kotlin 모듈 3"></p>
</li>
</ol>
<ul>
<li><p><code>fun main(){}</code> 은 Kotlin 의 시작이다. 없으면 실행이 안된다.</p>
</li>
<li><p>해당 코틀린 파일 (혹은 class) 을 오른쪽 클릭, 실행을 누르면 실행할 수 있다.</p>
</li>
<li><p>App 과 별개로 코틀린이 작동되며, 밑에 터미널처럼 결과가 나온다. (인텔리제이처럼 나온다.)</p>
</li>
<li><p><a href="https://play.kotlinlang.org/?_gl=1*1wujwke*_ga*MTU5NDEwOTY2OC4xNjQxMzA4NTMy*_ga_J6T75801PF*MTY0MTMwODUzMi4xLjAuMTY0MTMwODUzMi4w&amp;_ga=2.170054563.2015189665.1641308532-1594109668.1641308532#eyJ2ZXJzaW9uIjoiMS42LjEwIiwicGxhdGZvcm0iOiJqYXZhIiwiYXJncyI6IiIsIm5vbmVNYXJrZXJzIjp0cnVlLCJ0aGVtZSI6ImlkZWEiLCJjb2RlIjoiLyoqXG4gKiBZb3UgY2FuIGVkaXQsIHJ1biwgYW5kIHNoYXJlIHRoaXMgY29kZS4gXG4gKiBwbGF5LmtvdGxpbmxhbmcub3JnIFxuICovXG5cbmZ1biBtYWluKCkge1xuICAgICB2YWwgbiA9IDEyXG4gICAgIHZhbCBkaWdpdCA9IG4udG9TdHJpbmcoKS5tYXAgeyBpdC5jb2RlIC0gNDggfS50b1R5cGVkQXJyYXkoKVxuICAgICB2YXIgcCA9IGRpZ2l0LmNvbnRlbnREZWVwVG9TdHJpbmcoKS50b0ludCgpXG4gICAgIHByaW50bG4ocClcbn0ifQ==">Kotlin Playground</a> 에서도 가능하긴 하지만, 입력을 자유자재로 할 수 있는 이 방법이 더 편한 듯 하다.  </p>
<hr>
</li>
</ul>
<h3 id="jetpack-compose-함수를-쉽게-composable-로-분할해보자">Jetpack Compose 함수를 쉽게 Composable 로 분할해보자.</h3>
<h4 id="상황">상황</h4>
<p><img src="https://user-images.githubusercontent.com/80164141/148079503-48d4a778-2185-4904-965e-3705db05505e.jpg" alt="JetpackCompose 분할 1">
Column 안에 이러한 코드가 있는 상황에서, Surface 함수 전체를 Composable 함수로 분할하고 싶은 상황이다.</p>
<ol>
<li><p>분할하고자 하는 코드를 전부 드래그해서 블록을 씌운 후, <code>오른쪽 클릭 -&gt; Refactor -&gt; Function</code>
<img src="https://user-images.githubusercontent.com/80164141/148079512-5f246989-a2b6-4492-9b24-6dcc16bec3e2.jpg" alt="JetpackCompose 분할 2"></p>
</li>
<li><p>함수의 이름을 설정하면 ..?
<img src="https://user-images.githubusercontent.com/80164141/148079518-af97a90b-1f97-482f-8275-9a3d8c47a5e4.jpg" alt="JetpackCompose 분할 3"></p>
</li>
<li><p>무쳤다 ..
<img src="https://user-images.githubusercontent.com/80164141/148079521-0329d543-6156-4536-bc95-d9cb4e7a4f02.jpg" alt="JetpackCompose 분할 4"></p>
</li>
<li><p>modifier 로 파라미터를 넘겨주고 싶다면 <code>modifier: Modifier = Modifier</code> 를 넣자.
<img src="https://user-images.githubusercontent.com/80164141/148079523-b7582452-b6ff-47e6-93d4-aeb4a9319086.jpg" alt="JetpackCompose 분할 5"></p>
</li>
</ol>
<ul>
<li>이때, 함수 내부의 모든 <code>Modifier</code> 는 매개변수의 <code>modifier</code> 로 교체해주어야 한다.</li>
<li>새로운 <code>modifier</code> 가 들어오면 새로운 값은 <code>override</code>, 기존 값은 그대로 있는다. </li>
</ul>
<ol start="5">
<li>매개변수를 미리 넣고 싶다면 ..<blockquote>
<p>... 안되는 듯..?
<code>var image:String = &quot;abcde&quot;</code>형태로 미리 선언한 값을 넣은 후, Composable 분할 후 다시 복사해서 매개변수 값에 넣고 var 나 val 만 지우는 방법을 쓰면 그나마 편하긴 하지만, Refactor 단위에서 하는 방법은 없는 것 같다.</p>
</blockquote>
</li>
</ol>
]]></description>
        </item>
    </channel>
</rss>