<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>ted_kim.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Sun, 23 Apr 2023 07:06:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>ted_kim.log</title>
            <url>https://velog.velcdn.com/images/ted_kim/profile/426fc544-1d60-4225-ba74-04d95adadf54/social_profile.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. ted_kim.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/ted_kim" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[Swift] 맵, 필터, 리듀스]]></title>
            <link>https://velog.io/@ted_kim/Swift-%EB%A7%B5-%ED%95%84%ED%84%B0-%EB%A6%AC%EB%93%80%EC%8A%A4</link>
            <guid>https://velog.io/@ted_kim/Swift-%EB%A7%B5-%ED%95%84%ED%84%B0-%EB%A6%AC%EB%93%80%EC%8A%A4</guid>
            <pubDate>Sun, 23 Apr 2023 07:06:00 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/ted_kim/post/aae456d1-778c-48f7-8b27-82d53f16929c/image.png" alt=""></p>
<p>오늘은 맵, 필터, 리듀스에 대해 알아볼 예정이다. ps를 풀 때 맵, 필터, 리듀스가 많이 사용됐었는데, 이 기회에 조금 더 잘 활용할 수 있었으면 좋겠다.</p>
<br>




<p>스위프트는 함수를 일급 객체로 취급 → 함수를 다른 함수의 전달인자로 사용가능</p>
<p>매개변수로 함수를 갖는 함수 : <strong><em>‘고차함수’</em></strong></p>
<p>대표적인 고차함수로는 맵, 필터, 리듀스 등이  있음</p>
<br>

<h3 id="맵">맵</h3>
<ul>
<li>자신을 호출할 때 매개변수로 전달된 함수를 실행하여 그 결과를 다시 반환해주는 함수</li>
<li>컨테이너가 담고 있던 각각의 값을 매개변수를 통해 받은 함수에 적용한 후 다시 컨테이너에 포장하여 반환함</li>
<li>기존 컨테이너의 값은 변경되지 않고 새로운 컨테이너가 생성되어 반환됨<ul>
<li>스위프트는 타입에 엄격하기 때문에 타입을 변경하는데 유용하게 사용됨</li>
</ul>
</li>
<li><strong>기존 데이터를 변형</strong>하는 데 많이 사용</li>
<li>for in 구문과 별 차이가 없음<ul>
<li>하지만 코드의 재사용 측면이나 컴파일러 최적화 측면에서 성능 차이 존재</li>
<li>다중 스레드 환경일 때 발생하는 부작용 방지</li>
</ul>
</li>
</ul>
<pre><code class="language-swift">let numbers: [Int] = [0, 1, 2, 3, 4]

var doubleNumbers: [Int] = [Int]()
var strings: [String] = [String]()

//for in 사용
for number in numbers {
    doubleNumbers.append(number * 2)
    strings.append(&quot;\(number)&quot;)
}

//map 사용
doubleNumbers = numbers.map({ (number: Int) -&gt; Int in
    return number * 2
})
strings = numbers.map( { (number: Int) -&gt; String in
    return &quot;\(number)&quot;
})
</code></pre>
<p>클로저를 통해 더욱 간결하게 사용 가능</p>
<pre><code class="language-swift">//클로저 사용
doubleNumbers = numbers.map({ return $0 * 2 })</code></pre>
<br>

<h3 id="필터">필터</h3>
<ul>
<li>컨테이너 내부의 값을 걸러서 추출</li>
<li>map과 마찬가지로 새로운 컨테이너에 값을 담아 반환</li>
<li>특정 조건에 맞게 걸러내는 역할을 함</li>
<li>함수의 매개변수로 전달되는 함수의 반환 타입은 Bool<ul>
<li>컨테이너에 포함될 항목은 true, 아니면 false를 반환함</li>
</ul>
</li>
</ul>
<pre><code class="language-swift">let numbers: [Int] = [0, 1, 2, 3, 4, 5]

let evenNumbers: [Int] = numbers.filter { (number: Int) -&gt; Bool in
    return number % 2 == 0
}   //[0, 2, 4]</code></pre>
<br>

<h3 id="리듀스">리듀스</h3>
<ul>
<li>컨테이너 내부의 컨텐츠를 하나로 합하는 기능을 실행</li>
</ul>
<pre><code class="language-swift">let numbers: [Int] = [1, 2, 3]

var sum: Int = numbers.reduce(0, { (result: Int, next: Int) -&gt; Int in
    print(&quot;\(result) + \(next)&quot;)
    return result + next
})

// 0 + 1
// 1 + 2
// 3 + 3

print(sum)  // 6</code></pre>
<br>

<h3 id="맵-필터-리듀스의-활용">맵, 필터, 리듀스의 활용</h3>
<pre><code class="language-swift">//서울 외의 지역에 거주하며 25세 이상인 친구
var result: [Friend] = friends.map { Friend(name: $0.name, gender: $0.gender, location: $0.location, age: $0.age + 1)}

result = result.filter { $0.location != &quot;서울&quot; &amp;&amp; $0.age &gt;= 25 }

let string: String = result.reduce(&quot;서울 외의 지역에 거주하며 25세 이상인 친구&quot;) { $0 + &quot;\n&quot; + &quot;\($1.name) \($1.gender) \($1.location) \($1.age)세&quot;}</code></pre>
<ul>
<li>맵으로 한 살씩 더한 후, 필터로 서울 이외의 거주하며 25세 이상인 사람으로 구성한 후 리듀스로 원하는 모양으로 출력함</li>
</ul>
<br>
<br>

<p>맵, 필터, 리듀스 같은 경우에는 처음에도 언급했다싶이 ps에서 자주 활용되기 때문에 많이 사용해보기 !</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Swift] 제네릭]]></title>
            <link>https://velog.io/@ted_kim/Swift-%EC%A0%9C%EB%84%A4%EB%A6%AD</link>
            <guid>https://velog.io/@ted_kim/Swift-%EC%A0%9C%EB%84%A4%EB%A6%AD</guid>
            <pubDate>Wed, 19 Apr 2023 12:33:43 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/ted_kim/post/6422e0a2-b270-42c9-ba00-b6ae55353576/image.png" alt=""></p>
<p>오늘은 스위프트의 문법 중 매우 중요한 요소 중 하나인 제네릭에 대해 알아보았다. 
사실 아직 제대로 사용해본 적은 많이 없지만, 이번 기회를 통해 많이 사용해봐야겠다.</p>
<br>

<h2 id="제네릭">제네릭</h2>
<ul>
<li>&lt;&gt;로 정의</li>
<li>어떤 타입에도 유연하게 대응할 수 있음</li>
<li>제네릭으로 구현한 기능과 타입은 재사용하기도 쉽고, 코드의 중복을 줄일 수 있음<ul>
<li>깔끔하고 추상적인 표현 가능</li>
</ul>
</li>
</ul>
<pre><code>제네릭을 사용하고자 하는 타입 이름 &lt;타입 매개변수&gt; (함수의 매개변수 ...)</code></pre><br>

<ul>
<li>제네릭 함수는 실제 타입 이름을 써주는 대신에 플레이스홀더(주로 T)를 사용<ul>
<li>어떤 타입이 들어올 지 모르니깐 (호출되기 전까지) T(Type)라고 정의해두는 것</li>
</ul>
</li>
<li>플레이스홀더는 타입의 종류는 알려주지 않지만, 어떤 타입이라는 것은 알려줌<ul>
<li>실제 타입은 함수가 호출되는 순간에 결정됨<ul>
<li>만약 Int가 전달되었으면 T는 Int가 되고, String이 전달되었으면 T는 String이 됨</li>
</ul>
</li>
</ul>
</li>
</ul>
<pre><code class="language-swift">func swapTwoValues&lt;T&gt;(_ a: inout T, _ b: inout T) {    //둘 다 T로 정의했기 때문에, 타입이 같음
    let tmpA:T = a
    a = b
    b = tmpA
}

print(&quot;\(numberOne), \(numberTwo)&quot;)    // Ok
print(&quot;\(stringOne), \(stringOne)&quot;)    // Ok 

//string이나 Int가 둘 다 가능함

print(&quot;\(stringOne), \(numberOne)&quot;)    // 에러 -&gt; 둘의 타입이 다르기 때문에
</code></pre>
<br>


<p>제네릭 타입</p>
<ul>
<li>제네릭 타입을 구현하면 구조체, 클래스, 열거형 등이 어떤 타입과도 연관되어 동작할 수 있음<ul>
<li>Array나 Dictionary 타입이 자신의 요소로 모든 타입을 대상으로 동작할 수 있는 것과 유사</li>
</ul>
</li>
</ul>
<pre><code class="language-swift">//제네릭을 사용하지 않은 IntStack

struct IntStack {
    var items = [Int]()
    mutating func push(_ item: Int) {
        items.append(item)
    }

    mutating func pop() -&gt; Int {
        return items.removeLast()
    }
}

//제네릭을 사용한 Stack

struct Stack&lt;Element&gt; {
    var items = [Element]()
    mutating func push(_ item: Element) {
        items.append(item)
    }

    mutating func pop() -&gt; Element {
        return items.removeLast()
    }
}</code></pre>
<ul>
<li>익스텐션을 통해 제네릭을 사용하는 타입에 기능을 추가하고자 한다면 익스텐션 정의에 타입 매개변수를 정의하지 않아야 함</li>
<li>하지만 원래 명시한 타입 매개변수를 익스텐션에서 사용 가능</li>
</ul>
<pre><code class="language-swift">extension Stack {    //원래 정의는 Stack&lt;Element&gt;로 되어있지만, 정의하지 않음. 하지만 기존에 정의한 Element 사용 가능
    var topElement: Element? {
        return self.items.last
    }
}</code></pre>
<br>

<p>타입 제약</p>
<ul>
<li>제네릭 타입에 제약을 줄 수 있음</li>
<li>클래스 타입 또는 프로토콜로만 줄 수 있음 —&gt; 열거형, 구조체 등의 타입은 타입 제약의 타입으로 사용할 수 없음</li>
<li>타입 매개변수 뒤에 원하는 클래스 타입 또는 프로토콜을 명시하면 됨</li>
<li>ex. 빼기를 구현하여 사용할 수 있도록 하려면 빼기 연산자를 사용할 수 있는 타입이어야 함</li>
</ul>
<pre><code class="language-swift">struct Stack&lt;Element: Hashable&gt; {

}

//BinaryInteger 프로토콜을 준수하는 타입으로 연산을 제한함
func substractTwoValue&lt;T: BinaryInterger&gt;(_ a: T, _ b: T) -&gt; T {
    return a - b
}</code></pre>
<br>

<p>프로토콜 연관 타입</p>
<ul>
<li>프로토콜에서 사용할 수 있는 플레이스홀더 이름</li>
<li>‘종류는 알 수 없지만, 어떤 타입이 여기에 쓰일 것이다’</li>
</ul>
<pre><code class="language-swift">protocol Container {
    associatedtype ItemType
    var count: Int { get }
    mutating func append(_ item: ItemType)
    subscript(i: Int) -&gt; ItemType { get }
}

//Container에서는 타입에 대해 지정해주지 않았는데, MyContainer에서는 지정을 해줌
//연관 타입 ItemType 대신에 실제 타입인 Int 타입으로 구현
class MyContainer: Container {
    var items: Array&lt;Int&gt; = Array&lt;Int&gt;()

    var count: Int {
        return items.count
    }

    func append(_ item: Int) {
        items.append(item)
    }

    subscript(i: Int) -&gt; Int {
        return items[i]
    }
}</code></pre>
<p>제네릭 서브스크립트</p>
<ul>
<li>서브스크립트도 제네릭을 활용하여 타입에 제한 없이 구현 가능</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Swift] 익스텐션]]></title>
            <link>https://velog.io/@ted_kim/Swift-%EC%9D%B5%EC%8A%A4%ED%85%90%EC%85%98</link>
            <guid>https://velog.io/@ted_kim/Swift-%EC%9D%B5%EC%8A%A4%ED%85%90%EC%85%98</guid>
            <pubDate>Tue, 18 Apr 2023 11:44:46 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/ted_kim/post/95e14d6a-5c20-4e81-a2ab-cd2fe5478308/image.png" alt=""></p>
<p>오늘은 익스텐션을 대해 공부하였다. 사실 개념적으로는 어려운 건 아니라서 간단하게 적을 예정이다.</p>
<br>
<br>

<h2 id="익스텐션">익스텐션</h2>
<br>


<p>익스텐션</p>
<ul>
<li>구조체, 클래스, 열거형, 프로토콜 타입에 새로운 기능을 추가할 수 있도록 해줌</li>
</ul>
<p>ex. 클래스에 프로토콜을 확장시키고 싶을 때 등</p>
<ul>
<li><p>타입의 기능을 확장할 수도 있음</p>
</li>
<li><p>새로운 기능 추가는 가능하지만, 기존에 존재하는 기능을 재정의할 수는 없음</p>
</li>
</ul>
<table>
<thead>
<tr>
<th></th>
<th>상속</th>
<th>익스텐션</th>
</tr>
</thead>
<tbody><tr>
<td>확장</td>
<td>수직 확장</td>
<td>수평 확장</td>
</tr>
<tr>
<td>사용</td>
<td>클래스 타입에서만 사용</td>
<td>모든 타입에서 사용</td>
</tr>
<tr>
<td>재정의</td>
<td>재정의 가능</td>
<td>재정의 불가</td>
</tr>
</tbody></table>
<ul>
<li><p>기존에 존재하는 타입이 추가로 다른 프로토콜을 채택할 수 있도록 확장 가능</p>
</li>
<li><p>연산 프로퍼티, 메소드, 이니셜라이저, 서브스크립트, 중첩 데이터 타입 추가가능</p>
</li>
</ul>
<br>

<p>한 줄로 생각해보면 메소드나 프로퍼티 등을 &#39;확장&#39;하여 사용할 수 있게 해준다고 생각하면 될 것 같다. 익스텐션 단어 그대로,,</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Swift] 프로토콜]]></title>
            <link>https://velog.io/@ted_kim/Swift-%ED%94%84%EB%A1%9C%ED%86%A0%EC%BD%9C</link>
            <guid>https://velog.io/@ted_kim/Swift-%ED%94%84%EB%A1%9C%ED%86%A0%EC%BD%9C</guid>
            <pubDate>Sun, 16 Apr 2023 06:31:32 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/ted_kim/post/b01381d9-7f4a-4cf4-af2b-aebb8bdfbcef/image.png" alt=""></p>
<p>이번에는 프로토콜에 대해 알아보려고 한다. 사실 swift에서 매우 중요한 개념이기 때문에 이번 책을 통해 프로토콜에 대해 통달했다는 생각하지 않고, 그냥 이러한 개념이구나라는 정도로 알았습니다.</p>
<br>

<h2 id="프로토콜">프로토콜</h2>
<ul>
<li><p>특정 역할을 하기 위한 메소드 ,프로퍼티, 기타 요구사항 등의 청사진을 정의
  -&gt; 특정 역할을 하기 위해 필요한 것들을 정의해놓은 규범</p>
</li>
<li><p>프로토콜을 채택해서 특정 기능을 실행하기 위한 프로토콜의 요구사항을 실제로 구현할 수 있음</p>
</li>
<li><p>‘프로토콜을 준수한다’ → 프로토콜의 요구사항을 모두 따름</p>
</li>
<li><p>프로토콜은 정의를 하고 제시를 하는 것이지, 스스로가 기능을 구현하는 것은 아님!</p>
</li>
<li><p>프로토콜은 쉼표를 통해 여러 개 채택 가능</p>
<ul>
<li>상속과 같은 것도 함께 사용 가능</li>
</ul>
</li>
</ul>
<pre><code>struct SomeClass: SuperClass, AProtocol, AnotherProtocol {

}</code></pre><br>

