<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>짱구는 코딩중</title>
        <link>https://velog.io/</link>
        <description>응애 나 코린이(비트코인X 코딩O)</description>
        <lastBuildDate>Fri, 24 Feb 2023 11:23:06 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>짱구는 코딩중</title>
            <url>https://velog.velcdn.com/images/shin_ms/profile/a25eb6d7-a37c-48e1-9a64-e8f186b916e7/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. 짱구는 코딩중. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/shin_ms" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[좋은 단어 (백준 3986번)]]></title>
            <link>https://velog.io/@shin_ms/%EC%A2%8B%EC%9D%80-%EB%8B%A8%EC%96%B4-%EB%B0%B1%EC%A4%80-3986%EB%B2%88</link>
            <guid>https://velog.io/@shin_ms/%EC%A2%8B%EC%9D%80-%EB%8B%A8%EC%96%B4-%EB%B0%B1%EC%A4%80-3986%EB%B2%88</guid>
            <pubDate>Fri, 24 Feb 2023 11:23:06 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<blockquote>
<p>이번 계절학기에 심리학 개론을 수강 중인 평석이는 오늘 자정까지 보고서를 제출해야 한다. 보고서 작성이 너무 지루했던 평석이는 노트북에 엎드려서 꾸벅꾸벅 졸다가 제출 마감 1시간 전에 깨고 말았다. 안타깝게도 자는 동안 키보드가 잘못 눌려서 보고서의 모든 글자가 A와 B로 바뀌어 버렸다! 그래서 평석이는 보고서 작성을 때려치우고 보고서에서 &#39;좋은 단어&#39;나 세보기로 마음 먹었다.</p>
</blockquote>
<p>평석이는 단어 위로 아치형 곡선을 그어 같은 글자끼리(A는 A끼리, B는 B끼리) 쌍을 짓기로 하였다. 만약 선끼리 교차하지 않으면서 각 글자를 정확히 한 개의 다른 위치에 있는 같은 글자와 짝 지을수 있다면, 그 단어는 &#39;좋은 단어&#39;이다. 평석이가 &#39;좋은 단어&#39; 개수를 세는 것을 도와주자.</p>
<h2 id="입력">입력</h2>
<blockquote>
<p>첫째 줄에 단어의 수 N이 주어진다. (1 ≤ N ≤ 100)</p>
</blockquote>
<p>다음 N개 줄에는 A와 B로만 이루어진 단어가 한 줄에 하나씩 주어진다. 단어의 길이는 2와 100,000사이이며, 모든 단어 길이의 합은 1,000,000을 넘지 않는다.</p>
<h2 id="출력">출력</h2>
<blockquote>
<p>첫째 줄에 좋은 단어의 수를 출력한다.</p>
</blockquote>
<hr>
<h2 id="문제-풀이-코드🧑🏻💻">문제 풀이 코드🧑🏻‍💻</h2>
<p>해당 문제를 처음 봤을 때 <strong>&quot;단어 위로 아치형 곡선을 그어 같은 글자끼리(A는 A끼리, B는 B끼리) 쌍을 짓기로 하였다. 만약 선끼리 교차하지 않으면서 각 글자를 정확히 한 개의 다른 위치에 있는 같은 글자와 짝지을 수 있다면, 그 단어는 &#39;좋은 단어&#39;이다.&quot;</strong>라는 문구를 읽고 어떻게 문제에 접근해야 할지 몰라 고민했지만, 글자를 수직으로 세워(90°) 생각했을 때 해당 문제의 해결 방법을 찾을 수 있었습니다.</p>
<p>서로 마주 보고 있는 글자가 같다면 해당 글자쌍을 없앴으며, 글자를 담고 있는 배열의 크기가 0이면 해당 단어는 좋은 단어이기 때문에 count를 1씩 증가시키는 방식으로 문제를 풀어보았습니다. (테트리스 게임과 비슷한 느낌)
<img src="https://velog.velcdn.com/images/shin_ms/post/1a86c36c-a69e-4705-b5eb-1049b98bc75f/image.png" alt=""></p>
<pre><code class="language-swift">let n = Int(readLine()!)!
var count = 0
var stack = [String]()

for _ in 1...n{
    let str = readLine()!.map{String($0)}
    for j in 0..&lt;str.count{
        stack.append(str[j])
        if stack.count &gt; 1 &amp;&amp; stack[stack.endIndex-1] == stack[stack.endIndex-2]{
            stack.removeLast(2)
        }
    }
    if stack.count == 0{
        count += 1
    }
    stack = []
}

print(count)</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[패션왕 신해빈 (백준 9375번)]]></title>
            <link>https://velog.io/@shin_ms/%ED%8C%A8%EC%85%98%EC%99%95-%EC%8B%A0%ED%95%B4%EB%B9%88-%EB%B0%B1%EC%A4%80-9375%EB%B2%88</link>
            <guid>https://velog.io/@shin_ms/%ED%8C%A8%EC%85%98%EC%99%95-%EC%8B%A0%ED%95%B4%EB%B9%88-%EB%B0%B1%EC%A4%80-9375%EB%B2%88</guid>
            <pubDate>Sun, 19 Feb 2023 14:00:18 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<blockquote>
<p>해빈이는 패션에 매우 민감해서 <strong>한번 입었던 옷들의 조합을 절대 다시 입지 않는다.</strong> 예를 들어 오늘 해빈이가 안경, 코트, 상의, 신발을 입었다면, 다음날은 바지를 추가로 입거나 안경대신 렌즈를 착용하거나 해야한다. 해빈이가 가진 의상들이 주어졌을때 과연 해빈이는 <strong>알몸이 아닌 상태</strong>로 며칠동안 밖에 돌아다닐 수 있을까?</p>
</blockquote>
<h2 id="입력">입력</h2>
<blockquote>
<p>첫째 줄에 테스트 케이스가 주어진다. 테스트 케이스는 최대 100이다.</p>
</blockquote>
<p>각 테스트 케이스의 첫째 줄에는 해빈이가 가진 의상의 수 n(0 ≤ n ≤ 30)이 주어진다.
다음 n개에는 해빈이가 가진 의상의 이름과 의상의 종류가 공백으로 구분되어 주어진다. <strong>같은 종류의 의상은 하나만 입을 수 있다.</strong>
모든 문자열은 1이상 20이하의 알파벳 소문자로 이루어져있으며 <strong>같은 이름을 가진 의상은 존재하지 않는다.</strong></p>
<h2 id="출력">출력</h2>
<blockquote>
<p>각 테스트 케이스에 대해 해빈이가 <strong>알몸이 아닌 상태로 의상을 입을 수 있는 경우를 출력</strong>하시오.</p>
</blockquote>
<hr>
<h2 id="문제-풀이-코드🧑🏻💻">문제 풀이 코드🧑🏻‍💻</h2>
<p>해당 문제는 알몸(의상을 0개 입은 상태)이 아닌 상태의 경우의 수를 구하는 문제입니다.</p>
<p>같은 종류의 의상은 하나만 입을 수 있다는 조건하에 조합할 수 있는 모든 경우의 조합 수에서 알몸의 경우만 빼면 원하는 결과를 얻을 수 있습니다.
<img src="https://velog.velcdn.com/images/shin_ms/post/fd6e7a9e-3e70-4e2b-b16f-a5b540371d94/image.png" alt=""></p>
<p>또한 같은 이름을 가진 의상은 존재하지 않지만(key), 같은 종류의 의상은 중복을 허용(value)한다는 특징을 활용하여 코드 설계 시 배열(Array)이 아닌 <strong>딕셔너리(Dictionary)를 활용</strong>하였습니다.</p>
<blockquote>
<pre><code class="language-swift">let testCase = Int(readLine()!)!
var wearDic = [String:Int]()
var resultArray = [Int]()
for _ in 0..&lt;testCase{
    let n = Int(readLine()!)!
    for _ in 0..&lt;n{
        let wearKey = readLine()!.split(separator: &quot; &quot;).map{String($0)}[1]
        //Swift에는 증감 연산자(++)가 없기 때문에 if문 활용
        if wearDic[wearKey] != nil{  //딕셔너리에 값이 있으면 해당 값에 1추가
            wearDic[wearKey]! += 1
        }
        else{  //딕셔너리에 값이 없으면 2추가 (1이 아닌 2를 추가한 이유는 의상을 착용하지 않는 경우 때문)
            wearDic[wearKey] = 2
        }
    }
    if wearDic.values.count == 1{  //의상의 종류가 1개인 경우
        resultArray.append(wearDic.values.map{$0 - 1}[0])  //알몸의 경우 -1
    }
    else{  //의상의 종류가 1개 초과인 경우
        resultArray.append(wearDic.values.reduce(1){$0 * $1} - 1)  //알몸의 경우 -1
    }
    wearDic = [String:Int]()  //다음 testCase를 위해 빈 딕셔너리로 초기화
}
</code></pre>
</blockquote>
<p>for i in resultArray{
    print(i)
}
```</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[나는야 포켓몬 마스터 이다솜 (백준 1620번)]]></title>
            <link>https://velog.io/@shin_ms/%EB%82%98%EB%8A%94%EC%95%BC-%ED%8F%AC%EC%BC%93%EB%AA%AC-%EB%A7%88%EC%8A%A4%ED%84%B0-%EC%9D%B4%EB%8B%A4%EC%86%9C-%EB%B0%B1%EC%A4%80-1620%EB%B2%88</link>
            <guid>https://velog.io/@shin_ms/%EB%82%98%EB%8A%94%EC%95%BC-%ED%8F%AC%EC%BC%93%EB%AA%AC-%EB%A7%88%EC%8A%A4%ED%84%B0-%EC%9D%B4%EB%8B%A4%EC%86%9C-%EB%B0%B1%EC%A4%80-1620%EB%B2%88</guid>
            <pubDate>Sat, 18 Feb 2023 12:06:24 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<blockquote>
<p>안녕? 내 이름은 이다솜. 나의 꿈은 포켓몬 마스터야. 일단 포켓몬 마스터가 되기 위해선 포켓몬을 한 마리 잡아야겠지? 근처 숲으로 가야겠어.</p>
</blockquote>
<p>(뚜벅 뚜벅)</p>
<blockquote>
</blockquote>
<p>얏! 꼬렛이다. 꼬렛? 귀여운데, 나의 첫 포켓몬으로 딱 어울린데? 내가 잡고 말겠어. 가라! 몬스터볼~</p>
<blockquote>
</blockquote>
<p>(펑!) 헐랭... 왜 안 잡히지?ㅜㅜ 몬스터 볼만 던지면 되는 게 아닌가...ㅜㅠ</p>
<blockquote>
</blockquote>
<p>(터벅터벅)</p>
<blockquote>
</blockquote>
<p>어? 누구지?</p>
<blockquote>
</blockquote>
<p>오박사 : 나는 태초마을의 포켓몬 박사 오민식 박사라네. 다솜아, 포켓몬을 잡을 때는, 일단 상대 포켓몬의 체력을 적당히 바닥으로 만들어놓고 몬스터 볼을 던져야 한단다. 자, 내 포켓몬 이상해꽃으로 한번 잡아보렴. 포켓몬의 기술을 쓰는 것을 보고 포켓몬을 줄지 안줄지 결정을 하겠네. 자 한번 해보아라. 다솜아.</p>
<blockquote>
</blockquote>
<br>
>
~어쩌구 저쩌구~
>
<br>
오박사 : 그럼 다솜아 이제 진정한 포켓몬 마스터가 되기 위해 도감을 완성시키도록 하여라. 일단 네가 현재 가지고 있는 포켓몬 도감에서 포켓몬의 이름을 보면 포켓몬의 번호를 말하거나, 포켓몬의 번호를 보면 포켓몬의 이름을 말하는 연습을 하도록 하여라. 나의 시험을 통과하면, 내가 새로 만든 도감을 주도록 하겠네.

<h2 id="입력">입력</h2>
<blockquote>
<p>첫째 줄에는 도감에 수록되어 있는 포켓몬의 개수 N이랑 내가 맞춰야 하는 문제의 개수 M이 주어져. N과 M은 1보다 크거나 같고, 100,000보다 작거나 같은 자연수인데, 자연수가 뭔지는 알지? 모르면 물어봐도 괜찮아. 나는 언제든지 질문에 답해줄 준비가 되어있어.</p>
</blockquote>
<p>둘째 줄부터 N개의 줄에 포켓몬의 번호가 1번인 포켓몬부터 N번에 해당하는 포켓몬까지 한 줄에 하나씩 입력으로 들어와. 포켓몬의 이름은 모두 영어로만 이루어져있고, 또, 음... 첫 글자만 대문자이고, 나머지 문자는 소문자로만 이루어져 있어. 아참! 일부 포켓몬은 마지막 문자만 대문자일 수도 있어. 포켓몬 이름의 최대 길이는 20, 최소 길이는 2야. 그 다음 줄부터 총 M개의 줄에 내가 맞춰야하는 문제가 입력으로 들어와. 문제가 알파벳으로만 들어오면 포켓몬 번호를 말해야 하고, 숫자로만 들어오면, 포켓몬 번호에 해당하는 문자를 출력해야해. 입력으로 들어오는 숫자는 반드시 1보다 크거나 같고, N보다 작거나 같고, 입력으로 들어오는 문자는 반드시 도감에 있는 포켓몬의 이름만 주어져. 그럼 화이팅!!!</p>
<h2 id="출력">출력</h2>
<blockquote>
<p>첫째 줄부터 차례대로 M개의 줄에 각각의 문제에 대한 답을 말해줬으면 좋겠어!!!. 입력으로 숫자가 들어왔다면 그 숫자에 해당하는 포켓몬의 이름을, 문자가 들어왔으면 그 포켓몬의 이름에 해당하는 번호를 출력하면 돼. 그럼 땡큐~</p>
</blockquote>
<p>이게 오박사님이 나에게 새로 주시려고 하는 도감이야. 너무 가지고 싶다ㅠㅜ. 꼭 만점을 받아줬으면 좋겠어!! 파이팅!!!</p>
<hr>
<h2 id="문제-풀이-코드🧑🏻💻">문제 풀이 코드🧑🏻‍💻</h2>
<p>해당 문제를 처음 풀었을 때는 배열(Array)을 사용하여 문제를 풀어보았습니다.</p>
<blockquote>
<pre><code class="language-swift">//시간 초과 코드
let nm = readLine()!.split(separator:&quot; &quot;).map{Int($0)!}
let (n, m) = (nm[0], nm[1])
var pokemonArray = [String]()
var questionArray = [Any]()  //숫자 or 문자 질문을 모두 수용할 수 있도록 배열의 타입을 Any로 생성
</code></pre>
</blockquote>
<p>for _ in 1...n{
    pokemonArray.append(readLine()!)
}</p>
<blockquote>
</blockquote>
<p>for _ in 1...m{
    let question = readLine()!
    if Int(question) != nil{
        questionArray.append(Int(question)!)
    }
    else{
        questionArray.append(question)
    }
}</p>
<blockquote>
</blockquote>
<p>for i in questionArray{
    if type(of: i) == Int.self{
        print(pokemonArray[i as! Int - 1])
    }
    else{
        print(pokemonArray.firstIndex(of: i as! String)! + 1)
    }
}</p>
<pre><code>
배열을 사용하여 문제 자체는 해결할 수 있었지만, 문제가 요구하는 **시간을 초과해버리는 문제점이 발생**했습니다.

시간 초과 문제를 해결하기 위해 Swift에서 제공하는 컬렉션 타입 중에서 **딕셔너리(Dictionary)를 활용**해 보았습니다. (**딕셔너리는 배열의 시간복잡도보다 작으면서, 키(Int)와 값(String)을 활용**할 수 있기 때문에 해당 문제에 효과적이라 판단)

&gt;```swift
let nm = readLine()!.split(separator:&quot; &quot;).map{Int($0)!}
let (n, m) = (nm[0], nm[1])
var dic = [String : Int]()    //문자-&gt;숫자, dic[String] -&gt; optional(Int)
var rdic = [Int : String]()   //숫자-&gt;문자, rdic[Int] -&gt; optional(String)
&gt;
for i in 1...n{
    let pokemon = readLine()!
    dic[pokemon] = i
    rdic[i] = pokemon
}
&gt;
for _ in 1...m{
    let question = readLine()!
    if Int(question) != nil{  //질문이 숫자인 경우
        print(rdic[Int(question)!]!)
    }
    else{  //질문이 문자인 경우
        print(dic[question]!)
    }
}</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[수열 (백준 2559번)]]></title>
            <link>https://velog.io/@shin_ms/%EC%88%98%EC%97%B4-%EB%B0%B1%EC%A4%80-2559%EB%B2%88</link>
            <guid>https://velog.io/@shin_ms/%EC%88%98%EC%97%B4-%EB%B0%B1%EC%A4%80-2559%EB%B2%88</guid>
            <pubDate>Sat, 18 Feb 2023 08:35:47 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<blockquote>
