<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>som24.log</title>
        <link>https://velog.io/</link>
        <description>얼레벌레 취준 공부 중인 초보 개발자</description>
        <lastBuildDate>Thu, 08 Feb 2024 08:44:27 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>som24.log</title>
            <url>https://velog.velcdn.com/images/som24/profile/d569cea9-be76-4a5b-9bdf-c5d6c8c233ec/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. som24.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/som24" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Swift에도 Algorithm이 있다는 거 아셨나요?]]></title>
            <link>https://velog.io/@som24/Swift%EC%97%90%EB%8F%84-Algorithm%EC%9D%B4-%EC%9E%88%EB%8B%A4%EB%8A%94-%EA%B1%B0-%EC%95%84%EC%85%A8%EB%82%98%EC%9A%94</link>
            <guid>https://velog.io/@som24/Swift%EC%97%90%EB%8F%84-Algorithm%EC%9D%B4-%EC%9E%88%EB%8B%A4%EB%8A%94-%EA%B1%B0-%EC%95%84%EC%85%A8%EB%82%98%EC%9A%94</guid>
            <pubDate>Thu, 08 Feb 2024 08:44:27 GMT</pubDate>
            <description><![CDATA[<p>이번에 포스팅할 주제를 찾으려고 swift standard library를 뒤져보고 있었는데요. 세상에 Algorithm 문서가 있길래, 이게 뭐지? 하고 바로 공부하게 되었습니다.</p>
<p>저도 코테 준비하느라고 알고리즘 공부하고 있었는데, 너무 흥미로운 주제였습니다. 저한테는 완전 새로운 주제는 아니었어요. 기존에 알고 있었던 문법인데 이걸 swift에서는 알고리즘이라고 지칭하는 구나 정도로 이해하고 있습니다.</p>
<p>아래 내용은 <a href="https://github.com/apple/swift/blob/main/stdlib/public/core/Algorithm.swift">swift &gt; stdlib &gt; public &gt; core &gt; Algorithm.swift</a>을 참고하여 작성했습니다.</p>
<h2 id="개념">개념</h2>
<h3 id="mint-comparable_-x-t-_-y-t"><code>min&lt;T: Comparable&gt;(_ x: T, _ y: T)</code></h3>
<pre><code class="language-swift">@inlinable
public func min&lt;T: Comparable&gt;(_ x: T, _ y: T) -&gt; T {
  return y &lt; x ? y : x
}</code></pre>
<p><code>Comparable</code>한 두 값을 비교하여 더 작은 값을 반환하는 함수입니다. </p>
<h3 id="maxt-comparable_-x-t-_-y-t"><code>max&lt;T: Comparable&gt;(_ x: T, _ y: T)</code></h3>
<pre><code class="language-swift">@inlinable
public func min&lt;T: Comparable&gt;(_ x: T, _ y: T) -&gt; T {
  return y &lt; x ? y : x
}</code></pre>
<p><code>Comparable</code>한 두 값을 비교하여 더 큰 값을 반환하는 함수입니다.</p>
<p>저는 주로 알고리즘 문제를 풀 때 많이 사용했던 함수들이라 익숙했는데요! </p>
<pre><code class="language-swift">let lineCount = Int(readLine()!)!
var triangle: [[Int]] = []

for _ in 0..&lt;lineCount {
    triangle.append(readLine()!.components(separatedBy: &quot; &quot;).map { Int($0)! })
}

for i in 1..&lt;lineCount {
    for j in 0..&lt;i + 1 {
        if j == 0 {
            triangle[i][j] += triangle[i - 1][j]
        } else if j == i {
            triangle[i][j] += triangle[i - 1][j - 1]
        } else {
            triangle[i][j] += max(triangle[i - 1][j], triangle[i - 1][j - 1])
        }
    }
}

print(triangle[lineCount - 1].max()!)</code></pre>
<p>이건 DP 문제를 풀면서 적용해본 사례입니다. 전반적인 코드는 이해 안 하셔도 됩니다!
우리가 봐야할 부분은 <code>max()</code> 함수인데, 두 종류가 있죠!
엄연히 다른 함수라 함수명이 같다고 해서 혼동하시면 안 됩니다!</p>
<p>첫번째로 나온 <code>max(_: T, _: T)</code> 함수는 두 값을 비교하여 더 큰 값을 반환하는 앞에서 공부한 내용입니다.</p>
<p>두번째로 나온 <code>max()</code> 함수는 배열에서 제일 큰 수를 반환하는 함수입니다. </p>
<pre><code class="language-swift">@inlinable
@warn_unqualified_access
public func max() -&gt; Element? {
    return self.max(by: &lt;)
}</code></pre>
<p><code>Sequence</code> 타입에 속해있어 <a href="https://github.com/apple/swift/blob/main/stdlib/public/core/SequenceAlgorithms.swift#L203">SequenceAlgorithms</a>에서 더 자세한 내용 참고하실 수 있습니다.</p>
<h2 id="간단정리">간단정리</h2>
<p>이번 포스팅은 제가 올렸던 글들 중 상대적으로 짧았네요! 
다음 포스팅부터는 오픈소스 정리글 보다는 앱 런칭을 위주로 공부했던 내용들을 올려볼까 합니다!</p>
<blockquote>
<p>Swift의 알고리즘은 <code>min(_: T, _: T)</code>, <code>max(_: T, _: T)</code>로 이루어져 있습니다. 두 함수 모두 2개의 값을 비교하여 작거나 큰 수를 반환합니다. <code>Sequence</code>의 <code>min()</code>, <code>max()</code>와 혼동하지 않도록 주의해야 합니다.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/som24/post/edc4e574-3a1e-4180-86d2-db2193e857d3/image.png" alt=""></p>
<p>모두 새해 복 많이 받으세요~! 이번 년도도 힘차게 시작해봅시다 ㅎㅎ</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Swift Concurrency에 대해 알아봅시다]]></title>
            <link>https://velog.io/@som24/Swift-Concurrency%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B4%85%EC%8B%9C%EB%8B%A4</link>
            <guid>https://velog.io/@som24/Swift-Concurrency%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B4%85%EC%8B%9C%EB%8B%A4</guid>
            <pubDate>Mon, 29 Jan 2024 10:44:04 GMT</pubDate>
            <description><![CDATA[<p>정말 오랜만입니다...ㅠㅜㅠ
필자가 감기가 독하게 걸리는 바람에 이제서야 포스팅을 올리네요..</p>
<p>최근 제 포스팅은 주로 오픈 소스를 공부하고 소개하는 것이 목적이었는데요!
Sendable부터 Actor까지 공부를 하다보니, 최근에 Apple에서 Concurrency 관련된 문서를 업데이트했다는 것을 알게 되었어요!</p>
<p><img src="https://velog.velcdn.com/images/som24/post/73aa8a36-4c1a-4a81-af98-f97fda24b48d/image.png" alt=""></p>
<p>오픈 소스는 아닌데... 이것이 참 Swift 코드를 해부했다고 봐도 무방한가... 같이 스터디하는 분들에게도 여쭤보았는데, 스스로 학습한 것에 의의를 두자는 의견이 나와서 올리게 되었습니다.</p>
<p>그래도 양심상.. SwiftAnatomy 키워드나 시리즈에는 넣지 않겠습니다!</p>
<p>iOS는 동시성 프로그래밍에 매우 진심인 거 같습니다. 새로운 타입인 Actor, 새로운 동시성 프로그래밍 문법인 Concurrency까지 공부하니 개발진이 얼마나 고민해서 만들었는지 느껴질 정도였어요!</p>
<h2 id="개념">개념</h2>
<p>아래부터 나오는 해당 글은 <a href="https://docs.swift.org/swift-book/documentation/the-swift-programming-language/concurrency">Concurrency</a>를 참고하여 작성했습니다.</p>
<p>Concurrency는 크게 7개의 챕터가 있습니다.</p>
<ul>
<li>Defining and Calling Asynchronous Functions(비동기 함수 정의 및 호출) </li>
<li>Asynchronous Sequences(비동기 시퀀스)</li>
<li>Calling Asynchronous Functions in Parallel(병렬로 비동기 함수 호출)</li>
<li>Tasks and Task Groups(작업과 작업 그룹)</li>
<li>Unstructured Concurrency(구조화 되지 않은 동시성)</li>
<li>Actors</li>
<li>Sendable Types</li>
</ul>
<p>Actors와 Sendable Types은 읽어보니까 저번 포스팅과 겹치는 내용들이 간혹 있어서 Concurrency와 관련된 부분만 간략히 다뤄볼게요!</p>
<h3 id="배경">배경</h3>
<blockquote>
<p>Swift에는 구조화된 방식으로 비동기 및 병렬 코드를 작성하기 위한 지원 기능이 내장되어 있다. 한 번에 프로그램의 한 부분만 실행되지만 비동기 코드는 일시 중지했다가 나중에 다시 시작할 수 있다. 프로그램에서 코드를 일시 중지하고 다시 시작하면 UI 업데이트와 같은 단기 작업을 계속 진행하는 동시에 네트워크를 통해 데이터를 가져오거나 파일을 구문 분석하는 등 장기 실행 작업을 계속 진행할 수 있다. 병렬 코드는 여러 코드 조각이 동시에 실행되는 것을 의미한다. 예를 들어 4코어 프로세서가 탑재된 컴퓨터는 각 코어가 작업 중 하나를 수행하면서 4개의 코드 조각을 동시에 실행할 수 있다. 병렬 및 비동기 코드를 사용하는 프로그램은 한 번에 여러 작업을 수행하고 외부 시스템을 기다리는 작업을 일시 중지한다.</p>
</blockquote>
<p>Swift 공식문서는 첫 시작을 해당 문법을 왜 만들었고, 어디에 쓰면 좋은지 소개해줍니다. 많은 데이터가 도착하길 기다리는 비동기 코드와 앱 자체는 멈춰 있으면 안 되기에 동시에 UI 업데이트를 하기 위해선 동시성 프로그래밍을 활용해야 합니다.</p>
<pre><code class="language-swift">listPhotos(inGallery: &quot;Summer Vacation&quot;) { photoNames in
    let sortedNames = photoNames.sorted()
    let name = sortedNames[0]
    downloadPhoto(named: name) { photo in
        show(photo)
    }
}</code></pre>
<p>기존에 @escaping closure와 compeltion handler를 활용했습니다. 저도 처음에 iOS 프로그래밍을 배우면서 많이 썼던 방법입니다. 그런데 이 방법은 중첩 클로저를 쓸 수 밖에 없고, 복잡한 코드를 빠르게 다루기 어려워집니다. 코드 블록도 많이 복잡해지고요. 이러한 단점을 보완하고자 Concurrency 문법이 나왔습니다!</p>
<h3 id="defining-and-calling-asynchronous-functions"><a href="https://docs.swift.org/swift-book/documentation/the-swift-programming-language/concurrency#Defining-and-Calling-Asynchronous-Functions">Defining and Calling Asynchronous Functions</a></h3>
<p>비동기 함수를 정의하고 호출하는 방법입니다.</p>
<blockquote>
<p>비동기 함수 또는 비동기 메서드는 실행 도중에 일시 중지될 수 있는 특별한 종류의 함수 또는 메서드다. 이는 완료될 때까지 실행되거나 오류가 발생하거나 반환되지 않는 일반적인 동기 함수 및 메서드와 대조된다. 비동기 함수나 메서드는 여전히 이 세 가지 작업 중 하나를 수행하지만 무언가를 기다리는 동안 중간에 일시 중지될 수도 있다. 비동기 함수 또는 메서드의 본문 내에서 실행을 일시 중단할 수 있는 각 위치를 표시한다.</p>
</blockquote>
<p>여기서 눈여겨 봐야할 대목은 무언가를 기다리는 동안에 일시 중지될 수 있고, 일시 중단할 수 있는 각 위치를 표시할 수 있다는 점입니다.</p>
<pre><code class="language-swift">func listPhotos(inGallery name: String) async -&gt; [String] {
    let result = // ... some asynchronous networking code ...
    return result
}</code></pre>
<blockquote>
<p>함수나 메서드가 비동기임을 나타내려면 throw를 사용하여 throw 함수를 표시하는 방법과 유사하게 해당 선언의 매개 변수 뒤에 async 키워드를 작성한다. 함수나 메서드가 값을 반환하는 경우 반환 화살표(-&gt;) 앞에 async를 쓴다.</p>
</blockquote>
<pre><code class="language-swift">let photoNames = await listPhotos(inGallery: &quot;Summer Vacation&quot;)
let sortedNames = photoNames.sorted()
let name = sortedNames[0]
let photo = await downloadPhoto(named: name)
show(photo)</code></pre>
<blockquote>
<p>비동기 메서드를 호출하면 해당 메서드가 반환될 때까지 실행이 일시 중단된다. 가능한 일시 중단 지점을 표시하기 위해 호출 앞에 await를 쓴다. 이는 오류가 있는 경우 프로그램 흐름에 가능한 변경 사항을 표시하기 위해 던지는 함수를 호출할 때 try를 작성하는 것과 같다. 비동기 메서드 내에서 실행 흐름은 다른 비동기 메서드를 호출할 때만 일시 중단됩니다. 일시 중단은 암시적이거나 선점적이지 않습니다. 즉, 가능한 모든 일시 중단 지점이 await로 표시된다. 코드에서 가능한 모든 정지 지점을 표시하면 동시 코드를 더 쉽게 읽고 이해할 수 있다.</p>
</blockquote>
<p>async 키워드를 활용하여 비동기 함수를 설정합니다. 비동기 함수는 다른 작업으로 인해 일시 중단될 수 있습니다. 프로그램 내에서는 일시 중지할 지점을 모르기 때문에 사용자가 await 키워드를 활용하여 일시 중지 지점을 지정합니다.</p>
<p>비동기 함수를 정의할 때는 async를, 호출할 때는 await을 사용하면 된다, 정도로 이해가 됩니다! </p>
<p>그런데 문서를 읽어나가다 보면, 이런 대목이 나옵니다.</p>
<blockquote>
<p>코드에서 await로 표시된 일시 중단 지점은 비동기 함수 또는 메서드가 반환될 때까지 기다리는 동안 현재 코드 부분이 실행을 일시 중지할 수 있음을 나타낸다. 이를 yielding the thread라고도 한다. 왜냐하면 뒤에서 Swift가 현재 스레드에서 코드 실행을 일시 중지하고 대신 해당 스레드에서 다른 코드를 실행하기 때문이다. await가 있는 코드는 실행을 일시 중단할 수 있어야 하므로 프로그램의 특정 위치에서만 비동기 함수나 메서드를 호출할 수 있다.</p>
</blockquote>
<p>프로그램의 특정 위치에서만 호출할 수 있다는 것은 await을 특정되지 않은 위치에서는 사용하지 못 한다는 뜻일까요? 제가 생각하기엔, 프로그램의 특정 위치는 엔트리 포인트나 커맨드 라인의 main 파일 정도로 예상이 됩니다. 앱이나 프로그램의 시작 위치를 말하는 거 같은데, 아닌 경우에는 어떻게 활용할 수 있을까요?</p>
<blockquote>
<p>그러나 주기적으로 Task.yield()를 호출하여 정지 지점을 명시적으로 추가할 수 있다. 이러한 방식으로 장기 실행 코드를 구성하면 Swift가 이 작업을 진행하는 것과 프로그램의 다른 작업이 작업을 진행하도록 하는 것 사이의 균형을 맞출 수 있다. </p>
</blockquote>
<p>정리하자면, 일시 중단 지점 설정 방법은 다음과 같습니다.</p>
<ol>
<li>await : 비동기 함수나 메서드를 호출할 때, @main으로 표시된 구조체, 클래스 또는 열거형의 정적 main() 메서드</li>
<li>Task.yield() : 해당 메서드를 호출하여 일시 중단 지점을 명시적으로 삽입</li>
</ol>
<h3 id="asynchronous-sequences"><a href="https://docs.swift.org/swift-book/documentation/the-swift-programming-language/concurrency#Asynchronous-Sequences">Asynchronous Sequences</a></h3>
<p>비동기 시퀀스는 생각보다 간단합니다! for-in문에 await 키워드를 사용하면 됩니다.</p>
<pre><code class="language-swift">import Foundation

let handle = FileHandle.standardInput

for try await line in handle.bytes.lines {
    print(line)
}</code></pre>
<h3 id="calling-asynchronous-functions-in-parallel"><a href="https://docs.swift.org/swift-book/documentation/the-swift-programming-language/concurrency#Calling-Asynchronous-Functions-in-Parallel">Calling Asynchronous Functions in Parallel</a></h3>
<p>이 부분은 아래 챕터인 작업 단위와 연관이 있는 챕터입니다.</p>
<pre><code class="language-swift">let firstPhoto = await downloadPhoto(named: photoNames[0])
let secondPhoto = await downloadPhoto(named: photoNames[1])
let thirdPhoto = await downloadPhoto(named: photoNames[2])

let photos = [firstPhoto, secondPhoto, thirdPhoto]
show(photos)</code></pre>
<p>위의 코드를 보면 비동기 함수를 각 상수를 선언한 곳에 3번 호출을 하고 있습니다. 이럴 경우에 해당 함수는 3번이나 데이터가 올 때까지 일시 정지를 해야하는데, 효율성이 떨어져 보이죠?</p>
<p>이럴 때는 어떻게 해결할 수 있을까요? 챕터 이름대로 병렬 작업으로 해결할 수 있습니다.</p>
<pre><code class="language-swift">async let firstPhoto = downloadPhoto(named: photoNames[0])
async let secondPhoto = downloadPhoto(named: photoNames[1])
async let thirdPhoto = downloadPhoto(named: photoNames[2])

let photos = await [firstPhoto, secondPhoto, thirdPhoto]
show(photos)</code></pre>
<p>프로그램 내 리소스가 충분하다면 3개의 함수가 멀티 스레드에서 실행이 될 거고, photos라는 배열이 해당 요소들이 올 때까지 대기하면 됩니다! </p>
<blockquote>
<p>이 두 접근 방식의 차이점에 대해 생각해 볼 수 있는 방법은 다음과 같다.</p>
<ul>
<li>다음 줄의 코드가 해당 함수의 결과에 따라 달라지는 경우 <code>await</code>를 사용하여 비동기 함수를 호출하라. 이는 순차적으로 수행되는 작업을 생성한다.</li>
<li>나중에 코드에서 결과가 필요하지 않은 경우 <code>async-let</code>을 사용하여 비동기 함수를 호출하라. 이는 병렬로 수행될 수 있는 작업을 생성한다.</li>
<li><code>await</code>와 <code>async-let</code> 모두 일시 중지된 동안 다른 코드가 실행되도록 허용한다.</li>
<li>두 경우 모두 비동기 함수가 반환될 때까지 필요한 경우 실행이 일시 중지됨을 나타내기 위해 <code>await</code>로 가능한 일시 중지 지점을 표시한다.</li>
</ul>
</blockquote>
<h3 id="tasks-and-task-groups"><a href="https://docs.swift.org/swift-book/documentation/the-swift-programming-language/concurrency#Tasks-and-Task-Groups">Tasks and Task Groups</a></h3>
<p>위의 챕터에서 병렬로 하는 방법을 배웠는데, 그것을 작업 단위로 확대해서 생각해볼 수 있습니다. </p>
<pre><code class="language-swift">let photos = await withTaskGroup(of: Data.self) { group in
    let photoNames = await listPhotos(inGallery: &quot;Summer Vacation&quot;)

    for name in photoNames {
        group.addTask {
            return await downloadPhoto(named: name)
        }
    }

    var results: [Data] = []

    for await photo in group {
        results.append(photo)
    }

    return results
}</code></pre>
<p>각 작업 자체는 한 번에 한 가지 작업만 수행하지만 여러 작업을 생성하면 Swift는 해당 작업이 동시에 실행되도록 예약할 수 있습니다. 여러 작업을 그룹으로 생성하고, 하나의 작업은 하위, 그룹은 상위의 개념을 갖습니다.</p>
<blockquote>
<ul>
<li>하위 작업에 더 높은 우선순위를 설정하면 상위 작업의 우선순위가 자동으로 높아진다.</li>
<li>상위 작업이 취소되면 각 하위 작업도 자동으로 취소된다.</li>
<li>작업-로컬 값은 하위 작업에 효율적이고 자동으로 전파된다.</li>
</ul>
</blockquote>
<p>위와 같은 장점들이 있습니다. 여기서 나온 작업 취소의 개념을 살펴보면, 작업 취소는  </p>
<blockquote>
<ul>
<li><code>CancellationError</code>와 같은 오류 발생</li>
<li><code>nil</code> 또는 빈 컬렉션 반환</li>
<li>부분적으로 완료된 작업을 반환</li>
</ul>
</blockquote>
<p>이러한 경우에 일어난다고 합니다.</p>
<pre><code class="language-swift">let task = await Task.withTaskCancellationHandler {
    // ...
} onCancel: {
    print(&quot;Canceled!&quot;)
}

// ... some time later...
task.cancel()  // Prints &quot;Canceled!&quot;</code></pre>
<p><a href="https://developer.apple.com/documentation/swift/task/3814826-checkcancellation"><code>Task.checkCancellation()</code></a> 메서드를 호출하거나 <a href="https://developer.apple.com/documentation/swift/task/3814832-iscancelled"><code>Task.isCancelled</code></a> 프로퍼티를 읽는 두 가지 방법이 있는데.. </p>
<ul>
<li><code>checkCancellation()</code> : 작업이 취소되면 <code>checkCancellation()</code>을 호출하면 오류가 발생합니다. throw 작업은 오류를 작업 외부로 전파하여 작업의 모든 작업을 중지할 수 있습니다. 이는 구현과 이해가 간단하다는 장점이 있습니다.</li>
<li><code>isCancelled</code> : 이 프로퍼티를 사용하면 네트워크 연결 닫기, 임시 파일 삭제 등 작업 중지의 일부로 정리 작업을 수행할 수 있어 유연성이 좋습니다.</li>
</ul>
<h3 id="unstructured-concurrency"><a href="https://docs.swift.org/swift-book/documentation/the-swift-programming-language/concurrency#Unstructured-Concurrency">Unstructured Concurrency</a></h3>
<p>구조화되지 않은 동시성이 뭘까...
저도 공부하면서 많이 띠용했는데, 분리된 작업이라고 생각하면 편할 거 같네요!</p>
<p>따로 사용자 정의 타입 없이 작업을 생성할 때 쓰는 방법 정도로 참고하셔도 좋을 거 같습니다.</p>
<pre><code class="language-swift">let newPhoto = // ... some photo data ...
let handle = Task {
    return await add(newPhoto, toGalleryNamed: &quot;Spring Adventures&quot;)
}
let result = await handle.value</code></pre>
<blockquote>
<p>현재 actor에서 실행되는 구조화되지 않은 작업을 생성하려면 Task.init(priority:operation:) 초기화를 호출하라. 현재 actor의 일부가 아닌 구조화되지 않은 작업(더 구체적으로 분리된 작업이라고 함)을 생성하려면 Task.detached(priority:operation:) 클래스 메서드를 호출한다. 이 두 작업 모두 결과를 기다리거나 취소하는 등 상호 작용할 수 있는 작업을 반환한다.</p>
</blockquote>
<h3 id="actors"><a href="https://docs.swift.org/swift-book/documentation/the-swift-programming-language/concurrency#Actors">Actors</a></h3>
<p>편하게 액터라고 표현하겠습니다!</p>
<pre><code class="language-swift">actor TemperatureLogger {
    let label: String
    var measurements: [Int]
    private(set) var max: Int

    init(label: String, measurement: Int) {
        self.label = label
        self.measurements = [measurement]
        self.max = measurement
    }
}</code></pre>
<pre><code class="language-swift">let logger = TemperatureLogger(label: &quot;Outdoors&quot;, measurement: 25)
print(await logger.max)
// Prints &quot;25&quot;</code></pre>
<blockquote>
<p>이 예에서는 <code>logger.max</code>에 접근하는 것이 정지 지점이 될 수 있다. 액터는 한 번에 하나의 작업만 변경 가능한 상태에 접근하도록 허용하므로 다른 작업의 코드가 이미 <code>logger</code>와 상호 작용하고 있는 경우 이 코드는 프로퍼티에 접근하기를 기다리는 동안 일시 중지된다.</p>
</blockquote>
<blockquote>
<p>대조적으로, 액터의 일부인 코드는 액터의 프로퍼티에 접근할 때 <code>await</code>를 작성하지 않는다. 예를 들어, 새로운 온도로 <code>TemperatureLogger</code>를 업데이트하는 방법은 다음과 같다.</p>
</blockquote>
<pre><code class="language-swift">extension TemperatureLogger {
    func update(with measurement: Int) {
        measurements.append(measurement)
        if measurement &gt; max {
            max = measurement
        }
    }
}</code></pre>
<blockquote>
<p>update(with:) 메서드는 이미 액터에서 실행 중이므로 max와 같은 프로퍼티에 대한 접근을 await로 표시하지 않는다. 또한 이 방법은 액터가 변경 가능한 상태와 상호 작용하기 위해 한 번에 하나의 작업만 허용하는 이유 중 하나를 보여준다. 액터의 상태에 대한 일부 업데이트는 일시적으로 불변성을 깨뜨린다. TemperatureLogger 액터는 온도 목록과 최대 온도를 추적하고 새 측정값을 기록할 때 최대 온도를 업데이트한다. 업데이트 도중에 새 측정값을 추가한 후 최대값을 업데이트하기 전에 온도 로거가 일시적으로 일관되지 않은 상태에 있다. 여러 작업이 동일한 인스턴스와 동시에 상호 작용하는 것을 방지하면 다음과 같은 일련의 이벤트와 같은 문제를 방지할 수 있다.</p>
</blockquote>
<blockquote>
<ol>
<li>귀하의 코드는 <code>update(with:)</code> 메서드를 호출한다. 먼저 측정 배열을 업데이트한다.</li>
<li>코드가 최대값을 업데이트하기 전에 다른 곳의 코드는 최대값과 온도 배열을 읽는다.</li>
<li>코드는 최대값을 변경하여 업데이트를 완료한다.</li>
</ol>
</blockquote>
<blockquote>
<p>이 경우, 다른 곳에서 실행되는 코드는 데이터가 일시적으로 유효하지 않은 동안 <code>update(with:)</code> 호출 중간에 액터에 대한 접근이 인터리브되었기 때문에 잘못된 정보를 읽게 된다. Swift 액터는 상태에 대해 한 번에 하나의 작업만 허용하고 해당 코드는 <code>await</code>가 정지 지점을 표시하는 위치에서만 중단될 수 있기 때문에 Swift 액터를 사용할 때 이 문제를 방지할 수 있다. <code>update(with:)</code>에는 정지 지점이 포함되어 있지 않으므로 업데이트 도중에는 다른 코드가 데이터에 접근할 수 없다. </p>
</blockquote>
<blockquote>
<p>액터 외부의 코드가 구조체나 클래스의 프로퍼티에 접근하는 것처럼 해당 프로퍼티에 직접 접근하려고 하면 컴파일 시간 오류가 발생한다.</p>
</blockquote>
<p>하하 잘 모르는 개념이라 인용문을 엄청 활용했네요😅
간단히 정리하자면 액터는 하나의 작업만 변경 가능한 상태에 접근하도록 허용하기 때문에 다른 작업의 코드가 액터 내부의 코드를 활용하고 있을 때 일시 중지 상태가 됩니다. 그래서 액터의 프로퍼티에 접근할 때 따로 <code>await</code> 키워드가 없어도 됩니다. </p>
<p>하지만 외부에서 접근하게 되면 액터의 프로퍼티가 해당 액터와 격리된 로컬 상태의 일부이기 때문에 요럴 때는 <code>await</code> 키워드가 필요합니다.</p>
<h3 id="sendable-types"><a href="https://docs.swift.org/swift-book/documentation/the-swift-programming-language/concurrency#Sendable-Types">Sendable Types</a></h3>
<p>뭔가 async await 관련한 예제가 있나 했는데, 동시성 프로그래밍을 할 때 값 혹은 데이터를 안전하게 보내기 위해서는 Sendable을 채택하라.. 정도의 내용만 있어서 생략하도록 하겠습니다.</p>
<h2 id="간단정리">간단정리</h2>
<p>이 방대한 내용이 간단 정리가 될지 모르겠습니다...</p>
<blockquote>
<p>async await 이전의 비동기 함수는 주로 @escaping closure를 많이 활용했는데, async 키워드를 활용하여 비동기 함수를 설정할 수 있습니다. 비동기 함수는 다른 작업으로 인해 일시 중단될 수 있어, 사용자가 await 키워드를 활용하여 일시 중지 지점을 지정할 수 있습니다. </p>
</blockquote>
<p>한 달 정도를 동시성 프로그래밍 관련된 것만 공부하다보니, 새로운 환기가 필요한 거 같습니다 (지친 거 아닙니다.. 진짜루..)</p>
<p>그래서 다음 포스팅은 새로운 주제로 돌아오겠습니다! </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Actor에 대해 알아봅시다.]]></title>
            <link>https://velog.io/@som24/Actor%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B4%85%EC%8B%9C%EB%8B%A4-8d96pgen</link>
            <guid>https://velog.io/@som24/Actor%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B4%85%EC%8B%9C%EB%8B%A4-8d96pgen</guid>
            <pubDate>Fri, 12 Jan 2024 07:52:27 GMT</pubDate>
            <description><![CDATA[<p>저번에 <code>Sendable</code>에 대해 공부하면서 새로 등장한 타입, <code>Actor</code>에 대해 포스팅한다고 했습니다!</p>
<p><img src="https://velog.velcdn.com/images/som24/post/275aae60-d779-4e8e-8d1a-fd059922fea3/image.png" alt=""></p>
<p>그 약속 지키러 왔습니다! 후훗~</p>
<p>공부하면서 느낀 부분인데, <code>Actor</code> 요 녀석! 아주 요물입니다!
그러면 차근차근 알아보러 같이 떠나시죠!</p>
<h2 id="배경">배경</h2>
<p>먼저 <code>Actor</code>가 어떤 타입인지 알아보기 전에, Apple이 왜 만들었을까?를 파헤쳐보는 것이 좋을 거 같습니다.
이 질문에 대한 답변은 <a href="https://developer.apple.com/videos/play/wwdc2021/10133/">WWDC 2021 - Protect mutable state with Swift actors</a>에서 자세히 다루고 있습니다. 
관심 있으신 분들은 보시고, <code>Actor</code>에 대해 공부하시는 걸 추천드립니다.</p>
<blockquote>
<p>Swift에는 프로그램 전체에서 공유되는 변경 가능한 상태를 선언하는 메커니즘을 제공하는 클래스가 포함되어 있습니다. 그러나 클래스는 동시 프로그램 내에서 올바르게 사용하기가 매우 어렵기로 악명 높으며, 데이터 레이스를 피하기 위해 오류가 발생하기 쉬운 수동 동기화가 필요합니다. 우리는 공유 변경 가능 상태를 사용하는 동시에 데이터 레이스 및 기타 일반적인 동시성 버그에 대한 정적 감지 기능을 제공하고자 합니다.</p>
</blockquote>
<p>Sendable을 class 타입에 어떻게 준수해야하는지 다들 기억 나시나요?
생각 안 나시는 분들은 <a href="https://velog.io/@som24/Sendable%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B4%85%EC%8B%9C%EB%8B%A4#:~:text=%ED%95%9C%20%EB%B2%88%20%EB%8B%A4%EB%A4%84%EB%B4%90%EC%95%BC%EA%B2%A0%EC%96%B4%EC%9A%94!-,Sendable%20Classes,-Sendable%20%ED%94%84%EB%A1%9C%ED%86%A0%EC%BD%9C%EC%9D%98%20%EC%9A%94%EA%B5%AC">Sendable</a> 다시 읽고 와주십쇼!</p>
<p>결론부터 말하자면, 제약이 엄청 많았습니다. 
저는 참조 타입의 변동성을 컴파일러가 알 수 없어, 저런 제약이 걸려있다라고 생각했지만 반은 맞고 반은 틀렸네요.</p>
<p><img src="https://velog.velcdn.com/images/som24/post/71fbf6a9-e3d2-4579-aaf7-01ce9357e7dc/image.png" alt=""></p>
<p>클래스는 변경 가능한 상태라 데이터 레이스를 피할 수 없어 이러한 제약이 걸려 있었군요!</p>
<p>그렇다면 참조 타입은 클래스 밖에 없는데, 참조 타입으로는 데이터 레이스를 해결하기 힘들까요?</p>
<p>그래서 등장한 것이 <code>Actor</code> 타입입니다!</p>
<h2 id="개념">개념</h2>
<blockquote>
<p><code>Actor</code>는 공유된 변경 가능 상태에 대한 동기화 메커니즘입니다. <code>Actor</code>에는 자체 상태가 있으며 해당 상태는 프로그램의 나머지 부분과 격리됩니다. 해당 상태에 접근하는 유일한 방법은 <code>Actor</code>를 통과하는 것입니다. 그리고 <code>Actor</code>를 통과할 때마다 <code>Actor</code>의 동기화 메커니즘은 다른 코드가 <code>Actor</code>의 상태에 동시에 접근하지 않도록 보장합니다. 이는 잠금 또는 직렬 디스패치 큐를 수동으로 사용하여 얻는 것과 동일한 상호 배제 속성을 제공 하지만 <code>Actor</code>의 경우 Swift에서 기본적으로 제공합니다. 동기화를 수행해주지 않으면 Swift가 컴파일러 오류를 생성하므로 동기화 수행을 잊어서는 안 됩니다.</p>
</blockquote>
<p><code>Actor</code> 타입의 특징은 인스턴스 데이터를 프로그램의 나머지 부분과 분리하고 해당 데이터에 대한 동기화된 접근을 보장한다는 것입니다.
어떻게 가능할까요?</p>
<p>아래 인용문과 예제 코드는 <a href="https://github.com/apple/swift-evolution/blob/main/proposals/0306-actors.md#actors-1">swift-evolution &gt; proposals &gt; 0306-actors.md</a>을 참고하였습니다.</p>
<blockquote>
<p><code>Actor</code> 격리는 액터가 변경 가능한 상태를 보호하는 방법입니다. <code>Actor</code>의 경우 이 보호를 위한 기본 메커니즘은 저장된 인스턴스 속성에만 자체적으로 직접 액세스할 수 있도록 허용하는 것입니다. 예를 들어, 다음은 한 계좌에서 다른 계좌로 돈을 이체하는 방법입니다.</p>
</blockquote>
<pre><code class="language-swift">actor BankAccount {
  let accountNumber: Int
  var balance: Double

  init(accountNumber: Int, initialDeposit: Double) {
    self.accountNumber = accountNumber
    self.balance = initialDeposit
  }
}

extension BankAccount {
  enum BankError: Error {
    case insufficientFunds
  }

  func transfer(amount: Double, to other: BankAccount) throws {
    if amount &gt; balance {
      throw BankError.insufficientFunds
    }

    print(&quot;Transferring \(amount) from \(accountNumber) to \(other.accountNumber)&quot;)

    balance = balance - amount
    other.balance = other.balance + amount  // error: actor-isolated property &#39;balance&#39; can only be referenced on &#39;self&#39;
  }
}</code></pre>
<blockquote>
<p>BankAccount가 클래스인 경우 <code>transfer(amount:to:)</code> 메서드는 형식이 잘 구성되어 있지만 외부 잠금 메커니즘 없이 동시 코드에서 데이터 레이스가 발생할 수 있습니다.</p>
</blockquote>
<blockquote>
<p><code>Actor</code>의 경우 <code>other.balance</code>를 참조하려고 하면 컴파일러 오류가 발생합니다. 왜냐하면 <code>balance</code>는 자체에서만 참조될 수 있기 때문입니다. 오류 메시지에는 <code>balance</code>가 <code>Actor</code> 격리되어 있다는 점, 즉 <code>balance</code>가 연결되거나 &quot;격리된&quot; 특정 <code>Actor</code> 내에서만 직접 접근할 수 있음을 나타냅니다. 이 경우 <code>self</code>가 참조하는 <code>BankAccount</code> 인스턴스입니다. 저장 및 계산된 인스턴스 프로퍼티(예: <code>balance</code>), 인스턴스 메서드(예: <code>transfer(amount:to:)</code>) 및 인스턴스 첨자를 포함하여 <code>Actor</code> 인스턴스에 대한 모든 선언은 기본적으로 모두 <code>Actor</code> 격리됩니다. <code>Actor</code> 분리 선언은 동일한 행위자 인스턴스(<code>self</code>)의 다른 <code>Actor</code> 분리 선언을 자유롭게 참조할 수 있습니다. <code>Actor</code> 분리되지 않은 선언은 분리되지 않으며 <code>Actor</code> 분리 선언에 동기적으로 접근할 수 없습니다.</p>
</blockquote>
<p>정리하자면, Actor의 인스턴스 프로퍼티는 그 자체에서만 참조될 수 있기 때문에 외부에서 참조할 경우 컴파일러 오류가 발생합니다. 이러한 특징을 swift에서는 isolation(격리)라고 표현합니다.</p>
<p><img src="https://velog.velcdn.com/images/som24/post/49fc8cdb-3c99-4167-be4a-692b9f4e3b0c/image.png" alt=""></p>
<p><code>Actor</code>의 내부 동기화 메커니즘은 하나의 <code>increment()</code>가 완료된 후에 다음 <code>increment()</code>가 실행되도록 해줍니다. 따라서 실제로 실행해보면 하나가 먼저 처리되고 그 다음이 처리됩니다.
 
격리 기능으로 인한 것은 이해했지만, 정확히 어떤 원리로 가능한 것인지 아직은 의문이 생깁니다. 위의 WWDC를 보면서 그 의문이 조금 해결되었습니다.</p>
<p><img src="https://velog.velcdn.com/images/som24/post/f88972d5-f521-4e80-9b0f-a49261c4f6f0/image.png" alt=""></p>
<blockquote>
<p>외부에서 Actor와 상호작용할 때마다 비동기로 처리됩니다. 만약 Actor가 사용 중이라면 사용 중인 CPU가 Actor에 접근 중인 코드를 일시 정지하고 다른 작업을 수행합니다. 이후에 Actor의 사용이 끝나면 정지해둔 코드를 다시 실행해서 Actor에 접근합니다. 위 코드에서 await 키워드는 Actor에 대한 비동기 호출이 일시 정지될 수도 있음을 나타냅니다.
(이 부분은 해석이 잘 안 되어서 <a href="https://icksw.tistory.com/269">[WWDC 2021] Protect mutable state with Swift actors 블로그</a>를 참고했습니다.)</p>
</blockquote>
<p>오... 제 뇌피셜이긴 한데, 컴파일러가 Actor의 사용을 추적하여 작업 순서를 정해주는 느낌이 듭니다. 그러면 당연히 비동기 작업이 잠시 일시정지 될 수도 있겠군요!</p>
<p>다음 내용들은 <code>Actor</code>에 <code>protocol</code>을 어떻게 적용하는지, <code>closure</code>와 함수를 다루는 내용들도 있고.. 문서의 경우, <code>Cross-actor</code>를 다루고 있습니다. 관심 있으신 분들은 위의 링크를 눌러 공부해보셔도 좋을 거 같습니다👍</p>
<p>일단 여기까지 <code>Actor</code>에 대해 간단히 알아보았습니다. 
앞서 말씀드린 내용들도 같이 다뤄보고 싶었지만... 이번주는 취업 준비로 시간이 많이 없었네요🥺 죄송합니다🙇‍♀️</p>
<h2 id="간단정리">간단정리</h2>
<blockquote>
<p><code>Actor</code>는 공유된 변경 가능 상태에 대한 동기화 메커니즘입니다. <code>Actor</code> 격리 기능은 액터가 변경 가능한 상태를 보호하여 데이터 레이스를 방지해줍니다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Sendable에 대해 알아봅시다]]></title>
            <link>https://velog.io/@som24/Sendable%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B4%85%EC%8B%9C%EB%8B%A4</link>
            <guid>https://velog.io/@som24/Sendable%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B4%85%EC%8B%9C%EB%8B%A4</guid>
            <pubDate>Tue, 02 Jan 2024 11:31:29 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/som24/post/f3670f14-0cf3-48b9-9df7-3e6d1b5fef75/image.png" alt=""></p>