<p>프로퍼티 요구</p>
<ul>
<li>var 키워드를 통해 프로퍼티 요구사항을 정의할 수 있음</li>
<li>읽기와 쓰기가 모두 가능한 프로퍼티는 { get set }으로 정의할 수 있음</li>
<li>읽기 전용은 { get }으로 정의</li>
</ul>
<pre><code>protocol SomeProtocol {
    var settableProperty: String { get set }
    var notNeedToBeSettableProperty: String { get }
}
</code></pre><br>

<p>메소드 요구</p>
<ul>
<li>메소드의 실제 구현부인 중괄호({}) 부분은 제외하고 메소드의 이름, 매개변수, 반환 타입 등만 작성</li>
</ul>
<pre><code>//무언가를 수신받을 수 있는 기능

protocol Receivable {
    func received(data: Any, from: Sendable)
}


//무언가를 발신할 수 있는 기능
protocol Sendable {
    var from: Sendable { get }
    var to: Receivable? { get }

    func send(data: Any)

    static func isSendableInstance(_ instance: Any) -&gt; Bool
}


//수신,발신이 가능한 Message 클래스
class Message: Sendable, Receivable {
    //발신은 Sendable 프로토콜을 준수하는 타입의 인스턴스여야 함
    var from: Sendable {
        return self
    }

    //상대방은 Receivable 프로토콜을 준수하는 타입의 인스턴스여야 함
    var to: Receivable?

    //메세지 발신
    func send(data: Any) {
        guard let receiver: Receivable = self.to else {
            print(&quot;Message has no receiver&quot;)
            return
        }
        //수신 가능한 인스턴스의 received 메소드 호출
        receiver.received(data: data, from: self.from)
    }

    //메세지 수신
    func received(data: Any, from: Sendable) {
        print(&quot;Message received \(data) from \(from)&quot;)
    }

    //class 메소드로 상속 가능
    class func isSendableInstance(_ instance: Any) -&gt; Bool {
        if let sendableInstance: Sendable = instance as? Sendable {
            return sendableInstance.to != nil
        }
        return false
    }
}


//수신, 발신이 가능한 Mail 클래스
class Mail: Sendable, Receivable {
    var from: Sendable {
        return self
    }

    var to: Receivable?

    func send(data: Any) {
        guard let receiver: Receivable = self.to else {
            print(&quot;Mail has no receiver&quot;)
            return
        }
        receiver.received(data: data, from: self.from)
    }

    func received(data: Any, from: Sendable) {
        print(&quot;Mail received \(data) from \(from)&quot;)
    }

    //static 메소드로 상속 불가
    static func isSendableInstance(_ instance: Any) -&gt; Bool {
        if let sendableInstance: Sendable = instance as? Sendable {
            return sendableInstance.to != nil
        }
        return false
    }
}


//두 Message 인스턴스를 생성
let myPhoneMessage: Message = Message()
let yourPhoneMessage: Message = Message()

//아직 수신받을 인스턴스가 없다
myPhoneMessage.send(data: &quot;Hello&quot;)  //Message has no receiver

//수신받을 인스턴스가 있어서 메세지를 주고받을 수 있음
myPhoneMessage.to = yourPhoneMessage
myPhoneMessage.send(data: &quot;Hello&quot;)  //Message received Hello from Message</code></pre><br>

<p>이니셜라이저 요구</p>
<ul>
<li>이니셜라이저의 경우 ‘클래스’의 경우일 때 신경을 써야 함<ul>
<li>프로토콜의 이니셜라이저 요구에 부합하는 이니셜라이저를 구현할 때는 지정 이니셜라이저인지, 편의 이니셜라이저인지 중요하지 않음</li>
<li>하지만 이니셜라이저 요구에 부합하는 이니셜라이저를 구현할 때는 required 식별자를 붙여야 함</li>
<li>클래스에서 이니셜라이저가 필요할 때는 required를 붙인다.<ul>
<li>만약 상속받을 수 없는 final 클래스라면 required를 안붙여도 됨</li>
</ul>
</li>
<li>만약 클래스에 프로토콜이 요구하는 이니셜라이저가 이미 구현되어 있는 상황에서 그 클래스를 상속받은 클래스가 있다면, required와 override 식별자를 모두 명시하여 이니셜라이저를 구현해야 함</li>
</ul>
</li>
</ul>
<pre><code>protocol Named {
    var name: String { get }

    init(name: String)
}

struct Pet: Named {
    var name: String

    init(name: String) {
        self.name = name
    }
}

class Person: Named {
    var name: String

    required init(name: String) {    //class에서 이니셜라이저가 필요하기 때문에 required를 붙임
        self.name = name
    }
}



class School {
    var name: String

    init(name: String) {
        self.name = name
    }
}

class MiddleSchool: School, Named {
    required override init(name: String) {    //이미 School에서 정의가 되어 있어서 override 작성
        super.init(name: name)
    }
}

</code></pre><br>

<p>프로토콜 상속</p>
<ul>
<li>클래스와 상속 문법과 유사하게 상속할 수 있음</li>
<li>프로토콜의 상속 리스트에 class 키워드를 추가하면 프로토콜이 클래스 타입에만 채택될 수 있도록 제한 가능<ul>
<li>근데 이거 deprecated임!!</li>
</ul>
</li>
<li>맨 처음에 class 위치</li>
</ul>
<br>

<p>프로토콜 조합과 프로토콜 준수 확인</p>
<ul>
<li>하나의 매개변수가 여러 프로토콜을 모두 준수하는 타입이어야 한다면 하나의 매개변수에 여러 프로토콜을 한 번에 조합하여 요구할 수 있음</li>
<li>&amp;를 사용하여 여러 프로토콜 조합 가능</li>
</ul>
<pre><code>protocol: Named {
    var name: String { get }
}

protocol: Aged {
    var age: Int { get }
}

struct Person: Named, Aged {
    var name: String
    var age: Int
}



func celebrateBirthday(to celebrator: Named &amp; Aged) {    //&amp;를 사용하여 프로토콜 사용
    print(&quot;Happy Birthday \(celebrator.name)! Now you are \(celebrator.age)&quot;)
}

let ted: Person = Person(name: &quot;Ted&quot;, age: 26)    //이렇게해서 &amp;를 사용하지 않고도 가능
celebrateBirthday(to: ted)  </code></pre><br>

<p>프로토콜의 선택적 요구</p>
<ul>
<li>선택적 요구사항을 적용하려면 objc 속성이 부여된 프로토콜이어야 함<ul>
<li>objc 속성이 부여되는 프로토콜은 Objective-C 클래스를 상속받은 클래스에서만 채택할 수 있음<ul>
<li>열거형이나 구조체 등에서는 채택할 수 없음</li>
</ul>
</li>
<li>Foundation 프레임워크 모듈을 임포트해야함</li>
</ul>
</li>
<li>옵셔널을 통해 선택적 요구사항을 정의할 수 있음</li>
</ul>
<br>

<p>위임을 위한 프로토콜</p>
<ul>
<li><p>위임(Delegate) : 클래스나 구조체가 자신의 책임이나 임무를 다른 타비의 인스턴스에게 위임하는 디자인 패턴</p>
<ul>
<li>비동기 처리에서도 많이 쓰임</li>
</ul>
</li>
<li><p>Delegate Pattern</p>
<ul>
<li><p>애플의 프레임워크에서 중요한 패턴 중 하나</p>
<p>ex. UITableView 타입의 인스턴스가 해야 하는 일을 위임받아 처리하는 인스턴스는 UITableViewDelegate 프로토콜을 준수함</p>
<p>UITableViewDelegate 프로토콜을 준수하는 인스턴스는 UITableView의 인스턴스가 해야 하는 일을 대신 처리해 줌</p>
</li>
</ul>
</li>
</ul>
<br>
<br>

<p>한 문장으로 정리하면 <strong>프로토콜은 어떠한 규약을 정해놓고 그 규약을 채택하는 것?</strong> 정도로 생각하면 될 것 같다. Delegate pattern은 예전에 사용했던 것 같은데, 이에 대해서도 나중에 다시 공부해야겠다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Swift] 타입캐스팅]]></title>
            <link>https://velog.io/@ted_kim/Swift-%ED%83%80%EC%9E%85%EC%BA%90%EC%8A%A4%ED%8C%85</link>
            <guid>https://velog.io/@ted_kim/Swift-%ED%83%80%EC%9E%85%EC%BA%90%EC%8A%A4%ED%8C%85</guid>
            <pubDate>Sat, 15 Apr 2023 08:22:59 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/ted_kim/post/16ccfcb2-8d6a-4f40-8a4f-fd5979fbf56d/image.png" alt=""></p>
<p>이번에는 타입캐스팅에 대해 작성하고자 한다.</p>
<br>
<br>

<h2 id="타입캐스팅">타입캐스팅</h2>
<p>우선 스위프트는 다른 언어에 비해 다른 타입끼리의 값 교환을 엄격히 제한함</p>
<ul>
<li>암시적 타입 변환을 허용하지 않음</li>
</ul>
<br>

<p>타입캐스팅</p>
<ul>
<li><p>인스턴스의 타입을 확인하거나 자신을 다른 타입의 인스턴스인양 행세할 수 있는 방법으로 사용가능</p>
</li>
<li><p>자식 클래스는 부모클래스인 척을 할 수 있음 → 부모 클래스의 특성을 가지고 있기 때문</p>
<ul>
<li>Coffee는 Latte나 Americano의 특성을 가지고 있지 않지만,
Latte나 Americano는 Coffee의 특성을 가지고 있다!</li>
</ul>
</li>
<li><p>데이터 타입 확인 is</p>
<ul>
<li>is를 통해 인스턴스가 어떤 클래스의 인스턴스 타입인지 확인 가능</li>
<li>myCoffee는 Americano 타입이면서 Coffee 타입임</li>
</ul>
</li>
</ul>
<pre><code>let myCoffee: Americano
let yourCoffee: Latte

coffee is Coffee    //true
coffee is Americano    //false
coffee is Latte    //false

myCoffee is Coffee    //true
myCoffee is Americano    //true

myCoffee is Latte    //false
yourCoffee is Latte    //true
</code></pre><br>

<p>다운캐스팅</p>
<ul>
<li>하지만 진짜 본인의 타입을 사용해야 할 때가 있음</li>
<li>부모클래스의 타입을 자식클래스의 타입으로 캐스팅하여 다운캐스팅이라고 함</li>
</ul>
<p>타입캐스트 연산자 as?!</p>
<ul>
<li>타입캐스트 연산자를 통해 다운캐스팅할 수 있음</li>
<li>실패의 여지가 있기 때문에 옵셔널 타입</li>
</ul>
<pre><code>let actingConstant: Coffee = Latte(flavor: &quot;vanilla&quot;, shot: 2)


if let actingOne: Americano = coffee as? Americano {
    print(&quot;This is Americano&quot;)
} else { 
    print(coffee.description)
}

//1 shot(s) coffee


if let actingOne: Americano = myCoffee as? Americano {
    print(&quot;This is Americano&quot;)
} else {
    print(coffee.description)
}

//This is Americano</code></pre><br>

<p>Any, AnyObject의 타입캐스팅</p>
<ul>
<li>특정 타입을 지정하지 않고 여러 타입의 값을 할당할 수 있는 타입</li>
<li>Any : 함수 타입을 포함한 모든 타입, AnyObject : 클래스 타입만</li>
<li>하지만 Any나 AnyObject는 전달받은 데이터가 어떤 타입인지 확인하고 사용해야 함!<ul>
<li>스위프트는 암시적 타입 변환은 허용하지 않으며, 타입에 굉장히 엄격하기 때문</li>
</ul>
</li>
</ul>
<pre><code>func checkType(of item: AnyObject) {
    if item is Latte {
        print(&quot;item is Latte&quot;)
} else {
    print(&quot;Unknown Type&quot;)
}

checkType(of: coffee)    //Unknown Type
checkType(of: yourCoffee)    //item is Latte</code></pre><br>
<br>

<p>오랜만에 공부하니 좀 어색한 것 같다.. 후다닥 1회독을 해야겠다.</p>
<br>

<p>[출처] 스위프트 프로그래밍 (야곰), <a href="https://www.youtube.com/watch?v=2n-fSlW-jts&amp;list=PLz8NH7YHUj_ZmlgcSETF51Z9GSSU6Uioy">야곰의 스위프트 기초문법 강좌</a>, <a href="https://www.inflearn.com/course/%EC%A0%95%EB%8C%80%EB%A6%AC-%EC%8A%A4%EC%9C%84%ED%94%84%ED%8A%B8-%EA%B8%B0%EC%B4%88/dashboard">개발하는 정대리 스위프트 강좌</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[xcode] Resources 폴더 관련 버그]]></title>
            <link>https://velog.io/@ted_kim/xcode-Resources-%ED%8F%B4%EB%8D%94-%EA%B4%80%EB%A0%A8-%EB%B2%84%EA%B7%B8</link>
            <guid>https://velog.io/@ted_kim/xcode-Resources-%ED%8F%B4%EB%8D%94-%EA%B4%80%EB%A0%A8-%EB%B2%84%EA%B7%B8</guid>
            <pubDate>Sun, 02 Apr 2023 15:46:04 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/ted_kim/post/318d8603-9d58-4d75-abf8-ecee10af6811/image.png" alt=""></p>
<p>Playground app을 통해 앱을 만들어가는 도중, 이상한? 버그를 발견하였다.</p>
<p>버그는 Resources 폴더 안에 있는 데이터들을 인식하지 못하는 버그였다.</p>
<p>처음에 폰트를 가져오려고 했는데, 자꾸 폰트 관련 데이터가 없다고 떴다;;</p>
<p><img src="https://velog.velcdn.com/images/ted_kim/post/5a27a456-978f-42e5-936e-9833ab058f38/image.png" alt=""></p>
<p>심지어 다른 팀원이 진행했던 레퍼런스를 사용했는데 나만 자꾸 안되니 황당하였다.. </p>
<br>

<h3 id="해결법">해결법</h3>
<p>그래서 차근차근 하다보니, 팀원이 했던 방식과 내가 했던 방식 간의 차이점을 발견하였다..!</p>
<p>바로 &#39;<strong>Resources 폴더 생성 여부</strong>&#39;였다.</p>
<p>사실 나는 데이터를 넣을 때 <strong><em>Resources 폴더를 생성하고, 그 안에 데이터(폰트, 영상 등)를 넣은</em></strong> 반면에,</p>
<p>우리 팀원은 <strong>Resources 폴더를 따로 생성하지 않고 그대로 xcode에 데이터를 넣었다</strong>고 하였다!!</p>
<br>

<p>당연히 폴더를 만들어주고 그 안에 집어넣는 것인줄 알았는데, 그것이 아니었다,, 
심지어 이렇게 만들면 데이터를 인식조차 하지 못하기 때문에, </p>
<p><em><strong>mp3 등과 같은 데이터 폴더를 playground App에서 사용하고 싶다면, 그냥 드래그 앤 드랍을 하면 된다. (Resources 폴더를 자체적으로 만들지 마라!!)</strong></em> </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Swift] 상속]]></title>
            <link>https://velog.io/@ted_kim/Swift-%EC%83%81%EC%86%8D</link>
            <guid>https://velog.io/@ted_kim/Swift-%EC%83%81%EC%86%8D</guid>
            <pubDate>Sun, 02 Apr 2023 08:17:52 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/ted_kim/post/3f16cbcd-6f13-4f74-ab72-79637f13c2b6/image.png" alt=""></p>