<p>매일 아침 9시에 학교에서 측정한 온도가 어떤 정수의 수열로 주어졌을 때, 연속적인 며칠 동안의 온도의 합이 가장 큰 값을 알아보고자 한다.</p>
</blockquote>
<p>예를 들어, 아래와 같이 10일 간의 온도가 주어졌을 때, </p>
<blockquote>
</blockquote>
<p>3 -2 -4 -9 0 3 7 13 8 -3</p>
<blockquote>
</blockquote>
<p>모든 연속적인 이틀간의 온도의 합은 아래와 같다.</p>
<blockquote>
<p><img src="https://velog.velcdn.com/images/shin_ms/post/6d185cdd-46f1-4cc7-9ef9-f53436a14abb/image.png" alt=""></p>
<p>이때, 온도의 합이 가장 큰 값은 21이다. </p>
</blockquote>
<br>
>
또 다른 예로 위와 같은 온도가 주어졌을 때, 모든 연속적인 5일 간의 온도의 합은 아래와 같으며, 
>
>![](https://velog.velcdn.com/images/shin_ms/post/23e20a75-4068-4954-a1d5-acc41c9a3b05/image.png)
>
이때, 온도의 합이 가장 큰 값은 31이다.
>
매일 측정한 온도가 정수의 수열로 주어졌을 때, 연속적인 며칠 동안의 온도의 합이 가장 큰 값을 계산하는 프로그램을 작성하시오. 

<h2 id="입력">입력</h2>
<blockquote>
<p>첫째 줄에는 두 개의 정수 N과 K가 한 개의 공백을 사이에 두고 순서대로 주어진다. 첫 번째 정수 N은 온도를 측정한 전체 날짜의 수이다. N은 2 이상 100,000 이하이다. 두 번째 정수 K는 합을 구하기 위한 연속적인 날짜의 수이다. K는 1과 N 사이의 정수이다. 둘째 줄에는 매일 측정한 온도를 나타내는 N개의 정수가 빈칸을 사이에 두고 주어진다. 이 수들은 모두 -100 이상 100 이하이다. </p>
</blockquote>
<h2 id="출력">출력</h2>
<blockquote>
<p>첫째 줄에는 입력되는 온도의 수열에서 연속적인 K일의 온도의 합이 최대가 되는 값을 출력한다.</p>
</blockquote>
<hr>
<h2 id="문제-풀이-코드🧑🏻💻">문제 풀이 코드🧑🏻‍💻</h2>
<p>저는 해당 문제를 풀 때 <strong>구간 합(Prefix Sum)</strong>의 특징을 활용하여 풀어보았습니다.</p>
<blockquote>
<h3 id="✅-구간-합prefix-sum">✅ 구간 합(Prefix Sum)</h3>
<p><code>array = [1,2,3,4,5]</code>의 <strong>구간 합</strong>과 <strong>배열의 특정 범위 합</strong>은 아래와 같습니다.
<img src="https://velog.velcdn.com/images/shin_ms/post/8771c100-f4cc-4714-b2a5-75a256349f97/image.png" alt=""></p>
</blockquote>
<p>즉, <code>array[x]~array[y]</code>의 구간 합은 <code>pSum[y]-pSum[x-1]</code>입니다.</p>
<pre><code class="language-swift">let nk = readLine()!.split(separator: &quot; &quot;).map{Int($0)!}
let temperature = readLine()!.split(separator:&quot; &quot;).map{Int($0)!}
let (n, k) = (nk[0], nk[1])
var pSumArray = [Int]()
var pSum = 0
var resultArray = [Int]()

for i in 0..&lt;n{  //구간 합(Prefix Sum)을 계산해주는 코드
    pSum += temperature[i]
    pSumArray.append(pSum)
}

if n == k{  //측정 날짜(n)와 연속 날짜의 수(k)가 같은 경우 모든 요일의 온도를 더합니다.
    print(temperature.reduce(0){$0+$1})
}
else{
    resultArray.append(pSumArray[k-1])  //배열의 index는 0부터 시작함으로 초반에 k번째의 구간 합을 resultArray에 할당합니다.
    for j in 0..&lt;n-k{
        resultArray.append(pSumArray[k+j] - pSumArray[j])  //배열 공간을 한 칸씩 이동하면서 k의 구간 합을 계산한 뒤 resultArray에 할당합니다.
    }
    print(resultArray.max()!)  //resultArray의 최대값을 출력
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[iOS의 앱 라이프 사이클(App Life Cycle)]]></title>
            <link>https://velog.io/@shin_ms/iOS%EC%9D%98-%EC%95%B1-%EB%9D%BC%EC%9D%B4%ED%94%84-%EC%82%AC%EC%9D%B4%ED%81%B4App-Life-Cycle</link>
            <guid>https://velog.io/@shin_ms/iOS%EC%9D%98-%EC%95%B1-%EB%9D%BC%EC%9D%B4%ED%94%84-%EC%82%AC%EC%9D%B4%ED%81%B4App-Life-Cycle</guid>
            <pubDate>Sun, 29 Jan 2023 11:02:56 GMT</pubDate>
            <description><![CDATA[<h1 id="ios의-앱-라이프-사이클app-life-cycle">iOS의 앱 라이프 사이클(App Life Cycle)</h1>
<p>앱 사용 시 문자와 전화처럼 예기치 못한 상황 또는 사용자의 고의/실수로 앱을 종료하거나 백그라운드 등으로 전환하는 시점에 운영체제가 자동으로 호출하는 함수(메서드)들이 존재하며, 이러한 메서드 실행의 일련 과정을 <strong>앱 라이프 사이클(App Life Cycle)</strong>이라 부릅니다.</p>
<p><strong>앱 라이프 사이클(App Life Cycle)은 <span style="color:blue">AppDelegate</span>와 <span style="color:red">SceneDelegate</span>에 의해 관리</strong>되며 각각 하는 역할이 다릅니다.<img src="https://velog.velcdn.com/images/shin_ms/post/4105a6a3-77d3-42c0-b1bb-1e91417ec4f7/image.png" alt=""></p>
<h2 id="📌-앱-라이프-사이클의-실행-시점-및-메서드">📌 앱 라이프 사이클의 실행 시점 및 메서드</h2>
<p><img src="https://velog.velcdn.com/images/shin_ms/post/81470567-047a-4792-a044-a6f52d8725b7/image.png" alt=""></p>
<ul>
<li><p><strong>Not Running</strong>
App이 실행되지 않은 상태를 의미합니다.</p>
</li>
<li><p><strong>Foreground</strong>
App의 실행 화면(Scene)을 사용자에게 보여주는 상태(영역)를 의미합니다.</p>
<ul>
<li><strong>Active:</strong> 사용자가 App을 100% 컨트롤 할 수 있는 상태</li>
<li><strong>InActive:</strong> 사용자가 App을 100% 컨트롤 할 수 없는 상태(App 사용 중 전화 또는 문자와 같은 이벤트가 접근했을 때 App은 Active-&gt;InActive로 변환) </li>
</ul>
</li>
<li><p><strong>Background</strong>
App의 실행 화면(Scene)이 내려간 상태(영역)를 의미합니다.</p>
<ul>
<li><strong>Background Running:</strong> App의 화면은 내려갔지만 계속 작동하는 상태를 의미합니다. 애플은 보안 등의 이유로 Background 영역에서 App의 작동을 허용하지 않습니다. 하지만 일부 App은 작동이 가능합니다.(음악 App 같은 경우는 작동을 허용) </li>
</ul>
</li>
<li><p><strong>Suspended</strong>
실행 대기 상태(영역)를 의미합니다. App의 실행 화면(Scene)이 내려가면 대부분의 App은 대기상 태로 전환됩니다.</p>
</li>
</ul>
<blockquote>
<h2 id="span-stylecolorblue✔︎appdelegatespan"><span style="color:blue">✔︎AppDelegate</span></h2>
</blockquote>
<h3 id="1-didfinishlaunchingwithoptions">1. didFinishLaunchingWithOptions</h3>
<pre><code class="language-swift">func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -&gt; Bool {
        // Override point for customization after application launch.
        return true
    }</code></pre>
<p>Not Running 상태의 초기 App을 실행할 때 사용자에게 화면(Scene)이 보일 수 있도록 Foreground 영역에 접근하는 메서드이며, App 화면이 보이기 직전에 호출됩니다.
(해당 메서드는 Foreground 내부에 호출되는 메서드가 아님)</p>
<blockquote>
</blockquote>
<h3 id="2-configurationforconnecting">2. configurationForConnecting</h3>
<pre><code class="language-swift"> func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -&gt; UISceneConfiguration {
        // Called when a new scene session is being created.
        // Use this method to select a configuration to create the new scene with.
        return UISceneConfiguration(name: &quot;Default Configuration&quot;, sessionRole: connectingSceneSession.role)
    }</code></pre>
<p>새로운 화면(Scene)을 생성할 때 호출되는 메서드입니다.</p>
<blockquote>
</blockquote>
<p>iOS 12 이전에는 하나의 디바이스에 단일 화면(Scene)만이 존재할 수 있었지만, iOS 13 부터는 하나의 디바이스(iPad)에 여러 화면을 가질 수 있게 되었습니다. (iPad의 멀태스킹/멀티화면 기능)</p>
<blockquote>
</blockquote>
<h3 id="3-diddiscardscenesessions">3. didDiscardSceneSessions</h3>
<pre><code class="language-swift">func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set&lt;UISceneSession&gt;) {
        // Called when the user discards a scene session.
        // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
        // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
    }</code></pre>
<p>화면의 세션(Scene Session)이 제거되기(버려지기) 직전에 호출되는 메서드입니다. </p>
<blockquote>
</blockquote>
<p>해당 메서드는 운영체제의 판단하에 호출되는 메서드이며, 화면을 영구적으로 메모리에서 해제할 때만 해당 메서드가 호출됩니다. (Background에 있는 App이 종료되려고 할 때 호출되는 메서드는 <code>applicationWillTerminate:</code> 메서드입니다.)</p>
<blockquote>
</blockquote>
<br>
>
## <span style="color:red">✔︎SceneDelegate</span>
### 0. scene()
```swift
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
        // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
        // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
        guard let _ = (scene as? UIWindowScene) else { return }
    }
```
화면(Scene)이 해당 App에 추가(연결)될 때 호출되는 메서드입니다. 
>
### 1. sceneDidBecomeActive()
```swift
func sceneDidBecomeActive(_ scene: UIScene) {
        // Called when the scene has moved from an inactive state to an active state.
        // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
    }
```
화면(Scene)을 InActive에서 Active로 이동시킬 때 호출되는 메서드입니다.
>
App을 처음 실행할 때 사용자가 해당 App을 100% 조작할 수 있도록 Active로 안내?/이동? 시켜주는 메서드입니다. (해당 메서드는 Foreground 영역에서만 동작합니다.)
>
### 2. sceneWillResignActive()
```swift
func sceneWillResignActive(_ scene: UIScene) {
        // Called when the scene will move from an active state to an inactive state.
        // This may occur due to temporary interruptions (ex. an incoming phone call).
    }
```
화면(Scene)을 Active에서 InActive로 이동시킬 때 호출되는 메서드입니다.
>
App 사용 중 전화 또는 문자 등의 특정 이벤트가 접근했을 때 해당 App의 화면은 `sceneWillResignActive()`메서드를 통해 Active에서 InActive로 이동합니다. (해당 메서드는 Foreground 영역에서만 동작합니다.)
>
### 3. sceneDidEnterBackground()
```swift
func sceneDidEnterBackground(_ scene: UIScene) {
        // Called as the scene transitions from the foreground to the background.
        // Use this method to save data, release shared resources, and store enough scene-specific state information
        // to restore the scene back to its current state.
    }
```
화면(Scene)을 InActive에서 Background 영역으로 이동시킬 때 호출되는 메서드입니다.
>
### 4. sceneWillEnterForeground()
```swift
func sceneWillEnterForeground(_ scene: UIScene) {
        // Called as the scene transitions from the background to the foreground.
        // Use this method to undo the changes made on entering the background.
    }
```
화면(Scene)을 Background 영역에서 Foreground(InActive)영역으로 이동시킬 때 호출되는 메서드입니다.
>
### 5. sceneDidDisconnect()
```swift
func sceneDidDisconnect(_ scene: UIScene) {
        // Called as the scene is being released by the system.
        // This occurs shortly after the scene enters the background, or when its session is discarded.
        // Release any resources associated with this scene that can be re-created the next time the scene connects.
        // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
    }
```
화면(Scene)이 해제될 때 호출되는 메서드입니다. 
>
해당 메서드는 App의 화면이 Background 영역에 들어간 직후 또는 해당 화면의 세션(Scene Session)이 버려질 때 호출되는 메서드입니다. (메모리로부터 영구적으로 버려지는 것이 아닙니다. 이는 사용자가 해당 화면에 다시 접근할 수 있는 여지가 있기 때문입니다. 즉, 완전한 App 종료가 이님!!)

<p>작성한 내용 중 틀린 부분이 있다면 꼭 알려주세요!! (공부하면서 나름대로 이해한 부분만을 요약)
<br></p>
<hr>
<h1 id="reference">Reference</h1>
<p><a href="https://developer.apple.com/documentation/uikit/uiapplicationdelegate">Apple Developer - UIApplicationDelegate</a>
<a href="https://developer.apple.com/documentation/uikit/app_and_environment/scenes">Apple Developer - Scene</a>
<a href="https://www.youtube.com/watch?v=7GlwS2lOKbE">스위프트 하이</a>
<a href="https://www.inflearn.com/course/ios-uikit-15apps">앨런 iOS 아이폰 앱 개발</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[iOS의 뷰 라이프 사이클(View Life Cycle)]]></title>
            <link>https://velog.io/@shin_ms/iOS%EC%9D%98-%EB%B7%B0-%EB%9D%BC%EC%9D%B4%ED%94%84-%EC%82%AC%EC%9D%B4%ED%81%B4View-Life-Cycle</link>
            <guid>https://velog.io/@shin_ms/iOS%EC%9D%98-%EB%B7%B0-%EB%9D%BC%EC%9D%B4%ED%94%84-%EC%82%AC%EC%9D%B4%ED%81%B4View-Life-Cycle</guid>
            <pubDate>Sun, 29 Jan 2023 09:13:07 GMT</pubDate>
            <description><![CDATA[<h1 id="ios의-뷰-라이프-사이클view-life-cycle">iOS의 뷰 라이프 사이클(View Life Cycle)</h1>
<p>일반적으로 앱을 사용할 때는 해당 앱의 다양한 화면을 오가며 사용합니다.</p>
<p>현재 화면에서 어떠한 작업을 수행하고 다음 화면으로 넘어갈 때 현재 화면의 작업을 저장하거나 다음 화면으로 넘어갈 준비를 취해야지만 원활한 앱 사용이 가능하므로 특정 작업을 취해야 하며, (장바구니 기능, 좋아요 기능, 댓글 기능 등) 이러한 특정 작업은 뷰 라이프 사이클(View Life Cycle) 관련 메서드에 작성합니다.</p>
<p>앱의 현재 사용화면에서 특정 화면으로 넘어갈 때마다 운영체제에 의해 자동으로 작동하는 함수(메서드)들이 존재하며, 이러한 메서드 실행의 일련 과정을 <strong>뷰 라이프 사이클(View Life Cycle)</strong>이라 부릅니다.</p>
<br>

<h2 id="📌-뷰-라이프-사이클의-실행-시점-및-메서드">📌 뷰 라이프 사이클의 실행 시점 및 메서드</h2>
<blockquote>
<p><img src="https://velog.velcdn.com/images/shin_ms/post/637f1846-936b-4b29-9926-a4cde60739aa/image.png" alt=""></p>
</blockquote>
<h3 id="✅-loadview-">✅ loadView( )</h3>
<p><code>loadView()</code>는 <strong>코드로 작성한 뷰(view)를 메모리에 올릴 시점에 사용</strong>되는 메서드입니다. (뷰를 메모리에 올리는 시점에 사용)</p>
<blockquote>
</blockquote>
<p><code>loadView()</code>는 직접적으로 호출하여 사용하는 것을 권장하지 않기 때문에 뷰를 코드로 작성하는 경우를 제외하곤 사용하지 않는 것을 권장합니다.\</p>
<blockquote>
</blockquote>
<p>또한 <code>loadView()</code>는 <code>viewDidLoad()</code>보다 먼저 호출되며, 사용 시 상위 메서드 호출해서는 안 됩니다. (<code>super.loadView()</code> 작성 금지X)</p>
<h3 id="✅-viewdidload-">✅ viewDidLoad( )</h3>
<p><code>viewDidLoad( )</code>는 메모리에 할당되어 있는 <strong>데이터(객체 및 변수 등...)와 뷰(view)의 연결이 끝난 시점에 호출</strong>되는 메서드입니다.</p>
<blockquote>
</blockquote>
<p><code>viewDidLoad( )</code>는 뷰가 생성되었을 때 <strong>딱 한 번만 호출되는 메서드</strong>입니다. 때문에 초기설정 및 네트워크 호출처럼 한 번만 호출할 코드 등을 주로 <code>viewDidLoad( )</code>에 작성하여 사용합니다.</p>
<blockquote>
</blockquote>
<hr>
<h3 id="✅-viewwillappear-">✅ viewWillAppear( )</h3>
<p><code>viewWillAppear( )</code>는 <strong>뷰(view)가 화면에 출력되기 전에 호출되는 메서드</strong>입니다.</p>
<blockquote>
</blockquote>
<p>새로운 화면으로 이동할 때마다 호출되는 메서드이며, 화면이 출력되기 전에 호출되기 때문에 주로 데이터 갱신 및 화면 설정 등의 코드를 주로 <code>viewWillAppear( )</code>에 작성하여 사용합니다.</p>
<blockquote>
</blockquote>
<h3 id="✅-viewdidappear-">✅ viewDidAppear( )</h3>
<p><code>viewDidAppear( )</code>는 <strong>뷰(view)가 화면에 완전히 출력된 후 호출되는 메서드</strong>입니다.</p>
<blockquote>
</blockquote>
<h3 id="✅-viewwilldisappear-">✅ ViewWillDisappear( )</h3>
<blockquote>
</blockquote>
<p><code>ViewWillDisappear( )</code>는 <strong>현재 뷰(view) 화면이 사라지기 전에 호출되는 메서드</strong>입니다.</p>
<blockquote>
</blockquote>
<p>현재 사용 중인 화면에서 작업한 기록 등을 저장하는 코드 등을 주로 <code>ViewWillDisappear( )</code>에 작성하여 사용합니다.</p>
<h3 id="✅-viewdiddisappear-">✅ viewDidDisappear( )</h3>
<p><code>viewDidDisappear( )</code>는 <strong>뷰(view)가 화면에 완전히 사라진 후 호출되는 메서드</strong>입니다.</p>
<br>

<h2 id="✋-스크린의-종류에-따른-메서드-호출">✋ 스크린의 종류에 따른 메서드 호출</h2>
<p>뷰 라이프 사이클의 메서드 호출 시점은 스크린의 종류에 따라 다릅니다. (호출 순서는 동일)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[한국이 그리울 땐 서버에 접속하지 (백준 9996번)]]></title>
            <link>https://velog.io/@shin_ms/%ED%95%9C%EA%B5%AD%EC%9D%B4-%EA%B7%B8%EB%A6%AC%EC%9A%B8-%EB%95%90-%EC%84%9C%EB%B2%84%EC%97%90-%EC%A0%91%EC%86%8D%ED%95%98%EC%A7%80-%EB%B0%B1%EC%A4%80-9996%EB%B2%88</link>
            <guid>https://velog.io/@shin_ms/%ED%95%9C%EA%B5%AD%EC%9D%B4-%EA%B7%B8%EB%A6%AC%EC%9A%B8-%EB%95%90-%EC%84%9C%EB%B2%84%EC%97%90-%EC%A0%91%EC%86%8D%ED%95%98%EC%A7%80-%EB%B0%B1%EC%A4%80-9996%EB%B2%88</guid>
            <pubDate>Tue, 24 Jan 2023 07:31:29 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<blockquote>
<p>선영이는 이번 학기에 오스트레일리아로 교환 학생을 가게 되었다. </p>
</blockquote>
<p>호주에 도착하고 처음 며칠은 한국 생각을 잊으면서 즐겁게 지냈다. 몇 주가 지나니 한국이 그리워지기 시작했다. </p>
<blockquote>
</blockquote>
<p>선영이는 한국에 두고온 서버에 접속해서 디렉토리 안에 들어있는 파일 이름을 보면서 그리움을 잊기로 했다. 매일 밤, 파일 이름을 보면서 파일 하나하나에 얽힌 사연을 기억하면서 한국을 생각하고 있었다.</p>
<blockquote>
</blockquote>
<p>어느 날이었다. 한국에 있는 서버가 망가졌고, 그 결과 특정 패턴과 일치하는 파일 이름을 적절히 출력하지 못하는 버그가 생겼다.</p>
<blockquote>
</blockquote>
<p>패턴은 알파벳 소문자 여러 개와 별표(*) 하나로 이루어진 문자열이다.</p>
<blockquote>
</blockquote>
<p>파일 이름이 패턴에 일치하려면, 패턴에 있는 별표를 알파벳 소문자로 이루어진 임의의 문자열로 변환해 파일 이름과 같게 만들 수 있어야 한다. 별표는 빈 문자열로 바꿀 수도 있다. 예를 들어, &quot;abcd&quot;, &quot;ad&quot;, &quot;anestonestod&quot;는 모두 패턴 &quot;a*d&quot;와 일치한다. 하지만, &quot;bcd&quot;는 일치하지 않는다.</p>
<blockquote>
</blockquote>
<p>패턴과 파일 이름이 모두 주어졌을 때, 각각의 파일 이름이 패턴과 일치하는지 아닌지를 구하는 프로그램을 작성하시오.</p>
<h2 id="입력">입력</h2>
<blockquote>
<p>첫째 줄에 파일의 개수 N이 주어진다. (1 ≤ N ≤ 100)</p>
</blockquote>
<p>둘째 줄에는 패턴이 주어진다. 패턴은 알파벳 소문자와 별표(아스키값 42) 한 개로 이루어져 있다. 문자열의 길이는 100을 넘지 않으며, 별표는 문자열의 시작과 끝에 있지 않다.</p>
<blockquote>
</blockquote>
<p>다음 N개 줄에는 파일 이름이 주어진다. 파일 이름은 알파벳 소문자로만 이루어져 있고, 길이는 100을 넘지 않는다.</p>
<h2 id="출력">출력</h2>
<blockquote>
<p>총 N개의 줄에 걸쳐서, 입력으로 주어진 i번째 파일 이름이 패턴과 일치하면 &quot;DA&quot;, 일치하지 않으면 &quot;NE&quot;를 출력한다.</p>
</blockquote>
<p>참고로, &quot;DA&quot;는 크로아티어어로 &quot;YES&quot;를, &quot;NE&quot;는 &quot;NO&quot;를 의미한다.</p>
<hr>
<h2 id="문제-풀이-코드🧑🏻💻">문제 풀이 코드🧑🏻‍💻</h2>
<pre><code class="language-swift">let n = Int(readLine()!)!
let pattern = readLine()!
let firstPattern = pattern.split(separator: &quot;*&quot;)[0]
let lastPattern = pattern.split(separator: &quot;*&quot;)[1]
var result = [String]()

for _ in 1...n{
    let fileName = readLine()!

    if firstPattern.count + lastPattern.count &gt; fileName.count{
        result.append(&quot;NE&quot;)
    }
    else if (fileName.hasPrefix(firstPattern) == true) &amp;&amp; (fileName.hasSuffix(lastPattern) == true){
        result.append(&quot;DA&quot;)
    }
    else{
        result.append(&quot;NE&quot;)
    }
}

for i in result{
    print(i)
}</code></pre>
<blockquote>
<p><code>split()</code>함수를 사용하여 특정 문자(&#39;*&#39;)를 기준으로 시작 패턴과 마지막 패턴을 나눕니다.</p>
<pre><code class="language-swift">let firstPattern = pattern.split(separator: &quot;*&quot;)[0]
let lastPattern = pattern.split(separator: &quot;*&quot;)[1]</code></pre>
</blockquote>
<pre><code>
&gt;시작 패턴과 마지막 패턴의 길이합이 파일 이름보다 클 경우 해당 파일은 패턴과 일치하는 파일이 아니기 때문에 NE을 출력해야 합니다.
```swift
if firstPattern.count + lastPattern.count &gt; fileName.count{
        result.append(&quot;NE&quot;)
    }</code></pre><blockquote>
<p>시작/마지막 패턴과 파일 이름의 접두어/접미어가 일치할 경우 DA를 출력, 일치하지 않을 경우 NE을 출력할 수 있도록 해야 합니다.</p>
</blockquote>
<p>문자열의 <strong>접두어를 확인하는 함수:</strong> <code>hasPrefix(확인하고 싶은 접두어)</code>
문자열의 <strong>접미어를 확인하는 함수:</strong> <code>hasSuffix(확인하고 싶은 접미어)</code></p>
<blockquote>
</blockquote>
<pre><code class="language-swift"> else if (fileName.hasPrefix(firstPattern) == true) &amp;&amp; (fileName.hasSuffix(lastPattern) == true){
        result.append(&quot;DA&quot;)
    }
    else{
        result.append(&quot;NE&quot;)
    }</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[자료구조와 알고리즘]]></title>
            <link>https://velog.io/@shin_ms/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0%EC%99%80-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</link>
            <guid>https://velog.io/@shin_ms/%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0%EC%99%80-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</guid>
            <pubDate>Thu, 19 Jan 2023 13:16:43 GMT</pubDate>
            <description><![CDATA[<h1 id="자료구조">자료구조</h1>
<p>자료구조의 개념은 이름 그대로 <strong>자료(data)의 구조를 의미</strong>하고 있습니다. 이는 <strong>데이터를 특정 구조나 형태로 저장</strong>하여 해당 <strong>데이터를 접근, 추가, 삽입, 수정, 삭제할 수 있도록 하는 <span style="color:red">&quot;데이터 저장/관리의 전반적인 개념&quot;</span></strong>을 의미합니다.</p>
<h2 id="🤔-어떠한-자료구조가-있을까">🤔 어떠한 자료구조가 있을까?</h2>
<p><strong>데이터를 저장하는 방법과 관리하는 방법에 따라 작업의 효율성이 달라집니다.</strong> 때문에 해당 작업에 맞는 효율적인 데이터 저장 방식을 찾아야 합니다.</p>
<p>작업의 특징에 따라 <strong>데이터의 순서를 보장할 것인지</strong>, <strong>데이터의 중복을 허용할 것인지</strong>, <strong>데이터의 접근/검색이 효율적인지</strong>, <strong>데이터의 유지보수가 쉬운지</strong>를 고려하여 데이터 구조를 설계해야 합니다.</p>
<blockquote>
<h3 id="대표적인-자료구조의-예시">대표적인 자료구조의 예시</h3>
</blockquote>
<ul>
<li><strong>배열(Array)</strong><ul>
<li>데이터의 순서를 보장하고 중복을 허용</li>
</ul>
</li>
<li><strong>세트(Set)</strong><ul>
<li>데이터의 순서를 보장하지 않고 중복을 허용하지 않음( + 집합의 연산 가능)</li>
</ul>
</li>
<li><strong>딕셔너리(Dictionary)</strong><ul>
<li>데이터의 순서를 보장하지 않고 중복을 허용</li>
</ul>
</li>
<li><strong>튜플(Tuple)</strong><ul>
<li>서로 다른 타입의 데이터를 하나로 묶을 때 사용</li>
</ul>
</li>
<li><strong>스택(Stack)</strong><ul>
<li>먼저 들어온 데이터가 가장 마지막에 나가는 구조</li>
</ul>
</li>
<li><strong>큐(Queue</strong>)<ul>
<li>먼저 들어온 데이터가 가장 먼저 나가는 구조</li>
</ul>
</li>
</ul>
<hr>
<h1 id="알고리즘">알고리즘</h1>
<p>알고리즘은 <strong><span style="color:red">&quot;어떠한 문제를 해결하는 다양한 방법&quot;</span></strong>을 의미하고 있습니다. </p>
<p><strong>다양한 방법??</strong>
알고리즘은 데이터의 형태와 구조에 따라 다양한 방법으로 문제를 해결할 수 있습니다. 
<strong>(알고리즘은 자료구조와 밀접한 관계를 가지고 있음)</strong></p>
<p>또한 알고리즘을 구현할 때는 <strong>&quot;시간복잡도&quot;</strong>와 <strong>&quot;공간복잡도&quot;</strong>를 생각하면서 코드를 작성해야 합니다.</p>
<h2 id="시간복잡도-vs-공간복잡도">시간복잡도 vs 공간복잡도</h2>
<p><strong>두 복잡도 중에서는 시간복잡도가 더 중요</strong>합니다. 공간복잡도는 메모리 공간(하드웨어)과 관련 있으며, 시간복잡도는 작업의 처리 시간(소프트웨어)과 관련 있습니다.</p>
<p>하드웨어의 성능이 좋지 못했던 과거에는 몇 안 되는 메모리 공간이 중요했지만, 하드웨어의 성능이 발전한 현재에는 메모리 공간이 넉넉하므로 메모리 공간의 중요성이 많이 떨어졌습니다. (부족한 경우에는 금전적인 방법으로 충분하게 공간을 확보할 수 있습니다) 하지만 작업의 처리 시간은 물리적인 방법으론 해결할 수 없으므로 시간복잡도의 중요성이 상대적으로 더 큽니다.</p>
<p>시간복잡도의 효율성을 계산할 때는 <strong>&quot;빅오 표기법(Big-O notation)&quot;</strong>을 활용!!</p>
<h2 id="🤔어떠한-알고리즘이-있을까">🤔어떠한 알고리즘이 있을까?</h2>
<p>알고리즘은 문제의 특징과 자료구조에 따라 다양한 방법이 존재합니다.</p>
<blockquote>
<ul>
<li>정렬 알고리즘</li>
</ul>
</blockquote>
<ul>
<li>데이터를 순서대로 나열하는 알고리즘<ul>
<li>문자열 알고리즘</li>
</ul>
</li>
<li>문자열 다루는 알고리즘<ul>
<li>브루트 포스 알고리즘</li>
</ul>
</li>
<li>모든 경우의 수를 검사하는 알고리즘<blockquote>
</blockquote>
그 외에도 상황에 따라 사용되는 다양한 알고리즘이 존재합니다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[싱글톤 패턴(Singleton Pattern)]]></title>
            <link>https://velog.io/@shin_ms/%EC%8B%B1%EA%B8%80%ED%86%A4-%ED%8C%A8%ED%84%B4Singleton-Pattern</link>
            <guid>https://velog.io/@shin_ms/%EC%8B%B1%EA%B8%80%ED%86%A4-%ED%8C%A8%ED%84%B4Singleton-Pattern</guid>
            <pubDate>Tue, 17 Jan 2023 12:35:10 GMT</pubDate>
            <description><![CDATA[<h1 id="📌-싱글톤-패턴singleton-pattern">📌 싱글톤 패턴(Singleton Pattern)</h1>
<p><strong>싱글톤 패턴</strong>은 애플리케이션(Application) 구현 시 <strong>절대 유일한 객체 하나만을 구현하고 싶을 때 사용하는 디자인 패턴</strong>입니다.</p>
<p>싱글톤 패턴으로 만들어진 객체는 한번 생성되면 <strong>애플리케이션이 종료될 때까지 메모리의 데이터(Data) 영역에 상주</strong>합니다.</p>
<p>절대 유일 객체를 변수에 할당하여 사용할 경우 해당 변수에 접근이 이루어지는 경우에만 객체가 메모리의 데이터(Data) 영역에 할당됩니다. (지연 저장 속성의 특징과 비슷)</p>
<blockquote>
<h3 id="✅-싱글톤-패턴-형태">✅ 싱글톤 패턴 형태</h3>
<pre><code class="language-swift">class 클래스명{
    static let 변수이름 = 클래스명()

        ...원하는 코드 작성...

    private init() {}  //새로운 객체 생성을 막는 코드
}</code></pre>
</blockquote>
<pre><code>
클래스 내부에 `private init() {}` 코드를 구현하지 않으면 클래스로부터 새로운 객체를 계속해서 생성할 수 있으므로 싱글톤 패턴을 구현할 수 없습니다.
절대 유일 객체를 구현하고자 할 때는 접근 제어(Access Controls) 키워드인 **private**를 사용한 `private init() {}` 코드를 꼭 작성해주어야 합니다.

&lt;br&gt;

&gt;### ✅ 싱글톤 패턴 구현
```swift
class Man{
    static let shared = Man()  //클래스 내부에서 객체를 생성 -&gt; 생성한 객체를 전역변수에 할당
    var age = 5
    private init() {}  //새로운 객체 생성을 막는 코드
}
&gt;
// shared -&gt; 절대 유일 객체
let kim = Man.shared  //절대 유일 객체를 변수(상수)에 할당
let lee = Man.shared
kim.age  //5
lee.age  //5
&gt;
Man.shared.age = 100
kim.age  //100
lee.age  //100</code></pre><hr>
<h2 id="🤔-싱글톤-패턴은-왜-사용할까">🤔 싱글톤 패턴은 왜 사용할까?</h2>
<p><img src="https://velog.velcdn.com/images/shin_ms/post/6c1cd3a2-dc4f-4ebd-aeeb-226744106f1f/image.png" alt=""></p>
<p>싱글톤 패턴은 <strong>절대 유일한 하나의 객체를 생성한 뒤 해당 객체를 공유하여 사용하고 싶을 때 사용</strong>되는 디자인 패턴입니다.</p>
<p>하나의 객체만을 생성한 뒤 해당 <strong>객체를 공유하여 사용하기 때문에 메모리 공간을 효율적으로 사용할 수 있다는 장점</strong>을 가지고 있습니다.</p>
<p>싱글톤 패턴의 사용은 여러 <strong><em>ViewController</em></strong>에서 공통적인 데이터를 공유하여 사용해야 할 때 주로 사용됩니다. (로그인 후 사용자 데이터 등...)</p>
<p><del>단점은... 더 공부하고 작성하겠습니다..</del></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[경고창 Alert 구현하기]]></title>
            <link>https://velog.io/@shin_ms/%EA%B2%BD%EA%B3%A0%EC%B0%BD-Alert-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@shin_ms/%EA%B2%BD%EA%B3%A0%EC%B0%BD-Alert-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 10 Jan 2023 11:44:00 GMT</pubDate>
            <description><![CDATA[<h1 id="📌-경고창-alert-구현하기">📌 경고창 Alert 구현하기</h1>
<blockquote>
<p><img src="https://velog.velcdn.com/images/shin_ms/post/b707520d-7c7c-4412-b041-4869f68de483/image.gif" alt=""></p>
<pre><code class="language-swift">let alert = UIAlertController(title: &quot;비밀번호 변경&quot;, message: &quot;비밀번호를 변경하시겠습니까??&quot;, preferredStyle: .alert)

let confirmation = UIAlertAction(title: &quot;확인&quot;, style: .default) { confirmation in
    print(&quot;확인 버튼 터치&quot;)
}

let cancel = UIAlertAction(title: &quot;취소&quot;, style: .default) { cancel in
    print(&quot;취소 버튼 터치&quot;)
}

alert.addAction(confirmation)  //alert 객체에 confirmation 객체 올리기
alert.addAction(cancel)        //alert 객체에 cancel 객체 올리기

// present(): 다음 화면(alert 화면)으로 넘어가는 메서드
present(alert, animated: true, completion: nil)</code></pre>
</blockquote>
<pre><code>
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[셀렉터 #selector()]]></title>
            <link>https://velog.io/@shin_ms/%EC%85%80%EB%A0%89%ED%84%B0-selecter</link>
            <guid>https://velog.io/@shin_ms/%EC%85%80%EB%A0%89%ED%84%B0-selecter</guid>
            <pubDate>Tue, 10 Jan 2023 11:41:25 GMT</pubDate>
            <description><![CDATA[<h1 id="📌-셀렉터-selector">📌 셀렉터 #selector()</h1>
<p>Swift에서 <strong>셀렉터 #selector( )</strong>는 <strong>클래스 내부에 정의된 메서드를 가리키는 기능</strong>을 가지고 있습니다.</p>
<p>사용할 때는 <code>#selector(타입.메서드)</code> 방식으로 사용합니다.</p>
<p>또한 <code>#selector()</code>는 Objective-C 언어에서 사용하던 문법이기 때문에 가리키려는 메서드 이름 앞에 <code>@objc</code> 어트리뷰트 키워드를 작성해야 합니다.</p>
<blockquote>
<pre><code class="language-swift">class Man{
    var name: String
    var age: Int

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

    @objc func hello(){  // 메서드를 가리키기 위해서는 @objc 어트리뷰트 키워드 작성
        print(&quot;안녕&quot;)
    }
}
</code></pre>
</blockquote>
<p>var kim = Man(name: &quot;김철수&quot;, age: 25)
#selector(kim.hello)  // Man 클래스 내부의 hello() 메서드를 가리키는 코드</p>
<blockquote>
</blockquote>
<p>print(#selector(kim.hello))  // hello (hello는 Selector 타입입니다.)</p>
<pre><code>&gt;
위의 코드만을 봤을 때 `#selector()`의 필요성과 활용성을 느낄 순 없습니다.
&gt;
### **🤔 그렇다면 클래스의 메서드를 가리켜서 뭐에 사용할까??**

---

# 📌 addTarget( ) 메서드
`#selector()`는 `addTarget()` 메서드와 같이 사용하는 경우가 많습니다.

&gt;### ✋ 참고: addTarget( )메서드의 형태
`button.addTarget(target: Any?, action: Selector, for: UIControl.Event)`
&gt;
`button.addTarget(target: 연결할 객체, action: 연결할 메서드, for: 동작 이벤트)`

&gt;
&gt;### **🤔 addTarget( ) 메서드는 언제 사용하는 거지??**
**개발자가 Xcode에서 스토리보드의 오브젝트 라이브러리를 사용하지 않고 코드로 버튼(UIButton)을 만든다 가정해보자!!**
&gt;
스토리보드의 오브젝트 라이브러리를 사용하여 버튼을 만들 경우에는 별다른 코드 작성 없이 사용할 수 있었지만, **버튼을 코드로 작성할 경우에는 작동할 메서드를 연결해줘야 합니다.**
&gt;
이때 사용되는 메서드가 `addTarget( )` 메서드입니다.
&gt;
(즉, `addTarget( )` 메서드는 **버튼이 눌렸을 때 실행시킬 메서드를 연결해주는 메서드**)
&gt;
&lt;br&gt;
&gt;
### ✅ addTarget( ) 메서드 예시 코드
```swift
private var testButton: UIButton = {
        var button = UIButton(type: .custom)
        button.setTitle(&quot;버튼&quot;, for: .normal)        // 버튼 이름 설정
        button.setTitleColor(.white, for: .normal)  // 버튼 이름의 색상 설정
        button.titleLabel?.font = UIFont.systemFont(ofSize: 15, weight: .light)  // 버튼의 크기
        &gt;
        // testButton 객체가 눌리면 testFunc 메서드 호출!!
        button.addTarget(self, action: #selector(testFunc), for: .touchUpInside)
        return button
    }()
&gt;
    @objc func testFunc(){
        print(&quot;버튼이 눌렸습니다.&quot;)
    }</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[Swift 코드로 로그인 화면 만들기]]></title>
            <link>https://velog.io/@shin_ms/Swift-%EC%BD%94%EB%93%9C%EB%A1%9C-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%ED%99%94%EB%A9%B4-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@shin_ms/Swift-%EC%BD%94%EB%93%9C%EB%A1%9C-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%ED%99%94%EB%A9%B4-%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Sun, 08 Jan 2023 08:15:29 GMT</pubDate>
            <description><![CDATA[<h1 id="로그인-화면-만들기">로그인 화면 만들기</h1>
<p>Xcode에서 UI 화면을 만드는 방법은 크게 <strong>스토리보드 오브젝트 라이브러리를 사용하는 방법</strong>과 <strong>개발자가 UI 코드를 하나하나 작성하여 만드는 방법</strong>이 있습니다.</p>
<p>위 방법 중 <strong>UI 화면을 코드로 작성하는 방법을 포스팅</strong>하겠습니다.</p>
<h1 id="✋-만들려고-하는-로그인-화면">✋ 만들려고 하는 로그인 화면</h1>
<p><img src="https://velog.velcdn.com/images/shin_ms/post/40d43dfa-f8c6-4266-a828-7718b3510d71/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/shin_ms/post/3bfee9ff-1bea-40bc-8c19-7ebf6f8501a1/image.png" alt=""></p>
<hr>
<h1 id="📱-코드로-로그인-화면-만들기">📱 코드로 로그인 화면 만들기</h1>
<p>해당 포스팅은 로그인 화면(UI)만 설정하는 포스팅입니다.
UI 작동 관련 포스팅 -&gt; </p>
<h2 id="📌-로그인-화면의-상단-이미지-만들기">📌 로그인 화면의 상단 이미지 만들기</h2>
<blockquote>
<pre><code class="language-swift">private lazy var mainLoginImage: UIImageView = {
        let image = UIImageView()
        image.image = #imageLiteral(resourceName: &quot;swift-logo&quot;)
        image.layer.cornerRadius = 50 // 이미지 객체의 모서리를 둥글게
        image.clipsToBounds = true    // 이미지 객체의 모서리를 둥글게
        return image
    }()</code></pre>
</blockquote>
<pre><code>
---

## 📌 이메일/전화번호 입력 칸 만들기
&gt;### ✅ 밑바탕이 되는 뷰 객체 만들기
```swift
private lazy var emailTextFieldView: UIView = {
        let view = UIView()
        view.backgroundColor = #colorLiteral(red: 0.2549019754, green: 0.2745098174, blue: 0.3019607961, alpha: 1)
        view.layer.cornerRadius = 5 // 뷰 객체의 모서리를 둥글게
        view.clipsToBounds = true   // 뷰 객체의 모서리를 둥글게
&gt;
        // 뷰 객체(emailTextFieldView)에 emailTextField, emailInfoLabel 객체 올리기
        view.addSubview(emailTextField)  //emailTextField를 올리고
        view.addSubview(emailInfoLabel)  //emailTextField 위에 emailInfoLabel이 올라와야 함
        return view
    }()</code></pre><blockquote>
</blockquote>
<br>
>
>### ✅ 이메일/전화번호 안내 문구 만들기
```swift
private var emailInfoLabel: UILabel = {
        var label = UILabel()
        label.text = "이메일 주소 또는 전화번호"   //라벨 문구 설정
        label.font = UIFont.systemFont(ofSize: 18)  //라벨 폰트 크기 설정
        label.textColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1) //라벨 폰트 색상을 흰색으로 설정
        return label
    }()
```
>
<br>
>
>### ✅ 이메일/전화번호 입력 필드 만들기
```swift
private lazy var emailTextField: UITextField = {
        var textField = UITextField()
        textField.frame.size.height = 48    // textField의 높이 설정
        textField.backgroundColor = .clear  // textField의 배경색을 투명색으로 설정
        textField.textColor = .white
        textField.tintColor = .white  // textField를 눌렀을 때 흰색으로 살짝 변함
        textField.autocapitalizationType = .none  // 자동으로 입력값의 첫 번째 문자를 대문자로 변경
        textField.autocorrectionType = .no        // 틀린 글자가 있는 경우 자동으로 교정 (해당 기능은 off)
        textField.spellCheckingType = .no         // 스펠링 체크 기능 (해당 기능은 off)
        textField.keyboardType = .emailAddress    // 키보드 타입을 email 타입으로 설정
        return textField
    }()
```

<hr>
<h2 id="📌-비밀번호-입력-칸-만들기">📌 비밀번호 입력 칸 만들기</h2>
<blockquote>
<h3 id="✅-밑바탕이-되는-뷰-객체-만들기">✅ 밑바탕이 되는 뷰 객체 만들기</h3>
</blockquote>
<pre><code class="language-swift">private lazy var passWordTextFieldView: UIView = {
        let view = UIView()
        view.frame.size.height = 48
        view.backgroundColor = #colorLiteral(red: 0.2549019754, green: 0.2745098174, blue: 0.3019607961, alpha: 1)
        view.layer.cornerRadius = 5
        view.clipsToBounds = true
&gt;        
        뷰 객체(passWordTextFieldView)에 passWordTextField, passWordInfoLabel, passWordSecureButton를 올리는 코드
        view.addSubview(passWordTextField) // 순서 조심!!
        view.addSubview(passWordInfoLabel)
        view.addSubview(passWordSecureButton)
        return view
    }()</code></pre>
<blockquote>
</blockquote>
<br>
>
>### ✅ 비밀번호 안내 문구 만들기
```swift
private var passWordInfoLabel: UILabel = {
        var label = UILabel()
        label.text = "비밀번호"
        label.font = UIFont.systemFont(ofSize: 18)
        label.textColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)
        return label
    }()
```
>
<br>
>
>### ✅ 비밀번호 입력 필드 만들기
```swift
private lazy var passWordTextField: UITextField = {
        var textField = UITextField()
        textField.frame.size.height = 48  // 높이 설정
        textField.backgroundColor = .clear  // 투명색
        textField.textColor = .white
        textField.tintColor = .white  // passWordText를 눌렀을 때 흰색으로 살짝 변함
        textField.autocapitalizationType = .none  // 자동으로 입력값의 첫 번째 문자를 대문자로 변경
        textField.autocorrectionType = .no  // 틀린 글자가 있는 경우 자동으로 교정 (해당 기능은 off)
        textField.spellCheckingType = .no   // 스펠링 체크 기능 (해당 기능은 off)
        textField.isSecureTextEntry = true  // 비밀번호를 가리는 기능 (비밀번호 입력시 "ㆍㆍㆍ"으로 표시)
        textField.clearsOnBeginEditing = false  // 텍스트 필드 터치시 내용 삭제 (해당 기능은 off)
        return textField
    }()
```
>
<br>
>
>### ✅ 비밀번호 입력 필드 우측에 "표시" 버튼 만들기
```swift
private lazy var passWordSecureButton: UIButton = {
        var button = UIButton(type: .custom)
        button.setTitle("표시", for: .normal)        // 버튼 이름 설정
        button.setTitleColor(.white, for: .normal)  // 버튼 이름의 색상 설정
        button.titleLabel?.font = UIFont.systemFont(ofSize: 14, weight: .light)  // 버튼의 크기
        return button
    }()
```

<hr>
<h2 id="📌-로그인-버튼-만들기">📌 로그인 버튼 만들기</h2>
<blockquote>
<pre><code class="language-swift">lazy var loginButton: UIButton = {
        var button = UIButton(type: .custom)
        button.setTitle(&quot;로그인&quot;, for: .normal)
        button.titleLabel?.font = UIFont.systemFont(ofSize: 16, weight: .bold)
        button.backgroundColor = .clear
        button.layer.cornerRadius = 5 
        button.clipsToBounds = true  
        button.layer.borderWidth = 1   // 버튼의 테두리 두께 설정
        button.layer.borderColor = #colorLiteral(red: 0.2605174184, green: 0.2605243921, blue: 0.260520637, alpha: 1)  // 버튼의 테두리 색 설정
        button.isEnabled = false       // 버튼의 동작 설정 (처음에는 동작 off)
        return button
    }()</code></pre>
</blockquote>
<pre><code>
---

## 📌 위에서 만든 각각의 객체를 하나의 객체로 묶기 및 객체의 높이 설정
`emailTextFieldView, passWordTextFieldView, loginButton`을 하나의 객체(Stack View)로 묶어 위치, 크기, 간격, 비율 등을 설정할 수 있습니다.
&gt;
```swift
lazy var stackView: UIStackView = {
        // 배열을 사용하여 각각의 객체를 하나로 묶는 코드
        let stView = UIStackView(arrangedSubviews: [emailTextFieldView, passWordTextFieldView, loginButton])
&gt;        
        stView.spacing = 18      // 객체의 내부 간격 설정
        stView.axis = .vertical  // 세로 묶음으로 정렬 (가로 묶음은 horizontal)
        stView.distribution = .fillEqually  // 각 객체의 크기(간격) 분배 설정 (fillEqually: 여기서는 동일하게 분배)
        stView.alignment = .fill  // 정렬 설정 (fill: 전부 채우는 설정)
        return stView
    }()
&gt;    
&gt;
// + 각 텍스트필드 및 로그인 버튼의 높이 설정
private let textViewHeight: CGFloat = 48</code></pre><hr>
<h2 id="📌-비밀번호-재설정-버튼-만들기">📌 비밀번호 재설정 버튼 만들기</h2>
<blockquote>
<pre><code class="language-swift">private var passWordResetButton: UIButton = {
        let button = UIButton()
        button.backgroundColor = .clear
        button.setTitle(&quot;비밀번호 재설정&quot;, for: .normal)
        button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 14)
        return button
    }()</code></pre>
</blockquote>
<pre><code>
---

## 📌 각각의 객체의 오토 레이아웃 설정하기
&gt;```swift
func makeUI(){
        view.backgroundColor = .black  // 메인 뷰 객체의 배경색을 변경
&gt;        
        // 메인 뷰 객체(ViewController)에 stackView, passWordResetButton, mainLoginImage 객체 올리기
        view.addSubview(stackView)
        view.addSubview(passWordResetButton)
        view.addSubview(mainLoginImage)
&gt;        
        // 사용자가 코드로 정의한 Auto Layout 기능 활성화
        mainLoginImage.translatesAutoresizingMaskIntoConstraints = false
        emailInfoLabel.translatesAutoresizingMaskIntoConstraints = false
        emailTextField.translatesAutoresizingMaskIntoConstraints = false
        passWordInfoLabel.translatesAutoresizingMaskIntoConstraints = false
        passWordTextField.translatesAutoresizingMaskIntoConstraints = false
        passWordSecureButton.translatesAutoresizingMaskIntoConstraints = false
        stackView.translatesAutoresizingMaskIntoConstraints = false
        passWordResetButton.translatesAutoresizingMaskIntoConstraints = false
&gt;        
        // NSLayoutConstraint.activate([뷰 객체의 위치 및 크기])배열 안에 뷰 객체의 위치와 크기를 설정
        NSLayoutConstraint.activate([
        // 로그인 화면 상단 이미지 위치 및 크기 설정
            mainLoginImage.heightAnchor.constraint(equalToConstant: 200),
            mainLoginImage.widthAnchor.constraint(equalToConstant: 200),
            mainLoginImage.bottomAnchor.constraint(equalTo: stackView.topAnchor, constant: -30),
            mainLoginImage.centerXAnchor.constraint(equalTo: stackView.centerXAnchor),
&gt;            
        // 이메일 안내 문구 위치 설정
            emailInfoLabel.leadingAnchor.constraint(equalTo: emailTextFieldView.leadingAnchor, constant: 8),
            emailInfoLabel.trailingAnchor.constraint(equalTo: emailTextFieldView.trailingAnchor, constant: 8),
            emailInfoLabel.centerYAnchor.constraint(equalTo: emailTextFieldView.centerYAnchor),
&gt;            
        // 이메일 텍스트 필드 위치 설정
            emailTextField.leadingAnchor.constraint(equalTo: emailTextFieldView.leadingAnchor, constant: 8),
            emailTextField.trailingAnchor.constraint(equalTo: emailTextFieldView.trailingAnchor, constant: 8),
            emailTextField.topAnchor.constraint(equalTo: emailTextFieldView.topAnchor, constant: 15),
            emailTextField.bottomAnchor.constraint(equalTo: emailTextFieldView.bottomAnchor, constant: 2),
&gt;
        // 비밀번호 안내 문구 위치 설정
            passWordInfoLabel.leadingAnchor.constraint(equalTo: passWordTextFieldView.leadingAnchor, constant: 8),
            passWordInfoLabel.trailingAnchor.constraint(equalTo: passWordTextFieldView.trailingAnchor, constant: 8),
            passWordInfoLabel.centerYAnchor.constraint(equalTo: passWordTextFieldView.centerYAnchor),
&gt;            
        // 비밀번호 텍스트 필드 위치 설정
            passWordTextField.leadingAnchor.constraint(equalTo: passWordTextFieldView.leadingAnchor, constant: 8),
            passWordTextField.trailingAnchor.constraint(equalTo: passWordTextFieldView.trailingAnchor, constant: 8),
            passWordTextField.topAnchor.constraint(equalTo: passWordTextFieldView.topAnchor, constant: 15),
            passWordTextField.bottomAnchor.constraint(equalTo: passWordTextFieldView.bottomAnchor, constant: 2),
&gt;            
        // 비밀번호 재설정 위치 설정
            passWordSecureButton.topAnchor.constraint(equalTo: passWordTextFieldView.topAnchor, constant: 15),
            passWordSecureButton.bottomAnchor.constraint(equalTo: passWordTextFieldView.bottomAnchor, constant: -15),
            passWordSecureButton.trailingAnchor.constraint(equalTo: passWordTextFieldView.trailingAnchor, constant: -8),
&gt;            
        // 하나로 묶은 스택 뷰 위치 및 높이 설정
            stackView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            stackView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
            stackView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 30),
            stackView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -30),
            stackView.heightAnchor.constraint(equalToConstant: textViewHeight*3 + 36),  //stackView의 높이 설정
&gt;            
        // 비밀번호 재설정 위치 및 높이 설정
            passWordResetButton.topAnchor.constraint(equalTo: stackView.bottomAnchor, constant: 10),
            passWordResetButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 30),
            passWordResetButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -30),
&gt;             passWordResetButton.heightAnchor.constraint(equalToConstant: textViewHeight)  //비밀번호 재설정 버튼 높이 설정
        ])
    }</code></pre><hr>
<h2 id="📌-코드로-작성한-로그인-화면-실행하기">📌 코드로 작성한 로그인 화면 실행하기</h2>
<blockquote>
<pre><code class="language-swift">override func viewDidLoad() {
        super.viewDidLoad()
        makeUI()  // 코드로 작성한 UI 실행
    }</code></pre>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[코드로 Auto Layout 설정하기]]></title>
            <link>https://velog.io/@shin_ms/%EC%BD%94%EB%93%9C%EB%A1%9C-Auto-Layout-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@shin_ms/%EC%BD%94%EB%93%9C%EB%A1%9C-Auto-Layout-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0</guid>
            <pubDate>Thu, 05 Jan 2023 13:37:25 GMT</pubDate>
            <description><![CDATA[<h1 id="auto-layout">Auto Layout</h1>
<p>애플에서 출시하는 다양한 크기의 아이폰은 특정 <strong>애플리케이션을 동등하게 대응할 수 있도록 뷰의 위치와 크기를 설정</strong>해야 합니다.</p>
<p>이러한 뷰의 설정을 오토 <strong>레이아웃(Auto Layout)</strong>이라 부릅니다.</p>
<h1 id="코드로-auto-layout-설정하기">코드로 Auto Layout 설정하기</h1>
<p>오토 레이아웃은 Xcode에서 코드 없이 설정할 수 있지만, 반대로 코드로도 설정할 수 있습니다.</p>
<p>코드로 설정하는 방법은 크게 세 가지로
<strong>1. Layout Anchor,</strong>
<strong>2. NSLayoutContraint,</strong>
<strong>3. Visual Format Language</strong>
방법이 있습니다.</p>
<hr>
<h2 id="✋-참고-뷰-객체의-위치크기-설정">✋ 참고: 뷰 객체의 위치/크기 설정</h2>
<p>들어가기에 앞서 뷰의 객체는 아래의 그림처럼 위치와 크기를 나누고 있습니다.
<img src="https://velog.velcdn.com/images/shin_ms/post/01fa82e6-70e9-4da1-8e84-1b6f914ee7d3/image.png" alt="">
<strong>뷰 객체의 위치는</strong> top(위), bottom(아래), leading(왼쪽), trailing(오른쪽), centerX(X축 중심), centerY(Y축 충심) 등이 있습니다.</p>
<p><strong>뷰 객체의 크기는</strong> height(높이), width(넓이)가 있습니다.</p>
<hr>
<h2 id="📌-auto-layout-코드layout-anchor">📌 Auto Layout 코드(Layout Anchor)</h2>
<blockquote>
<h3 id="✅-스토리보드에-뷰-객체-생성하기">✅ 스토리보드에 뷰 객체 생성하기</h3>
<p>스토리보드에 오브젝트 라이브러리를 사용하여 객체를 생성할 경우  ViewController.swift에는 코드가 표시되지 않습니다.
(객체는 코드로 표현되지 않지만, Xcode 내부 어딘가에 자동으로 생성)</p>
</blockquote>
<p>때문에 ViewController.swift에 객체 코드가 표시될 수 있도록 작업해야 합니다.</p>
<blockquote>
</blockquote>
<pre><code class="language-swift">//testView 객체를 메모리에 올리는 코드 (ViewController에 표시되는 것은 아님!!)
 let testView = UIView()  </code></pre>
<p>저는 <code>UIView()</code> 타입의 <code>testView</code> 객체를 만들어 보았습니다.
<br></p>
<blockquote>
<h3 id="✅-오토-레이아웃-코드-활성화하기-⭐️">✅ 오토 레이아웃 코드 활성화하기 ⭐️</h3>
<p>Xcode에서 자동으로 잡아주는 Auto Layout 기능을 무시하고, <strong>사용자가 코드로 직접 작성한 Auto Layout 기능을 사용할 수 있도록</strong> <code>.translatesAutoresizingMaskIntoConstraints</code> <strong>속성을 사용하여 활성화해야 합니다.</strong></p>
</blockquote>
<pre><code class="language-swift">testView.translatesAutoresizingMaskIntoConstraints = false</code></pre>
<br>
>
>### ✅ view 객체의 위치 설정하기
뷰 객체의 위치를 설정할 때는 `constraint(equalTo: 기준, constant: 띌 거리)` 매서드를 사용하여 뷰 객체의 위치를 설정해야 합니다.
>
그 다음 해당 설정을 활성화할 수 있도록 `.isActive = true` 속성을 사용하여 활성화해야 합니다.
```swift
testView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 30).isActive = true
>
testView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -30).isActive = true
>
testView.topAnchor.constraint(equalTo: view.topAnchor, constant: 200).isActive = true
```
<br>
>
>### ✅ view 객체의 크기 설정하기
뷰 객체의 크기를 설정할 때는 `constraint(equalToConstant: 객체의 크기)`매서드를 사용하여 객체의 크기를 설정해야 합니다.
(객체의 크기를 설정할 때는 기준 위치가 필요하지 않습니다.)
```swift       
testView.heightAnchor.constraint(equalToConstant: 40).isActive = true
```



<blockquote>
<h3 id="✅-종합-코드">✅ 종합 코드</h3>
<pre><code class="language-swift">import UIKit
</code></pre>
</blockquote>
<p>class ViewController: UIViewController {</p>
<blockquote>
</blockquote>
<pre><code>let testView = UIView()  //testView 객체를 메모리에 올리는 코드 (ViewController에 표시되는 것은 아님!!)</code></pre><blockquote>
<pre><code>override func viewDidLoad() {
    super.viewDidLoad()
    makeUI()
}

func makeUI(){
    testView.backgroundColor = #colorLiteral(red: 0.501960814, green: 0.501960814, blue: 0.501960814, alpha: 1)

    view.addSubview(testView)  //ViewController에 testView를 올리는 코드(아직 화면에 보이는것은 아님!!)

    // 사용자가 코드로 정의한 Auto Layout 기능 활성화
   testView.translatesAutoresizingMaskIntoConstraints = false


    // 뷰 객체의 위치 설정
    testView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 30).isActive = true
    testView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -30).isActive = true
    testView.topAnchor.constraint(equalTo: view.topAnchor, constant: 200).isActive = true


    // 뷰 객체의 크기 설정
   testView.heightAnchor.constraint(equalToConstant: 40).isActive = true
}</code></pre><p>}</p>
</blockquote>
<pre><code>
---

## 📌 Auto Layout 코드(NSLayoutContraint)
이번 방법은 **NSLayoutContraint클래스를 사용하여 뷰 객체의 오토레이아웃을 설정하는 방법**입니다.

Layout Anchor 방법과 비슷하지만, **뷰 객체의 위치와 크기를 설정할 때 하나의 배열에 묶어 정의**하는 부분이 가장 큰 차이점입니다.

&gt;### ✅ 오토 레이아웃 코드 활성화하기 ⭐️
Xcode에서 자동으로 잡아주는 Auto Layout 기능을 무시하고, **사용자가 코드로 직접 작성한 Auto Layout 기능을 사용할 수 있도록** `.translatesAutoresizingMaskIntoConstraints` **속성을 사용하여 활성화해야 합니다.**
```swift
testView.translatesAutoresizingMaskIntoConstraints = false</code></pre><br>
>
>### ✅ view 객체의 위치, 크기 설정하기
`NSLayoutConstraint.activate([뷰 객체의 위치 및 크기])`배열 안에 뷰 객체의 위치와 크기를 설정해야 합니다.
```swift
NSLayoutConstraint.activate([
            // 뷰 객체의 위치 설정
            testView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 30),
            testView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -30),
            testView.topAnchor.constraint(equalTo: view.topAnchor, constant: 200),
>           
            // 뷰 객체의 크기 설정
>            testView.heightAnchor.constraint(equalToConstant: 40)
        ])
```
<br>
>
>### ✅ 종합 코드
```swift
class ViewController: UIViewController {
>
    let testView = UIView()  //testView 객체를 메모리에 올리는 코드 (ViewController에 표시되는 것은 아님!!)
>   
    override func viewDidLoad() {
        super.viewDidLoad()
        makeUI()
    }
>   
    func makeUI(){
        testView.backgroundColor = #colorLiteral(red: 0.501960814, green: 0.501960814, blue: 0.501960814, alpha: 1)
>       
        view.addSubview(testView)  //ViewController에 testView를 올리는 코드(아직 화면에 보이는것은 아님!!)
>       
        // 사용자가 코드로 정의한 Auto Layout 기능 활성화
>       testView.translatesAutoresizingMaskIntoConstraints = false
>       
        NSLayoutConstraint.activate([
            // 뷰 객체의 위치 설정
            testView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 30),
            testView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -30),
            testView.topAnchor.constraint(equalTo: view.topAnchor, constant: 200),
>           
            // 뷰 객체의 크기 설정
>            testView.heightAnchor.constraint(equalToConstant: 40)
        ])
    }
}
```]]></description>
        </item>
        <item>
            <title><![CDATA[ViewController에서 UITextField작업 수행하기]]></title>
            <link>https://velog.io/@shin_ms/ViewController%EC%97%90%EC%84%9C-UITextField%EC%9E%91%EC%97%85-%EC%88%98%ED%96%89%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@shin_ms/ViewController%EC%97%90%EC%84%9C-UITextField%EC%9E%91%EC%97%85-%EC%88%98%ED%96%89%ED%95%98%EA%B8%B0</guid>
            <pubDate>Wed, 04 Jan 2023 13:07:59 GMT</pubDate>
            <description><![CDATA[<h1 id="uitextfield-타입의-간단한-속성-및-기능">UITextField 타입의 간단한 속성 및 기능</h1>
<blockquote>
<p>ViewController내부에서 UITextField타입의 속성을 생성하면 UITextField의 다양한 속성기능을 사용할 수 있습니다.</p>
</blockquote>
<p>해당 작업은 델리게이트 패턴(Delegate Pattern)방식 없이 사용 가능합니다.</p>
<pre><code class="language-swift">// UITextField타입의 속성 생성
@IBOutlet weak var textField: UITextField!
&gt;
// 모바일 키보드를 Email전용 키보드로 변환
textField.keyboardType = .emailAddress
&gt;
// textField에 힌트값 설정
textField.placeholder = &quot;이메일&quot;
&gt;
// textField의 테두리를 둥근 사각형으로 설정
textField.borderStyle = .roundedRect
&gt;
// textField에 값 입력 시 오른쪽에 전체 삭제 버튼 생성
textField.clearButtonMode = .always
&gt;
// 모바일 키보드의 return 버튼을 search로 변경 (기능은 동일)
textField.returnKeyType = .search
&gt;
// 별다른 이벤트없이 앱을 실행하자마자 모바일 키보드를 나타나게 설정 (속성이아닌 메서드)
textField.becomeFirstResponder()</code></pre>
<hr>
<h1 id="uitextfield의-작업을-위임받아-사용">UITextField의 작업을 위임받아 사용</h1>
<p>ViewController에서 UITextField의 작업이 필요한 경우가 종종 있지만, <strong>각각의 객체는 서로 하는 작업이 다르기 때문에 일반적인 방법으로는 UITextField의 작업을 수행할 수 없습니다.</strong></p>
<p>이러한 문제점을 해결하기 위해 만들어진 방법이 <strong><a href="https://velog.io/@shin_ms/%EB%8D%B8%EB%A6%AC%EA%B2%8C%EC%9D%B4%ED%8A%B8-%ED%8C%A8%ED%84%B4-Delegate-Pattern">델리게이트 패턴(Delegate Pattern)</a></strong>입니다.</p>
<h2 id="📌-uitextfielddelegate-프로토콜-채택하기">📌 UITextFieldDelegate 프로토콜 채택하기</h2>
<blockquote>
<p>ViewController에서 UITextField타입의 작업(메서드)을 위임받아 사용하기 위해서는 <code>UITextFieldDelegate</code> 프로토콜을 채택해야 합니다.</p>
<p>위임 프로토콜을 채택해야지만 해당 프로토콜에 정의된 다양한 작업을 위임받아 사용할 수 있습니다.</p>
</blockquote>
<pre><code class="language-swift">class ViewController: UIViewController, UITextFieldDelegate {
...
}</code></pre>
<h2 id="📌-uitextfield의-작업-대리자-설정하기">📌 UITextField의 작업 대리자 설정하기</h2>
<blockquote>
<p><code>.delegate</code>속성을 사용하여 textField의 대리자를 ViewController로 설정해야합니다.</p>
</blockquote>
<pre><code class="language-swift">textField.delegate = self  //textField.delegate = ViewController</code></pre>
<h2 id="📌-uitextfield로부터-위임받은-작업-수행">📌 UITextField로부터 위임받은 작업 수행</h2>
<p>UITextFieldDelegate 프로토콜 내부에 정의되어있는 다양한 작업(메서드 등)을 위임받아서 사용하는 방식입니다.</p>
<blockquote>
<h3 id="✅-텍스트필드의-입력을-시작할-때-호출-시작의-여부를-물어보는-작업">✅ 텍스트필드의 입력을 시작할 때 호출 (시작의 여부를 물어보는 작업)</h3>
</blockquote>
<pre><code class="language-swift">    func textFieldShouldBeginEditing(_ textField: UITextField) -&gt; Bool {
        print(#function)
        return true
    }</code></pre>
<blockquote>
</blockquote>
<br>
>
>### ✅ 텍스트필드의 입력이 시작되면 해당 시점을 호출
```swift
    func textFieldDidBeginEditing(_ textField: UITextField) {
        print(#function)
        print("유저가 텍스트필드에 입력을 시작했습니다.")
    }
```
>
<br>
>
>### ✅ 텍스트필드의 입력값을 한 번에 없에는 버튼을 누를 때 호출
입력값을 한 번에 없에는 버튼은 `textField.clearButtonMode = .always` 코드에 의해 만들어집니다.
``` swift
    func textFieldShouldClear(_ textField: UITextField) -> Bool {
        print(#function)
        return true
    }
```
>
<br>
>
>### ✅ ⭐️텍스트필드에 글자 내용(한 글자 한 글자)이 입력되거나 지워질 때 호출 (입력 허용 여부까지 선택 가능)
```swift
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        print(#function)
        print(string)  // 출력 창에 문자(String type) 하나하나 출력되는걸 확인할 수 있음, 문자열만 출력
        return true
    }    
```
>
<br>
>
**텍스트필드의 입력값을 문자로만 한정하는 코드(숫자 입력을 허용하지 않는 논리식)**
```swift
    if Int(string) != nil {  // (숫자로 변환이 된다면 nil이 아닐테니)
        return false
    }
    else{
    // 10글자이상 입력되는 것을 막는 코드 + 10글자 이하만 받기
        guard let text = textField.text else { return true }
        let newLength = text.count + string.count - range.length
        return newLength <= 10
    }
```
>
><br>
>
>**텍스트필드의 입력값을 10자리로 한정하는 코드**
```swift
    if (textField.text?.count)! + string.count > 10 {
        return false
    } 
    else {
        return true
    }
```
>
<br>
>
>### ✅ 텍스트필드의 엔터(return)키가 눌려질 때 호출(엔터키를 누른 다음 동작의 허용 여부까지 선택 가능)
```swift
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        print(#function)
        if textField.text?.isEmpty == true{
            textField.placeholder = "이메일을 입력하세요"
            return false // 다음동작 허용X
        }
        else{
            return true // 다음동작 허용O
        }
    }
```
>
<br>
>
>### ✅ 텍스트필드의 입력이 끝날 때 호출 (텍스트 필드의 종료 여부를 허락)
```swift
    func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
        print(#function)
        return true
    }
```
>
<br>
>
>### ✅ 텍스트필드의 입력이 실제로 종료되었을 때 종료 시점을 기준으로 호출
```swift
    func textFieldDidEndEditing(_ textField: UITextField, reason: UITextField.DidEndEditingReason) {
        print(#function)
        print("텍스트 필드 입력 종료")
    }
```

<hr>
<h1 id="종합-코드">종합 코드</h1>
<blockquote>
<pre><code class="language-swift">import UIKit
</code></pre>
</blockquote>
<p>class ViewController: UIViewController, UITextFieldDelegate {</p>
<blockquote>
</blockquote>
<pre><code>@IBOutlet weak var textField: UITextField!</code></pre><blockquote>
<pre><code>override func viewDidLoad() {
    super.viewDidLoad()
    view.backgroundColor = UIColor.gray
    textField.placeholder = &quot;email&quot;
    textField.borderStyle = UITextField.BorderStyle.roundedRect
    textField.clearButtonMode = UITextField.ViewMode.always
    textField.keyboardType = .emailAddress
    textField.returnKeyType = .next

    textField.becomeFirstResponder()</code></pre></blockquote>
<pre><code>    textField.delegate = self
}</code></pre><blockquote>
<pre><code>// 텍스트필드의 입력을 시작할때 호출
func textFieldShouldBeginEditing(_ textField: UITextField) -&gt; Bool {
    print(#function)
    return true
}

// 텍스트필드의 입력이 시작되면 호출
func textFieldDidBeginEditing(_ textField: UITextField) {
    print(#function)
}

// 텍스트필드 내용을 삭제할 때 호출
func textFieldShouldClear(_ textField: UITextField) -&gt; Bool {
    print(#function)
    return true
}

// 텍스트필드에 글자내용이 (한글자 한글자) 입력되거나 지워질때 호출
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -&gt; Bool {
    print(#function)
    print(string)
    return true
}

// 텍스트필드의 엔터키가 눌러졌을때 호출
func textFieldShouldReturn(_ textField: UITextField) -&gt; Bool {
    print(#function)
    return true
}

// 텍스트필드의 입력이 끝날때 호출
func textFieldShouldEndEditing(_ textField: UITextField) -&gt; Bool {
    print(#function)
    return true
}

// 텍스트필드의 입력이 실제로 끝났을때 해당 시점에서 호출
func textFieldDidEndEditing(_ textField: UITextField) {
    print(#function)
}</code></pre><p>}
```</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[델리게이트 패턴 (Delegate Pattern)]]></title>
            <link>https://velog.io/@shin_ms/%EB%8D%B8%EB%A6%AC%EA%B2%8C%EC%9D%B4%ED%8A%B8-%ED%8C%A8%ED%84%B4-Delegate-Pattern</link>
            <guid>https://velog.io/@shin_ms/%EB%8D%B8%EB%A6%AC%EA%B2%8C%EC%9D%B4%ED%8A%B8-%ED%8C%A8%ED%84%B4-Delegate-Pattern</guid>
            <pubDate>Sun, 01 Jan 2023 14:08:09 GMT</pubDate>
            <description><![CDATA[<h1 id="델리게이트-패턴-delegate-pattern">델리게이트 패턴 (Delegate Pattern)</h1>
<p><strong>델리게이트 패턴(위임 패턴)</strong>은 서로 다른 객체 간의 원활한 작업 및 원하는 결과를 얻기 위해 만들어진 디자인 패턴입니다. </p>
<p>델리게이트 패턴의 원리를 설명하자면 이래와 같습니다.</p>
<blockquote>
<p><img src="https://velog.velcdn.com/images/shin_ms/post/25cd0720-8733-45c2-8179-24a83a15ecbc/image.png" alt=""></p>
</blockquote>
<p>위 그림은 A객체만이 할 수 있는 작업(메서드 등)을 B객체가 할 수 있도록 위임해주는 델리게이트 패턴을 간단하게 시각화한 것입니다.</p>
<blockquote>
</blockquote>
<p><strong>A객체의 작업을 B객체에서도 할 수 있도록 도와주는(연결해주는) 연결고리가 필요한데, 이러한 연결고리 역할을 A객체의 <code>delegate</code> 속성이 하고 있습니다.</strong></p>
<hr>
<h2 id="📌-델리게이트-패턴-구현">📌 델리게이트 패턴 구현</h2>
<p>서로 다른 작업을 하는 <strong>에어컨 객체</strong>와 <strong>리모컨 객체</strong>가 있다고 가정한 뒤 코드를 구현해보겠습니다.</p>
<ul>
<li><p><strong>에어컨 객체가 하는 일</strong></p>
<ul>
<li>원하는 온도의 바람 출력</li>
<li>에어컨 필터 청소</li>
</ul>
<br>
</li>
<li><p><strong>리모컨 객체가 하는 일</strong></p>
<ul>
<li>원하는 온도의 바람 설정</li>
<li>에어컨 필터 청소 설정</li>
</ul>
</li>
</ul>
<blockquote>
<h3 id="✅-위임-프로토콜-구현">✅ 위임 프로토콜 구현</h3>
<p>위임 프로토콜을 채택한 타입의 객체만이 프로토콜의 기능(작업)을 수행할 수 있습니다.</p>
</blockquote>
<pre><code class="language-swift">@objc protocol AirconRemoteControlDelegate{
    @objc optional func windTemperatureUp()     // 에어컨 바람 온도 조절 기능
    @objc optional func windTemperatureDown()   // 에어컨 바람 온도 조절 기능
    @objc optional func autoFilterCleaning()    // 에어컨 자동 청소 기능
}</code></pre>
<blockquote>
<h3 id="✅-리모컨-타입-구현">✅ 리모컨 타입 구현</h3>
<p>리모컨 타입을 정의할 때는 <strong>다른 객체에서 리모컨 타입의 작업을 수행할 수 있도록 delegate속성을 정의</strong>했습니다.</p>
</blockquote>
<p>delegate속성의 타입은 프로토콜 타입(AirconRemoteControlDelegate)으로 정의하여 해당 프로토콜을 채택한 타입의 객체가 작업을 위임받을 수 있도록 해야 합니다.</p>
<pre><code class="language-swift">class AirconRemoteControl{
    // ⭐️ 리모컨 객체의 작업을 에어컨 객체에서도 할 수 있도록 delegate 속성 정의
    var delegate: AirconRemoteControlDelegate? 
&gt;
    func windTemperatureUp(){    // 바람 온도 올리기
        delegate?.windTemperatureUp!()
    }
    func windTemperatureDown(){  // 바람 온도 내리기
        delegate?.windTemperatureDown!()
    }
    func autoFilterCleaning(){  // 바람 온도 내리기
        delegate?.autoFilterCleaning!()
    }
}</code></pre>
<blockquote>
<h3 id="✅-에어컨-타입-구현">✅ 에어컨 타입 구현</h3>
<p>에어컨 타입은 위임 <strong>프로토콜(AirconRemoteControlDelegate)을 채택하여 리모컨의 작업을 위임받도록 해야 합니다.</strong></p>
</blockquote>
<p>@objc, optional 키워드를 사용하여 프로토콜을 정의했기 때문에 기능을 선택적으로 구현할 수 있습니다.</p>
<pre><code class="language-swift">class Aircon: AirconRemoteControlDelegate{
    func windTemperatureUp() {
        print(&quot;삐빅 (에어컨 바람의 온도가 올라갔습니다.)&quot;)
    }
    func windTemperatureDown() {
        print(&quot;삐빅 (에어컨 바람의 온도가 내려갔습니다.)&quot;)
    }
//    func autoFilterCleaning() {  // 생략 가능
//        print(&quot;삐빅 (에어컨 필터를 청소합니다.)&quot;)
//    }
}</code></pre>
<blockquote>
<h3 id="✅-리모컨의-작업-위임받아-실행">✅ 리모컨의 작업 위임받아 실행</h3>
<p>각각의 타입으로부터 생성된 LG에어컨 객체와 LG리모컨 객체는 하는 작업이 서로 다릅니다.</p>
</blockquote>
<p><strong>하지만 LG리모컨의 작업을 LG에어컨에게 위임하는 코드(<code>LG_RemoteControl.delegate = LG_Aircon</code>)를 작성하면 에어컨 객체에서도 LG리모컨의 작업을 수행할 수 있습니다.</strong></p>
<pre><code class="language-swift">let LG_RemoteControl = AirconRemoteControl()
let LG_Aircon = Aircon()
&gt;
//⭐️ 리모컨의 작업을 에어컨에게 위임!! ⭐️  즉, LG_Aircon에서 LG_RemoteControl 작업 실행 가능
LG_RemoteControl.delegate = LG_Aircon    
&gt;
LG_RemoteControl.windTemperatureUp()    // 삐빅 (에어컨 바람의 온도가 올라갔습니다.)
LG_RemoteControl.windTemperatureDown()  // 삐빅 (에어컨 바람의 온도가 내려갔습니다.)</code></pre>
<blockquote>
<h3 id="✅-종합적인-코드">✅ 종합적인 코드</h3>
</blockquote>
<pre><code class="language-swift">@objc protocol AirconRemoteControlDelegate{
    @objc optional func windTemperatureUp()     // 에어컨 바람 온도 조절 기능
    @objc optional func windTemperatureDown()
    @objc optional func autoFilterCleaning()    // 에어컨 자동 청소 기능
}
&gt;
class AirconRemoteControl{
    // 리모컨 객체의 작업을 에어컨 객체에서도 할 수 있도록 delegate 속성 정의
    var delegate: AirconRemoteControlDelegate?
&gt;
    func doSomething(){
        print(&quot;리모컨에 특정 이벤트가 발생했습니다.&quot;)
    }
&gt;
    func windTemperatureUp(){    // 바람 온도 올리기
        delegate?.windTemperatureUp!()
    }
    func windTemperatureDown(){  // 바람 온도 내리기
        delegate?.windTemperatureDown!()
    }
    func autoFilterCleaning(){  // 바람 온도 내리기
        delegate?.autoFilterCleaning!()
    }
}
&gt;
class Aircon: AirconRemoteControlDelegate{
    func windTemperatureUp() {
        print(&quot;삐빅 (에어컨 바람의 온도가 올라갔습니다.)&quot;)
    }
    func windTemperatureDown() {
        print(&quot;삐빅 (에어컨 바람의 온도가 내려갔습니다.)&quot;)
    }
//    func autoFilterCleaning() {  // 생략 가능
//        print(&quot;삐빅 (에어컨 필터를 청소합니다.)&quot;)
//    }
}
&gt;
let LG_RemoteControl = AirconRemoteControl()
let LG_Aircon = Aircon()
&gt;
LG_RemoteControl.delegate = LG_Aircon    //⭐️ 리모컨의 작업을 에어컨에게 위임!! ⭐️  -&gt; LG_Aircon에서 LG_RemoteControl 작업 실행 가능
&gt;
LG_RemoteControl.windTemperatureUp()    // 삐빅 (에어컨 바람의 온도가 올라갔습니다.)
LG_RemoteControl.windTemperatureDown()  // 삐빅 (에어컨 바람의 온도가 내려갔습니다.)</code></pre>
<hr>
<h2 id="📢-요약-설명">📢 요약 설명</h2>
<blockquote>
<p>각각의 타입으로부터 생성된 LG에어컨 객체와 LG리모컨 객체는 하는 작업이 서로 다릅니다.</p>
</blockquote>
<p><span style="color:red">리모컨의 주된 작업은 에어컨의 온도 설정</span>이고, <span style="color:blue">에어컨의 주된 작업은 설정된 온도의 바람 출력</span>입니다. (<strong>각 객체의 작업은 서로 밀접한 관계를 가지고 있지만 엄연히 다른 성격의 작업입니다</strong>)</p>
<blockquote>
</blockquote>
<h3 id="이제-에어컨-사용자가-리모컨을-사용하여-바람의-온도를-높인다고-가정해보자"><em>이제 에어컨 사용자가 리모컨을 사용하여 바람의 온도를 높인다고 가정해보자</em></h3>
<blockquote>
</blockquote>
<p>에어컨과 리모컨은 서로 다른 객체이기 때문에 에어컨 객체에서 리모컨 객체의 작업을 입력받을 수 없습니다. <strong>즉, 에어컨은 리모컨의 동작(작업)을 알 수 없음</strong></p>
<blockquote>
</blockquote>
<p>때문에 <strong>에어컨 객체에서 리모컨의 온도 설정 작업을 입력받아 사용할 수 있도록 리모컨 작업을 위임받아 사용</strong>해야 합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[iOS의 프레임워크(Framework)]]></title>
            <link>https://velog.io/@shin_ms/iOS%EC%9D%98-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%ACFramework</link>
            <guid>https://velog.io/@shin_ms/iOS%EC%9D%98-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%ACFramework</guid>
            <pubDate>Thu, 29 Dec 2022 10:43:56 GMT</pubDate>
            <description><![CDATA[<h1 id="프레임워크framework">프레임워크(Framework)</h1>
<p>App을 개발할 때는 해당 App의 목적과 특징에 따라 작업 규칙이 달라지는데, 이러한 <strong>작업 규칙을 프레임워크(Framework)라 부릅니다.</strong></p>
<hr>
<h1 id="ios의-프레임워크framework-계층">iOS의 프레임워크(Framework) 계층</h1>
<p>iOS의 프레임워크(Framework)는 4계층으로 나뉘어 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/shin_ms/post/160f5187-8036-40a4-b071-b90356c7b644/image.png" alt=""></p>
<p>App과 가까운 계층(상위 계층)일수록 App/사용자 구현 기능 및 처리 방법 등이 담겨있습니다.</p>
<p>반대로 H/W(하드웨어)와 가까운 계층(하위 계층)일수록 H/W(하드웨어)/운영체제 구현 기능 및 처리 방법 등이 담겨있습니다.</p>
<h2 id="📌-cocoa-touch-framework-계층">📌 Cocoa Touch Framework 계층</h2>
<p>Cocoa Touch Framework는 최상위 계층의 프레임워크이며, <strong>App 개발에 있어 기초적인/필수적인 기능 등을 제공해주는 프레임워크</strong>입니다.</p>
<blockquote>
<h3 id="⚙️-cocoa-touch-framework의-종류">⚙️ Cocoa Touch Framework의 종류</h3>
</blockquote>
<ul>
<li><strong>⭐️UIKit</strong> : 사용자에 의해 발생하는 이벤트, UI(화면)와 관련된 작업등을 처리할 때 사용합니다.<blockquote>
</blockquote>
(참고: UIkit 프레임워크 안에는 Foundation 프레임워크가 내포되어 있으므로 <strong>UIkit 프레임워크만 선언하면 Foundation 프레임워크의 기능을 사용할 수 있습니다.</strong>)<br>
></li>
<li>AddressBookUI: 주소록 관련 처리</li>
<li>EventKitUI: 달력과 일정 관련 처리</li>
<li>GameKit: 게임 관련 처리</li>
<li>MapKit: 위치, 지도 관련 처리</li>
<li>NotificationCenter: 노티피케이션 관련 처리
...</li>
</ul>
<hr>
<h2 id="📌-media-framework-계층">📌 Media Framework 계층</h2>
<p>Media Framework는 <strong>미디어/그래픽 (이미지, 영상) 관련 기능 등을 제공해주는 프레임워크</strong>입니다.</p>
<blockquote>
<h3 id="⚙️-media-framework의-종류">⚙️ Media Framework의 종류</h3>
</blockquote>
<ul>
<li>Photos: 사진 관련 처리</li>
<li>CoreGraphics: 2D 화면 그리기 관련 처리</li>
<li>AssetsLibrary: 앨범 관련 처리</li>
<li>AVFoundation: 영상 관련 처리
...</li>
</ul>
<hr>
<h2 id="📌-core-services-framework-계층">📌 Core Services Framework 계층</h2>
<p>Core Services Framework는 <strong>각종 시스템 설정 및 데이터 접근 서비스 등을 제공해주는 프레임워크</strong>입니다.
(문자열 처리, 데이터 접근, 네트워크, 주소록 관리, 환경 설정 등의 기능을 제공)</p>
<blockquote>
<h3 id="⚙️-core-services-framework의-종류">⚙️ Core Services Framework의 종류</h3>
</blockquote>
<ul>
<li><strong>⭐️Foundation</strong>: 문자열, 날짜 처리, 런루프, GCD, 쓰레드, URL 작업등을 처리할 때 사용합니다.<blockquote>
</blockquote>
(참고: <strong>Objective - C 언어와 관련된 기능 또는 NS가 붙은 타입을 사용할 때는 Foundation 프레임워크를 선언</strong>해야 합니다.)<blockquote>
</blockquote>
</li>
<li>Webkit: HTML 관련 처리</li>
<li>CloudKit: iCloud 연동 처리</li>
<li>CoreLocation: 위치, 방향 정보 처리 </li>
<li>StoreKit: In-App Purchase구현
...</li>
</ul>
<hr>
<h2 id="📌-core-os-framework-계층">📌 Core O/S Framework 계층</h2>
<p>Core O/S Framework는 최하위 계층의 프레임워크이며, <strong>보안 서비스 및 하드웨어 기기와의 연동 서비스 등을 제공해주는 프레임워</strong>크입니다.</p>
<blockquote>
<h3 id="⚙️-core-os-framework의-종류">⚙️ Core O/S Framework의 종류</h3>
</blockquote>
<ul>
<li>CoreBluetooth: 블루투스 연결 관련 처리 </li>
<li>LocalAuthentication: TouchID, 사용자 인증 관련 처리</li>
<li>Security: 키체인 및 인증서 관련 보안 처리
...</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[컬렉션] - 세트(Set)]]></title>
            <link>https://velog.io/@shin_ms/%EC%BB%AC%EB%A0%89%EC%85%98-%EC%84%B8%ED%8A%B8Set</link>
            <guid>https://velog.io/@shin_ms/%EC%BB%AC%EB%A0%89%EC%85%98-%EC%84%B8%ED%8A%B8Set</guid>
            <pubDate>Sat, 24 Dec 2022 09:24:20 GMT</pubDate>
            <description><![CDATA[<h1 id="세트set">세트(Set)</h1>
<p><strong>수학에서 사용하는 집합과 동일한 기능(교집합, 차집합 등...)을 제공하는 컬렉션 타입</strong>입니다. </p>
<p>세트(Set)는 <strong>데이터의 순서를 고려하지 않으며, 데이터는 중복을 허용하지 않습니다.</strong>(세트안에 중복 값이 있으면 1개의 값으로 취급)</p>
<p>세트안에 들어가는 데이터는 Hashable 프로토콜을 채택한 자료형(Swift의 기본 자료형 등...)만 저장할 수 있다.(Hashble한 타입: 값의 고정된 길이와 유일성을 보장해주는 타입)</p>
<hr>
<h2 id="📌-세트-만들기">📌 세트 만들기</h2>
<blockquote>
<h3 id="✅-빈-세트-만들기">✅ 빈 세트 만들기</h3>
</blockquote>
<pre><code class="language-swift">var st1 = Set&lt;Int&gt;()
var st2: Set&lt;Int&gt; = []</code></pre>
<hr>
<h2 id="📌-세트에-데이터-추가하기">📌 세트에 데이터 추가하기</h2>
<p>세트는 순서를 고려하지 않는 컬렉션 타입이기 때문에 <code>append(), insert()</code> 같은 메서드는 존재하지 않습니다.</p>
<p>대신 <strong><code>update(with: 값)</code> 메서드를 사용하여 데이터를 추가</strong>합니다.</p>
<blockquote>
<h3 id="✅-세트에-데이터-추가">✅ 세트에 데이터 추가</h3>
</blockquote>
<pre><code class="language-swift">st.update(with: 1)  //세트에 값 1 추가</code></pre>
<hr>
<h2 id="📌-세트에-데이터-삭제하기">📌 세트에 데이터 삭제하기</h2>
<blockquote>
<h3 id="✅-세트의-데이터-삭제">✅ 세트의 데이터 삭제</h3>
</blockquote>
<pre><code class="language-swift">st.remove(1)    // 데이터 1 삭제
st.removeAll()  // 모든 데이터 삭제</code></pre>
<hr>
<h2 id="📌-세트의-데이터-접근-및-추출">📌 세트의 데이터 접근 및 추출</h2>
<p><strong>세트는 배열의 인덱스(index), 또는 딕셔너리의 키(key)처럼 데이터를 지목할 수 있는 기능이 없기 때문에 첨자(subscript)를 활용하여 데이터에 접근하는 것이 불가능</strong>합니다.</p>
<hr>
<h2 id="📌-세트의-데이터-정렬">📌 세트의 데이터 정렬</h2>
<p>세트에서도 정렬이 가능하지만, 정렬할 때는 세트(Set)에서 배열(Array)로 전환되어 반환됩니다.</p>
<p>또한 세트는 순서가 없는 컬렉션 타입이기 때문에 원본을 변경하는 정렬 기능은 없습니다.</p>
<blockquote>
<h3 id="✅-세트의-데이터-정렬">✅ 세트의 데이터 정렬</h3>
</blockquote>
<pre><code class="language-swift">st.sorted()       // 오름차순
st.sorted(by: &lt;)  // 오름차순
st.sorted(by: &gt;)  // 내림차순</code></pre>
<hr>
<h2 id="📌-세트의-최대최소값-데이터">📌 세트의 최대/최소값 데이터</h2>
<p>세트에 할당된 데이터의 최대/최소값을 알고 싶을 때는 <code>max(), min()</code> 메서드를 사용합니다.</p>
<p>세트의 최대/최소값 메서드를 사용하면 반환 값을 <strong>Optional(옵셔널) 타입으로 받게 됩니다. 이는 빈 세트의 가능성 때문</strong>입니다. (빈 세트에 <code>max(), min()</code> 메서드를 사용하면 nil이 출력)</p>
<blockquote>
<h3 id="✅-세트의-최대최소값">✅ 세트의 최대/최소값</h3>
</blockquote>
<pre><code class="language-swift">st.max()  // 최대값
st.min()  // 최소값</code></pre>
<hr>
<h2 id="📌-세트의-집합-연산">📌 세트의 집합 연산</h2>
<p><span style="color:red"><strong>Swift에서 세트(Set)는 유일하게? 집합 연산 메서드를 지원하는 타입</strong></span>입니다.</p>
<p>대표적인 집합 연산 메서드로는 아래와 같습니다.</p>
<blockquote>
<h3 id="✅-합집합">✅ 합집합</h3>
</blockquote>
<pre><code class="language-swift">st1.union(st2)   //st1세트와 st2세트를 합친결과를 return</code></pre>
<h3 id="✅-교집합">✅ 교집합</h3>
<pre><code class="language-swift">st1.intersection(st2)    //st1세트와 st2세트의 공통부분을 return</code></pre>
<h3 id="✅-차집합">✅ 차집합</h3>
<pre><code class="language-swift">st1.subtracting(st2)     //합집합에서 교집합을 뺀 부분을 return</code></pre>
<h3 id="✅-여집합">✅ 여집합</h3>
<pre><code class="language-swift">st1.symmetricDifference(st2)   //st1세트에서 st2세트를 뺀 결과를 return</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[컬렉션] - 딕셔너리(Dictionary)]]></title>
            <link>https://velog.io/@shin_ms/%EC%BB%AC%EB%A0%89%EC%85%98-%EB%94%95%EC%85%94%EB%84%88%EB%A6%ACDictionary</link>
            <guid>https://velog.io/@shin_ms/%EC%BB%AC%EB%A0%89%EC%85%98-%EB%94%95%EC%85%94%EB%84%88%EB%A6%ACDictionary</guid>
            <pubDate>Fri, 23 Dec 2022 13:59:38 GMT</pubDate>
            <description><![CDATA[<h1 id="딕셔너리dictionary">딕셔너리(Dictionary)</h1>
<p>딕셔너리(Dictionary)는 <strong>키값(key)과 벨류값(value)을 쌍으로 갖는 컬렉션 타입</strong>입니다.</p>
<p>딕셔너리 내부의 <strong>키값은 고유한(유일한) 값</strong>을 가져야 하지만, <strong>벨류값은 중복을 허용</strong>하고 있습니다.</p>
<p><strong>딕셔너리는 고유한 키값을 가지고 있기 때문에 순서를 고려하지 않습니다.</strong></p>
<p>딕셔너리의** 키값은 Hashble한 타입을 사용해야 합니다.** Swift의 기본 타입(String, Int, Double, Bool 등)은 Hashble 가능하므로 Dictionary의 key로 사용할 수 있습니다.
(Hashble한 타입: 값의 고정된 길이와 유일성을 보장해주는 타입)</p>
<hr>
<h2 id="📌-딕셔너리-만들기">📌 딕셔너리 만들기</h2>
<p>딕셔너리에는 두 개의 값이 존재하며 각각의 위치가 정해져 있습니다.** 키값(key)은 왼쪽 그리고 데이터값(value)은 오른쪽에 정의**합니다.</p>
<p>딕셔너리를 만드는 대표적인 방법으로는 세 가지가 존재합니다.</p>
<blockquote>
<h3 id="✅-빈-딕셔너리-만들기">✅ 빈 딕셔너리 만들기</h3>
</blockquote>
<pre><code class="language-swift">// [키:벨류]
var dic1 = [Int: String]()
var dic2: Dictionary&lt;Int, String&gt; = [:]
var dic3 = Dictionary&lt;Int, String&gt;()</code></pre>
<blockquote>
</blockquote>
<h3 id="✅-초기값이-있는-딕셔너리-만들기">✅ 초기값이 있는 딕셔너리 만들기</h3>
<pre><code class="language-swift">var dic1 : [Int:String] = [1:&quot;일&quot;, 2:&quot;이&quot;, 3:&quot;삼&quot;]
var dic2 : Dictionary&lt;Int, String&gt; = [1:&quot;일&quot;, 2:&quot;이&quot;, 3:&quot;삼&quot;]
var dic3 = [1:&quot;일&quot;, 2:&quot;이&quot;, 3:&quot;삼&quot;]</code></pre>
<hr>
<h2 id="📌-딕셔너리에-데이터-추가하기">📌 딕셔너리에 데이터 추가하기</h2>
<p>데이터를 추가할 때는 <code>updateValue(&lt;벨류값&gt;, forKey:&lt;키값&gt;)</code>를 사용합니다.</p>
<p>*<em>딕셔너리에는 중간에 데이터를 추가하는 메서드가 존재하지 않습니다.(순서를 고려하지 않기 때문) *</em>그 때문에 데이터를 추가하는 메서드는 <code>updateValue()</code> 하나뿐입니다.</p>
<blockquote>
<h3 id="✅-딕셔너리에-데이터-추가">✅ 딕셔너리에 데이터 추가</h3>
</blockquote>
<pre><code class="language-swift">dic.updateValue(2, forKey:&quot;일&quot;)</code></pre>
<hr>
<h2 id="📌-딕셔너리에-데이터-삭제하기">📌 딕셔너리에 데이터 삭제하기</h2>
<p>딕셔너리에 데이터를 삭제하는 방법은 크게 두 가지가 존재합니다. (순서를 고려하지 않기 때문에 삭제 메서드가 적습니다.)</p>
<blockquote>
<h3 id="✅-딕셔너리에-데이터-삭제">✅ 딕셔너리에 데이터 삭제</h3>
</blockquote>
<pre><code class="language-swift">dic.removeValue(forKey: 키값)  // 키값을 기준으로 데이터 삭제</code></pre>
<blockquote>
</blockquote>
<h3 id="✅-딕셔너리의-모든-데이터-삭제">✅ 딕셔너리의 모든 데이터 삭제</h3>
<pre><code class="language-swift">dic.removeAll() </code></pre>
<hr>
<h2 id="📌-딕셔너리의-데이터-접근-및-추출">📌 딕셔너리의 데이터 접근 및 추출</h2>
<p>딕셔너리에서 특정 데이터를 추출할 때는 <code>dic[keyValue]</code> 방식으로 접근할 수 있습니다.
<strong>(value를 활용하여 key값을 접근할 수는 없습니다.)</strong></p>
<p>딕셔너리의 모든 키값을 추출하고 싶을 때는 <code>.keys</code> 속성을 사용합니다.</p>
<p>딕셔너리의 모든 값(value)을 추출하고 싶을 때는 <code>.values</code> 속성을 사용합니다.</p>
<blockquote>
<h3 id="✅-딕셔너리의-모든-key값-추출">✅ 딕셔너리의 모든 key값 추출</h3>
</blockquote>
<pre><code class="language-swift">dic.keys</code></pre>
<blockquote>
</blockquote>
<h3 id="✅-딕셔너리의-모든-value값-추출">✅ 딕셔너리의 모든 value값 추출</h3>
<pre><code class="language-swift">dic.values</code></pre>
<hr>
<h2 id="📌-딕셔너리의-데이터-정렬">📌 딕셔너리의 데이터 정렬</h2>
<p>딕셔너리에서 <strong>원본값을 변경하는 정렬은 없으며</strong>, <strong>key값 또는 value값을 나누어 정렬해야 합니다.</strong> (동시 비교는 불가능하지만, 키값을 기준으로 정렬한 뒤 value값과 같이 반환하는 방법은 있습니다.)</p>
<blockquote>
<h3 id="✅-key값을-기준으로-정렬">✅ key값을 기준으로 정렬</h3>
</blockquote>
<pre><code class="language-swift">dic.keys.sorted()       // 오름차순
dic.keys.sorted(by: &lt;)  // 오름차순
dic.keys.sorted(by: &gt;)  // 내림차순</code></pre>
<blockquote>
</blockquote>
<h3 id="✅-value값을-기준으로-정렬">✅ value값을 기준으로 정렬</h3>
<pre><code class="language-swift">dic.values.sorted()       // 오름차순
dic.values.sorted(by: &lt;)  // 오름차순
dic.values.sorted(by: &gt;)  // 내림차순</code></pre>
<blockquote>
</blockquote>
<h3 id="✅-key값을-기준으로-정렬-value값과-같이-반환">✅ key값을 기준으로 정렬 (value값과 같이 반환)</h3>
<pre><code class="language-swift">dic.sorted(by: &lt;)  // 오름차순 
dic.sorted(by: &gt;)  // 내림차순</code></pre>
<hr>
<h2 id="📌-딕셔너리의-최대최소값-데이터">📌 딕셔너리의 최대/최소값 데이터</h2>
<p>딕셔너리에 할당된 데이터의 최대/최소값을 알고 싶을 때는 <code>max()</code>, <code>min()</code> 메서드를 사용합니다.</p>
<p>딕셔너리의 <strong>최대/최소값 메서드를 사용하면 반환 값을 Optional(옵셔널) 타입으로 받게 됩니다. 이는 빈 딕셔너리의 가능성 때문</strong>입니다. (빈 딕셔너리에 <code>max()</code>, <code>min()</code> 메서드를 사용하면 nil이 출력)</p>
<p>문자(Character), 문자열(String)이 할당된 딕셔너리의 경우에는 유니코드 값을 기준으로 최대/최소값이 반환됩니다.</p>
<blockquote>
<h3 id="✅-key값-기준의-최대최소값">✅ key값 기준의 최대/최소값</h3>
</blockquote>
<pre><code class="language-swift">dic.keys.min()    // key값의 최소값
dic.keys.max()    // key값의 최대값</code></pre>
<blockquote>
</blockquote>
<h3 id="✅-value값-기준의-최대최소값">✅ value값 기준의 최대/최소값</h3>
<pre><code class="language-swift">dic.values.min()  // value값의 최소값
dic.values.max()  // value값의 최대값</code></pre>
<blockquote>
</blockquote>
<h3 id="✅-key값을-기준의-최대최소값-value값과-같이-반환">✅ key값을 기준의 최대/최소값 (value값과 같이 반환)</h3>
<pre><code class="language-swift">dic.max(by: &lt;)  // 키값 기준 최대값
dic.max(by: &gt;)  // 키값 기준 최소값
&gt;
dic.min(by: &lt;)  // 키값 기준 최소값
dic.min(by: &gt;)  // 키값 기준 최대값</code></pre>
<hr>
<h2 id="📌-그-외-딕셔너리의-기타-기능">📌 그 외 딕셔너리의 기타 기능</h2>
<blockquote>
<h3 id="✅-딕셔너리의-데이터-수를-반환">✅ 딕셔너리의 데이터 수를 반환</h3>
</blockquote>
<pre><code class="language-swift">dic.count      // 딕셔너리의 데이터 수를 return</code></pre>
<blockquote>
</blockquote>
<h3 id="✅-딕셔너리에-데이터-여부-확인">✅ 딕셔너리에 데이터 여부 확인</h3>
<pre><code class="language-swift">dic.isEmpty    // 딕셔너리안에 데이터가 없으면 true, 있으면 false return</code></pre>
<p>이 외에도 딕셔너리에서 사용 가능한 메서드 및 기능들이 많이 있습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[컬렉션] - 배열(Array)]]></title>
            <link>https://velog.io/@shin_ms/%EC%BB%AC%EB%A0%89%EC%85%98-%EB%B0%B0%EC%97%B4Array</link>
            <guid>https://velog.io/@shin_ms/%EC%BB%AC%EB%A0%89%EC%85%98-%EB%B0%B0%EC%97%B4Array</guid>
            <pubDate>Fri, 23 Dec 2022 12:26:25 GMT</pubDate>
            <description><![CDATA[<h1 id="배열array">배열(Array)</h1>
<p>배열(Array)은 Swift뿐만 아니라 모든 프로그래밍 언어를 통틀어서 가장 많이 사용하는 <strong>컬렉션(Collection) 타입</strong>입니다.</p>
<p><strong>배열은 순서가 있는 컬렉션 타입</strong>이기 때문에 값의 <strong>중복을 허용</strong>합니다. 또한 같은 <strong>배열에는 동일한 데이터 타입만 할당</strong>할 수 있습니다. <del>(Any타입을 사용하면 모든 타입 가능하긴 하지만... 추천하는 방법은 아닙니다...)</del></p>
<p><strong>배열 공간에는 각각의 인덱스 번호가 부여</strong>됩니다. 인덱스 번호는 0부터 시작되며, 각각의 인덱스 번호는 순서(오름차순)가 존재합니다.</p>
<h2 id="📌-빈-배열-만들기">📌 빈 배열 만들기</h2>
<p>빈 배열을 만드는 대표적인 방법으로는 세 가지가 존재합니다.</p>
<blockquote>
<h3 id="✅-빈-배열-만들기">✅ 빈 배열 만들기</h3>
</blockquote>
<pre><code class="language-swift">var arr1 = [Int]()
var arr2: [Int] = []
var arr3 = Array&lt;Int&gt;()</code></pre>
<hr>
<h2 id="📌-배열에-데이터-추가하기">📌 배열에 데이터 추가하기</h2>
<p>데이터를 추가할 때는 <code>append(추가할 값)</code> 메서드를 사용합니다.</p>
<p>배열 중간에 데이터를 추가할 때는 <code>insert(추가할 값, at: 추가될 인덱스)</code> 메서드를 사용합니다.</p>
<blockquote>
<h3 id="✅-배열에-데이터-추가">✅ 배열에 데이터 추가</h3>
</blockquote>
<pre><code class="language-swift">// 배열에 값을 추가할 때는 append(&lt;값&gt;)를 사용한다.
// 배열 중간에 값을 추가 할 때는 insert(&lt;값&gt;, at:&lt;인덱스&gt;)
var arr = [1,2,3,4]
&gt;
arr.append(5)         // [1, 2, 3, 4, 5]
arr.insert(0, at: 0)  // [0, 1, 2, 3, 4, 5]</code></pre>
<hr>
<h2 id="📌-배열에-데이터-삭제하기">📌 배열에 데이터 삭제하기</h2>
<p>배열에 데이터를 삭제하는 방법은 크게 네 가지가 존재합니다.</p>
<blockquote>
<h3 id="✅-특정-인덱스의-데이터를-삭제">✅ 특정 인덱스의 데이터를 삭제</h3>
</blockquote>
<pre><code class="language-swift">arr.remove(at:n)   //배열의 n번째 값을 삭제</code></pre>
<blockquote>
<h3 id="✅-배열의-모든-데이터를-삭제">✅ 배열의 모든 데이터를 삭제</h3>
</blockquote>
<pre><code class="language-swift">arr.removeAll()</code></pre>
<blockquote>
<h3 id="✅-배열의-첫-번째-데이터을-삭제">✅ 배열의 첫 번째 데이터을 삭제</h3>
</blockquote>
<pre><code class="language-swift">arr.removeFirst()
arr.removeFirst(n)  // 배열의 첫 번째(0)부터 n개 삭제 </code></pre>
<blockquote>
<h3 id="✅-배열의-마지막-데이터를-삭제">✅ 배열의 마지막 데이터를 삭제</h3>
</blockquote>
<pre><code class="language-swift">arr.removeLast()
arr.removeLast(n)  // 배열의 마지막 번째부터 n개 삭제 </code></pre>
<hr>
<h2 id="📌-배열의-데이터-정렬">📌 배열의 데이터 정렬</h2>
<p>배열에서는 <strong>오름차순, 내림차순, 역순(반대) 정렬</strong>을 할 수 있는 메서드가 존재합니다.</p>
<blockquote>
<h3 id="✅-오름차순-정렬">✅ 오름차순 정렬</h3>
<p>오름차순 정렬 메서드는 <code>sort()</code> == <code>sort(by:&lt;)</code>이 있습니다.</p>
</blockquote>
<pre><code class="language-swift">arr.sort()  ==  arr.sort(by:&lt;)</code></pre>
<p>오름차순의 정렬 결과를 리턴하고, 원본을 그대로 하고 싶을 때는 <code>sorted()</code> 메서드를 사용합니다.</p>
<pre><code class="language-swift">arr.sorted(by:&lt;)  ==  arr.sorted(by:&lt;)</code></pre>
<blockquote>
<h3 id="✅-내림차순-정렬">✅ 내림차순 정렬</h3>
<p>내림차순 정렬 메서드는 <code>sort(by:&gt;)</code>이 있습니다.</p>
</blockquote>
<pre><code class="language-swift">arr.sort(by:&gt;)</code></pre>
<p>내림차순의 정렬 결과를 리턴하고, 원본을 그대로 하고 싶을 때는 <code>sorted(by:&gt;)</code> 메서드를 사용합니다.</p>
<pre><code class="language-swift">arr.sorted(by:&gt;)</code></pre>
<blockquote>
<h3 id="✅-역순반대-정렬">✅ 역순(반대) 정렬</h3>
<p>역순(반대) 정렬 메서드는 <code>reverse()</code>이 있습니다.</p>
</blockquote>
<pre><code class="language-swift">arr.reverse()</code></pre>
<p>역순(반대) 정렬 결과를 리턴하고, 원본을 그대로 하고 싶을 때는 <code>reversed()</code> 메서드를 사용합니다.</p>
<pre><code class="language-swift">arr.reversed()</code></pre>
<hr>
<h2 id="📌-배열의-최대최소값-데이터">📌 배열의 최대/최소값 데이터</h2>
<p>배열에 할당된 데이터의 최대/최소값을 알고 싶을 때는 <code>max(), min()</code> 메서드를 사용합니다.</p>
<p>배열의 최대/최소값 메서드를 사용하면 <strong>반환 값을 Optional(옵셔널) 타입으로 받게 됩니다. 이는 빈 배열의 가능성 때문</strong>입니다. (빈 배열에 <code>max(), min()</code> 메서드를 사용하면 nil이 출력)</p>
<p>문자(Character), 문자열(String)이 할당된 배열의 경우에는 유니코드 값을 기준으로 최대/최소값이 반환됩니다.</p>
<blockquote>
<h3 id="✅-배열의-최대값">✅ 배열의 최대값</h3>
</blockquote>
<pre><code class="language-swift">arr.max()     // 배열의 최대값 return</code></pre>
<blockquote>
<h3 id="✅-배열의-최소값">✅ 배열의 최소값</h3>
</blockquote>
<pre><code class="language-swift">arr.min()     // 배열의 최솟값 return</code></pre>
<hr>
<h2 id="📌-배열에-특정값repeating을-원하는-개수count만큼-초기화">📌 배열에 특정값(repeating)을 원하는 개수(count)만큼 초기화</h2>
<p>배열은 <code>repeating:</code>키워드와 <code>count:</code>키워드를 사용하여 특정 값을 원하는 개수만큼 초기화할 수 있습니다.</p>
<blockquote>
<h3 id="✅-특정값을-원하는-개수만큼-초기화">✅ 특정값을 원하는 개수만큼 초기화</h3>
</blockquote>
<pre><code class="language-swift">var x1 = Array(repeating: 1, count: 4)
var x2 = [Int](repeating:2, count: 4)
&gt;
print(x,x1,x2)
&gt;
/*
출력 결과
[1, 1, 1, 1] [2, 2, 2, 2]
*/</code></pre>
<hr>
<h2 id="📌-그-외-배열의-기타-기능">📌 그 외 배열의 기타 기능</h2>
<blockquote>
<h3 id="✅-배열의-데이터-수를-반환">✅ 배열의 데이터 수를 반환</h3>
</blockquote>
<pre><code class="language-swift">arr.count     // 배열안에 데이터 수를 return</code></pre>
<blockquote>
<h3 id="✅-배열에-데이터-여부-확인">✅ 배열에 데이터 여부 확인</h3>
</blockquote>
<pre><code class="language-swift">arr.isEmpty   // 배열안에 데이터가 없으면 true, 있으면 false return</code></pre>
<blockquote>
<h3 id="✅-배열의-첫-번째-데이터를-옵셔널-타입으로-반환">✅ 배열의 첫 번째 데이터를 옵셔널 타입으로 반환</h3>
</blockquote>
<pre><code class="language-swift">arr.first     // 배열의 첫 번째 데이터를 옵셔널 타입으로 return</code></pre>
<blockquote>
<h3 id="✅-배열의-마지막-데이터를-옵셔널-타입으로-반환">✅ 배열의 마지막 데이터를 옵셔널 타입으로 반환</h3>
</blockquote>
<pre><code class="language-swift">arr.last      // 배열의 마지막 데이터를 옵셔널 타입으로 return</code></pre>
<blockquote>
<h3 id="✅-배열안의-데이터-교환">✅ 배열안의 데이터 교환</h3>
</blockquote>
<pre><code class="language-swift">arr.swapAt(n, m)    // 배열안의 n번 인덱스값과 m번 인덱스값을 교환</code></pre>
<blockquote>
<h3 id="✅-배열에-특정-데이터의-여부-확인">✅ 배열에 특정 데이터의 여부 확인</h3>
</blockquote>
<pre><code class="language-swift">arr.contains(&lt;value&gt;)  // 배열안에 해당 값이 있으면 true return</code></pre>
<p>이 외에도 배열에서 사용 가능한 메서드 및 기능들이 많이 있습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[셀렉터(selector)]]></title>
            <link>https://velog.io/@shin_ms/%EC%85%80%EB%A0%89%ED%84%B0selector</link>
            <guid>https://velog.io/@shin_ms/%EC%85%80%EB%A0%89%ED%84%B0selector</guid>
            <pubDate>Wed, 21 Dec 2022 14:04:15 GMT</pubDate>
            <description><![CDATA[<h1 id="셀렉터selector">셀렉터(selector)</h1>
<p>셀렉터(selector)는 <strong>메서드의 주소를 통해 특정 메서드를 가리키는 개념</strong>입니다. (셀렉터는 메서드를 가리키기만 할 뿐, 메서드를 실행하는 것이 아닙니다.)</p>
<p>셀렉터(selector)의 경우에는 <strong>Objective-C 언어의 문법이기 때문에 가리키고 싶은 함수 앞에</strong> <code>@objc</code> <strong>어트리뷰트를 작성</strong>하여 사용합니다.</p>
<hr>
<h2 id="📌-셀렉터selector의-문법">📌 셀렉터(selector)의 문법</h2>
<p>셀렉터를 사용할 때는 <code>#selector(클래스명.메서드)</code> 형태로 작성해야 합니다.</p>
<p>일반 메서드와 계산속성 메서드의 경우에는 셀렉터를 사용하는 방법이 조금 다릅니다. (계산 속성의 경우에는 자세하게 작성해야 함)</p>
<blockquote>
<h3 id="✅-셀렉터selector의-문법-표현">✅ 셀렉터(selector)의 문법 표현</h3>
</blockquote>
<pre><code class="language-swift">class Man{
    var name: String
    var age: Int
&gt;    
    @objc var agePlus: Int{   // 가리키고 싶은 메서드 앞에 @objc 어트리뷰트를 작성
        get{
            return age + 1
        }
        set{
            age = newValue
        }
    }
&gt;    
    init(name: String, age: Int){
        self.name = name
        self.age = age
    }
&gt;    
    @objc func hello(){     // 가리키고 싶은 메서드 앞에 @objc 어트리뷰트를 작성
        print(&quot;안녕 내 이름은 \(self.name)&quot;)
    }
}
&gt;
var kim = Man(name: &quot;김철수&quot;, age: 25)
&gt;
&gt;
//일반 메서드
#selector(Man.hello)  // hello 
&gt;
//계산 속성 메서드
#selector(getter: Man.agePlus)  // agePlus
#selector(setter: Man.agePlus)  // setAgePlus:</code></pre>
<p><strong>😮 위의 코드만 보면 셀렉터(selector) 문법의 필요성을 찾을 수 없습니다. 하지만 실무에서는 셀렉터 문법을 많이 사용합니다.</strong></p>
<hr>
<h2 id="📌-셀렉터selector의-문법-사용">📌 셀렉터(selector)의 문법 사용</h2>
<p>Xcode에서 UI을 표현하는 방법은 크게 2가지가 있습니다. </p>
<ul>
<li><strong>스토리보드(Storyboard)를 사용</strong>하여 UI 작성</li>
<li><strong>코드(Code)를 사용</strong>하여 UI 작성</li>
</ul>
<p><strong>스토리보드(Storyboard)를 사용하여 UI 기능(메서드)을 구현한 경우에는 **<code>@IBAction</code></strong>에 의해 내부적으로 UI의 기능(메서드)이 자동으로 연결**되었습니다. </p>
<p>하지만 <span style="color:red"><strong>코드(Code)를 사용하여 UI 기능(메서드)을 구현한 경우에는</strong></span> <code>@IBAction</code><strong><span style="color:red">를 사용할 수 없기 때문에 내부적으로 UI의 기능(메서드)을 가리키는 셀렉터(selector) 문법이 필요</strong></span>합니다.</p>
<blockquote>
<h3 id="✅-셀렉터selector의-문법-사용">✅ 셀렉터(selector)의 문법 사용</h3>
</blockquote>
<pre><code class="language-swift">Button.addTarget(self, action: #selector(버튼을 누를 시 사용될 메서드), for: .touchUpInside)
&gt;
// .touchUpInside : 버튼 누름 이벤트</code></pre>
]]></description>
        </item>
    </channel>
</rss>