<p>2024년 첫 포스팅을 <code>Sendable</code>로 하게 되었습니다~
<del>(작년에 하려고 한 건데 이게 맞나)</del></p>
<p>이 글을 보시는 분들 2024년 한 해도 잘 보내시길 바랍니다 0.&lt;~</p>
<h2 id="개념">개념</h2>
<p>해당 코드는 <a href="https://github.com/apple/swift/blob/2cf7b3a063698d1f0e4c2a8e981f328ae077e7f4/stdlib/public/core/Sendable.swift">swift &gt; stdlib &gt; public &gt; core &gt; Sendable.swift</a>에서 볼 수 있습니다.</p>
<pre><code class="language-swift">@_marker public protocol Sendable { }</code></pre>
<blockquote>
<p>복사를 통해 동시성 도메인 간에 값을 안전하게 전달할 수 있는 타입입니다.
한 동시성 도메인에서 다른 동시성 도메인으로 <code>Sendable</code>한 타입의 값을 안전하게 전달할 수 있습니다. 예를 들어 행위자의 메소드를 호출할 때 <code>Sendable</code>한 값을 인수로 전달할 수 있습니다. 다음은 모두 <code>Sendable</code>으로 표시될 수 있습니다.</p>
<ul>
<li>값 타입</li>
<li>변경 가능한 저장소가 없는 참조 타입</li>
<li>내부적으로 상태에 대한 액세스를 관리하는 참조 타입</li>
<li>함수 및 클로저(<code>@Sendable</code>로 표시)</li>
</ul>
<p>이 프로토콜에는 필수 메서드나 프로퍼티가 없지만 컴파일 타임에 적용되는 의미론적 요구 사항이 있습니다. 이러한 요구 사항은 아래 섹션에 나열되어 있습니다. <code>Sendable</code>에 대한 적합성은 해당 타입의 선언과 동일한 파일에서 선언되어야 합니다.</p>
<p>컴파일러 적용 없이 <code>Sendable</code>에 대한 적합성을 선언하려면 <code>@unchecked Sendable</code>을 작성하세요. 예를 들어 잠금 또는 대기열을 사용하여 해당 상태에 대한 모든 액세스를 보호함으로써 확인되지 않은 <code>Sendable</code> 타입의 정확성에 대한 책임이 있습니다. <code>Sendable</code>에 대한 확인되지 않은 적합성은 적합성이 동일한 파일에 있어야 한다는 규칙의 적용을 비활성화합니다.</p>
</blockquote>
<p>즉, <code>Sendable</code>은 동시성 과정에서 안전하게 값을 전달하는 타입입니다. 따로 해당 프로토콜에 필수 메서드나 프로퍼티가 없지만 의미상 <code>Sendable</code>은 해당 타입의 선언과 동일한 파일에서 선언되어야 합니다. 어렵게 보이지만 별로 어려운 이야기는 아닙니다. <code>Sendable</code>을 적용할 타입과 같은 파일 안에서 채택이 되어야 한다는 통상적인 의미로 보입니다.</p>
<p>컴파일러 적용 없이 <code>@unchecked Sendable</code>을 선언하여 직접 <code>Sendable</code>한지 체크하는 방법도 있습니다. 어떤 값이 오는지 확실하게 알 때만 사용하는 것이 좋아보입니다.</p>
<h3 id="sendable-structures-and-enumerations">Sendable Structures and Enumerations</h3>
<blockquote>
<p><code>Sendable</code> 프로토콜의 요구 사항을 충족하려면 열거형 또는 구조체에 전송 가능한 멤버 및 관련 값만 있어야 합니다. 어떤 경우에는 요구 사항을 충족하는 구조체와 열거형이 암시적으로 <code>Sendable</code>을 준수합니다.</p>
<ul>
<li>고정된 구조 및 열거형</li>
<li>구조체 및 열거형
공개되지 않고 <code>@usableFromInline</code>으로 표시되지 않습니다.</li>
</ul>
<p>그렇지 않으면 <code>Sendable</code>에 대한 적합성을 명시적으로 선언해야 합니다.</p>
<p>보낼 수 없는 저장된 프로퍼티와 보낼 수 없는 관련 값이 있는 열거형이 있는 구조체는 <code>@unchecked Sendable</code>로 표시되어 <code>Sendable</code> 프로토콜의 의미론적 요구 사항을 충족하는지 수동으로 확인한 후 컴파일 시간 정확성 검사를 비활성화할 수 있습니다.</p>
</blockquote>
<p><code>Sendable</code> 프로토콜의 요구 사항을 충족하려면 열거형 또는 구조에 전송 가능한 멤버 및 관련 값만 있어야 한다는 것을 보면, 참조가 있을 경우에는 <code>Sendable</code>을 채택할 수 없는 거 같습니다. 이러한 요구사항을 충족하면 암시적으로 <code>Sendable</code>을 준수한다고 합니다. </p>
<p><img src="https://velog.velcdn.com/images/som24/post/1555d790-4657-4611-9e21-19f284de2836/image.png" alt=""></p>
<p>그래서 코린이 시절.. 제가 동시성 프로그래밍할 때 작업할 값타입에 <code>Sendable</code>을 준수하지 않아도 잘 동작했던 것이었군요...!</p>
<h3 id="sendable-actors">Sendable Actors</h3>
<blockquote>
<p><code>Actor</code>는 변경 가능한 상태에 대한 모든 액세스가 순차적으로 수행되도록 보장하므로 모든 <code>Actor</code> 타입은 암시적으로 <code>Sendable</code>을 준수합니다.</p>
</blockquote>
<p>오 <code>Actor</code>에 대해서는 잘 몰라서 그러려니 하고 넘어가는데... 다음 포스팅은 <code>Actor</code>에 대해서 한 번 다뤄봐야겠어요!</p>
<h3 id="sendable-classes">Sendable Classes</h3>
<blockquote>
<p>Sendable 프로토콜의 요구 사항을 충족하려면 클래스는 다음을 수행해야 합니다. </p>
<ul>
<li><code>final</code>으로 표시됨 </li>
<li>변경할 수 없고 전송할 수 있는 저장된 속성만 포함 </li>
<li>슈퍼클래스가 없거나 <code>NSObject</code>를 슈퍼클래스로 사용</li>
</ul>
<p><code>@MainActor</code>로 표시된 클래스는 기본 행위자가 해당 상태에 대한 모든 액세스를 조정하기 때문에 암시적으로 전송 가능합니다. 이러한 클래스에는 변경 가능하고 전송할 수 없는 속성이 저장되어 있을 수 있습니다.</p>
<p>위의 요구 사항을 충족하지 않는 클래스는 <code>@unchecked Sendable</code>로 표시되어 Sendable 프로토콜의 의미론적 요구 사항을 충족하는지 수동으로 확인한 후 컴파일 시간 정확성 검사를 비활성화할 수 있습니다.</p>
</blockquote>
<p>참조타입인 클래스는 수정에 대한 가능성을 컴파일러가 알 수 없기 때문에 저러한 제약이 생긴 거 같습니다. </p>
<h3 id="sendable-functions-and-closures">Sendable Functions and Closures</h3>
<blockquote>
<p><code>Sendable</code> 프로토콜을 따르는 대신 <code>@Sendable</code> 프로퍼티를 사용하여 전송 가능한 함수와 클로저를 표시합니다. 함수나 클로저가 캡처하는 모든 값은 전송 가능해야 합니다. 또한 전송 가능한 클로저는 값별 캡처만 사용해야 하며 캡처된 값은 전송 가능한 타입이어야 합니다.</p>
<p>전송 가능한 클로저를 기대하는 컨텍스트에서 요구 사항을 충족하는 클로저는 묵시적으로 <code>Sendable</code>을 준수합니다(예: <code>Task.detached(priority:Operation:)</code> 호출에서).</p>
<p><code>@Sendable</code>을 타입 주석의 일부로 작성하거나 클로저 매개변수 앞에 <code>@Sendable</code>을 작성하여 클로저를 전송 가능으로 명시적으로 표시할 수 있습니다. 예를 들면 다음과 같습니다.</p>
</blockquote>
<pre><code class="language-swift">let sendableClosure = { @Sendable (number: Int) -&gt; String in
    if number &gt; 12 {
        return &quot;More than a dozen.&quot;
    } else {
        return &quot;Less than a dozen&quot;
    }
}</code></pre>
<p>오... 클로저나 메서드도 Sendable을 적용할 수 있군요! 어트리뷰트로 적용을 할 수 있는 것처럼 보입니다! 연산을 통해서 해당 값을 동시성 프로그래밍에 적용을 할 때 사용하면 요긴할 거 같습니다 ㅎㅎ</p>
<h3 id="sendable-tuples">Sendable Tuples</h3>
<blockquote>
<p><code>Sendable</code> 프로토콜의 요구 사항을 충족하려면 튜플의 모든 요소가 전송 가능해야 합니다. 요구 사항을 충족하는 튜플은 암시적으로 <code>Sendable</code>을 따릅니다.</p>
</blockquote>
<h3 id="sendable-metatypes">Sendable Metatypes</h3>
<blockquote>
<p><code>Int.Type</code>과 같은 메타타입은 암시적으로 <code>Sendable</code> 프로토콜을 따릅니다.</p>
</blockquote>
<p>튜플과 메타타입도 암시적으로 <code>Sendable</code> 프로토콜을 준수한다고 합니다!</p>
<h2 id="간단정리">간단정리</h2>
<blockquote>
<p><code>Sendable</code>은 복사를 통해 동시성 프로그래밍에서 안전하게 값을 보내주는 타입이기 때문에, 값의 안정성을 보장해줄 수 있는 타입입니다. </p>
</blockquote>
<p>따란~ 이미 암시적으로 준수하고 있는 부분들이 많아서 따로 오류가 뜨지 않기 때문에 많이 쓰지는 않은 문법이었는데, 명시적으로 이 타입은 안전하다!를 표현해주는 방식으로도 활용해보면 좋을 거 같습니다~ </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Hashable에 대해 알아봅시다]]></title>
            <link>https://velog.io/@som24/Hashable%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B4%85%EC%8B%9C%EB%8B%A4</link>
            <guid>https://velog.io/@som24/Hashable%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B4%85%EC%8B%9C%EB%8B%A4</guid>
            <pubDate>Fri, 29 Dec 2023 06:41:44 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/som24/post/e66a3127-1aeb-4c15-a76e-c1cf6796c63e/image.png" alt=""></p>