<p>이번에는 상속에 대해 작성해보려고 한다. 
사실 상속에 관해서 다양한 이니셜라이저가 나타나는데, 이런 것들을 제외하고 가장 중요한 개념들 위주로 정리해볼 예정이다.</p>
<br>

<h3 id="상속">상속</h3>
<ul>
<li>클래스는 다른 클래스로부터 메소드나 프로퍼티 등을 _<strong>상속</strong>_받을 수 있음</li>
<li>상속에는 부모클래스 자식클래스가 있는데, 
  부모클래스는 상위클래스로 자식클래스에게 상속해주는 것이고(부모 클래스의 메소드나 프로퍼티를 자식클래스가 사용할 수 있음), 
  자식클래스는 하위클래스로 부모클래스로부터 상속을 받는 것이다.(부모클래스의 메소드나 프로퍼티를 사용하는 클래스)</li>
<li>스위프트에서 상속은 <strong>클래스만의 특징</strong>으로, 다른 타입에서는 상속을 할 수 없음</li>
</ul>
<pre><code>class Person {
    var name: String = &quot;&quot;
    var age: Int = 0

    var introduction: String {
        return &quot;이름 : \(name). 나이 : \(age)&quot;
    }

    func speak() {
        print(&quot;가나다라마바사&quot;)
    }
}


//Person을 상속 받은 Student
class Student: Person {
    var grade: String = &quot;F&quot;

    func study() {
        print(&quot;Study hard...&quot;)
    }
}


let ted: Student = Student()
ted.speak() //Person에 있는 메소드 사용 가능</code></pre><br>

<p>재정의</p>
<ul>
<li>자식클래스는 부모클래스로부터 물려받은 특성을 그대로 사용하지 않고, 자신만의 기능으로 변경하여 사용할 수 있음</li>
<li>상속받은 특성을 재정의하려면 <strong>override</strong>라는 키워드를 통해 재정의할 수 있음</li>
<li>재정의한 메소드의 부모 버전을 호출하고 싶다면 <strong>super.</strong>라는 키워드를 통해 호출할 수 있음</li>
</ul>
<pre><code>//override를 통한 메소드 재정의

class Student: Person {
    var grade: String = &quot;F&quot;

    func study() {
        print(&quot;Study hard...&quot;)
    }

    override func speak() {
        print(&quot;저는 학생입니다.&quot;)
    }
}</code></pre><br>

<p>재정의 방지 (final)</p>
<ul>
<li>만약 재정의를 할 수 없도록 하고 싶으면, final 키워드를 명시하면 됨</li>
<li>final 키워드가 있는 프로퍼티나 메소드를 재정의하려고 하면 에러가 뜸</li>
</ul>
<br>
<br>

<p>[출처] 스위프트 프로그래밍 (야곰), <a href="https://www.youtube.com/watch?v=2n-fSlW-jts&amp;list=PLz8NH7YHUj_ZmlgcSETF51Z9GSSU6Uioy">야곰의 스위프트 기초문법 강좌</a>, <a href="https://www.inflearn.com/course/%EC%A0%95%EB%8C%80%EB%A6%AC-%EC%8A%A4%EC%9C%84%ED%94%84%ED%8A%B8-%EA%B8%B0%EC%B4%88/dashboard">개발하는 정대리 스위프트 강좌</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Swift] 서브스크립트]]></title>
            <link>https://velog.io/@ted_kim/Swift-%EC%84%9C%EB%B8%8C%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EB%9E%80</link>
            <guid>https://velog.io/@ted_kim/Swift-%EC%84%9C%EB%B8%8C%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8%EB%9E%80</guid>
            <pubDate>Mon, 27 Mar 2023 09:33:09 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/ted_kim/post/1ca8ec4d-30c8-41f6-813d-4b13b6209d17/image.png" alt=""></p>
<p>이번 글은 서브스크립트에 대해 작성해보겠다. 지금까지 공부했던 것 중에 뭔가 가장 애매모호했던,,? 느낌이었다.</p>
<br>

<p><strong>서브스크립트</strong></p>
<p>클래스, 구조체, 열거형에는 컬렉션, 리스트, 시퀀스 등 _<strong>타입의 요소</strong>_에 접근하는 단축 문법인 서브스크립트를 정의할 수 있다.</p>
<p>타입의 요소란 쉽게 말해서 대괄호로 감싼 인덱스와 같은 개념으로 생각하면 될 것 같다.</p>
<ul>
<li><p>인스턴스의 이름 뒤에 대괄호로 감싼 값을 통해 접근할 수 있다</p>
</li>
<li><p>-&gt; <em><strong>인덱스처럼(인덱스에) 접근이 가능함!</strong></em></p>
</li>
<li><p>subscript 키워드를 통해 정의</p>
</li>
<li><p>연산 프로퍼티나 인스턴스 메소드 문법과 유사</p>
</li>
<li><p>정의하는 코드는 각 타입의 구현부 또는 타입의 익스텐션 구현부에 위치함</p>
</li>
<li><p>별도의 설정자(setter) 또는 접근자(getter) 등을 구현하지 않아도 인덱스를 통해 값을 설정하거나 가져올 수 있음 (대괄호)</p>
<p>  ex. someArray의 index를 통해 해당 인덱스의 값에 접근하고 싶을 때
  —&gt; <strong>someArray[index]</strong> : 이렇게 표현하는 것이 서브스크립트임</p>
</li>
</ul>
<pre><code>subscript(index: Int) -&gt; Int {
    get {
        //서브스크립트 결괏값 반환
    }
    set(newValue) {
        //설정자 역할 수행
    }
}


struct TimesTable {
    let multiplier: Int
    subscript(index: Int) -&gt; Int {
        return multiplier * index
    }
}
let threeTimesTable = TimesTable(multiplier: 3)
print(&quot;six times three is \\(threeTimesTable[6])&quot;) 
// six times three is 18
// 인덱스 값을 이용하여 계산을 진행하였다. (인덱스를 사용)</code></pre><br>


<ul>
<li>자신이 가지는 시퀀스나 컬렉션, 리스트 등의 요소를 반환하고 설정할 때 주로 사용</li>
<li>여러 개의 매개변수를 가질 수 있음</li>
<li>입출력 매개변수는 가질 수 없음</li>
</ul>
<pre><code>struct Student {
    var name: String
    var number: Int
}

class School {
    var number: Int = 0
    var students: [Student] = [Student]()

    func addStudent(name: String) {
        let student: Student = Student(name: name, number: self.number)
        self.students.append(student)
        self.number += 1
    }

    func addStudents(names: String...) {    //들어올 매개변수의 개수가 불확실할 때 ... 사용
        for name in names {
            self.addStudent(name: name)
        }
    }

    subscript(index: Int = 0) -&gt; Student? {    //서브스크립트를 정의하면 인덱스처럼 사용할 수 있게 됨
        if index &lt; self.number {
            return self.students[index]
        }
        return nil
    }
}

let highSchool: School = School()
highSchool.addStudents(names: &quot;Ted&quot;, &quot;DY&quot;, &quot;JJ&quot;, &quot;JW&quot;)

let aStudent: Student? = highSchool[1]    //구조체 형식이기 때문에 인덱스를 달아주지 않는 이상 값을 추출할 수 없음
                                          //서브스크립트를 통해 인덱스를 지정해주어 값을 할당 받을 수 있게 됨!
print(&quot;\(aStudent?.number) \(aStudent?.name)&quot;)  //Optional(1) Optional(&quot;DY&quot;)
print(highSchool[]?.name)   //매개변수 기본값 사용 -&gt; Optional(&quot;Ted&quot;)</code></pre><br>

<p>사용 예시</p>
<ul>
<li>String을 배열처럼 [index]로 접근하고 싶을 때 사용!</li>
</ul>
<pre><code>let ted = &quot;Hi, Ted!&quot;
ted[0]    //error!! (해당 서브스크립트를 사용할 수 없음)


extension String {    //문자열을 인덱스로 추출할 수 있는 서브스크립트
    subscript(idx: Int) -&gt; String? {
        guard (0..&lt;count).contains(idx) else {
            return nil
        }
        let target = index(startIndex, offsetBy: idx)
        return String(self[target])
    }
}


ted[0]    //Optional(&quot;H&quot;)</code></pre><br>

<p>그래도 계속 보니깐 어느 정도는 이해가 되는데,, 익숙해지고 활용하기 위해서는 더욱 많이 봐야 할 것 같다.</p>
<br>
<br>

<p>[출처] 스위프트 프로그래밍 (야곰), <a href="https://www.youtube.com/watch?v=2n-fSlW-jts&amp;list=PLz8NH7YHUj_ZmlgcSETF51Z9GSSU6Uioy">야곰의 스위프트 기초문법 강좌</a>, <a href="https://www.inflearn.com/course/%EC%A0%95%EB%8C%80%EB%A6%AC-%EC%8A%A4%EC%9C%84%ED%94%84%ED%8A%B8-%EA%B8%B0%EC%B4%88/dashboard">개발하는 정대리 스위프트 강좌</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[디자인 패턴] MVC]]></title>
            <link>https://velog.io/@ted_kim/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-MVC</link>
            <guid>https://velog.io/@ted_kim/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-MVC</guid>
            <pubDate>Sun, 26 Mar 2023 15:03:08 GMT</pubDate>
            <description><![CDATA[<h3 id="디자인-패턴">디자인 패턴</h3>
<p>디자인 패턴이란 코드의 유지보수와 협업적인 측면에 있어서 용이하도록 정해놓은 일련의 규칙(템플릿)이다.</p>
<p>여러 가지 디자인 패턴들이 있는데, 그 중에서 가장 기본이 되는 _<strong>MVC패턴</strong>_에 대해 알아보았다.</p>
<h3 id="mvc">MVC</h3>
<p><img src="https://velog.velcdn.com/images/ted_kim/post/6d6732ba-b6f6-47b7-9b34-fceb51118f10/image.png" alt=""></p>
<p>우선 MVC는 Model, View, Controller로 구성되어 있으며, 기존에 많이 사용하는 <strong><em>UIKit</em></strong> 프레임워크에 적합한 디자인 패턴이다(아마 MVC 패턴을 기반으로 UIKit 프레임워크가 만들어 진 것으로 알고 있다).</p>
<br>

<p><strong>Model</strong></p>
<ul>
<li><p>앱에 사용되는 데이터와 비즈니스 로직을 담당하는 함수 등을 정의한다.</p>
<p>  ex. Data.swift, WeatherData.swift 등</p>
</li>
</ul>
<p><strong>View</strong></p>
<ul>
<li><p>사용자가 볼 수 있는 화면을 구성한다.</p>
</li>
<li><p>스토리보드를 생각하면 될 것 같다.</p>
<p>  ex. Main.storyboard 등</p>
</li>
</ul>
<p><strong>Controller</strong></p>
<ul>
<li>Model의 데이터를 View에 띄워주는 역할을 한다.</li>
<li>Model과 View의 중간다리 역할로, Model과 View 사이에서 데이터를 전달해준다. 
(Model과 View는 직접적으로 접근할 수 없고, Controller를 통해 소통할 수 있다)</li>
<li>ViewController 파일을 생각하면 될 것 같다.
ex. ViewController.swift 등</li>
</ul>
<br>

<p>장점</p>
<ul>
<li>애플(UIKit)에서 기본적으로 지원하고 있는 패턴이라 쉽게 적용할 수 있음</li>
<li>다른 패턴에 비해 코드량이 적음</li>
<li>개발속도가 빠르기 때문에 아키텍쳐가 크게 중요하지 않고, 규모가 작은 프로젝트에서 사용하기 편하다.</li>
</ul>
<p>단점</p>
<ul>
<li>Controller에 의존성이 너무 높다.
→ View와 Controller가 밀접하게 연결되어 있어, 이 둘을 분리하기가 어렵다</li>
<li>ViewController에 너무 많은 코드가 작성되어 (Model 데이터 처리, @IBOutlet을 이용한 View와의 결합) </li>
<li><em>&#39;Massive View Controller&#39;*</em>라고도 부름</li>
<li>규모가 큰 프로젝트일수록 코드가 복잡해지기 때문에 유지보수하기 어려워진다.</li>
</ul>
<br>
<br>

<p>이번 정리를 통해 MVC 패턴에 대해 어느정도 알게 되었다.
SwiftUI는 MVC 패턴보단 MVVM 패턴에 적합하다고 하는데, 다음에는 MVVM 패턴과 같은 다른 디자인 패턴에 대해 정리해보겠다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Swift] 옵셔널 체이닝과 빠른 종료]]></title>
            <link>https://velog.io/@ted_kim/Swift-%EC%98%B5%EC%85%94%EB%84%90-%EC%B2%B4%EC%9D%B4%EB%8B%9D%EA%B3%BC-%EB%B9%A0%EB%A5%B8-%EC%A2%85%EB%A3%8C</link>
            <guid>https://velog.io/@ted_kim/Swift-%EC%98%B5%EC%85%94%EB%84%90-%EC%B2%B4%EC%9D%B4%EB%8B%9D%EA%B3%BC-%EB%B9%A0%EB%A5%B8-%EC%A2%85%EB%A3%8C</guid>
            <pubDate>Sun, 26 Mar 2023 02:24:15 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/ted_kim/post/10cf6b14-df54-4834-b3a3-9eab60d3179f/image.png" alt=""></p>
<p>이번 글에서는 옵셔널 체이닝과 빠른 종료에 대해 작성해보려고 한다.</p>
<br>

<p>옵셔널 체이닝</p>
<ul>
<li>옵셔널에 속해 있는 nil일지 모르는 프로퍼티, 메소드, 서브스크립션 등을 가져오거나 호출할 때 사용할 수 있는 과정</li>
<li>프로퍼티나 메소드 또는 서브스크립트를 호출하고 싶은 옵셔널 변수나 상수 뒤에 물음표(?)를 붙여 표현</li>
</ul>
<pre><code>class Room {
    var number: Int

    init(number: Int) {
        self.number = number
    }
}

class Building {
    var name: String
    var room: Room?

    init(name: String) {
        self.name = name
    }
}

struct Address {
    var province: String
    var city: String
    var street: String
    var building: Building?
    var detailAddress: String?
}

class Person {
    var name: String
    var address: Address?

    init(name: String) {
        self.name = name
    }
}

let ted: Person = Person(name: &quot;ted&quot;)

let tedRoomViaOptionalChaining: Int? = ted.address?.building?.room?.number  //nil
let tedRoomViaOptionalUnwraping: Int? = ted.address!.building!.room!.number  //런타임 에러</code></pre><ul>
<li>옵셔널 바인딩을 통해 옵셔널 체이닝을 간단하게 표현할 수 있음</li>
</ul>
<pre><code>let ted: Person = Person(name: &quot;ted&quot;)

if let roomNumber: Int = ted.address?.building?.room?.number {
    print(roomNumber)
} else {
    print(&quot;Can not find room number&quot;)
}</code></pre><ul>
<li>옵셔널 체이닝을 통해 값을 할당해주려면 옵셔널 체인에 존재하는 프로퍼티를 실제로 할당해줘야 값이 반환됨</li>
<li>만약 값이 없다면 nil로 반환됨</li>
</ul>
<pre><code>ted.address = Address(province: &quot;인천광역시&quot;, city: &quot;부평구&quot;, street: &quot;마장로&quot;, building: nil, detailAddress: nil)
ted.address?.building = Building(name: &quot;무지개아파트&quot;)    //값 할당
ted.address?.building?.room = Room(number: 0)
ted.address?.building?.room?.number = 1508

print(ted.address?.building?.room?.number)    //Optional(1508)</code></pre><br>

<h3 id="빠른-종료">빠른 종료</h3>
<p>guard 구문</p>
<ul>
<li><p>Bool 타입의 값으로 동작하는 기능</p>
</li>
<li><p>guard 뒤에 따라붙는 코드의 실행 결과가 true일 때 코드가 계속 실행됨</p>
</li>
<li><p>항상 else 구문이 뒤에 따라와야 함</p>
</li>
<li><p>else에는 자신보다 상위의 코드 블록을 종료하는 코드가 들어가게 됨</p>
<p>  —&gt; 특정 조건에 부합하지 않다는 판단이 되면 코드 블록의 실행을 종료함</p>
</li>
<li><p>예외사항만을 처리하고 싶다면 사용 !</p>
</li>
<li><p>하지만 제어문 전환 명령어 (return, break, continue, throw)를 쓸 수 없다면 사용 불가능</p>
</li>
</ul>
<pre><code>//if 구문
for i in 0...3 {
    if i == 2 {
        print(i)
    } else {    //else를 통해 continue를 진행해야 한다
        continue
    }
}

//guard 구문
for i in 0...3 {
    guard i == 2 else { continue }
    print(i)
}</code></pre><br>
<br>

<p>[출처] 스위프트 프로그래밍 (야곰), <a href="https://www.youtube.com/watch?v=2n-fSlW-jts&amp;list=PLz8NH7YHUj_ZmlgcSETF51Z9GSSU6Uioy">야곰의 스위프트 기초문법 강좌</a>, <a href="https://www.inflearn.com/course/%EC%A0%95%EB%8C%80%EB%A6%AC-%EC%8A%A4%EC%9C%84%ED%94%84%ED%8A%B8-%EA%B8%B0%EC%B4%88/dashboard">개발하는 정대리 스위프트 강좌</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Swift] 클로저]]></title>
            <link>https://velog.io/@ted_kim/Swift-%ED%81%B4%EB%A1%9C%EC%A0%80</link>
            <guid>https://velog.io/@ted_kim/Swift-%ED%81%B4%EB%A1%9C%EC%A0%80</guid>
            <pubDate>Fri, 24 Mar 2023 08:38:00 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/ted_kim/post/5e29718f-c0fe-49c7-81b3-a5bffe70a501/image.png" alt=""></p>
<p>이번 내용은 클로저에 관한 내용이다. 책으로만 읽었을 때는 감이 잘 안와서, 여러 영상과 블로그를 찾아보고 나름대로 정리한 것이다.</p>
<p>스위프트는 객체 지향형 프로그래밍에 함수형 프로그래밍 패러다임을 더한 언어이다. 함수형 프로그래밍 패러다임 중 가장 먼저 알아야 하고, 스위프트를 배운다면 무조건 마주치게 될 것이 바로 &#39;<strong>클로저</strong>&#39;이다.</p>
<br>
<br>

<h3 id="클로저">클로저</h3>
<p>클로저는 어떤 테스크를 수행하기 위한 코드 블록을 말한다. 그럼 함수랑 다른 점이 있는가? 라고 생각을 해보면 사실 함수가 클로저의 일부이다 !</p>
<p>이름 있는 클로저 -&gt; 함수
이름 없는 클로저 -&gt; 일반적으로 클로저라고 부르는 형태
<br></p>
<p>클로저는 매개변수와 반환 값의 타입을 생략할 수 있음</p>
<ul>
<li>파마리터를 받을 수 있음</li>
<li>특정값을 반환할 수도 있음</li>
<li>함수 파라미터로 받을 수도 있음<ul>
<li>클로저를 따로 만들어 놓지 않고, 함수 수행 시 바로 작성 가능</li>
</ul>
</li>
<li>축약된 전달인자 이름 사용 가능</li>
<li>후행 클로저 (trailing closure) 문법 사용 가능</li>
</ul>
<pre><code>{ (parameters) -&gt; return type in
    statements
}</code></pre><br>

<ul>
<li>in을 기준으로 _<strong>클로저 선언부</strong>_와 _<strong>클로저 실행부</strong>_가 나뉨<ul>
<li>클로저 선언부 : 파라미터와 리턴타입을 명시해줌</li>
<li>클로저 실행부 : 실행 코드를 작성하는 곳</li>
</ul>
</li>
<li>Swift에서는 클로저와 함수를 타입으로 사용할 수 있음 (일급 시민)<ul>
<li>일급 시민이기 때문에 <strong>변수에 할당</strong>할 수 있고, 다<strong>른 함수 파라미터로 전달</strong>할 수도 있음</li>
</ul>
</li>
</ul>
<pre><code>let checking = { print(&quot;checking!!&quot;) }
checking()    //checking!!



let checking = { (id: String) in    //파라미터를 받을 수 있음
    print(&quot;checking id: \(id)&quot;)
}
checking(&quot;User1&quot;)    //checking id: User1



let checking = { (id: String) -&gt; Bool in    //리턴값 존재
    if id == &quot;User1&quot; {
        return false
    } 
    return true
}

let isValid = checking(&quot;User2&quot;)    //true
let isValid = checking(&quot;User1&quot;)    //false



func validate(id: String, checking: (String) -&gt; Bool) -&gt; Bool {    //위에 작성한 checking 클로저를 파라미터로 사용함
    let isValid = checking(id)
    return isValid
}

let validationResult = validate(id: &quot;User2&quot;, checking: checking)    //true (리턴 값이 true임)





let validationResult2 = validate(id: &quot;User1&quot;, checking: { (id: String) -&gt; Bool in
    if id == &quot;User0&quot; {
        return false
    }
    return true
})    //checking에 대한 클로저를 따로 정의하지 않고, 함수 안에서 만들었음


doSomeClosure ({ print(&quot;Hello World&quot;) }    // 클로저를 안에서 만들고 바로 사용</code></pre><br>

<p>클로저 표현 간소화</p>
<ul>
<li>클로저는 생략이나 짧게 만들 수 있음</li>
<li>선언부를 줄이거나 in을 없앨 수도 있음</li>
<li>맨 마지막에 들어오는 클로저는 파라미터를 작성해주지 않아도 됨 (trailing closure)</li>
<li>하지만 너무 줄이면 코드의 가독성이 떨어질 수도 있기 때문에 적절하게 줄여줘야 함!</li>
</ul>
<p>종류</p>
<ul>
<li>문맥을 이용한 타입 유추<ul>
<li>매개변수의 타입이나 반환 값의 타입을 굳이 표현해주지 않고 생략하더라도 문제가 없음</li>
</ul>
</li>
<li>단축 인자 이름<ul>
<li>첫 번째 전달인자부터 $0, $1, $2, … 순서로 표현 가능<ul>
<li>단축 인자 표현을 사용하면 선언부와 실행부를 나누기 위한 in을 사용할 필요도 없어짐</li>
</ul>
</li>
</ul>
</li>
<li>암시적 반환 표현<ul>
<li>return 키워드 생략 가능</li>
</ul>
</li>
</ul>
<pre><code>let validationResult = validate(id: &quot;User0&quot;, checking: { (id: String) -&gt; Bool in
    if id == &quot;User1&quot; {
        return false
    }
    return true
})



let validationResult2 = validate(id: &quot;User1&quot;, checking: { id in    //클로저 선언부를 줄일 수 있음 (return이 있기 때문에 스위프트에서 알아서 추론함)
    if id == &quot;User0&quot; {
    return false
    }
    return true
})




let validationResult3 = validate(id: &quot;User1&quot;, checking: { id in    //if문을 리팩토링함
    let isValide = id != &quot;User0&quot;
    return isValid
})



let validationResult4 = validate(id: &quot;User1&quot;, checking: { $0 != &quot;User0&quot; })    //$0, $1, ... : 클로저로 들어오는 input을 나타냄


let validationResult5 = validate(id: &quot;User1&quot;) { $0 != &quot;User0&quot; }    //trailing closure: 맨 마지막에 들어오는 클로저는 파라미터를 작성하지 않아도 됨</code></pre><br>

<p>값 획득</p>
<ul>
<li>자신이 정의된 위치의 주변 문맥을 통해 상수나 변수를 획득(Capture)할 수 있음</li>
<li>클로저는 주변에 정의한 상수나 변수가 존재하지 않더라도 해당 상수나 변수의 값을 자신 내부에서 참조하거나 수정할 수 있음</li>
<li>클로저는 비동기 작업에 많이 사용되는데, 클로저를 통해 비동기 콜백을 작성하는 경우, 현재 상태를 획득해두지 않으면, 클로저의 기능을 실행하는 순간에 메모리에 존재하지 않는 경우가 발생할 수 있음</li>
</ul>
<br>

<p>참조 타입</p>
<ul>
<li>클로저는 참조 타입임 → 값 획득을 통해 변수를 증가시킬 수 있음</li>
<li>함수나 클로저를 할당할 때 사실은 참조를 설정하는 것임</li>
<li>상수에 클로저를 할당한다는 것은 값을 할당하는 것이 아니라 해당 클로저의 참조를 할당하는 것임!</li>
</ul>
<br>

<p>탈출 클로저 (@escaping)</p>
<ul>
<li><p>함수의 전달인자로 전달한 클로저가 함수 종료 후에 호출될 때 클로저가 함수를 <strong>탈출</strong>한다고 표현함</p>
</li>
<li><p>클로저를 매개변수로 갖는 함수를 선언할 때 매개변수 이름의 콜론(:) 뒤에 @escaping 키워드를 통해 클로저가 탈출하는 것을 허용</p>
</li>
<li><p>클로저의 기본값은 비탈출 클로저임</p>
<ul>
<li>비탈출 클로저는 함수 내부 스코프 안에서만 사용 가능</li>
<li>외부 상수, 변수에 저장 불가능</li>
</ul>
</li>
<li><p>함수 외부에 정의된 변수나 상수에 저장되어 함수가 종료된 후에 사용할 경우에 탈출 클로저 사용</p>
<p>  ex. 비동기 작업할 때 캠플리션 핸들러를 전달인자를 이용해 클로저 형태로 받는 함수들이 있음 → 함수가 작업을 종료하고 난 이후(return 이후)에 컴플리션 핸들러인 클로저를 호출하기 때문에 클로저는 함수를 탈출해 있어야만 함</p>
</li>
<li><p>탈출 클로저를 사용한다면</p>
<ul>
<li>해당 클로저를 외부 변수, 상수에 저장 가능</li>
<li>해당 함수가 끝나서 리턴된 이후에도 클로저 실행 가능</li>
</ul>
</li>
</ul>
<pre><code>var sampleClosure: () -&gt; Void = { }

func callback(closure: @escaping() -&gt; Void) {    //만약 @escaping이 없다면 에러 발생
    sampleClosure = closure
    sampleClosure()
}</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[Swift] 접근제어]]></title>
            <link>https://velog.io/@ted_kim/Swift-%EC%A0%91%EA%B7%BC%EC%A0%9C%EC%96%B4</link>
            <guid>https://velog.io/@ted_kim/Swift-%EC%A0%91%EA%B7%BC%EC%A0%9C%EC%96%B4</guid>
            <pubDate>Wed, 22 Mar 2023 14:41:40 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/ted_kim/post/3c67923c-2d20-43da-bf85-7cffb50dce94/image.png" alt=""></p>
<p>이번 글은 접근제어에 대해 작성해보고자 한다.</p>
<br>

<p>접근 제어</p>
<ul>
<li>코드끼리 상호작용을 할 때 파일 또는 모듈 간에 접근을 제한할 수 있는 기능</li>
<li>객체지향 프로그래밍 패러다임에서 중요한 &#39;<strong><em>캡슐화</em></strong>&#39;와 &#39;<strong><em>은닉화</em></strong>&#39;와 연관이 있음</li>
<li>불필요한 접근으로 의도치 않은 결과 초래 가능성이 존재하는데, 이를 방지해줌</li>
</ul>
<br>

<p>모듈</p>
<ul>
<li>배포할 코드의 묶음 단위</li>
<li>import를 통해 불러옴</li>
</ul>
<br>

<p>소스파일</p>
<ul>
<li>하나의 스위프트 소스 코드 파일</li>
</ul>
<br>

<p>접근 수준</p>
<table>
<thead>
<tr>
<th>접근 수준</th>
<th>키워드</th>
<th>접근도</th>
<th>범위</th>
<th>비고</th>
</tr>
</thead>
<tbody><tr>
<td>개방 접근수준</td>
<td>open</td>
<td>높음</td>
<td>모듈 외부까지</td>
<td>클래스에서만 사용</td>
</tr>
<tr>
<td>공개 접근수준</td>
<td>public</td>
<td></td>
<td>모듈 외부까지</td>
<td></td>
</tr>
<tr>
<td>내부 접근수준</td>
<td>internal</td>
<td></td>
<td>모듈 내부</td>
<td></td>
</tr>
<tr>
<td>파일 외부 비공개 접근 수준</td>
<td>fileprivate</td>
<td></td>
<td>파일 내부</td>
<td></td>
</tr>
<tr>
<td>비공개 접근수준</td>
<td>private</td>
<td>낮음</td>
<td>기능 정의 내부</td>
<td></td>
</tr>
</tbody></table>
<br>

<p>public (공개 접근 수준)</p>
<ul>
<li>어디서든 쓰일 수 있음</li>
<li>프레임워크를 만들 때(API 등) 지정</li>
</ul>
<br>

<p>open (개방 접근수준)</p>
<ul>
<li>클래스와 클래스의 멤버에서만 사용 가능</li>
<li>클래스를 개방 접근 수준(open)으로 명시하는 것은 <strong>그 클래스를 다른 모듈에서도 부모클래스로 사용하겠다는 목적</strong>으로 클래스를 설계하고 코드를 작성했음을 의미함!!</li>
</ul>
<pre><code>open class NSString: NSObject, NSCopying, NSMutableCopying, NSSecureCoding {
    open var length: Int { get }
    open func character(at index: Int) -&gt; unichar
    public init()
    public init?(coder aDecoder: NSCoder)
}</code></pre><br>

<p>internal (내부 접근수준)</p>
<ul>
<li>기본적으로 모든 요소에 암묵적으로 지정하는 기본 접근수준 (생략 시 default)</li>
<li>외부 모듈에서는 접근 불가능</li>
<li>모듈 내부에서 광역적으로 사용할 경우 사용</li>
</ul>
<br>

<p>fileprivate (파일 외부 비공개 접근수준)</p>
<ul>
<li>그 요소가 구현된 소스파일 내부에서만 사용가능</li>
<li>소스파일 외부에서 값이 변경되거나 함수를 호출하면 부작용이 생길 수 있는 경우에 사용</li>
</ul>
<br>

<p>private (비공개 접근수준)</p>
<ul>
<li>기능을 정의하고 구현한 범위 내에서만 사용 가능</li>
</ul>
<p>‘상위 요소보다 하위 요소가 더 높은 접근 수준을 가질 수 없다’</p>
<p>ex. 상위 class가 private이면 그 안에 정의되어 있는 public class 또한 private으로 취급됨</p>
<br>
<br>