<p>2023년이 얼마 남지 않았네요....ㅠ
고로.. <code>Hashable</code>이 2023년의 마지막 포스트가 되겠네요 ㅎㅎ</p>
<h2 id="개념">개념</h2>
<pre><code class="language-swift">public protocol Hashable: Equatable {
    var hashValue: Int { get }

    func hash(into hasher: inout Hasher)
    func _rawHashValue(seed: Int) -&gt; Int
}</code></pre>
<p>해당 오픈 소스 코드는 <a href="https://github.com/apple/swift/blob/2cf7b3a063698d1f0e4c2a8e981f328ae077e7f4/stdlib/public/core/Hashable.swift">swift &gt; stdlib &gt; public &gt; core &gt; Hashable.swift</a>에서 자세히 볼 수 있습니다.</p>
<blockquote>
<p>정수 해시 값을 생성하기 위해 <code>Hasher</code>로 해시될 수 있는 유형입니다. <code>Set</code> 또는 <code>Dictionary Key</code>로 <code>Hashable</code> 프로토콜을 준수하는 모든 타입을 사용할 수 있습니다. 표준 라이브러리의 많은 타입은 <code>Hashable</code>을 준수합니다. <code>String</code>, <code>Int</code>, <code>Float</code> 및 <code>Bool</code>, 심지어 <code>Set</code>도 기본적으로 해시 가능합니다. <code>Optional</code>, <code>Array</code>, <code>Ranges</code>와 같은 일부 다른 유형은 해당 타입 인수가 동일하게 구현되면 자동으로 해시 가능해집니다.</p>
<p>사용자 정의 타입도 <code>Hashable</code>이 가능합니다. 연관된 값 없이 열거형을 정의하면 <code>Hashable</code> 적합성을 자동으로 얻고, <code>hash(into:)</code> 메서드를 구현하여 다른 사용자 정의 타입에 <code>Hashable</code> 적합성을 추가할 수 있습니다. 저장된 프로퍼티가 모두 <code>Hashable</code>인 구조체와 모든 <code>Hashable</code> 관련 값이 있는 열거형 타입의 경우 컴파일러는 자동으로 <code>hash(into:)</code> 구현을 제공할 수 있습니다.</p>
<p>값을 해싱하는 것은 <code>Hasher</code> 타입으로 표시되는 해시 함수에 필수 구성 요소를 공급하는 것을 의미합니다. 필수 구성 요소는 유형의 <code>Equatable</code> 구현에 기여하는 구성 요소입니다. 동일한 두 인스턴스는 <code>hash(into:)</code>의 <code>Hasher</code>에 동일한 값을 동일한 순서로 공급해야 합니다.</p>
</blockquote>
<p>공식문서는 Hashable을 어떻게 사용하는지를 집중적으로 알려주고 있습니다.
그런데 <code>hashValue</code>, <code>Hasher</code> 이런 개념들은 해당 문서만 보고 이해하기에는 아리송합니다.</p>
<h3 id="hashvalue"><code>hashValue</code></h3>
<p><code>hashValue</code>는 어떤 데이터가 와도 64비트짜리 정수로 치환됩니다. 즉 암호화 작업을 한다고 생각하면 이해가 쉬울 거 같습니다. 원본 데이터를 특정 규칙에 따라 처리하여 간단한 숫자로 만든 것이고, 2개의 데이터 비교시 데이터가 동일할 때 둘의 해시값은 같습니다.</p>
<h3 id="hasher"><a href="https://developer.apple.com/documentation/swift/hasher"><code>Hasher</code></a></h3>
<blockquote>
<p>Set 및 Dictionary에서 사용되는 범용 해시 함수입니다.</p>
<p>Hasher는 임의의 바이트 시퀀스를 정수 해시 값으로 매핑하는 데 사용할 수 있습니다. <code>combine()</code> 메서드를 변경하는 일련의 호출을 사용하여 해셔에 데이터를 공급할 수 있습니다. 해시 입력이 끝나면 <code>finalize()</code>를 호출하여 해시 값을 검색할 수 있습니다.</p>
</blockquote>
<pre><code class="language-swift">var hasher = Hasher()
hasher.combine(23)
hasher.combine(&quot;Hello&quot;)
let hashValue = hasher.finalize()</code></pre>
<blockquote>
<p>Swift 프로그램 실행 내에서 Hasher는 완전히 동일한 바이트 시퀀스가 공급되는 한 프로그램 종료가 항상 동일한 해시 값을 생성하도록 보장합니다. 그러나 기본 해시 알고리즘은 눈사태 효과를 나타내도록 설계되었습니다. 즉, 시드 또는 입력 바이트 시퀀스가 약간 변경되면 일반적으로 생성된 해시 값이 크게 변경됩니다.</p>
</blockquote>
<p>또 모르는 개념이 나왔습니다! 눈사태 효과라... 느낌상 나비효과처럼 작은 변화가 전체적으로 변화를 주는 개념같이 생각이 됩니다.</p>
<h4 id="눈사태-효과">눈사태 효과</h4>
<blockquote>
<p>눈사태 효과는 암호학 용어로, 원문(Plaintext)의 한 비트의 변화가 최종 암호문(Ciphertext)에 큰 변화를 주는 효과입니다. </p>
</blockquote>
<p>설명이 너무 간단한 거 같지만.. 너무 깊게 파면 암호학까지 공부하게 될 거 같아서 여기까지만 알아보기로 했습니다...ㅎㅎ</p>
<p>그러면 조금 더 코드를 뜯어볼까요?</p>
<h3 id="func-hashinto-hasher-inout-hasher"><code>func hash(into hasher: inout Hasher)</code></h3>
<blockquote>
<p>이 값의 필수 구성 요소를 지정된 <code>Hasher</code>에 공급하여 해시합니다. <code>Hashable</code> 프로토콜을 준수하도록 이 메서드를 구현하세요. 해싱에 사용되는 구성 요소는 타입의 <code>==</code> 연산자 구현에서 비교되는 구성 요소와 동일해야 합니다. 이러한 각 구성 요소와 함께 <code>hasher.combine(_:)</code>을 호출하세요.</p>
<p><code>hash(into:)</code> 구현 시 제공된 <code>hasher</code> 인스턴스에서 <code>finalize()</code>를 호출하지 않거나 다른 인스턴스로 바꾸지 마세요. 그렇게 하면 나중에 컴파일 시간 오류가 발생할 수 있습니다.</p>
</blockquote>
<p>오~ 미리 <code>Hasher</code>에 대해 공부하길 잘한 거 같네요👍</p>
<p>Swift 표준 라이브러리에 속한 타입들은 기본적으로 <code>Hashable</code>을 채택하고 있어서 사용자 정의 타입에 <code>Hashable</code>을 채택해도, 저장 프로퍼티가 모두 표준 라이브러리에 속한 타입들이라 따로 이 메서드를 구현해본 적은 없는 거 같아요.</p>
<p>설명을 읽어보니, 해당 값을 <code>Hasher</code>로 암호화하는 기능을 하는 메서드로 보입니다. </p>
<h3 id="func-_rawhashvalueseed-int---int"><code>func _rawHashValue(seed: Int) -&gt; Int</code></h3>
<blockquote>
<p>원시 최상위 해싱 인터페이스. 일부 표준 라이브러리 타입(주로 기본 라이브러리)은 이를 전문화하여 작은 복원력 오버헤드를 제거합니다.</p>
</blockquote>
<p>소스 코드 주석에 딱 이렇게만 쓰여있어서 으잉? 하고 따로 공식문서가 있는지 찾아보았으나... 이 메서드에 대한 공식 문서는 없더라고요. 그래서 이 부분은 몰루? 상태로 넘어가야될 거 같습니다.. (더 성장해서 오겠습니다😅)</p>
<h2 id="간단정리">간단정리</h2>
<blockquote>
<p><code>Hash</code> 자체는 데이터의 암호화를 위해 사용되는 알고리즘입니다.
Swift에서는 <code>Dictionary</code>나 <code>Set</code>의 특정 요소를 검색하기 위한 수단으로 많이 사용됩니다. <code>Array</code>와 다르게 순서라는 개념이 존재하지 않기 때문이죠.</p>
</blockquote>
<p>오늘은 간단하게 <code>Hashable</code>에 대해 공부해보았습니다. 
연말이다보니, 조금은 드문드문 포스팅하고 있지만... 다음주부터는 열심히 올리려고 합니다! </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Equatable에 대해 알아봅시다!]]></title>
            <link>https://velog.io/@som24/Equatable%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B4%85%EC%8B%9C%EB%8B%A4</link>
            <guid>https://velog.io/@som24/Equatable%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B4%85%EC%8B%9C%EB%8B%A4</guid>
            <pubDate>Tue, 19 Dec 2023 03:55:34 GMT</pubDate>
            <description><![CDATA[<p>저번에 예고한 대로 <code>Equatable</code>, <code>Hashable</code>, <code>Sendable</code>을 다뤄보려고 합니다. </p>
<p><img src="https://velog.velcdn.com/images/som24/post/b7eeb1d7-62af-4c76-83fa-5581fd44868f/image.png" alt=""></p>
<p>그 첫번째 포스트! <code>Equatable</code>입니다~ </p>
<h2 id="개념">개념</h2>
<p>해당 코드는 <a href="https://github.com/apple/swift/blob/9858f398320e70e357f636674845938b41d9290e/stdlib/public/core/Equatable.swift#L167">swift &gt; stdlib &gt; public &gt; core &gt; Equatable.swift</a>에서 볼 수 있습니다!</p>
<pre><code class="language-swift">public protocol Equatable {
  /// Returns a Boolean value indicating whether two values are equal.
  ///
  /// Equality is the inverse of inequality. For any values `a` and `b`,
  /// `a == b` implies that `a != b` is `false`.
  ///
  /// - Parameters:
  ///   - lhs: A value to compare.
  ///   - rhs: Another value to compare.
  static func == (lhs: Self, rhs: Self) -&gt; Bool
}</code></pre>
<blockquote>
<p>값 동등성을 비교할 수 있는 타입입니다.<code>Equatable</code> 프로토콜을 준수하는 타입은 같음 연산자(<code>==</code>)를 사용하여 같은지 비교하거나 같지 않음 연산자(<code>!=</code>)를 사용하여 같지 않은지 비교할 수 있습니다. Swift 표준 라이브러리의 대부분의 기본 유형은 <code>Equatable</code>을 따릅니다.</p>
</blockquote>
<blockquote>
<p>일부 시퀀스 및 컬렉션 작업은 요소가 <code>Equatable</code>을 준수하는 경우 더 간단하게 사용할 수 있습니다. 예를 들어, 배열에 특정 값이 포함되어 있는지 확인하려면 동등성을 결정하는 클로저를 제공하는 대신 배열의 요소가 <code>Equatable</code>을 준수할 때 값 자체를 <code>contains(_:)</code> 메서드에 전달할 수 있습니다. </p>
</blockquote>
<p><code>Equatable</code>은 동일한 값인지 비교해주는 프로토콜입니다. 내부 메서드인 <code>==</code>로 매개변수로 들어온 값이 서로 같은 지의 여부를 <code>Bool</code> 타입으로 반환합니다. </p>
<blockquote>
<p>사용자 정의 타입에 <code>Equatable</code> 적합성을 추가하면 컬렉션에서 특정 인스턴스를 검색할 때 더 편리한 API를 사용할 수 있습니다. <code>Equatable</code>은 <code>Hashable</code> 및 <code>Comparable</code> 프로토콜의 기본 프로토콜이기도 하며, 이를 통해 세트 구성이나 컬렉션 요소 정렬과 같은 사용자 정의 타입을 더 많이 사용할 수 있습니다. </p>
<p>타입의 원래 선언에서 <code>Equatable</code> 적합성을 선언하고 유형이 다음 기준을 충족하는 경우 사용자 정의 타입에 대한 <code>Equatable</code> 프로토콜 요구 사항의 자동 합성에 의존할 수 있습니다.</p>
<ul>
<li><code>struct</code>의 경우 모든 저장 프로퍼티는 <code>Equatable</code>을 준수해야 합니다.</li>
<li><code>enum</code>의 경우 연관된 모든 값은 <code>Equatable</code>을 준수해야 합니다. (관련 값이 없는 <code>enum</code>은 선언 없이도 <code>Equatable</code> 적합성을 갖습니다.)</li>
</ul>
</blockquote>
<p>ㅇ0ㅇ! 생각보다 <code>Equatable</code>은 많은 타입에서 준수하고 있었군요! </p>
<blockquote>
<p>타입의 <code>Equatable</code> 적합성을 맞춤설정하려면, 위에 나열된 기준을 충족하지 않는 타입에서 <code>Equatable</code>을 채택하거나, <code>Equatable</code>을 따르도록 기존 타입을 확장하려면 같음 연산자(<code>==</code>)를 해당 타입의 정적 메서드로 사용합니다. 표준 라이브러리는 사용자 정의 <code>==</code> 함수를 호출하고 그 결과를 부정하는 <code>Equatable</code> 타입에 대해 같지 않음 연산자(<code>!=</code>)에 대한 구현을 제공합니다.</p>
</blockquote>
<pre><code class="language-swift">extension Equatable {
  /// Returns a Boolean value indicating whether two values are not equal.
  ///
  /// Inequality is the inverse of equality. For any values `a` and `b`, `a != b`
  /// implies that `a == b` is `false`.
  ///
  /// This is the default implementation of the not-equal-to operator (`!=`)
  /// for any type that conforms to `Equatable`.
  ///
  /// - Parameters:
  ///   - lhs: A value to compare.
  ///   - rhs: Another value to compare.
  // transparent because sometimes types that use this generate compile-time
  // warnings, e.g. that an expression always evaluates to true

  @_transparent
  public static func != (lhs: Self, rhs: Self) -&gt; Bool {
    return !(lhs == rhs)
  }
}</code></pre>
<ul>
<li><code>@_transparent</code>
이 어트리뷰트는 <a href="https://velog.io/@som24/Optional%EC%9D%B4%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EC%A7%80-%EC%84%A4%EB%AA%85%ED%95%98%EC%8B%9C%EC%98%A4.2#:~:text=%EC%A0%9C%EC%96%B4%EC%9E%90%EC%9D%98%20%EB%8A%90%EB%82%8C%EC%9D%B4%EB%9D%BC%20%EC%8B%A0%EC%84%A0%ED%95%98%EB%84%A4%EC%9A%94%F0%9F%98%B3-,%40_transparent,-%EC%9D%98%EB%AF%B8%EC%83%81%20%40_transparent%EB%8A%94">옵셔널</a>에서도 한 번 공부했었죠? 
<code>@_transparent</code>이 명시된 함수는 수정이 되어서는 안 된다는 제약이 있고, 구현 시 비공개 항목(진정 비공개 함수 또는 다음 릴리스에서 사라질 수 있는 내부 함수)이 사용되는 것도 권장하지 않습니다. 즉, <code>public</code> 또는 <code>@usableFromInline</code>된 코드만 권장하고 있습니다.</li>
</ul>
<p>확장된 <code>Equatable</code>에는 기존 내부 메서드와 다르게 <code>!=</code> 메서드가 있습니다. 이 메서드는 두 인스턴스가 서로 다른 ID를 가지고 있는지 여부를 테스트합니다. 상황에 따라 <code>==</code>와 <code>!=</code>를 적절히 활용하면 되겠네요! </p>
<h2 id="간단-정리">간단 정리</h2>
<p>이번 포스트는 <code>Equatable</code>에 대해서 다루어 보았습니다.</p>
<blockquote>
<p><code>Equatable</code>은 값 동등성을 비교할 수 있는 타입입니다.<code>Equatable</code> 프로토콜을 준수하는 타입은 같음 연산자(<code>==</code>)를 사용하여 같은지 비교하거나 같지 않음 연산자(<code>!=</code>)를 사용하여 같지 않은지 비교할 수 있습니다. Swift 표준 라이브러리의 대부분의 기본 유형은 <code>Equatable</code>을 따릅니다.</p>
</blockquote>
<p>다음 포스트에서 뵈어요~!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Result 타입에 대해 알아봅시다!]]></title>
            <link>https://velog.io/@som24/Result-%ED%83%80%EC%9E%85%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B4%85%EC%8B%9C%EB%8B%A4</link>
            <guid>https://velog.io/@som24/Result-%ED%83%80%EC%9E%85%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B4%85%EC%8B%9C%EB%8B%A4</guid>
            <pubDate>Thu, 14 Dec 2023 12:49:28 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/som24/post/f5efb77a-70a8-40ab-9474-4816f0b19923/image.png" alt=""></p>