<p>[출처] 스위프트 프로그래밍 (야곰), <a href="https://www.youtube.com/watch?v=2n-fSlW-jts&amp;list=PLz8NH7YHUj_ZmlgcSETF51Z9GSSU6Uioy">야곰의 스위프트 기초문법 강좌</a>, <a href="https://www.inflearn.com/course/%EC%A0%95%EB%8C%80%EB%A6%AC-%EC%8A%A4%EC%9C%84%ED%94%84%ED%8A%B8-%EA%B8%B0%EC%B4%88/dashboard">개발하는 정대리 스위프트 강좌</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Swift] 인스턴스]]></title>
            <link>https://velog.io/@ted_kim/Swift-%EC%9D%B8%EC%8A%A4%ED%84%B4%EC%8A%A4</link>
            <guid>https://velog.io/@ted_kim/Swift-%EC%9D%B8%EC%8A%A4%ED%84%B4%EC%8A%A4</guid>
            <pubDate>Wed, 22 Mar 2023 14:32:15 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/ted_kim/post/749c56cf-bfd9-453c-8bab-7bc28ec81f22/image.png" alt=""></p>
<p>오늘은 인스턴스에 대해 정리해보려고 한다.
인스턴스란 클래스나 구조체 등에 소속된 개별적인 객체를 말한다. 
객체 지향 언어에서 객체가 메모리에 할당되어 실제로 사용될 때 인스턴스라고 말한다.
객체와 인스턴스의 차이점은 객체는 &#39;<em>선언</em>&#39;하는 것이고, 인스턴스는 객체를 &#39;<em><strong>실체화</strong></em>&#39;하는 것이라고 생각하면 될 것 같다.</p>
<br>

<h3 id="인스턴스-생성-in-swift">인스턴스 생성 (in Swift)</h3>
<p>우리가 인스턴스를 사용하기 위해서는 초기화를 진행해야 한다. 초기화는 새로운 인스턴스를 사용할 준비를 하기 위해 저장 프로퍼티의 초깃값을 설정하는 등의 일을 진행하는 것으로, 초기화를 해줘야 인스턴스를 사용할 수 있다.</p>
<p>초기화를 해주는 방법 중 하나로 이니셜라이저를 정의하여 초기화를 직접 구현할 수 있는데, 이니셜라이저를 정의하면 새로운 인스턴스를 생성할 수 있는 메소드가 된다.
이니셜라이저는 반환 값이 없고, 그저 인스턴스의 사용을 위해 초기화하는 용도이다.</p>
<br>

<p>이니셜라이저 (init)</p>
<ul>
<li>새로운 인스턴스를 생성하기 위해 호출되는 키워드</li>
</ul>
<br>

<p>초깃값(initial value)과 기본값(default value)</p>
<ul>
<li>구조체와 인스턴스는 처음 생성할 때 <strong>초깃값</strong>을 할당해야 함</li>
<li>하지만 프로퍼티의 <strong>기본값</strong>을 할당하면 초깃값을 할당하지 않더라도 기본값으로 프로퍼티의 값이 초기화된다.</li>
</ul>
<pre><code>struct Area {
    var squareMeter: Double

    init() {    //init으로 인스턴스 초기화
        squareMeter = 0.0    //프로퍼티에 초기값 할당
    }
}

let room: Area = Area()
print(room.squareMeter)    //0.0



struct Area {
    var squareMeter: Double = 0.0    //프로퍼티 기본값 할당
}

let room: Area = Area()
print(room.squareMeter)    //0.0</code></pre><br>

<p>사용자 정의 이니셜라이저 (이니셜라이저 매개변수)</p>
<ul>
<li>인스턴스를 초기화하는 과정에 필요한 값을 전달받을 수 있음</li>
<li>사용자 정의 이니셜라이저를 만들면 기본 이니셜라이저(init())을 별도로 구현하지 않는 이상 기본 이니셜라이저를 사용할 수 없음</li>
</ul>
<pre><code>//사용자 정의 이니셜라이저
struct Area {
    var squareMeter:Double

    init(fromPy py: Double) {    //첫 번째 이니셜라이저
        squareMeter = py * 3.3058
    }

    init(fromSquareMeter squareMeter: Double) {     //두 번째 이니셜라이저
        self.squareMeter = squareMeter
    }

    init(value: Double) {   //세 번째 이니셜라이저
        squareMeter = value
    }

    init(_ value: Double) { //네 번째 이니셜라이저
        squareMeter = value
    }
}


let roomOne: Area = Area(fromPy: 15.0)
print(roomOne.squareMeter    //49.857

let roomTwo: Area = Area(froomSquareMeter: 33.06)
print(roomTwo.squareMeter)    //33.06

let roomThree: Area = Area(value: 30)    //30

let roomFour: Area = Area(10)    //10

Area()  //에러 : 사용자 정의 이니셜라이저를 사용했는데, 기본 이니셜라이저를 정의하지 않았기 때문</code></pre><br>

<p>옵셔널 프로퍼티 타입</p>
<ul>
<li>인스턴스가 사용되는 동안에 값을 꼭 갖지 않아도 되는 저장 프로퍼티가 있다면 해당 프로퍼티를 옵셔널로 선언할 수 있음</li>
<li>또한 초기화 과정에서 값을 지정해주기 어려운 경우 저장 프로퍼티를 옵셔널로 선언할 수 있음</li>
<li>옵셔널 프로퍼티는 값이 할당되어 있지 않다면 nil로 할당됨</li>
</ul>
<pre><code>class Person {
    var name: String
    var age: Int?   //옵셔널로 프로퍼티 할당

    init(name: String) {
        self.name = name
    }
}

let ted: Person = Person(name: &quot;Ted&quot;)   //Ted
print(ted.age)  //nil
ted.age = 99
print(ted.age)  //Optional(99)</code></pre><br>

<p>상수 프로퍼티</p>
<ul>
<li>만약 할당된 값이 변하지 않는 상수로 만들고 싶다면 프로퍼티를 상수(let)로 선언하면 됨</li>
<li>하지만 상수로 선언된 프로퍼티는 인스턴스를 초기화하는 과정에서만 값을 할당할 수 있으며, 처음 할당된 이후로는 값을 변경할 수 없음</li>
</ul>
<pre><code>class Person {
    let name: String    //상수 프로퍼티 (let)
    var age: Int?   //옵셔널로 프로퍼티 할당

    init(name: String) {
        self.name = name
    }
}

let ted: Person = Person(name: &quot;Ted&quot;)   //Ted
ted.name = &quot;rlaxogud&quot;   //에러</code></pre><br>

<p>기본 이니셜라이저와 멤버와이즈 이니셜라이저</p>
<ul>
<li><p>저장 프로퍼티를 선언할 때 기본값을 지정해주지 않으면 이니셜라이저에서 초깃값을 설정해야함 </p>
</li>
<li><p>-&gt; 하지만 프로퍼티 때문에 매번 이니셜라이저를 추가하고 변경하는 것은 귀찮은 일임!</p>
</li>
<li><p>구조체에서는 이니셜라이저를 구현하지 않으면 프로퍼티의 이름을 매개변수로 갖는 이니셜라이저인 &#39;<em><strong>멤버와이즈 이니셜라이저</strong></em>&#39;를 제공함 (클래스는 제공하지 않음)</p>
</li>
<li><p>-&gt; <strong><em>이로 인해 구조체에서는 이니셜라이저를 굳이 선언해주지 않아도 됨!!</em></strong></p>
</li>
</ul>
<pre><code>struct Point {
    var x: Double = 0.0
    var y: Double = 0.0
}

struct Size {
    var width: Double = 0.0
    var height: Double = 0.0
}

let point: Point = Point(x: 0,y: 0)  //Point를 class로 바꾸면 이렇게 사용하지 못함 (init이 없기 때문에 -&gt; class는 멤버와이즈 이니셜라이저를 제공하지 않기 때문에)
let size: Size = Size(width: 50, height: 50)

let somePoint: Point = Point()
print(somePoint)

let someSize: Size = Size(width: 50)    //필요한 매개변수만 초기화 할 수도 있음

let anotherPoint: Point = Point(y: 40)</code></pre><br>

<h3 id="정리">정리</h3>
<p>사용자 정의 이니셜라이저 : 사용자가 이니셜라이저에 프로퍼티(변수, 상수 등)를 정의해놓은 것</p>
<p>사용자 정의 이니셜라이저를 정의해주지 않으면 모든 프로퍼티에 기본값이 지정되어 있다는 전제하에 <strong><em>기본 이니셜라이저</em></strong>를 사용함</p>
<p>기본 이니셜라이저 : 프로퍼티 기본값으로 프로퍼티를 초기화해서 인스턴스를 생성</p>
<ul>
<li>저장 프로퍼티의 기본값이 모두 지정되어 있고, 동시에 사용자 정의 이니셜라이저가 정의되어 있지 않은 상태에서 제공됨</li>
</ul>
<br>

<p>초기화 위임</p>
<ul>
<li>값 타입인 구조체와 열거형은 초기화 위임을 간단하게 구현할 수 있지만, 
클래스는 ‘상속’을 지원하기 때문에 간단한 초기화 위임도 할 수 없음</li>
<li>값 타입에서 다른 이니셜라이저를 호출하려면 self.init을 사용해야함
—&gt; self.init을 사용하는 것 자체가 사용자 정의 이니셜라이저를 정의하고 있는 것임!!</li>
<li>사용자 정의 이니셜라이저를 정의하면 기본 이니셜라이저와 멤버와이즈 이니셜라이저를 사용할 수 없음 
따라서 초기화 위임을 하려면 <strong>최소 두 개 이상의 사용자 정의 이니셜라이저를 정의해야 함!!
(기본 이니셜라이저 + 사용자 정의 이니셜라이저)</strong></li>
<li>코드를 중복으로 쓰지 않고도 효율적으로 여러 개의 이니셜라이저를 생성할 수 있음</li>
</ul>
<pre><code>enum Student {
    case elementary, middle, high
    case none

    init() {    //사용자 정의 이니셜라이저가 있어서, init()을 구현해줘야 기본 이니셜라이저를 사용할 수 있음
        self = .none
    }

    init(koreanAge: Int) {  //사용자 정의 이니셜라이저
        switch koreanAge {
        case 8...13:
            self = .elementary
        case 14...16:
            self = .middle
        case 17...19:
            self = .high
        default:
            self = .none
        }
    }

    init(bornAt: Int, currentYear: Int) {   //사용자 정의 이니셜라이저
        self.init(koreanAge: currentYear - bornAt + 1)
    }
}


var younger: Student = Student(koreanAge: 16)   //middle
younger = Student(bornAt: 1998, currentYear: 2016)  //high</code></pre><br>

<p>실패 가능한 이니셜라이저</p>
<ul>
<li>실패 가능성을 내포한 이니셜라이저</li>
<li>이니셜라이저를 잘못 전달하는 등의 상황 때 인스턴스 초기화에 실패할 수 있음</li>
<li>init? 키워드</li>
<li>실패 가능한 이니셜라이저는 특정 값을 반환하지는 않음<ul>
<li>초기화 실패 시 nil, 초기화 성공 시 초기화의 성공 or 실패 여부를 표현</li>
</ul>
</li>
<li>열거형일 때 유용함<ul>
<li>특정 case에 맞지 않는 값이 들어올 때</li>
</ul>
</li>
</ul>
<pre><code>class Person {
    let name: String
    var age: Int?

    init?(name: String) {   //실패 가능한 이니셜라이저
        if name.isEmpty {
            return nil
        }
        self.name = name
    }
}

let ted: Person? = Person(name: &quot;Ted&quot;)</code></pre><br>

<p>디이니셜라이저 (인스턴스의 소멸)</p>
<ul>
<li>메모리에서 소멸되기 바로 직전에 호출</li>
<li>deinit</li>
<li>클래스의 인스턴스에서만 구현할 수 있음</li>
<li>스위프트에서는 인스턴스가 필요없다면 자동으로 메모리에서 해제시켜줌 (ARC)
—&gt; 디이니셜라이저를 사용해 별도의 메모리 관리 작업을 할 필요는 없음</li>
<li>하지만 인스턴스 내부에서 외부 자원을 사용했다면(인스턴스 내부에서 외부 파일을 열어보는 등) 인스턴스 소멸 직전에 파일을 닫아주는 등의 작업을 해야 함</li>
</ul>
<pre><code>class FileManager {
    var fileName: String

    init(fileName: String) {
        self.fileName = fileName
    }
    func openFile() {
        print(&quot;Open File: \(self.fileName)&quot;)
    }
    func writeFile() {
        print(&quot;Write File: \(self.fileName)&quot;)
    }
    func closeFile() {
        print(&quot;Close File: \(self.fileName)&quot;)
    }
    deinit {
        print(&quot;Deinit instance&quot;)
        self.writeFile()
        self.closeFile()
    }
}

var fileManager: FileManager? = FileManager(fileName: &quot;abc.txt&quot;)
if let manager: FileManager = fileManager {
    manager.openFile()  //Open File: abc.txt
}

fileManager = nil   //Deinit instance
                    //Write File: abc.txt
                    //Close File: abc.txt</code></pre><br>
<br>

<p>[출처] 스위프트 프로그래밍 (야곰), <a href="https://www.youtube.com/watch?v=2n-fSlW-jts&amp;list=PLz8NH7YHUj_ZmlgcSETF51Z9GSSU6Uioy">야곰의 스위프트 기초문법 강좌</a>, <a href="https://www.inflearn.com/course/%EC%A0%95%EB%8C%80%EB%A6%AC-%EC%8A%A4%EC%9C%84%ED%94%84%ED%8A%B8-%EA%B8%B0%EC%B4%88/dashboard">개발하는 정대리 스위프트 강좌</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Swift] 프로퍼티와 메소드]]></title>
            <link>https://velog.io/@ted_kim/Swift-%ED%94%84%EB%A1%9C%ED%8D%BC%ED%8B%B0%EC%99%80-%EB%A9%94%EC%86%8C%EB%93%9C</link>
            <guid>https://velog.io/@ted_kim/Swift-%ED%94%84%EB%A1%9C%ED%8D%BC%ED%8B%B0%EC%99%80-%EB%A9%94%EC%86%8C%EB%93%9C</guid>
            <pubDate>Sun, 19 Mar 2023 15:12:43 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/ted_kim/post/15a3470f-2335-4ec2-8ad1-b729d7cf1d41/image.png" alt=""></p>
<p>이번 글은 프로퍼티와 메소드에 대해 작성하고자 한다. </p>
<br>

<h3 id="프로퍼티">프로퍼티</h3>
<ul>
<li>클래스, 구조체, 열거형 등에 관련된 값 (값에 대한 개념)</li>
<li>저장 프로퍼티, 연산 프로퍼티, 타입 프로퍼티</li>
<li>지역변수, 전역변수에도 사용 가능</li>
</ul>
<br>

<p><strong>저장 프로퍼티</strong></p>
<ul>
<li>값을 저장하는 프로퍼티</li>
<li>지연 저장 프로퍼티 (lazy var)<ul>
<li>해당하는 인스턴스가 메모리에 바로 올라가는 것이 아니라, 사용할 때 메모리에 올라감 !</li>
<li>다른 인스턴스를 할당해야 할 때 굳이 메모리에 올려놓을 필요가 없어 사용</li>
<li>성능 상향 및 공간 낭비 줄일 수 있음</li>
</ul>
</li>
</ul>
<br>

<p>연산 프로퍼티</p>
<ul>
<li>인스턴스 내, 외부의 값을 연산하여 적절한 값을 돌려줌</li>
<li>get만 구현 : 읽기 전용</li>
<li>newValue<ul>
<li>set에서 정의된 이름</li>
<li>set 파라미터를 가지고 올 때 사용</li>
</ul>
</li>
</ul>
<br>

<p><strong>타입 프로퍼티</strong></p>
<ul>
<li>인스턴스 생성 없이 객체 내의 프로퍼티에 접근을 가능하게 하고, 값도 변경할 수 있음</li>
<li>static 키워드로 정의</li>
</ul>
<br>

<p><strong>프로퍼티 감시자(옵저버)</strong></p>
<ul>
<li>프로퍼티의 값이 변경될 때 적절한 작업을 취할 수 있도록 해줌</li>
<li>프로퍼티의 값이 새로 할당될 때마다 호출됨</li>
<li>변경되는 값이 현재의 값과 같더라도 호출됨</li>
<li>willSet, didSet<ul>
<li>willSet<ul>
<li>프로퍼티의 값이 변경되기 직전에 호출</li>
<li>프로퍼티가 <strong>변경될 값</strong>이 전달됨</li>
</ul>
</li>
<li>didSet<ul>
<li>프로퍼티의 값이 변경된 직후에 호출</li>
<li>프로퍼티가 <strong>변경되기 전의 값</strong>이 전달됨</li>
</ul>
</li>
</ul>
</li>
<li>연산 프로퍼티와 프로퍼티 감시자는 동시에 사용 불가능
(감시자는 저장되는 값이 변경될 때 호출되기 때문)</li>
<li>지역변수, 전역변수에 모두 사용 가능</li>
</ul>
<br>

<pre><code>var westernAge: int {
    get {
            return koreanAge - 1
    }
    set(inputValue) {
            koreanAge = inputValue + 1
    }
}


//연산 프로퍼티
struct Money {
    var currencyRate: Double = 1100
    var dollar: Double = 0
    var won: Double {
        get {
                return dollar * currencyRate
        }
        set {
                dollar = newValue / currencyRate   //set 파라미터 설정을 newValue로 설정
        }
    }
}

var assets = Money(dollar: 2300, currencyRate: 2)
print(assets.won)    //4600 



var moneyInMyPocket = Money()
moneyInMyPocket.dollar = 10
print(moneyInMyPocket.won)   //11000




//타입 프로퍼티
var account = Account()
account.credit = 1000

struct SomeStructure {
    static var storedTypeProperty = &quot;Some value.&quot;    //타입 프로퍼티
    static var computedTypeProperty: Int {
        return 1
    }
}

SomeStructure.storedTypeProperty = &quot;hello&quot;    //인스턴스의 생성없이 접근하여 값을 변경



//프로퍼티 감시자

struct Money {
    var currencyRate: Double = 1100 {
        willSet(newRate) {
            print(&quot;환율이 \(currencyRate)에서 \(newRate)으로 변경될 예정입니다&quot;)
        }
        didSet(oldRate) {
            print(&quot;환율이 \(oldRate)에서 \(currencyRate)으로 변경되었습니다.&quot;)
    }
}</code></pre><br>

<p><strong>키 경로</strong></p>
<ul>
<li>프로퍼티의 위치를 참조할 수 있음</li>
<li>백슬래시()와 마침표(.) 경로로 구성됨</li>
</ul>
<pre><code>class Person {
    var name: String
    init(name: String) {
        self.name = name
    }
}

print(type(of: \Person.name))    //ReferenceWritableKeyPath&lt;Person, String&gt;    </code></pre><br>

<h3 id="메소드">메소드</h3>
<ul>
<li>특정 타입에 관련된 함수</li>
<li>인스턴스 메소드, 타입 메소드 (class method, static method)</li>
</ul>
<br>

<p><strong>인스턴스 메소드</strong></p>
<ul>
<li>특정 타입의 인스턴스에 속한 함수</li>
<li>인스턴스 내부의 프로퍼티 값을 변경하거나 특정 연산 결과를 반환하는 등 인스턴스와 관련된 기능을 실행</li>
<li><strong>함수와 문법이 거의 같음 (기본적인 함수라고 생각하면 될듯!!)</strong><ul>
<li>함수와 차이점 : 특정 타입 내부에 구현할 수 있음 —&gt; 인스턴스가 존재할 때만 사용 가능</li>
</ul>
</li>
<li><strong>인스턴스를 생성</strong>해야 해당 메소드 사용 가능!</li>
<li>self 프로퍼티는 인스턴스 자기 자신을 가리킨다</li>
</ul>
<p><strong>mutating</strong></p>
<ul>
<li>struct는 생성자를 만들어줘도 되는데, 안만들어도 알아서 만들어줌</li>
<li>대신에 struct는 값 타입이기 때문에 class처럼 값을 그냥 바꾼다고해서 멤버변수의 이름이 바뀌지 않음 ! --&gt; mutating을 통해 바꿔줌</li>
<li>struct의 멤버변수 값(인스턴스 내부의 값)을 변경하고 싶으면 mutating을 해주면 된다 !</li>
</ul>
<br>

<p><strong>타입 메소드</strong></p>
<ul>
<li>타입 자체에 호출이 가능한 메소드 (객체지향 프로그래밍에서의 클래스 메소드와 유사)</li>
<li>static, class 키워드로 정의</li>
<li>static은 오버라이드 불가능 ! (class는 오버라이드 가능)</li>
<li>self 프로퍼티가 타입 그 자체를 가리킨다</li>
</ul>
<br>

<pre><code>class Friend18 {
    var name: String

    func changeName(newName: String) {
        self.name = newName
    }
    init(_ name: String) {
        self.name = name
    }

}

var myFriend18 = Friend18(&quot;김태형&quot;)
myFriend18.changeName(newName: &quot;개발하는 테드&quot;)
myFriend18.name     //참조 타입이기 때문에 바로 접근하여 값을 바꿀 수 있음


struct BestFriend18 {
    var name: String

    mutating func changeName(newName: String) {     //struct는 mutating을 써주지 않으면 해당 멤버변수의 이름이 바뀌지 않음 !
        self.name = newName
    }
}

var myBestFriend18 = BestFriend18(name: &quot;태형&quot;)
myBestFriend18.changeName(newName: &quot;Ted&quot;)



struct SystemVolume {
    //타입 프로퍼티를 사용하면 언제나 유일한 값이 된다.
    static var volume: Int = 5

    //타입 메소드 사용
    static func mute() {
        self.volume = 0   //SystemVolume.volume = 0과 같은 표현
    }
}
</code></pre><br>
<br>

<p>[출처] 스위프트 프로그래밍 (야곰), <a href="https://www.youtube.com/watch?v=2n-fSlW-jts&amp;list=PLz8NH7YHUj_ZmlgcSETF51Z9GSSU6Uioy">야곰의 스위프트 기초문법 강좌</a>, <a href="https://www.inflearn.com/course/%EC%A0%95%EB%8C%80%EB%A6%AC-%EC%8A%A4%EC%9C%84%ED%94%84%ED%8A%B8-%EA%B8%B0%EC%B4%88/dashboard">개발하는 정대리 스위프트 강좌</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Swift] 구조체와 클래스]]></title>
            <link>https://velog.io/@ted_kim/Swift-%EA%B5%AC%EC%A1%B0%EC%B2%B4%EC%99%80-%ED%81%B4%EB%9E%98%EC%8A%A4</link>
            <guid>https://velog.io/@ted_kim/Swift-%EA%B5%AC%EC%A1%B0%EC%B2%B4%EC%99%80-%ED%81%B4%EB%9E%98%EC%8A%A4</guid>
            <pubDate>Sun, 19 Mar 2023 14:55:34 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/ted_kim/post/55b7a846-e4cb-41de-9db4-38a340791d9f/image.png" alt=""></p>
<p>이번 포스팅은 구조체와 클래스에 대해 작성하고자 한다. 
사실 우리가 변수 하나만 가지고 원하는 것을 만드지 못한다. 따라서 여러 가지 변수를 통해 모델을 만드는데, 이 모델을 class와 struct로 생성할 수 있는 것이다.</p>
<br>

<h3 id="구조체-struct">구조체 (struct)</h3>
<ul>
<li>기본 데이터 타입은 모두 구조체로 이루어져 있음</li>
<li>upper camel case (타입을 정의하는 것이기 때문)</li>
<li>생성자를 자동으로 만들어주기 때문에 꼭 생성할 필요는 없음</li>
<li><strong>값 타입</strong> : <strong>전달될 값이 복사</strong>되어 전달됨 --&gt; 선언된 인스턴스들은 다 다른 것들임 (singleton 제외)</li>
<li>값 타입이기 때문에 <strong>참조 횟수 계산이 적용되지 않음</strong></li>
<li>값 타입이기 때문에 멤버변수의 이름을 그냥 바꾼다고 해서 바뀌지 않음 </li>
<li><blockquote>
<p><strong>mutating</strong>을 통해 바꿔줌</p>
</blockquote>
</li>
<li>상속할 수 없음</li>
</ul>
<pre><code>struct Student {    //구조체 선언
    var name: String = &quot;unknown&quot;    //가변 프로퍼티
    var `class`: String = &quot;Swift&quot;   //백틱 : class라는 변수명을 쓰고 싶어서 사용,   가변 프로퍼티

    static func selfIntroduce() {   //타입 메서드
        print(&quot;학생타입입니다&quot;)
    }

    func selfIntroduce() {   //인스턴스 메서드
        print(&quot;저는 \(self.class)반 \(name)입니다&quot;)
    }
}



Student.selfIntroduce()   //학생타입입니다. (구조체 타입 자체(Student)를 가져왔기 때문에 타입메서드를 사용 가능

var yagom: Student = Student()   //인스턴스 선언 (가변 인스턴스)
yagom.name = &quot;yagom&quot;
yagom.class = &quot;스위프트&quot;
yagom.selfInroduce()   //저는 스위프트반 yagom입니다. (가변 인스턴스이기 때문에 인스턴스 메서드가 사용됨)</code></pre><br>
<br>

<h3 id="클래스-class">클래스 (class)</h3>
<ul>
<li>upper camel case (타입을 생성하는 것이기 때문)</li>
<li><strong>참조 타입</strong></li>
<li>상속 가능<ul>
<li>클래스 이름 뒤에 콜론(:)을 붙이고 부모클래스 이름을 명시</li>
</ul>
</li>
<li>init을 통해 생성자를 만들어줘야 함 (메모리에 올린다)</li>
<li>참조 횟수 계산(reference counting)이 적용됨 </li>
<li>참조가 필요없을 때 메모리에서 해제됨 (ARC 관련)<ul>
<li>deinit을 통해 인스턴스가 메모리에서 해제되기 직전에 처리할 코드를 작성할 수 있음</li>
</ul>
</li>
<li>인스턴스에서 타입캐스팅이 허용됨</li>
<li>참조 타입이기 때문에 인스턴스를 상수 let으로 선언해도 내부 프로퍼티 값을 변경할 수 있음</li>
<li><strong>식별 연산자</strong>(===, !==)를 통해 참조가 같은지 확인 가능</li>
</ul>
<pre><code>let jenny: Person = Person()    
jenny.height = 123.4    //가능
jenny.weight = 123.4    //가능  </code></pre><h3 id="구조체-vs-클래스">구조체 vs 클래스</h3>
<p><em><strong>구조체 : 값타입
클래스 : 참조타입</strong></em></p>
<p>구조체 : 전달될 값이 <strong>복사되어 전달됨</strong> (새로운 것이 계속 생성되는 느낌)
클래스 : 전달될 값이 복사되는 것이 아니라** 기존 인스턴스의 참조(주소)가 전달됨** (그렇다고 모든 인스턴스들이 같은 값을 가진다는 뜻은 아님. 그냥 주소에서 클래스만 가져오는 느낌,,?)</p>
<pre><code>class Person {
  var name: String
  var age: Int

  init(name: String, age: Int) {
    self.name = name
    self.age = age
  }
}

var A = Person(name: &quot;aa&quot;, age: 12)
var B = Person(name: &quot;bb&quot;, age: 13)

print(A.name)    //aa
print(B.name)    //bb
print(A.name)    //aa

//기존 인스턴스의 참조를 전달한다고 해서 변수에 들어가는 값이 같아진다는 뜻은 아님!</code></pre><br>
<br>

<p>[출처] 스위프트 프로그래밍 (야곰), <a href="https://www.youtube.com/watch?v=2n-fSlW-jts&amp;list=PLz8NH7YHUj_ZmlgcSETF51Z9GSSU6Uioy">야곰의 스위프트 기초문법 강좌</a>, <a href="https://www.inflearn.com/course/%EC%A0%95%EB%8C%80%EB%A6%AC-%EC%8A%A4%EC%9C%84%ED%94%84%ED%8A%B8-%EA%B8%B0%EC%B4%88/dashboard">개발하는 정대리 스위프트 강좌</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Swift] 옵셔널]]></title>
            <link>https://velog.io/@ted_kim/Swift-%EC%98%B5%EC%85%94%EB%84%90</link>
            <guid>https://velog.io/@ted_kim/Swift-%EC%98%B5%EC%85%94%EB%84%90</guid>
            <pubDate>Sun, 19 Mar 2023 07:31:19 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/ted_kim/post/fee29977-2609-4dd6-9c74-43dfa507d9ae/image.png" alt=""></p>
<p>이번 글은 옵셔널에 대해 다뤄보려고 한다. 옵셔널은 스위프트의 특징 중 하나인 안전성을 문법으로 담보하는 기능으로, C언어에서는 찾아볼 수 없는 개념이다.</p>
<h3 id="옵셔널">옵셔널</h3>
<ul>
<li>값이 있을 수도, 없을 수도 있다!</li>
<li>nil의 가능성을 명시적으로 표현해줌 <ul>
<li>문서화하지 않아 nil의 가능성을 표현해줘 시간을 절약할 수 있다</li>
</ul>
</li>
<li>optional이 아닐 때는 nil을 보낼 수 없음</li>
<li>열거형(enum)과 제네릭(generic)으로 구성되어 있음<ul>
<li>nil일 때는 case non일 때고, 값이 있을 때는 Wrapped되어 있음</li>
</ul>
</li>
</ul>
<pre><code>enum Optional&lt;Wrapped&gt; : ExpressibleByNilLiteral {  
    case none
    case some(Wrapped)
}</code></pre><br>

<h3 id="옵셔널-값-추출">옵셔널 값 추출</h3>
<ul>
<li>옵셔널을 출력해보면 &#39;Optional(값)&#39;으로 나타나기 때문에 값을 추출해줘야 함<br>

</li>
</ul>
<p>! (암시적 추출 옵셔널)</p>
<ul>
<li>추출 뒤엔 기존 변수처럼 사용할 수 있음</li>
<li>nil 할당 가능</li>
<li>하지만 nil일 때 사용한다면 런타임 오류 발생</li>
</ul>
<br>

<p>? </p>
<ul>
<li>nil 할당 가능</li>
<li>기존 변수처럼 사용불가</li>
<li>옵셔널과 일반 값은 다른 타입으로 연산불가 <em><strong>(옵셔널의 타입은 옵셔널이다!)</strong></em>
—&gt; 옵셔널을 꺼내는 방법을 배워야 함 </li>
</ul>
<br>

<h3 id="옵셔널-값-추출-1">옵셔널 값 추출</h3>
<br>

<p>옵셔널은 값을 <strong>보호해주는 상자</strong>가 있다고 생각하면 됨
값 추출을 하는 것은 상자 안에 값이 있는지 없는지 확인을 하는 것임 !!</p>
<p><img src="https://velog.velcdn.com/images/ted_kim/post/0f478216-0dbc-46eb-96ab-ffa0f5bf677d/image.png" alt="">(출처 : 야곰의 스위프트 유튜브)
<br></p>
<p>옵셔널 바인딩</p>
<ul>
<li>값이 있는지 없는지 확인하고 가져옴</li>
<li>nil 체크를 함과 동시에 안전하게 값을 추출할 수 있음</li>
<li>if-let 사용<ul>
<li>하지만 if-let에서 사용된 변수는 이 내부에서만 사용 가능</li>
<li>-&gt; _<strong>guard let</strong>_을 통해 해결 가능</li>
</ul>
</li>
<li>쉼표를 통해, 한 번에 여러 개의 optional 타입을 바인딩할 수 있음 !</li>
<li>but, 모든 조건을 성립해야 에러가 뜨지 않음<br>