<p>이번 포스트는 <code>Optional</code>로 지친 심신을 쉬어가는 과정으로 가볍게 <code>Result</code> 타입에 대해 해부해보려고 합니다! </p>
<h2 id="개념">개념</h2>
<p>해당 코드는 <a href="https://github.com/apple/swift/blob/2cf7b3a063698d1f0e4c2a8e981f328ae077e7f4/stdlib/public/core/Result.swift#L16">swift &gt; stdlib &gt; public &gt; core &gt; Result.swift</a>에서 볼 수 있습니다!</p>
<pre><code class="language-swift!">@frozen
public enum Result&lt;Success, Failure: Error&gt; {
  /// A success, storing a `Success` value.
  case success(Success)

  /// A failure, storing a `Failure` value.
  case failure(Failure)

  ...</code></pre>
<blockquote>
<p>각 경우의 관련 값을 포함하여 성공 또는 실패를 나타내는 값입니다. </p>
</blockquote>
<p><code>@frozen</code> 어트리뷰트! 저번에 <a href="https://velog.io/@som24/Optional%EC%9D%B4%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EC%A7%80-%EC%84%A4%EB%AA%85%ED%95%98%EC%8B%9C%EC%98%A4.1#:~:text=..%0A%7D-,%40frozen,-%ED%95%B4%EB%8B%B9%20%EC%96%B4%ED%8A%B8%EB%A6%AC%EB%B7%B0%ED%8A%B8%EB%8A%94%20Swift"><code>Optional</code></a>에서 다뤘는데, 기억 나시나요?
기억 안 나시는 분들은 한 번 보고 오시는 것도 좋을 거 같습니다! (어트리뷰트만 모아서 정리를 해봐야겠어요..!)</p>
<p>코드를 보면, <code>Result</code> 타입은 열거형이라는 정보를 알 수 있네요!
<code>Success</code>와 <code>Failure</code>은 제네릭 타입인데, <code>Failure</code>은 <code>Error</code>를 채택한 타입만 가능하게 설정해두었네요! 
그리고 각 타입은 <code>success</code>, <code>failure</code> 케이스에 각각 저장이 됩니다.</p>
<h3 id="resultmap"><code>Result.map()</code></h3>
<pre><code class="language-swift!">@inlinable
  public func map&lt;NewSuccess&gt;(
    _ transform: (Success) -&gt; NewSuccess
  ) -&gt; Result&lt;NewSuccess, Failure&gt; {
    switch self {
    case let .success(success):
      return .success(transform(success))
    case let .failure(failure):
      return .failure(failure)
    }
  }</code></pre>
<blockquote>
<p>지정된 변환을 사용하여 성공 값을 매핑하여 새로운 결과를 반환합니다. 성공을 나타내는 <code>Result</code> 인스턴스의 값을 변환해야 할 때 이 방법을 사용하세요.</p>
</blockquote>
<p><code>@inlinable</code>도 역시 저번에 <a href="https://velog.io/@som24/Optional%EC%9D%B4%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EC%A7%80-%EC%84%A4%EB%AA%85%ED%95%98%EC%8B%9C%EC%98%A4.2#:~:text=%EC%8B%A4%ED%96%89%EB%90%98%EB%8A%94%20%EA%B1%B0%20%EA%B0%99%EC%8A%B5%EB%8B%88%EB%8B%A4.-,%40inlinable,-%EC%9D%B4%20%ED%8A%B9%EC%84%B1%EC%9D%84%20%ED%95%A8%EC%88%98"><code>Optional</code></a>에서 다뤘습니다 ㅎㅎ
짧게 복기해보자면! 해당 어트리뷰트는 함수, 메서드, 계산된 속성, 첨자, 편의 초기화 또는 초기화 해제 선언에 적용하여 해당 선언의 구현을 모듈 공개 인터페이스의 일부로 노출합니다.</p>
<p>고차함수 <code>map()</code>은 내부 값을 다른 타입으로 변환할 때 많이 쓰이는데요! <code>Result</code> 타입에 있는 <code>map()</code> 메서드도 같은 역할을 합니다.</p>
<pre><code class="language-swift">// Result.map() 예시
func getNextInteger() -&gt; Result&lt;Int, Error&gt; { /* ... */ }

let integerResult = getNextInteger()
// integerResult == .success(5)

let stringResult = integerResult.map { String($0) }
// stringResult == .success(&quot;5&quot;)</code></pre>
<h3 id="resultmaperror"><code>Result.mapError()</code></h3>
<pre><code class="language-swift">@inlinable
  public func mapError&lt;NewFailure&gt;(
    _ transform: (Failure) -&gt; NewFailure
  ) -&gt; Result&lt;Success, NewFailure&gt; {
    switch self {
    case let .success(success):
      return .success(success)
    case let .failure(failure):
      return .failure(transform(failure))
    }
  }</code></pre>
<blockquote>
<p>지정된 변환을 사용하여 실패 값을 매핑하여 새 결과를 반환합니다. 실패를 나타낼 때 <code>Result</code> 인스턴스의 값을 변환해야 할 때 이 방법을 사용하십시오. 다음 예에서는 결과를 사용자 정의 <code>Error</code> 유형으로 래핑하여 결과의 오류 값을 변환합니다.</p>
</blockquote>
<pre><code class="language-swift">// Result.map() 예시
struct DatedError: Error {
    var error: Error
    var date: Date