</li>
</ul>
<p>강제 언래핑</p>
<ul>
<li>강제로 추출</li>
<li>nil이 있다면, 강제 추출할 값이 없으므로 런타임 오류 발생</li>
<li>전달할 때 알아서 !를 붙여주는 효과와 같음</li>
<li>그다지 추천되지는 않음<br>



</li>
</ul>
<pre><code>func printName( name: String) {
    print(name)
}

var myName: String? = nil

printName(myName)  //값의 타입이 달라 컴파일 오류 발생 : string과 optional은 다른 타입



//if-let

func printName( name: String) {
    print(name)
}

var myName: String! = nil

if let name: String = myName {    //if-let에서 지정된 상수는 if-let 구문 내에서만 사용 가능
    printName(name)
} else {
        print(&quot;myName == nil&quot;)
}

printName(name)   //이렇게 밖에서 사용 불가능



var myName: String? = &quot;yagom&quot;
var yourName: String? = nil

if let name = myName, let friend = yourName {   //두 가지 다 nil이 아니어야 실행 가능
    print(&quot;\(name) and \(friend)&quot;)
}   //yourName이 nil이기 때문에 실행 안됨



//optional 강제 추출

func printName( name: String) {    //String 타입
    print(name)
}

var myName: String? = &quot;yagom&quot;    //optional 타입
printName(myName!)  //yagom  --&gt; optional과 String은 다른 타입이라 원래는 불가능한데, !를 통해 optional을 강제 추출하여 가능해짐

myName = nil 
print(myName!)   //강제 추출 시 값이 없으므로 런타임 오류 발생


var yourName: String! = nil   //암시적 추출

printName(yourName)   //런타임 오류, 암시적 추출해서는 알아서 느낌표를 붙여주는 효과 --&gt; printName(yourName!)과 같음


//guard let
var firstValue: Int? = 30
var secondValue: Int? = 50

func unwrap(parameter: Int?) {
    print(&quot;unwrap() called&quot;)
    //값이 없으면 리턴
    guard let unWrappedParam = parameter else { return }
    print(&quot;unWrapped Param : \(unWrappedParam)&quot;)
}

unwrap(parameter: firstValue)   //firstValue값이 nil이라면 unWrappedParam : 부분은 print되지 않음 !</code></pre><br>
<br>


<p>[출처] 스위프트 프로그래밍 (야곰), <a href="https://www.youtube.com/watch?v=2n-fSlW-jts&amp;list=PLz8NH7YHUj_ZmlgcSETF51Z9GSSU6Uioy">야곰의 스위프트 기초문법 강좌</a>, <a href="https://www.inflearn.com/course/%EC%A0%95%EB%8C%80%EB%A6%AC-%EC%8A%A4%EC%9C%84%ED%94%84%ED%8A%B8-%EA%B8%B0%EC%B4%88/dashboard">개발하는 정대리 스위프트 강좌</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Swift]함수란]]></title>
            <link>https://velog.io/@ted_kim/Swift%ED%95%A8%EC%88%98%EB%9E%80</link>
            <guid>https://velog.io/@ted_kim/Swift%ED%95%A8%EC%88%98%EB%9E%80</guid>
            <pubDate>Sun, 19 Mar 2023 07:07:09 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/ted_kim/post/c0b55ef9-58c3-46c1-a8bc-55ca877b300b/image.png" alt=""></p>
<p>이번 글은 함수에 대해서 다뤄볼 예정이다. 함수는 작업의 가장 작은 단위이자 하나의 작은 프로그램으로, 기본적으로 메서드와 같다고 생각하면 된다.</p>
<br>

<pre><code>
//기본값을 갖는 매개변수는 매개변수 목록 중 뒤쪽에 위치하는 것이 좋음
func 함수이름(매개변수1이름: 매개변수1타입, 매개변수2이름: 매개변수2타입 = 매개변수 기본값 ...) -&gt; 반환타입 {
    함수 구현부
     return 반환값
}

func greeting(friend: String, me: String = &quot;yagom&quot;) {
    print(&quot;Hello \(friend)! I&#39;m \(me)&quot;)
}

//기본값을 가지는 매개변수는 생략 가능함 !
greeting(friend: &quot;hana&quot;) //Hello hana! I&#39;m yagom
greeting(friend: &quot;john&quot;, me: &quot;eric&quot;) //Hello john! I&#39;m eric</code></pre><br>

<p>전달인자 레이블</p>
<ul>
<li>함수를 호출할 때 매개변수의 역할을 좀 더 명확하게 하거나 함수 사용자의 입장에서 표현하고자 할 때 사용<ul>
<li>전달인자 레이블이 있으면, 함수의 이름이 같아도 다른 함수로 취급받을 수 있음</li>
</ul>
</li>
<li>매개변수 이름조차 쓰기 싫을 때는 _를 사용하면 된다</li>
</ul>
<pre><code>
//전달인자 레이블
func 함수이름(전달인자 레이블 매개변수1이름: 매개변수1타입, 전달인자 레이블 매개변수2이름: 매개변수2타입 ...) -&gt; 반환타입 {
    함수 구현부
    return
}


//함수 내부에서 전달인자를 사용할 때에는 매개변수 이름을 사용
func greeting(to friend: String. from me: String) {
    print(&quot;Hello \(friend)! I&#39;m \(me)&quot;)
}

//함수 호출 시 전달인자 레이블을 사용
greeting(to: &quot;hana&quot;, from: &quot;yagom&quot;) //Hello hana! I&#39;m yagom

//중요! greeting이라는 함수를 위에서도 선언하였지만, 전달인자 레이블을 통해 함수의 이름 자체가 바뀐 효과를 얻을 수 있음!
//스위프트에서는 greeting &amp;&amp;to &amp;&amp;from까지 함수의 이름으로 취급되어 위의 함수와 다른 함수로 취급됨


//매개변수 이름조차 쓰기 싫을 때는 _를 사용하면 된다
func myFunctionThird(_ name: String) -&gt; String {
    return &quot;안녕하세요? \(name)입니다!&quot;
}

myFunctionThird(&quot;Ted&quot;)  //매개변수 이름 선언 없이도 잘 동작한다.</code></pre><br>

<p>가변 매개변수</p>
<ul>
<li>매개변수가 몇 개가 들어올지 모를 때 사용</li>
<li>0개 이상의 값을 받아올 수 있음</li>
<li>인자 값은 배열처럼 사용할 수 있음</li>
<li>함수마다 하나의 가변 매개변수를 가질 수 있음</li>
<li>...은 띄어쓰면 안됨</li>
</ul>
<pre><code>//가변 매개변수

func 함수이름(매개변수1이름: 매개변수1타입, 전달인자 레이블 매개변수2이름: 매개변수2타입...) -&gt; 반환타입 {
    함수 구현부
    return
}


func sayHelloToFriends(me: String, friends: String...) -&gt; String {   //friends의 값이 몇 개인지 모를 때 사용
    return &quot;Hello \(friends)! I&#39;m \(me)!&quot;
}
print(sayHelloToFriends(me: &quot;yagom&quot;, friends: &quot;hana&quot;, &quot;eric&quot;, &quot;wing&quot;))  //Hello [&quot;hana&quot;, &quot;eric&quot;, &quot;wing&quot;]! I&#39;m yagom!
print(sayHelloToFriends(me: &quot;yagom&quot;)   //Hello []! I&#39;m yagom!</code></pre><br>

<p>함수의 타입표현</p>
<pre><code>//함수 내부에서 전달인자를 사용할 때에는 매개변수 이름을 사용
func greeting(to friend: String. from me: String) {
    print(&quot;Hello \(friend)! I&#39;m \(me)&quot;)
}


//함수 호출 시 전달인자 레이블을 사용
greeting(to: &quot;hana&quot;, from: &quot;yagom&quot;) //Hello hana! I&#39;m yagom

(매개변수1타입, 매개변수2타입 ...) -&gt; 반환타입

var someFunction: (String, String) -&gt; Void = greeting(to:from:)    //반환값이 없는 String 타입의 매개변수 2개가 greeting이라는 함수에 들어가서 새로운 함수 someFunction을 만듦
someFunction(&quot;eric&quot;, &quot;yagom&quot;)   //Hello eric! I&#39;m yagom!

someFunction = greeting(friend:me:)    //위에 있는 greeting과는 다른 함수!!
someFunction(&quot;eric&quot;, &quot;yagom&quot;)   //Hello eric! I&#39;m yagom



//함수 타입을 매개변수 타입으로 지정을 해주고 실행 가능 !
func runAnother(function: (String, String) -&gt; Void) {
    function(&quot;jenny&quot;, &quot;mike&quot;)
}   //String type 2개를 매개변수로 가지는 함수가 function의 매개변수 타입

runAnother(function: greeting(friend:me:))   //Hello jenny! I&#39;m mike
runAnother(function: someFunction)   //Hello jenny! I&#39;m mike</code></pre><br>
<br>

<p>[출처] 스위프트 프로그래밍 (야곰), <a href="https://www.youtube.com/watch?v=2n-fSlW-jts&amp;list=PLz8NH7YHUj_ZmlgcSETF51Z9GSSU6Uioy">야곰의 스위프트 기초문법 강좌</a>, <a href="https://www.inflearn.com/course/%EC%A0%95%EB%8C%80%EB%A6%AC-%EC%8A%A4%EC%9C%84%ED%94%84%ED%8A%B8-%EA%B8%B0%EC%B4%88/dashboard">개발하는 정대리 스위프트 강좌</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Swift] 연산자]]></title>
            <link>https://velog.io/@ted_kim/Swift-%EC%97%B0%EC%82%B0%EC%9E%90</link>
            <guid>https://velog.io/@ted_kim/Swift-%EC%97%B0%EC%82%B0%EC%9E%90</guid>
            <pubDate>Sun, 19 Mar 2023 03:16:01 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/ted_kim/post/2819b785-126b-4829-b30d-9c2e47de11ff/image.png" alt=""></p>
<p>연산자는 이름 그래도 무엇인가를 연산할 때 사용하는 기호이다.
음 사실 연산자의 종류는 매우 많기 때문에 매우 간단하게 정리해보려고 한다.</p>
<br>
<br>

<h2 id="기본-및-주요-연산자">기본 및 주요 연산자</h2>
<p>할당 연산자</p>
<ul>
<li>값을 할당할 때 사용</li>
<li>서로 다른 데이터 타입이라면 에러 발생</li>
</ul>
<pre><code>A = B    //A에 B값을 할당</code></pre><br>

<p>산술 연산자</p>
<ul>
<li>수학에서 사용되는 연산자 (+, -, *, /, %)</li>
<li>다른 자료형끼리의 연산을 엄격히 제한하므로, 같은 타입으로 변경시켜주어야 함
(ex. Int와 UInt 타입도 같은 타입으로 변경 후 계산해야 함)<br>

</li>
</ul>
<p>비교 연산자</p>
<ul>
<li>두 값을 비교할 때 사용</li>
<li>참조가 같다. A === B<ul>
<li>A와 B가 같은 인스턴스를 가리키는지 비교하여 불리언 값을 반환<br>

</li>
</ul>
</li>
</ul>
<p>삼항 조건 연산자</p>
<ul>
<li>피연산자가 3개인 연산자</li>
</ul>
<pre><code>Question ? A : B    //Question이 true이면 A, false이면 B를 실행</code></pre><br>

<p>범위 연산자</p>
<ul>
<li>값(수)의 범위를 나타내고자 할 때 사용</li>
<li>점이 3개이면 포함, 점이 2개이면 미포함 (오른쪽 값)</li>
<li>A…B : A와 B 포함</li>
<li>A.. &lt; B : A포함, B 미포함</li>
<li>A… , …A : A포함</li>
<li>.. &lt; A : A 미포함</li>
</ul>
<br>

<p>부울 연산자</p>
<ul>
<li>불리언 값의 논리 연산</li>
<li>NOT = !B</li>
<li>AND = A &amp;&amp; B</li>
<li>OR = A || B</li>
</ul>
<br>

<p>비트 연산자</p>
<ul>
<li>비트 논리 연산</li>
<li>NOT = ~A</li>
<li>AND = A &amp; B</li>
<li>OR = A | B</li>
<li>XOR = A ^ B</li>
<li>비트 이동 (시프트) = A &gt;&gt; B or A &gt;&gt; B</li>
</ul>
<br>

<p>복잡 할당 연산자 (compound assignment operator)</p>
<ul>
<li>A += 1과 같이 연산자가 하는 일을 한 번에 처리할 수 있도록 결합</li>
</ul>
<br>

<p>오버플로 연산자</p>
<ul>
<li>오버플로에 대해 연산 가능</li>
<li>&amp;+, &amp;-, &amp;*</li>
</ul>
<br>
<br>

<p>[출처] 스위프트 프로그래밍 (야곰), <a href="https://www.youtube.com/watch?v=2n-fSlW-jts&amp;list=PLz8NH7YHUj_ZmlgcSETF51Z9GSSU6Uioy">야곰의 스위프트 기초문법 강좌</a>, <a href="https://www.inflearn.com/course/%EC%A0%95%EB%8C%80%EB%A6%AC-%EC%8A%A4%EC%9C%84%ED%94%84%ED%8A%B8-%EA%B8%B0%EC%B4%88/dashboard">개발하는 정대리 스위프트 강좌</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Swift] 데이터 타입 - 2]]></title>
            <link>https://velog.io/@ted_kim/Swift-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%83%80%EC%9E%85-2</link>
            <guid>https://velog.io/@ted_kim/Swift-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%83%80%EC%9E%85-2</guid>
            <pubDate>Sun, 19 Mar 2023 03:00:35 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/ted_kim/post/28ae0dfb-b477-4c1b-9e24-d10d0805510c/image.png" alt=""></p>
<br>
<br>

<h3 id="데이터-타입-안심">데이터 타입 안심</h3>
<ul>
<li><p>스위프트는 다른 타입끼리의 데이터 교환은 꼭! <strong><em>타입캐스팅</em></strong>을 거쳐야 한다! </p>
</li>
<li><p>-&gt; 데이터 타입 간의 자료 교환이 까다로움</p>
</li>
<li><p>하지만 까다롭기 때문에 데이터 타입을 <strong>안심</strong>하고 사용할 수 있음</p>
</li>
</ul>
<br>

<p>타입 추론</p>
<ul>
<li>특정 타입을 명시하지 않아도 (값의 타입이 명확하다면) 컴파일러가 타입을 결정해줄 수 있음</li>
<li>하지만 타입이 지정된 후에는 다른 타입을 할당할 수 없음</li>
</ul>
<pre><code>var name = &quot;Ted&quot;    //타입을 지정하지 않았으나, 타입 추론으로 인해 String 타입으로 선언
name = 100    //String 타입으로 지정되었기 때문에 오류 발생</code></pre><br>

<p><strong>타입 별칭 (typealias)</strong></p>
<ul>
<li>이미 존재하는 데이터 타입에 임의로 다른 이름(별칭)을 부여할 수 있음</li>
<li>&amp;를 통해 여러 가지를 묶을 수도 있음</li>
<li>모든 타입을 typealias로 지정할 수 있음 (클로저, 클래스 안에 있는 enum 등)</li>
</ul>
<pre><code>protocol Naming {
    func getName() -&gt; String
}

protocol Aging {
    func getAge() -&gt; Int
}

typealias Friendable = Naming &amp; Aging   // Naming과 Aging을 합친 것을 Friendable로 부르겠다

typealias FummNaming = Naming   //하나만 설정해줘도 됨

struct Friend25: Friendable {    //Friend25: Naming &amp; Aging 으로 쓴 것과 같은 것임

    var name: String
    var age: Int

    func getName() -&gt; String {
        return self.name
    }

    func getAge() -&gt; Int {
        return self.age
    }

}


typealias StringBlock = (String) -&gt; Void

func sayHi(completion: StringBlock) {   //completion: (String) -&gt; Void 와 같은 것
    print(&quot;안녕하세요?&quot;)
    completion(&quot;테드입니다&quot;)
}

sayHi(completion: { saying in
    print(&quot;여기서 받음 : &quot;, saying)
})
</code></pre><br>
<br>

<h1 id="컬렉션-타입">컬렉션 타입</h1>
<h3 id="배열-딕셔너리-세트">배열, 딕셔너리, 세트</h3>
<br>
<br>

<p><strong>배열 (Array)</strong></p>
<ul>
<li>순서가 있는 컬렉션 타입</li>
</ul>
<br>

<p><strong>딕셔너리 (Dictionary)</strong></p>
<ul>
<li>순서 없이 키(key)와 값(value)의 쌍으로 이루어진 컬렉션</li>
<li>키는 중복해서 사용할 수 없음</li>
<li>내부에 없는 키로 접근한다면 에러가 아니라 nil이 반환됨</li>
</ul>
<br>

<p><strong>세트 (Set)</strong></p>
<ul>
<li>순서가 없고, 멤버가 유일한 컬렉션 (수학에서의 집합)</li>
<li>교집합, 합집합, 차집합 등 표현 가능</li>
</ul>
<br>

<pre><code>//빈 Int Array 생성
var integers: Array&lt;Int&gt; = Array&lt;Int&gt;()   //[]로 생성해도 됨
integers.append(1)   //[1]
integers.append(100)   //[1, 100]

integers.append(101.1)   //에러

integers.contains(100)   //true
integers.contains(99)   //false

integers.remove(at: 0)  //Array 안에 특정 인덱스 안의 부분을 삭제
integers.removeLast()  //Array 안에 마지막 인덱스 삭제
integers.removeAll()    //Array 안에 모든 인덱스 삭제

integers.count   //인덱스 안의 값 개수


//Array&lt;Double&gt;과 [Double]은 같은 표현 !
//빈 Double Array 생성
var doubles: Array&lt;Double&gt; = [Double]()

//빈 String Array 생성
var strings: [String] = [String]()

//빈 character Array 생성
var characters: [Character] = [] //이렇게도 가능함


//let을 선언하여 Array를 선언하면 불변 Array 
let immutableArray = [1, 2, 3]


//let array는 remove, append 등 사용 불가



var anyDictionary: Dictionary&lt;String, Any&gt; = [String: Any]()
anyDictionary[&quot;someKey&quot;] = &quot;value&quot;
anyDictionary[&quot;anotherkey&quot;] = 100 

anyDictionary.removeValue(forKey, &quot;anotherKey&quot;)  //anotherKey라는 키값과 value값 없앰
anyDictionary[&quot;someKey&quot;] = nil   //someKey 키값 삭제

let emptyDictionary: [String: String] = [:]
let initialzedDictionary: [String: String] = [&quot;name&quot; : &quot;yagom&quot;, &quot;gender&quot; : &quot;male&quot;]   //let을 선언했기 때문에, 값의 변경은 불가능함


let someValue: String = initializedDictionary[&quot;name&quot;]  //에러 발생. 딕셔너리의 key에 해당하는 값이 없을 수도 있는 불확실성 때문에 없음




//빈 Int Set 생성
var integerSet: Set&lt;Int&gt; = Set&lt;Int&gt;()
integerSet.insert(1)  //(inserted true, memberAfterInsert 1)
intergerSet.insert(100)   //(inserted true, memberAfterInsert 100)

intergerSet.insert(99)    //(inserted true, memberAfterInsert 99)
intergerSet.insert(99)    //(inserted false, memberAfterInsert 100)
intergerSet.insert(99)    //(inserted false, memberAfterInsert 100)



let setA: Set&lt;Int&gt; = [1, 2, 3, 4, 5]   //{5, 2, 3, 1, 4)
let setB: Set&lt;Int&gt; = [3, 4, 5, 6, 7]

let union: Set&lt;Int&gt; = setA.union(setB)   //합집합   {2, 4, 5, 6, 7, 3, 1}

let sortUnion: [Int] = union.sorted()
let intersction: Set&lt;Int&gt; = setA.intersection(setB)    //교집합   {5, 3, 4}
let subtracting: Set&lt;Int&gt; = setA.subtracking(setB)   //차집합    {2,1} </code></pre><br>

<h1 id="기타">기타</h1>
<p><strong>튜플</strong></p>
<ul>
<li>지정된 데이터의 묶음</li>
<li>타입의 이름이 따로 지정되어 있지는 않음</li>
<li>파이썬의 튜플과 비슷</li>
</ul>
<pre><code>var person: (String, Int, Double) = (&quot;Ted&quot;, 26, 177)
//person.1 등으로 값을 빼 올 수 있음

인덱스만으로는 데이터의 의미 유추가 힘들기 때문에 이름을 붙여줄 수 있음

var person: (name: String, age: Int, height: Double) = (&quot;Ted&quot;, 26, 177)
//person.name 등으로 값을 빼올 수 있음

튜플을 선언할 때마다 계속 써주면 불편함 --&gt; 타입 별칭을 사용하여 깔끔하게 작성 가능

typealias PersonTuple = (name: String, age: Int, height: Double)
let ted: PeronsTuple = (&quot;Ted&quot;, 26, 177)
//계속 (name: String, age: Int, height: Double)를 선언할 필요가 없어짐</code></pre><br>

<p><strong>열거형 (enum)</strong></p>
<ul>
<li>각각의 케이스가 고유의 값으로 취급됨</li>
<li>메서드도 추가 가능</li>
<li>다른 열거형의 시각으로 보지 말기</li>
<li>rawValue(원시값)를 통해 case에 대한 값을 가질 수 있음</li>
<li>열거형의 Int값은 값을 지정하지 않으면 자동으로 1씩 증가함</li>
<li>rawValue를 통해 초기화 한 인스턴스는 옵셔널 타입임</li>
<li>열거형에 메서드도 추가 가능</li>
</ul>
<pre><code>//열거형

enum Weekday {
    case mon
    case tue
    case wed
    case thu, fri, sat, sun   //그냥 한번에 ,로 묶어도 상관없음
}

var day = Weekday.mon
day = .tue

switch day {
    case .mon, .tue, .wed, .thu:
        print(&quot;평일입니다&quot;)
    case Weekday.fri:
        print(&quot;금요일&quot;)
    case .sat, .sun:
        print(&quot;신나는 주말!&quot;)
}


//정수값을 가질 수 있음
//만약 정수값을 정의하고 뒤에 정의하지 않는다면, +1 증가하여 저장됨

enum Fruit: Int {
    case apple = 0
    case grape = 3
    case peach    //4 (grape가 3인데, peach는 정의가 되어있지 않아 자동으로 1이 증가)
    case orange
}




enum School: String {
    case elementary = &quot;초등&quot;
    case middle = &quot;중등&quot;
    case high = &quot;고등&quot;
    case university
}

print(\(School.university.rawValue))  //university : case의 이름을 그대로 가져옴

let apple: Fruit? = Fruit(rawValue: 0)   //옵셔널이 아니면 에러

if let orange: Fruit = Fruit(rawValue: 5) {
    print(&quot;rawValue 5에 해당하는 케이스는 \(orange)입니다&quot;)
} else {
        print(&quot;rawValue 5에 해당하는 케이스가 없습니다&quot;)
}




//메서드 추가 가능

enum Month {
    case dec, jan, feb
    case mar, apr, may
    case jun, jul, aug
    case sep, oct, nov

    func printMessage() {    //메서드
        switch self {    //enum Month안에 func가 있기 때문에 self == Month가 된다
            case .mar, .apr, .may:
                print(&quot;봄&quot;)
            case .jun, .jul, .aug:
                print(&quot;여름&quot;)
            case .sep, .oct, .nov:
                print(&quot;가을&quot;)
            case .dec, .jan, .feb:
                print(&quot;겨울&quot;)
            }
    }
}

Month.mar.printMessage()</code></pre><br>

<p>연관값</p>
<ul>
<li>열거형 내의 항목(case)이 자신과 연관된 값을 가질 수 있음</li>
<li>모든 항목(case)이 연관 값을 가질 필요는 없음</li>
</ul>
<pre><code>enum MainDish {
    case pasta(taste: String)
    case pizza(dough: String, topping: String)
    case rice
}

var dinner: MainDish = MainDish.pasta(taste: &quot;크림&quot;)    //크림 파스타
dinner = .pizza(dough: &quot;치즈 크러스트&quot;, topping: &quot;불고기&quot;)    //불고기 치즈 크러스트 피자</code></pre><br>

<p>[출처] 스위프트 프로그래밍 (야곰), <a href="https://www.youtube.com/watch?v=2n-fSlW-jts&amp;list=PLz8NH7YHUj_ZmlgcSETF51Z9GSSU6Uioy">야곰의 스위프트 기초문법 강좌</a>, <a href="https://www.inflearn.com/course/%EC%A0%95%EB%8C%80%EB%A6%AC-%EC%8A%A4%EC%9C%84%ED%94%84%ED%8A%B8-%EA%B8%B0%EC%B4%88/dashboard">개발하는 정대리 스위프트 강좌</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Swift] 데이터 타입 기본]]></title>
            <link>https://velog.io/@ted_kim/Swift-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%83%80%EC%9E%85-%EA%B8%B0%EB%B3%B8</link>
            <guid>https://velog.io/@ted_kim/Swift-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%83%80%EC%9E%85-%EA%B8%B0%EB%B3%B8</guid>
            <pubDate>Sat, 18 Mar 2023 15:26:33 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/ted_kim/post/f9e14f54-7d89-4533-a311-cebd6a15a8a7/image.png" alt=""></p>
<p>이번 글에서는 기본적인 데이터 타입에 대해 작성해보고자 한다.</p>
<br>
<br>

<h1 id="데이터-타입">데이터 타입</h1>
<p>우선 스위프트의 모든 데이터 타입 이름은 첫 글자가 대문자로 시작하는 <strong>&#39;대문자 카멜케이스&#39;</strong>를 사용한다.</p>
<br>

<p>콘솔 로그</p>
<ul>
<li>print() / dump()</li>
<li>dump()는 print()보다 조금 더 자세한 정보들을 출력해줌
  (ex. 구조체에 대해 자세히)</li>
</ul>
<br>

<p>기본 데이터 타입</p>
<ul>
<li>Bool, Int, UInt, Float, Double, Character, String</li>
</ul>
<br>

<p><strong>Int와 UInt</strong></p>
<ul>
<li>정수 타입</li>
<li>UInt : 음수를 포함하지 않는 정수</li>
<li>Int와 UInt는 엄연히 다른 것임! (타입 에러)</li>
<li>2진수 : 0b  /  8진수  :  0o  /  16진수  :  0x</li>
</ul>
<pre><code>let binaryInteger: Int = 0b11100    //10진수 28과 동일</code></pre><p><strong>Bool</strong></p>
<ul>
<li>참 (true) / 거짓 (false)</li>
<li>다른 언어처럼 참을 1, 거짓을 0으로 지정할 수 없다 !<br>

</li>
</ul>
<p><strong>Float와 Double</strong></p>
<ul>
<li>Double : 최소 15자리의 십진수 표현 가능</li>
<li>Float : 6자리의 숫자까지 표현 가능</li>
<li>만약 둘 중 애매하다면, Double을 쓰는 것 권장 
(더 큰 범위를 포함하고 있기 때문에 더욱 정확할 수 있음)</li>
</ul>
<p>임의의 수 만들기</p>
<ul>
<li>random(in:) : 정수, 실수 모두 임의의 수를 만들 수 있음</li>
</ul>
<pre><code>Int.random(in: -100 ...100)
Double.random(in: 1.5 ...4.3)</code></pre><br>

<p><strong>Character</strong></p>
<ul>
<li>문자 (문자열 X)</li>
<li>스위프트는 유니코드 9 문자를 사용
→ 유니코드에서 지원하는 모든 언어 및 특수기호 등을 사용할 수 있음</li>
</ul>
<pre><code>let commandCharacter: Character = &quot;♡&quot;    //가능 (유니코드 하트)</code></pre><br>

<p><strong>String</strong></p>
<ul>
<li>문자열</li>
<li>여러 줄의 문자열을 쓰고 싶다면 큰따옴표 3개를 사용하면 됨</li>
</ul>
<br>

<p><strong>특수문자(제어문자)</strong></p>
<ul>
<li>백슬래시에 특정한 문자를 조합하여 사용</li>
</ul>
<table>
<thead>
<tr>
<th align="left">특수문자</th>
<th align="left">설명</th>
</tr>
</thead>
<tbody><tr>
<td align="left">\n</td>
<td align="left">줄바꿈 문자</td>
</tr>
<tr>
<td align="left">\\</td>
<td align="left">문자열 내에서 백슬래시를 표현할 때 사용</td>
</tr>
<tr>
<td align="left">&quot;</td>
<td align="left">문자열 내에서 큰따옴표를 표현할 때 사용</td>
</tr>
<tr>
<td align="left">\t</td>
<td align="left">탭 문자</td>
</tr>
<tr>
<td align="left">\0</td>
<td align="left">문자열이 끝났음을 알려주느ㄴ null 문자</td>
</tr>
</tbody></table>
<br>

<p><strong>Any, AnyObject와 nil</strong></p>
<p><strong>Any</strong></p>
<ul>
<li>스위프트의 모든 데이터 타입을 사용할 수 있다는 뜻</li>
<li><em><strong>할당되는 타입으로 변환되는 것이 아니라, 명시적으로 타입을 변환해주어야 함!</strong></em>
(Any 타입에 String을 넣었다고 String 타입으로 변환되는 것이 아님!)</li>
</ul>
<br>

<p><strong>AnyObject</strong></p>
<ul>
<li>클래스의 인스턴스만 할당할 수 있음</li>
<li>다른 것이 들어오면 에러발생</li>
</ul>
<br>
되도록이면 Any와 AnyObject는 사용하지 않는 것을 권장

<p>--&gt; <strong>타입에 민감</strong>한 스위프트 언어에서 예기치 못한 에러 발생 가능
<br></p>
<p><strong>nil</strong></p>
<ul>
<li>특정 타입이 아니라, ‘없음’을 나타내는 키워드 —&gt; 값이 비어있음</li>
<li>nil일때 접근하면 런타임 오류 발생</li>
<li>Any 타입과 AnyObject 타입에 nil을 할당할 수 없음</li>
</ul>
<br>

<p>[출처] 스위프트 프로그래밍 (야곰), <a href="https://www.youtube.com/watch?v=2n-fSlW-jts&amp;list=PLz8NH7YHUj_ZmlgcSETF51Z9GSSU6Uioy">야곰의 스위프트 기초문법 강좌</a>, <a href="https://www.inflearn.com/course/%EC%A0%95%EB%8C%80%EB%A6%AC-%EC%8A%A4%EC%9C%84%ED%94%84%ED%8A%B8-%EA%B8%B0%EC%B4%88/dashboard">개발하는 정대리 스위프트 강좌</a></p>
]]></description>
        </item>
    </channel>
</rss>