    init(_ error: Error) {
        self.error = error
        self.date = Date()
    }
}

let result: Result&lt;Int, Error&gt; = // ...
// result == .failure(&lt;error value&gt;)

let resultWithDatedError = result.mapError { DatedError($0) }
// result == .failure(DatedError(error: &lt;error value&gt;, date: &lt;date&gt;))</code></pre>
<p>오... <code>Failure</code>도 <code>map()</code>으로 변환이 가능하군요! 
새로운 사실을 알게 되었네요👍</p>
<h3 id="resultflatmap"><code>Result.flatMap()</code></h3>
<pre><code class="language-swift">@inlinable
  public func flatMap&lt;NewSuccess&gt;(
    _ transform: (Success) -&gt; Result&lt;NewSuccess, Failure&gt;
  ) -&gt; Result&lt;NewSuccess, Failure&gt; {
    switch self {
    case let .success(success):
      return transform(success)
    case let .failure(failure):
      return .failure(failure)
    }
  }</code></pre>
<blockquote>
<p>지정된 변환을 사용하여 성공 값을 매핑하고 생성된 결과를 언래핑하여 새로운 결과를 반환합니다. 변환이 다른 <code>Result</code> 유형을 생성할 때 중첩된 결과를 방지하려면 이 방법을 사용하십시오. 이 예에서는 결과 유형을 반환하는 변환과 함께 <code>map</code>과 <code>flatMap</code>을 사용한 결과의 차이점에 유의하세요.</p>
</blockquote>
<p>이 메서드도 고차함수 <code>flatMap</code>과 같은 기능을 합니다!</p>
<pre><code class="language-swift">// Result.flatMap() 예시
func getNextInteger() -&gt; Result&lt;Int, Error&gt; {
    .success(4)
}

func getNextAfterInteger(_ n: Int) -&gt; Result&lt;Int, Error&gt; {
    .success(n + 1)
}

let result = getNextInteger().map { getNextAfterInteger($0) }
// result == .success(.success(5))

let result = getNextInteger().flatMap { getNextAfterInteger($0) }
// result == .success(5)</code></pre>
<h3 id="resultflatmaperror"><code>Result.flatMapError()</code></h3>
<pre><code class="language-swift">@inlinable
  public func flatMapError&lt;NewFailure&gt;(
    _ transform: (Failure) -&gt; Result&lt;Success, NewFailure&gt;
  ) -&gt; Result&lt;Success, NewFailure&gt; {
    switch self {
    case let .success(success):
      return .success(success)
    case let .failure(failure):
      return transform(failure)
    }
  }</code></pre>
<blockquote>
<p>지정된 변환을 사용하여 실패 값을 매핑하고 생성된 결과를 언래핑하여 새 결과를 반환합니다.</p>
</blockquote>
<h3 id="resultget"><code>Result.get()</code></h3>
<pre><code class="language-swift">@inlinable
  public func get() throws -&gt; Success {
    switch self {
    case let .success(success):
      return success
    case let .failure(failure):
      throw failure
    }
  }
}</code></pre>
<blockquote>
<p>성공 값을 던지는 표현식으로 반환합니다. 성공을 나타내는 경우 이 결과의 값을 검색하거나, 실패를 나타내는 경우 값을 포착하려면 이 메서드를 사용합니다.</p>
<ul>
<li>매개변수 변환: 인스턴스의 성공 값을 취하는 클로저입니다.</li>
<li><code>throws</code>: 클로저 또는 이전 <code>.failure</code>의 <code>Result</code> 인스턴스.</li>
</ul>
</blockquote>
<pre><code class="language-swift">// Result.get() 예시
let integerResult: Result&lt;Int, Error&gt; = .success(5)
do {
    let value = try integerResult.get()
    print(&quot;The value is \(value).&quot;)
} catch {
    print(&quot;Error retrieving the value: \(error)&quot;)
}
// Prints &quot;The value is 5.&quot;</code></pre>
<p><code>do-catch문</code>을 활용한 <code>get()</code> 메서드는 저 같은 경우는 잘 안 쓸 거 같네요🧐
<code>Result</code> 타입을 쓰는 이유는 코드의 간결함을 유지할 수 있어서 쓴다고 생각하는데, <code>do-catch문</code>을 사용하면 간결성이 떨어지기 때문에 잘 활용하지 않을 거 같습니다!
혹시나 이 부분은 제가 잘못 이해하고 있거나, 더 좋은 활용법이 있으시면 댓글로 알려주세요!😉</p>
<h3 id="extension"><code>extension</code></h3>
<ul>
<li><code>Result where Failure == Swift.Error</code></li>
</ul>
<pre><code class="language-swift">extension Result where Failure == Swift.Error {
  @_transparent
  public init(catching body: () throws -&gt; Success) {
    do {
      self = .success(try body())
    } catch {
      self = .failure(error)
    }
  }
}</code></pre>
<blockquote>
<p><code>throw</code>하는 클로저를 평가하고, 반환된 값을 성공으로 캡처하거나, 발생한 오류를 실패로 캡처하여 새 결과를 생성합니다.</p>
</blockquote>
<p>단순 초기화 구문인데 왜 <code>extension</code>으로 뺐을까요...? 이미 열거형에서 <code>Error</code>를 채택한 타입만 <code>failure</code>으로 설정하도록 제약을 두었는데 말이죠..
아시는 분 있으시면 댓글 달아주세요!! </p>
<ul>
<li><code>Equatable</code></li>
</ul>
<pre><code class="language-swift">extension Result: Equatable where Success: Equatable, Failure: Equatable { }</code></pre>
<ul>
<li><code>Hashable</code></li>
</ul>
<pre><code class="language-swift">extension Result: Hashable where Success: Hashable, Failure: Hashable { }</code></pre>
<ul>
<li><code>Sendable</code><pre><code class="language-swift">extension Result: Sendable where Success: Sendable { }</code></pre>
</li>
</ul>
<p>그리고 성공 값일 경우, <code>Equatable</code>, <code>Hashable</code>, <code>Sendable</code>을 채택하고 있습니다!</p>
<p>각각이 어떤 프로토콜인지는 다음 포스트에서 다뤄보겠습니다! </p>
<h2 id="간단정리">간단정리</h2>
<p>오늘은 가볍게 <code>Result</code> 타입에 대해서 다뤄보았습니다!</p>
<blockquote>
<p><code>Result</code> 타입은 성공과 실패에 대한 반환값을 사용하고 싶은 경우에 사용합니다.</p>
<p><code>Result</code> 타입이란 Swift5에서부터 Standard library에 추가되었으며, <code>Generic Enumeration</code>으로 선언되어 <code>success</code> 또는 <code>failure</code> 두가지 <code>case</code>를 포함하는 타입입니다. 여기서 <code>success</code>는 별도의 제약 조건이 없지만, <code>failure</code>같은 경우에는 <code>Error</code>를 상속받은 타입이어야만 합니다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Optional이란 무엇인지 설명하시오.(2)]]></title>
            <link>https://velog.io/@som24/Optional%EC%9D%B4%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EC%A7%80-%EC%84%A4%EB%AA%85%ED%95%98%EC%8B%9C%EC%98%A4.2</link>
            <guid>https://velog.io/@som24/Optional%EC%9D%B4%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EC%A7%80-%EC%84%A4%EB%AA%85%ED%95%98%EC%8B%9C%EC%98%A4.2</guid>
            <pubDate>Tue, 12 Dec 2023 14:04:10 GMT</pubDate>
            <description><![CDATA[<p>빠르게 돌아온(?) <code>Optional</code>, 두 번째 시간입니다!
공부할수록 안정성에 대한 아주 매력적인 문법이라는 걸 깨닫고 있습니다😊</p>
<p>혹시 1편을 안 보고 오신 분들은 <a href="https://velog.io/@som24/Optional%EC%9D%B4%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EC%A7%80-%EC%84%A4%EB%AA%85%ED%95%98%EC%8B%9C%EC%98%A4.1">요기</a>를 클릭해서 보고 오시면 됩니다!</p>
<p>그러면 더 파헤치러 가볼까요?</p>
<h2 id="개념">개념</h2>
<h3 id="unsafelyunwrapped"><code>unsafelyUnwrapped</code></h3>
<pre><code class="language-swift">@inlinable
  public var unsafelyUnwrapped: Wrapped {
    @inline(__always)
    get {
      if let x = self {
        return x
      }
      _debugPreconditionFailure(&quot;unsafelyUnwrapped of nil optional&quot;)
    }
  }</code></pre>
<p>해당 코드는 <a href="https://github.com/apple/swift/blob/main/stdlib/public/core/Optional.swift#L240">Apple &gt; swift &gt; public &gt; ... &gt; Optional.swift</a>에서 볼 수 있습니다.</p>
<blockquote>
<p>인스턴스가 &#39;nil&#39;인지 여부를 확인하지 않고 래핑 해제된 값입니다. <code>unsafelyUnwrapped</code> 프로퍼티는 강제 unwrap 연산자(후위 <code>!</code>)와 동일한 값을 제공합니다. 그러나 최적화된 빌드(<code>-O</code>)에서는 현재 인스턴스에 실제로 값이 있는지 확인하기 위한 검사가 수행되지 않습니다. &#39;nil&#39; 값의 경우 이 프로퍼티에 접근하는 것은 심각한 프로그래밍 오류이며 정의되지 않은 동작이나 런타임 오류로 이어질 수 있습니다.</p>
<p>디버그 빌드(<code>-Onone</code>)에서 <code>unsafelyUnwrapped</code> 프로퍼티는 접미사 <code>!</code> 연산자를 사용하는 것과 동일한 동작을 가지며 인스턴스가 <code>nil</code>인 경우 런타임 오류를 트리거합니다.</p>
<p><code>unsafelyUnwrapped</code> 프로퍼티가 더 제한적이므로 <code>unsafeBitCast(_:)</code> 함수를 호출하는 것보다 권장됩니다. 프로퍼티에 접근하면 디버그 빌드에서 확인이 가능하기 때문입니다.</p>
<p>경고: 이 프로퍼티는 성능을 위해 안전이 보장되지 않습니다. 이 인스턴스가 결코 <code>nil</code>과 같지 않을 것이라고 확신하는 경우에만 그리고 후위 <code>!</code> 연산자를 사용해 본 후에만 <code>unsafelyUnwrapped</code>를 사용하십시오.</p>
</blockquote>
<p>오호! 결국에는 이것도 강제언래핑인 <code>!</code>와 쓰임이 같은 거 같습니다. 
코드 내부를 보면 <code>if let문</code>을 사용해서 값이 있다면 값을 리턴하지만 없는 경우에는 <code>_debugPreconditionFailure()</code>이 실행되는 거 같습니다. </p>
<h4 id="inlinable"><code>@inlinable</code></h4>
<blockquote>
<p>이 특성을 함수, 메서드, 계산된 속성, 첨자, 편의 초기화 또는 초기화 해제 선언에 적용하여 해당 선언의 구현을 모듈 공개 인터페이스의 일부로 노출합니다. 컴파일러는 인라인 가능한 기호에 대한 호출을 호출 사이트의 기호 구현 복사본으로 대체할 수 있습니다. </p>
<p>인라인 가능 코드는 모든 모듈에 선언된 공용 기호와 상호 작용할 수 있으며, <code>usableFromInline</code> 프로퍼티로 표시된 동일한 모듈에 선언된 내부 기호와 상호 작용할 수 있습니다. 인라인 가능한 코드는 <code>private</code> 또는 <code>fileprivate</code> 기호와 상호 작용할 수 없습니다.</p>
</blockquote>
<h4 id="_debugpreconditionfailure"><code>_debugPreconditionFailure()</code></h4>
<pre><code class="language-swift">@usableFromInline @_transparent
internal func _debugPreconditionFailure(
  _ message: StaticString = StaticString(),
  file: StaticString = #file, line: UInt = #line
) -&gt; Never {
#if SWIFT_STDLIB_ENABLE_DEBUG_PRECONDITIONS_IN_RELEASE
  _preconditionFailure(message, file: file, line: line)
#else
  if _slowPath(_isDebugAssertConfiguration()) {
    _precondition(false, message, file: file, line: line)
  }
  _conditionallyUnreachable()
#endif
}</code></pre>
<p><img src="https://velog.velcdn.com/images/som24/post/11814cca-c1bc-4d64-9ef7-0e3c9fd79cd0/image.png" alt=""></p>
<p>...워워.. 처음 보는 형태의 코드가 나오는 군요?</p>
<blockquote>
<p>디버그 라이브러리 전제 조건 확인은 디버그 모드에서만 활성화됩니다. 릴리스 및 빠른 모드에서는 비활성화됩니다. 디버그 모드에서는 오류 메시지를 인쇄하고 중단합니다. 이는 검사가 가능한 모든 오류를 포괄적으로 검사하지 않을 때 사용하도록 고안되었습니다.</p>
</blockquote>
<p>아~ 디버그 모드에서만 사용되는 오류 처리 방법인 거 같습니다만... 여기서 끝내면 너무 이해가 덜 된 상태에서 끝나는 거 같아 Apple 공식문서를 뒤져보았습니다!</p>
<ul>
<li><a href="https://docs.swift.org/swift-book/documentation/the-swift-programming-language/attributes/#usableFromInline"><code>@usableFromInline</code></a></li>
</ul>
<blockquote>
<p>이 특성을 함수, 메서드, 계산된 속성, 첨자, 초기화 또는 초기화 해제 선언에 적용하여 선언과 동일한 모듈에 정의된 인라인 가능 코드에서 해당 기호를 사용할 수 있도록 합니다. 선언에는 내부 액세스 수준 수정자가 있어야 합니다. <code>usableFromInline</code>으로 표시된 구조나 클래스는 해당 속성에 <code>public</code> 또는 <code>usableFromInline</code>인 타입만 사용할 수 있습니다. <code>usableFromInline</code>으로 표시된 열거형은 해당 사례의 원시 값과 관련 값에 대해 <code>public</code> 또는 <code>usableFromInline</code>인 타입만 사용할 수 있습니다.</p>
</blockquote>
<p>간단히 말하면, <code>usableFromInline</code>는 같은 접근 제어자끼리만 사용이 가능하다는 뜻입니다. 또다른 접근 제어자의 느낌이라 신선하네요😳</p>
<ul>
<li><a href="https://github.com/apple/swift/blob/main/docs/TransparentAttr.md"><code>@_transparent</code></a></li>
</ul>
<blockquote>
<p>의미상 <code>@_transparent</code>는 &quot;이 작업을 기본 작업인 것처럼 처리&quot;와 같은 것을 의미합니다. 이 이름은 컴파일러와 컴파일된 프로그램 모두 작업에서 구현까지 &quot;투시&quot;한다는 의미입니다.</p>
<p>이는 여러 가지 결과를 가져옵니다.</p>
<ul>
<li><code>@_transparent</code>로 표시된 함수에 대한 모든 호출은 -Onone에서도 데이터 흐름 관련 진단을 수행하기 전에 인라인되어야 합니다. 이는 데이터 흐름 오류를 포착하는 데 필요할 수 있습니다.</li>
<li>이 때문에 <code>@_transparent</code> 함수는 암시적으로 인라인 가능합니다. 즉, 구현을 변경해도 기존 컴파일된 바이너리의 호출자에게 영향을 주지 않을 가능성이 높습니다.</li>
<li>이 때문에 <code>public</code> 또는 <code>@usableFromInline</code> <code>@_transparent</code> 함수는 공개 기호만 참조해야 하며 해당 함수가 포함된 모듈에 대한 지식을 기반으로 최적화되어서는 안 됩니다. [전자는 Sema의 검사에 의해 포착됩니다.]</li>
<li>디버그 정보는 호출 함수를 한 단계씩 실행할 때 인라인 작업을 건너뛰어야 합니다(SHOULD).</li>
</ul>
</blockquote>
<p>ㅇ0ㅇ... 제가 대충 이해했을 때, Apple 측에서 swift 코드를 만들 때의 용도로 사용되는 거 같습니다. <code>@_transparent</code>이 명시된 함수는 수정이 되어서는 안 된다는 제약이 있고, 구현 시 비공개 항목(진정 비공개 함수 또는 다음 릴리스에서 사라질 수 있는 내부 함수)이 사용되는 것도 권장하지 않습니다. 즉, <code>public</code> 또는 <code>@usableFromInline</code>된 코드만 권장하고 있습니다. </p>
<ul>
<li><a href="https://developer.apple.com/documentation/swift/preconditionfailure(_:file:line:)"><code>preconditionFailure(_:file:line:)</code></a></li>
</ul>
<pre><code class="language-swift">func preconditionFailure(
    _ message: @autoclosure () -&gt; String = String(),
    file: StaticString = #file,
    line: UInt = #line
) -&gt; Never</code></pre>
<p>오~ 형태가 앞의 코드와 비슷하고 같은 문서에 있는 코드라 열심히 읽어보았는데요!</p>
<blockquote>
<p><strong><code>message</code></strong>
플레이그라운드 또는 -Onone 빌드에서 인쇄할 문자열입니다. 기본값은 빈 문자열입니다.</p>
<p><strong><code>file</code></strong>
메시지와 함께 인쇄할 파일 이름입니다. 기본값은 preconditionFailure(_:file:line:)이 호출되는 파일입니다.</p>
<p><strong><code>line</code></strong>
메시지와 함께 인쇄할 줄 번호입니다. 기본값은 preconditionFailure(_:file:line:)이 호출되는 줄 번호입니다.</p>
</blockquote>
<blockquote>
<p>API가 부적절하게 사용되었고 실행 흐름이 호출에 도달할 것으로 예상되지 않는 경우에만 제어 흐름이 호출에 도달할 수 있는 경우 이 함수를 사용하여 프로그램을 중지합니다. 예를 들어, 다른 경우 중 하나가 충족되어야 한다는 것을 알고 있는 스위치의 <code>default</code> 경우입니다.</p>
<p>이 함수의 효과는 사용된 빌드 플래그에 따라 달라집니다.</p>
<ul>
<li>플레이그라운드 및 -Onone 빌드(Xcode 디버그 구성의 기본값)에서는 메시지를 인쇄한 후 디버그 가능한 상태에서 프로그램 실행을 중지합니다.</li>
<li>-O 빌드(Xcode 릴리스 구성의 기본값)에서는 프로그램 실행을 중지합니다.</li>
<li>-Ounchecked 빌드에서 최적화 프로그램은 이 함수가 호출되지 않는다고 가정할 수 있습니다. 해당 가정을 충족하지 못하는 것은 심각한 프로그래밍 오류입니다.</li>
</ul>
</blockquote>
<p>공부하는 내내 -Onone 빌드가 무엇인지 궁금했는데, Xcode 디버그 구성의 기본값이라고 하네요! 
정리해보자면, <code>preconditionFailure(_:file:line:)</code> 함수가 실행되면 프로그램 실행이 중지된다고 합니다. </p>
<pre><code class="language-swift">@inlinable
  public var unsafelyUnwrapped: Wrapped {
    @inline(__always)
    get {
      if let x = self {
        return x
      }
      _debugPreconditionFailure(&quot;unsafelyUnwrapped of nil optional&quot;)
    }
  }</code></pre>
<p>해당 코드를 다시 보면, &quot;unsafelyUnwrapped of nil optional&quot;이라는 메세지를 -Onone 빌드에서 출력하고 프로그램 실행이 중지된다는 걸 알 수 있네요!</p>
<h3 id=""><code>??</code></h3>
<p>옵셔널 병합 연산자에서 많이 보던 함수죠! </p>
<blockquote>
<p>nil 병합 작업을 수행하여 래핑된 값을 반환합니다. <code>Optional</code> 인스턴스 또는 기본값입니다. nil 병합 작업은 값이 있는 경우 왼쪽을 풀거나 오른쪽을 기본값으로 반환합니다. 이 작업의 결과는 왼쪽의 <code>Wrapped</code> 타입의 비선택적 타입을 갖게 됩니다.</p>
</blockquote>
<pre><code class="language-swift">@_transparent
public func ?? &lt;T&gt;(optional: T?, defaultValue: @autoclosure () throws -&gt; T)
    rethrows -&gt; T {
  switch optional {
  case .some(let value):
    return value
  case .none:
    return try defaultValue()
  }
}</code></pre>
<ul>
<li><a href="https://docs.swift.org/swift-book/documentation/the-swift-programming-language/closures/#Autoclosures"><code>@autoclosure</code></a></li>
</ul>
<blockquote>
<p><code>autoclosure</code>는 함수에 인수로 전달되는 표현식을 래핑하기 위해 자동으로 생성되는 클로저입니다. 어떤 인수도 취하지 않으며, 호출되면 그 안에 포함된 표현식의 값을 반환합니다. 이러한 구문상의 편리함을 통해 명시적 클로저 대신 일반 표현식을 작성하여 함수 매개변수 주위의 중괄호를 생략할 수 있습니다.</p>
</blockquote>
<pre><code class="language-swift">let notSoGoodNumber = Int(&quot;invalid-input&quot;) ?? Int(&quot;42&quot;)</code></pre>
<p>이렇게 간결하게 표현할 수 있는 방법이죠!</p>
<p>이 함수를 정리해보자면, <code>nil</code>일 경우에는 defaultValue로 받은 클로저를 반환하고, <code>nil</code>이 아닐 경우에는 옵셔널에 감싸져 있던 값을 반환하는 함수네요! </p>
<h2 id="간단정리">간단정리</h2>
<p><code>Optional</code>의 내부코드는 제가 쓴 부분보다 훨씬 방대하지만... 다하면 너무 길어질 거 같아서 옵셔널 강제 추출과 바인딩 부분만 살짝 정리를 해보았습니다.</p>
<blockquote>
<p>!를 사용하는 강제언래핑, guard let 구문 등, 옵셔널 바인딩을 통해 옵셔널 내부의 값을 가져올 수 있다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Optional이란 무엇인지 설명하시오.(1)]]></title>
            <link>https://velog.io/@som24/Optional%EC%9D%B4%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EC%A7%80-%EC%84%A4%EB%AA%85%ED%95%98%EC%8B%9C%EC%98%A4.1</link>
            <guid>https://velog.io/@som24/Optional%EC%9D%B4%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EC%A7%80-%EC%84%A4%EB%AA%85%ED%95%98%EC%8B%9C%EC%98%A4.1</guid>
            <pubDate>Tue, 05 Dec 2023 12:05:02 GMT</pubDate>
            <description><![CDATA[<p><code>Optional</code>은 swift에만 있는 기능 중 하나입니다.
그래서 저는 처음에 swift 문법을 공부하면서 제일 어려웠던 부분이었습니다. </p>
<h2 id="개념">개념</h2>
<p>그러면 <code>Optional</code>이 어떻게 구현되어 있는지 한 번 살펴볼까요?
자세한 내용은 <a href="https://github.com/apple/swift/blob/main/stdlib/public/core/Optional.swift">Apple &gt; swift &gt; public &gt; ... &gt; Optional.swift</a>에서 확인할 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/som24/post/10d707c3-608c-4ede-a4c7-6b1b4cf1915e/image.png" alt=""></p>
<p><code>map</code>과 <code>flatMap</code>이 <code>Optional</code>과 같은 파일에 있어서 의외였는데요😳</p>
<h3 id="optionalmap"><code>Optional.map</code></h3>
<ul>
<li><p>구현부</p>
<pre><code class="language-swift">@inlinable
public func map&lt;U&gt;(
  _ transform: (Wrapped) throws -&gt; U
) rethrows -&gt; U? {
  switch self {
  case .some(let y):
    return .some(try transform(y))
  case .none:
    return .none
  }
}</code></pre>
</li>
<li><p>예제 코드</p>
<pre><code class="language-swift">let possibleNumber: Int? = Int(&quot;42&quot;)
let possibleSquare = possibleNumber.map { $0 * $0 }
print(possibleSquare)
// Prints &quot;Optional(1764)&quot;
</code></pre>
</li>
</ul>
<p>let noNumber: Int? = nil
let noSquare = noNumber.map { $0 * $0 }
print(noSquare)
// Prints &quot;nil&quot;</p>
<pre><code>
&gt; 이 `Optional` 인스턴스가 `nil`이 아닐 때 주어진 클로저를 평가하여 래핑되지 않은 값을 매개변수로 전달합니다. 선택 사항이 아닌 값을 반환하는 클로저와 함께 `map` 메서드를 사용하세요. 이 예에서는 선택적 정수에 대해 산술 연산을 수행합니다.

배열 요소를 연산하는 `map`하고는 조금 느낌이 다르더라고요! 
`Optional` 타입 연산을 위한 `map`처럼 보입니다.

그러면 다시 돌아가서 Optional를 살펴봅시다!

### `Optional`

```swift
@frozen
public enum Optional&lt;Wrapped&gt;: ExpressibleByNilLiteral {

  case none
  case some(Wrapped)

  @_transparent
  public init(_ some: Wrapped) { self = .some(some) }

  ...
}</code></pre><h4 id="frozen"><code>@frozen</code></h4>
<p>해당 어트리뷰트는 <a href="https://docs.swift.org/swift-book/documentation/the-swift-programming-language/attributes/#frozen">Swift Documentation - Attributes</a>에서 자세히 볼 수 있습니다.</p>
<blockquote>
<p>이 어트리뷰트는 구조체 또는 열거형 선언에 적용하여 타입에 적용할 수 있는 변경 종류를 제한합니다. 이 속성은 라이브러리 evolution mode에서 컴파일할 때만 허용됩니다. 향후 버전의 라이브러리에서는 열거형의 케이스 또는 구조체의 저장된 인스턴스 프로퍼티를 추가, 제거 또는 재정렬하여 선언을 변경할 수 없습니다. 이러한 변경은 고정되지 않은 유형에서 허용되지만 고정된 유형에 대한 ABI 호환성이 손상됩니다.</p>
<p>라이브러리 evolution mode에서 고정되지 않은 구조체 및 열거형의 멤버와 상호 작용하는 코드는 라이브러리의 향후 버전이 해당 유형의 멤버 중 일부를 추가, 제거 또는 재정렬하는 경우에도 다시 컴파일하지 않고 계속 작업할 수 있는 방식으로 컴파일됩니다. 컴파일러는 런타임에 정보를 조회하고 간접 계층을 추가하는 등의 기술을 사용하여 이를 가능하게 합니다. 구조체나 열거형을 고정으로 표시하면 성능을 얻을 수 있는 유연성이 포기됩니다. 라이브러리의 향후 버전에서는 유형을 제한적으로만 변경할 수 있지만 컴파일러는 유형의 멤버와 상호 작용하는 코드에서 추가 최적화를 수행할 수 있습니다.</p>
</blockquote>
<p>...어렵네?🤪</p>
<p>한 마디로 정리해보자면, <code>@frozen</code>을 적용하면 해당 타입의 수정이 일어날 가능성을 배제하기 때문에 컴파일 시간을 줄여준다고 합니다. 열거형일 경우, <code>switch문</code>에서 <code>default</code> 과정을 줄여주기 때문에 많이 사용된다고 하지만, 구조체는 주로 라이브러리 아니면 잘 사용되지 않는다고 합니다.</p>
<h4 id="wrapped"><code>Wrapped</code></h4>
<p><code>Wrapped</code>는 Generic 타입으로 명시되어 어느 타입이든 사용 가능한 범용 코드입니다.</p>
<h4 id="expressiblebynilliteral"><code>ExpressibleByNilLiteral</code></h4>
<p><a href="https://developer.apple.com/documentation/swift/expressiblebynilliteral">Apple Developer - ExpressibleByNilLiteral</a>에서 굉장히 간단하게 정리되어 있어서, 코드를 해부해보려 했지만 현재 나와있는 github에는 공개되지 않은 거 같습니다😅</p>
<blockquote>
<p><code>nil</code> 리터럴인 <code>nil</code>을 사용하여 초기화할 수 있는 타입입니다.</p>
<p><code>nil</code>은 <code>Swift</code>에서 값이 없다는 특별한 의미를 갖습니다. <code>Optional</code> 타입만 <code>ExpressibleByNilLiteral</code>을 따릅니다. 다른 목적으로 <code>nil</code>을 사용하는 타입에 대한 <code>ExpressibleByNilLiteral</code> 준수는 권장되지 않습니다.</p>
</blockquote>
<h4 id="코드-내부">코드 내부</h4>
<p><code>Optional</code>은 <code>none</code>과 <code>some(Wrapped)</code>으로 이루어진 열거형 타입입니다. 값이 존재한다면 <code>some(Wrapped)</code>을 존재하지 않는다면 <code>none</code>을 대입합니다. </p>
<h2 id="간단정리">간단정리</h2>
<p><img src="https://velog.velcdn.com/images/som24/post/9df5500e-9e0d-4f3d-86f9-98b98e2bdf32/image.png" alt=""></p>
<p>정리하다보니, 엄청 길어져서 <code>Optional</code> 타입의 값을 추출하는 방법은 다음 포스트에서 다루겠습니다. 이렇게 개념을 딥하게 정리했지만, 간단하게 2문장으로 정리해보겠습니다 ㅎㅎ!</p>
<blockquote>
<p><code>Optional</code>이란, 값이 있을 수도 있고 없을 수도 있다는 것을 표현해주는 열거형 타입입니다. 보통 변수안에 값이 정확히 있는지 없는지 확신할 수 없을 때에 많이 사용합니다. </p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Copy On Write는 어떤 방식으로 동작하는지 설명하시오.]]></title>
            <link>https://velog.io/@som24/Copy-On-Write%EB%8A%94-%EC%96%B4%EB%96%A4-%EB%B0%A9%EC%8B%9D%EC%9C%BC%EB%A1%9C-%EB%8F%99%EC%9E%91%ED%95%98%EB%8A%94%EC%A7%80-%EC%84%A4%EB%AA%85%ED%95%98%EC%8B%9C%EC%98%A4</link>
            <guid>https://velog.io/@som24/Copy-On-Write%EB%8A%94-%EC%96%B4%EB%96%A4-%EB%B0%A9%EC%8B%9D%EC%9C%BC%EB%A1%9C-%EB%8F%99%EC%9E%91%ED%95%98%EB%8A%94%EC%A7%80-%EC%84%A4%EB%AA%85%ED%95%98%EC%8B%9C%EC%98%A4</guid>
            <pubDate>Mon, 04 Dec 2023 06:08:03 GMT</pubDate>
            <description><![CDATA[<h2 id="개념">개념</h2>
<blockquote>
<p>Copy On Write은 컴퓨터 프로그래밍에서 복사 동작을 할 때, 실제 원본이나 복사본이 수정되기 전까지는 복사를 하지 않고 원본 리소스를 공유한다. 원본이나 복사본에서 수정이 일어날 경우, 그때 복사하는 작업을 한다.</p>
</blockquote>
<p>흔히 컴퓨터 프로그래밍에서 Copy On Write는 이렇게 정의됩니다.</p>
<p>하지만 swift 환경에서 어떻게 동작하는지 보려면 구현된 코드를 한 번 살펴봐야겠죠?</p>
<pre><code class="language-swift">@propertyWrapper
struct CopyOnWrite&lt;Value: Copyable&gt; {
  init(wrappedValue: Value) {
    self.wrappedValue = wrappedValue
  }

  var wrappedValue: Value

  var projectedValue: Value {
    mutating get {
      if !isKnownUniquelyReferenced(&amp;wrappedValue) {
        wrappedValue = wrappedValue.copy()
      }
      return wrappedValue
    }
    set {
      wrappedValue = newValue
    }
  }
}
</code></pre>
<p><a href="https://github.com/apple/swift/blob/520e12430e4766e9f186750116198bb5ed9ca0c9/test/decl/var/property_wrappers.swift#L1834">Apple &gt; swift &gt; ... &gt; property_wrappers.swift</a>에서 찾은 구현부입니다.</p>
<h3 id="propertywrapper는-무엇일까요"><code>@propertyWrapper</code>는 무엇일까요?</h3>
<p><code>@propertyWrapper</code>는 swift5.1부터 나온 개념으로 자세한 내용은 <a href="https://docs.swift.org/swift-book/documentation/the-swift-programming-language/properties/#Property-Wrappers">Swift Documentation - Property Wrappers</a>에서 확인 가능합니다.</p>
<p>간단하게 정리하자면...
Propery Wrapper를 붙여 한번만 정의해주면 이후 다른 프로퍼티들에서 해당 Property Wrapper를 적용하면 깔끔하게 코드를 재사용할 수 있습니다.</p>
<p>저도 문서만 읽으니 감이 잘 안 오는데요😵‍💫
나중에 기회가 된다면 더 자세하게 파보도록 하겠습니다🕵️</p>
<h3 id="isknownuniquelyreferenced_는-무엇일까요"><code>isKnownUniquelyReferenced(_:)</code>는 무엇일까요?</h3>
<p><a href="https://developer.apple.com/documentation/swift/isknownuniquelyreferenced(_:)-98zpp">Apple Developer - isKnownUniquelyReferenced(_:)</a>에서 자세한 내용을 찾아볼 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/som24/post/424d0f69-540c-4484-b427-bd07e49eb68f/image.png" alt=""></p>
<p>docs의 목록에서 알 수 있듯이, 컬렉션 타입의 버퍼를 관리하는 메서드로 보입니다.</p>
<blockquote>
<p><code>isKnownUniquelyReferenced(_:)</code>는 주어진 개체가 단일 강력한 참조를 갖는 것으로 알려져 있는지 여부를 나타내는 부울 값을 반환합니다. <code>isKnownUniquelyReferenced(_:)</code>는 주어진 객체에 대한 강력한 참조만 확인합니다. 객체에 추가적인 약하거나 소유되지 않은 참조가 있는 경우 결과는 여전히 true일 수 있습니다. 약한 참조와 소유되지 않은 참조는 객체에 대한 유일한 참조일 수 없기 때문에 약한 참조나 소유되지 않은 참조를 객체로 전달하면 항상 false가 됩니다. <code>isKnownUniquelyReferenced(_:)</code> 함수는 값 타입의 deep storage을 위한 <code>copy-on-write</code> 최적화를 구현하는 데 유용합니다.</p>
</blockquote>
<p>다시 위의 코드로 돌아가보면, 유일한 참조가 아닐 때(수정이 일어날 때) <code>isKnownUniquelyReferenced(_:)</code>는 false가 반환되어 <code>copy()</code>를 통한 복사가 일어나 <code>copy-on-write</code>가 일어나는 거였네요!</p>
<h2 id="간단-정리">간단 정리</h2>
<p>휴... 근데 이걸 면접에서 이야기하기에는 너무 긴 거 같네요!
물론 꼬리 질문에서 &quot;제가 이렇게 코드를 해부해봤는데~&quot;라며 이야기해도 좋지만 처음부터 답하기에는 너무 딥하게 왔습니다.</p>
<blockquote>
<p>Swift에서는 String과 Collection Type을 복사해서 사용할 때 일어납니다. 값에 대한 수정이 일어날 때 복사하는 기능으로, 변경되기 전에는 참조를 통해서 불필요한 복사를 줄여서 메모리를 아낄 수 있습니다.</p>
</blockquote>
<p>정도로 대답을 준비할 수 있겠네요!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[mutating 키워드에 대해 설명하시오.]]></title>
            <link>https://velog.io/@som24/mutating-%ED%82%A4%EC%9B%8C%EB%93%9C%EC%97%90-%EB%8C%80%ED%95%B4-%EC%84%A4%EB%AA%85%ED%95%98%EC%8B%9C%EC%98%A4</link>
            <guid>https://velog.io/@som24/mutating-%ED%82%A4%EC%9B%8C%EB%93%9C%EC%97%90-%EB%8C%80%ED%95%B4-%EC%84%A4%EB%AA%85%ED%95%98%EC%8B%9C%EC%98%A4</guid>
            <pubDate>Sun, 03 Dec 2023 10:14:38 GMT</pubDate>
            <description><![CDATA[<p>The Swift Programming Language (5.9.2 beta) 기준 <a href="https://docs.swift.org/swift-book/documentation/the-swift-programming-language/methods/#Modifying-Value-Types-from-Within-Instance-Methods">Modifying Value Types from Within Instance Methods
</a>에서 해당 내용을 찾아볼 수 있습니다.</p>
<h2 id="개념">개념</h2>
<p>구조체와 열거형은 값 타입입니다. 
기본적으로 값 타입의 프로퍼티는 해당 인스턴스 메서드 내에서 수정할 수 없습니다. </p>
<p><img src="https://velog.velcdn.com/images/som24/post/1a94efd2-8684-4843-b34a-6d438e8f454e/image.png" alt=""></p>
<p>엥? 그러면 프로퍼티 수정도 안 되는데 어떡하라는 거지? 싶죠??</p>
<p>이럴 때 사용되는 키워드가 <code>mutating</code> 입니다!
<code>mutating</code> 메서드는 메서드 내에서 해당 속성을 변경(즉, 변경)할 수 있으며 변경된 내용은 메서드가 종료될 때 원래 값 타입(구조체, 열거형)에 다시 기록됩니다.
메서드는 암시적 self 프로퍼티에 완전히 새로운 인스턴스를 할당할 수도 있으며, 이 새 인스턴스는 메서드가 종료될 때 기존 인스턴스를 대체합니다.</p>
<p>열거형에 대한 변경 메서드는 암시적 self 매개변수를 동일한 열거형과 다른 경우로 설정할 수 있습니다.</p>
<pre><code class="language-swift">struct Point {
    var x = 0.0, y = 0.0

    mutating func moveBy(x deltaX: Double, y deltaY: Double) {
        x += deltaX
        y += deltaY
    }
}</code></pre>
<p>이렇게 function 앞에 mutating 키워드를 붙여주면 사용할 수 있습니다.  </p>
<h2 id="간단-정리">간단 정리</h2>
<p>Struct는 값타입이기 때문에 Struct의 속성은 기본적으로 인스턴스 메서드 내에서 수정할 수 없습니다. 만약 수정해야할 상황이 생긴다면 mutating을 붙여주면 됩니다. </p>
<p>mutating을 선언한 메서드는 메서드 내에서 프로퍼티를 변경할 수 있고, 메서드가 종료될 때 변경한 모든 내용을 원래 struct에 다시 기록합니다. 또한 메서드는 self property에 새 인스턴스를 할당할 수도 있습니다.</p>
<p>mutating 키워드는 해당 메서드가 호출된다면 실제 복사를 해야한다고 알려주는 역할입니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[야곰 아카데미] 커리어 스타터 7기 후기]]></title>
            <link>https://velog.io/@som24/%EC%95%BC%EA%B3%B0-%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8-%EC%BB%A4%EB%A6%AC%EC%96%B4-%EC%8A%A4%ED%83%80%ED%84%B0-7%EA%B8%B0-%ED%9B%84%EA%B8%B0</link>
            <guid>https://velog.io/@som24/%EC%95%BC%EA%B3%B0-%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8-%EC%BB%A4%EB%A6%AC%EC%96%B4-%EC%8A%A4%ED%83%80%ED%84%B0-7%EA%B8%B0-%ED%9B%84%EA%B8%B0</guid>
            <pubDate>Thu, 23 Feb 2023 08:10:37 GMT</pubDate>
            <description><![CDATA[<h1 id="🐻-야곰-아카데미란">🐻 야곰 아카데미란?</h1>
<p><img src="https://velog.velcdn.com/images/som24/post/fdcecc24-35a4-4b67-87e1-9ae368f9b991/image.png" alt=""></p>
<p>6개월 동안 <a href="https://www.yagom-academy.kr/caedac9a-fedc-4392-8a7d-272b326e7602">커리큘럼</a>에 따른 프로젝트를 진행하면서, 해당 프로젝트에 필요한 기술들을 능동적으로 공부하고, 현업 리뷰어에게 리뷰를 받을 수 있는 아카데미입니다.</p>
<p>더 자세한 내용은 <a href="https://www.yagom-academy.kr/">여기</a>로~!</p>
<blockquote>
<p><strong>용어정리</strong>
캠프: &#39;야곰 아카데미&#39;를 지칭함
캠퍼: 아카데미 수강생
크루: 아카데미 운영진
서포터즈: 캠퍼의 서포터(멘토 개념)</p>
</blockquote>
<h2 id="6개월-과정">6개월 과정</h2>
<h3 id="활동학습">활동학습</h3>
<p>매주 월, 목에 진행되는 활동학습은 미리 캠퍼들에게 예습할 수 있도록 주제를 알려주고 크루분들과 함께 주제에 대해 배워가는 시간입니다.
여기서 iOS 지식에 관한 개념을 제대로 이해할 수 있어 도움이 많이 되었습니다.
만약 커리어 스타터를 들을 의향이 있으시다면 무조건!!! 예습 필수입니다. (진지)</p>
<h3 id="프로젝트">프로젝트</h3>
<p>메인으로 진행되는 부분이 프로젝트인데, 커리큘럼은 위 링크로 볼 수 있습니다!
iOS의 기초를 다지는 프로젝트를 시작하여, 네트워킹, 오픈 소스 활용하기 등 많은 부분을 얻어갈 수 있습니다. iOS 개념들을 실제로 구현해보면서 어떻게 동작하는 지 알아가는 재미가 있었습니다ㅎㅎ
다만, 팀 프로젝트로 진행하다보니 팀원과의 커뮤니케이션이 중요합니다.
그리고 Step 별 진행하는 프로젝트에 따라 현업 리뷰어분이 피드백해주시면서 어떤 부분을 보안해야할지 알아가는 시간이 되었습니다.</p>
<h3 id="멘토링">멘토링</h3>
<p>서포터즈분들이 2주동안(1주 1회) 캠퍼들의 프로젝트 복습을 도와주면서 어렵게 느끼는 부분들을 같이 해결해주는 시간입니다. 언급했듯이 프로젝트 복습이 되는 것이 큰 장점이었고, 캠프 생활 중 힘들었던 부분들을 털어놓을 수 있는 기회가 되어 좋았습니다.</p>
<h3 id="til">TIL</h3>
<p>TIL이란, Today I Learn의 약자로 오늘 하루 배웠던 내용들을 정리하는 시간입니다.
캠프 사이트 내에 주 4회(수요일, 주말 제외) TIL을 쓸 수 있는 티켓이 발급됩니다. 발급된 티켓으로 TIL을 쓸 수 있으며, 작성된 내용은 TIL 카테고리에서 확인 가능합니다.
TIL을 되돌아봤던 기억은 잘 없지만...ㅎㅎ TIL을 쓰기 위해 공부를 해야한다는 목적의식이 생기기 때문에 나름 열심히 썼던 기억이 납니다.
TIL로 남기는 방법도 좋지만, TIL에 썼던 내용을 블로그나 노션을 활용하여 주제에 맞는 카테고리로 정리하는 것도 중요하다고 생각이 듭니다.</p>
<h3 id="마치며">마치며</h3>
<p><img src="https://velog.velcdn.com/images/som24/post/2eac7acf-7464-40af-a38d-c7bb63358940/image.png" alt="">
럭키 세븐 7기<del>!</del>! 다들 너무 감사했고 좋은 시간이었습니다~</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[ios] 야곰 아카데미 코드 스타터 캠프 4기 후기]]></title>
            <link>https://velog.io/@som24/ios-%EC%95%BC%EA%B3%B0-%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8-%EC%BD%94%EB%93%9C-%EC%8A%A4%ED%83%80%ED%84%B0-%EC%BA%A0%ED%94%84-4%EA%B8%B0-%ED%9B%84%EA%B8%B0</link>
            <guid>https://velog.io/@som24/ios-%EC%95%BC%EA%B3%B0-%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8-%EC%BD%94%EB%93%9C-%EC%8A%A4%ED%83%80%ED%84%B0-%EC%BA%A0%ED%94%84-4%EA%B8%B0-%ED%9B%84%EA%B8%B0</guid>
            <pubDate>Mon, 16 May 2022 12:15:03 GMT</pubDate>
            <description><![CDATA[<p>길다면 길, 짧다면 짧은 5주의 대장정이 막을 내렸다.
코딩이 처음도 아닌데, 언어가 다르다는 이유로 많이 해매서 조금 아쉬웠다.
5주의 이야기를 담기에는 방대하지만 간략하게 줄여보도록 하겠다.</p>
<h1 id="야곰-아카데미를-선택한-이유">야곰 아카데미를 선택한 이유</h1>
<p><a href="https://www.yagom-academy.kr/camp">야곰 아카데미</a>는 ios를 전문으로 교육하는 부트캠프다. 
야곰 아카데미의 가장 큰 매력은 1:1 코드 리뷰를 해주는 리뷰어가 있다는 것이다.
사실 이거 하나만 보고 선택하기는 했지만, 진행하면서 더 많은 장점들을 발견했다!</p>
<h2 id="1-github">1. GitHub</h2>
<p>야곰 아카데미는 주마다 2~3개의 미션이 주어진다.
미션을 수행하는 코드를 리뷰어에게 보여줄 때, 여기서 깃헙을 사용한다.</p>
<p><em>나는 깃헙이 뭔지도 모르는데...?</em></p>
<p>겁 먹을 필요 없다! 코드 스타터 캠프의 이름에 걸맞게 모든 것을 처음 start 하는 기분으로 야곰 아카데미에서 깃헙을 다루는 방법의 강의가 올라와있다. 처음에는 따라하는 것조차 버겁지만(mac의 터미널과 친숙해질 시간이 필요함) 나중에는 척척 깃헙을 통해 PR을 보내는 자신과 마주하게 될 것이다.</p>
<h2 id="2-적절한-난이도">2. 적절한 난이도</h2>
<p>여기서 적절하다는 것은 나의 기준일지도 모르겠지만...
뼈문과형인 내가 적절했다 생각이 들 정도면 보시는 여러분도 적절하지 않을까 싶다.</p>
<p>각 주차마다 쉬운 난이도~어려운 난이도가 적절하게 섞여 있다. 
이해 못 하는 내용이 나와도 걱정하지 말라!
주에 1번씩 야곰의 라이브 세션에서 직접 물어볼 수도 있고, 대게 캠퍼들이 어려움을 느낄 것 같은 부분들을 야곰이 풀어 설명해주는 경우가 대다수다.
빠른 이해를 원한다면 담당 리뷰어님의 DM을 활용하는 것도 좋다! (본인이 많이 한 방법)</p>
<h2 id="3-스터디의-존재">3. 스터디의 존재</h2>
<p>첫주차에 디코방에서 스터디원을 모집하는 글이 올라오는데, 거기서 신청하고 본인이 원하는 시간대를 고르면, 그 시간대를 선택한 사람들과 랜덤으로 스터디가 결성된다.
정말 낯을 많이 가리고 내성적이라면 스터디 선택을 안 하면 되지만...
필자는 간절했기 때문에 내성적인 성격은 집어치우고 스터디를 선택했다 ㅎㅎ</p>
<p>결론적으로 정말 잘한 선택이었다.</p>
<p>주차마다 주어지는 미션을 수행하면서 어려운 점을 공유하면서 해답을 얻을 수 있고, 캠프를 진행하면서의 즐거움이나 어려움 등을 나누는 것이 캠프를 진행하면서 하나의 힐링 포인트가 되었다. 
혼자 머리 싸매면서 하는 고민보다는 다같이 고민을 나누었을 때 줄어드는 기분을 많이 느꼈다.</p>
<h2 id="4-영어공부">4. 영어공부(?)</h2>
<p>야곰 아카데미의 공부 지향성은 스위프트 원서를 보면서 직접 알아가는 것이다.
물론 이것이 장점이자, 단점이 될 수 있겠지만... 필자 생각에는 개발 공부는 &#39;끝&#39;이란 존재하지 않는다. 언어는 계속 업그레이드가 되고 그럴 때마다 누군가 유튜브나 강의로 설명해주는 것을 마냥 기다릴 수는 없다.</p>
<p>로마에서 로마 법을 따르듯이, 이 언어를 만든 사람들이 미쿡사람이니 그들의 언어를 따를 수 밖에 없다. </p>
<p>필자도 학창시절에 제일 싫어했던 과목이 수학과 영어였는데... 업보빔을 맞은 기분이다.
아무튼 처음에는 원서를 보기만 해도 속이 울렁거릴 정도로 싫었는데, 참고 보다보면 읽히긴 한다. 학교에서 배운 영어처럼 그렇게(?) 어렵지는 않다. </p>
<p>개발자가 되려면 언젠가는 거쳐야할 단계였는데, 야곰 아카데미에서 이 부분에 대한 극복을 할 수 있었다.</p>
<h2 id="5-간결한-코드-작업">5. 간결한 코드 작업</h2>
<p>앞서 야곰 아카데미를 선택한 이유에서 언급한 리뷰어의 장점이다.
깃헙 서버로 직접 내가 작성한 코드를 보내면 리뷰어가 그것을 보고 </p>
<p><em>왜 이런 코드를 작성하셨어요?
이 코드는 이렇게 되는 게 더 나을 거 같아요.</em></p>
<p>라고 질문과 조언을 동시에 해주신다. 보통 코드를 작성할 때, 내가 무슨 생각으로 이렇게 했지?를 늘상 생각하지 않는 게 대부분이라 이런 질문을 받을 때 허가 찔린 기분을 느낄 수도 있다. </p>
<p>그래서 필자 같은 경우는 코드를 메서드마다 나눠서 왜 이런 생각을 했고, 어느 부분이 구현하는 데 어려웠고, 이 부분이 부족한 거 같고, 이런 부분을 더 추가하고 싶은데 방법을 모르겠다, 등 PR을 보낼 때 같이 남겼다. 
이 과정이 정말 도움이 되었다. 야곰 아카데미에서 제공하는 강의 뿐만 아니라 다른 부분에 있어서도 어떤 부분을 공부하면 되는지 리뷰어 분이 남겨주시기 때문에 피가 되고 살이 되는 코멘트들이 정말 많았다.</p>
<h1 id="마무리">마무리</h1>
<p>야곰 아카데미를 진행하면서 정말 호불호가 갈릴 수 있겠구나 싶은 곳이었다.
보통 사람들이 무엇을 배울 때, 교육자가 하나하나 알려주기를 바라지만 야곰 아카데미는 하나를 알면 둘은 알아서 해라~ 느낌이다. </p>
<p>하지만 교육이라는 것은...
물고기를 직접 잡아주는 것보다는 <em>물고기를 잡는 방법</em>을 알려주는 게 아닌가 싶다.
계속 물고기를 잡아주면 배우는 사람 입장에서는 떠먹는 행위밖에 하지 않으니 말이다.</p>
<p>이런 방식의 교육이
*너 정말 코딩을 좋아하니? 적성에 맞니? *
를 판단하게 해주는 길인 거 같다. 정말 좋으면 하나를 알면 열을 알고 싶어서 미친듯이 찾아보게 되니까! 마치 게임 공략을 알아서 찾는 것처럼 말이다 ㅎㅎ</p>
<p>정말 마지막으로! 보실 지는 모르겠지만 새벽에 리뷰 남겨주시느라 너무 고생하셨습니다, 예거!
제가 감사하다는 말을 많이 했지만 아직도 부족한 거 같아요☺️
장황하게 글을 썼지만 아직도 야곰 아카데미의 향수에 빠져있습니다... 나올려면 엄청난 시간이 필요할 거 같아요.</p>
]]></description>
        </item>
    </channel>
</rss>