<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>alpha-kwhn.log</title>
        <link>https://velog.io/</link>
        <description>iOS🍎</description>
        <lastBuildDate>Thu, 29 Dec 2022 15:43:41 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. alpha-kwhn.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/alpha-kwhn" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[협업회고] 34명과 함께하는 쇼핑몰 앱 제작 프로젝트]]></title>
            <link>https://velog.io/@alpha-kwhn/%ED%98%91%EC%97%85%ED%9A%8C%EA%B3%A0-34%EB%AA%85%EA%B3%BC-%ED%95%A8%EA%BB%98%ED%95%98%EB%8A%94-%EC%87%BC%ED%95%91%EB%AA%B0-%EC%95%B1-%EC%A0%9C%EC%9E%91-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8</link>
            <guid>https://velog.io/@alpha-kwhn/%ED%98%91%EC%97%85%ED%9A%8C%EA%B3%A0-34%EB%AA%85%EA%B3%BC-%ED%95%A8%EA%BB%98%ED%95%98%EB%8A%94-%EC%87%BC%ED%95%91%EB%AA%B0-%EC%95%B1-%EC%A0%9C%EC%9E%91-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8</guid>
            <pubDate>Thu, 29 Dec 2022 15:43:41 GMT</pubDate>
            <description><![CDATA[<h4 id="20221226월">2022.12.26(월)</h4>
<p><br><br/></p>
<h2 id="✔️-대규모-협업의-시작">✔️ 대규모 협업의 시작</h2>
<p><br><br/></p>
<p>얼마 전 부트캠프에서 대규모 인원과 함께하는 &quot;쇼핑몰 앱 제작 프로젝트&quot;가 시작되었다.</p>
<p>부트캠프에 소속된 90명의 성향에 따라 크게 A, B, C 3개의 프로젝트 팀으로 나눠졌다.</p>
<blockquote>
<p><strong>A팀: 자율적으로 프로젝트 진행</strong>
<strong>B팀: 큰 틀을 미리 짜준 상태에서 프로젝트 진행</strong>
<strong>C팀: 세부내용까지 미리 정해준 상태에서 프로젝트 진행</strong></p>
</blockquote>
<p>나는 이 3개의 팀 중 A팀에 배정되었다.</p>
<p>선정기준이 궁금했는데 강사님과 운영진분들 말로는 평소 팀활동을 진행할 때 드러났던 수강생들 개개인의 성향이 비슷한 사람들끼리 조를 편성하셨다고 한다.</p>
<p>그리고, 내가 속한 A팀은 평소에 자기 의견을 적극적으로 제시하는 성향을 보였던 사람들로만 구성되었다고 한다. </p>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/c598a576-9453-4e92-83ba-e2caa2fb816a/image.png" alt=""></p>
<p>강사님께서는 위와 같이 간이 조직도를 편성해주셔서 실제 회사에서 일하는 것처럼 협업을 진행할 예정이며, 이번 프로젝트는 배포를 위해 앱의 완성도에 초점을 두기보다는 이러한 실무형 협업을 경험해보는데에 초점을 두라고 말씀하셨다.</p>
<hr>
<h2 id="✔️-팀-내부-조직체계-잡기">✔️ 팀 내부 조직체계 잡기</h2>
<p><br><br/></p>
<p>팀 배치가 끝나고 본격적인 팀 내 조직체계를 잡기 활동에 들어갔다. 그래서 A팀으로 배정받은 34명의 인원들이 Voice Channel로 들어왔고, 그러면서 순식간에 채널이 북적북적해지기 시작했다.</p>
<p>모두가 들어왔음을 확인한 후에, A팀 PM님과 팀장님들을 중심으로 본격적인 조직체계 구성에 들어가게되었다.</p>
<p>(PM과 부서 팀장은 부트캠프 운영진들이 회의를 거쳐 선별하였음)
<br><br/></p>
<h3 id="1-할일과-일정파악">1. 할일과 일정파악</h3>
<p>가장 먼저 진행한 일은 개발 총괄자(강사님)님이 공지하신 일정을 파악한 후 그에 맞게 할 일을 정하고 부서를 나누는 것이었다.</p>
<p>일정은 아래와 같았다
<img src="https://velog.velcdn.com/images/alpha-kwhn/post/782c5542-760c-4353-949d-e470280f73a3/image.png" alt=""></p>
<p>당일 안으로 기획, 리서치, 시나리오 작성을 해야했는데 부서도 정해지지 않은 상태에서 오후 1시~6시 안에 이 모든 것을 끝내야 한다니 조금 막막했다. 
<br><br/></p>
<h3 id="2-부서배치">2. 부서배치</h3>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/e339b9db-5a6f-490a-bcce-44ad7e254273/image.png" alt=""></p>
<p>부서는 위의 사진과 같이 총 5개로 나눴다
<br><br/></p>
<ul>
<li><p><strong>고객파트</strong></p>
<ul>
<li>쇼핑몰 앱의 전반적인 UI 설계를 담당</li>
</ul>
</li>
<li><p><strong>서버파트</strong></p>
<ul>
<li>쇼핑몰의 데이터를 관리하는 Firebase를 설계하고 CRUD 로직 구현</li>
</ul>
</li>
<li><p><strong>스토어</strong></p>
<ul>
<li>입점한 스토어에 관한 데이터를 다루고 모니터링 하는 padOS 제작</li>
</ul>
</li>
<li><p><strong>백오피스</strong></p>
<ul>
<li>쇼핑몰 앱의 관리자 페이지 제작을 담당</li>
</ul>
</li>
<li><p><strong>TF팀</strong></p>
<ul>
<li>위의 4가지 부서들 중에서 업무량이 많아서 도움이 필요할 때 투입되는 팀</li>
</ul>
</li>
</ul>
<p><br><br/>
나는 처음에 서버파트에 지원했었는데, 팀장들과 PM의 회의 끝에 TF팀으로 강제 배치되었다.</p>
<p>내가 서버파트에 지원했던 이유는,,,</p>
<p>이전에 MVP 수준의 앱을 만드는 실습을 할 때, Firebase의 구조설계를 잘못하여 프로젝트 기간에 애를 먹었던 기억이있어서 이번기회에 Firebase의 구조를 다른 부서들과의 소통을 통해 제대로 설계해보는 연습을 하고싶음이 컸다. </p>
<p>어쩔수 없이 TF팀으로 배치됐지만, TF팀은 여러 부서의 일을 여기저기 경험해볼 수 있다는 나름의 장점이 있었기에 이를 기대하며 프로젝트에 임하기로 마음을 바로잡았다.
<br><br/></p>
<h2 id="✔️-tf팀-내부규약-설정">✔️ TF팀 내부규약 설정</h2>
<p><br><br/></p>
<p>TF팀에는 나포함 총 4명으로 구성되었다.</p>
<p>막판에 내가 TF팀으로 추가합류하면서 팀장님의 주도하에 본격적인 팀 회의가 시작되었다.</p>
<p>회의를 시작하면서 모두가 공통으로 떠올린 안건은 바로 &quot;팀 내부규약 설정&quot;이었다.</p>
<p>내부규약이 필요하다고 팀원 모두가 느꼈던 이유는 아래의 이유에서였다.</p>
<blockquote>
<p><strong>TF팀의 팀원들 제각각은 매번 다른 부서에 배치되어 일하기 때문에 각 부서의 업무 진행상황에 대한 공유가 필요하다</strong></p>
</blockquote>
<p>이러한 이유 때문에 TF팀은 매일 오후 5시에 모여서 별도의 회의를 진행하기로했다.</p>
<p>하지만 회의를 하더라도 나는 나름의 체계가 잡혀있어야한다고 생각했다. </p>
<p>그래서 TF팀만의 Notion Page에 부서 업무 진행상황 정보를 공유할 때 준수해야 할 규약을 아래와 같이 제시했다.</p>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/04001044-4150-45f0-bc33-68b18434ec5d/image.png" alt=""></p>
<p>부서-Task 단위로 업무보고를 하면 효율적일 것 같다는 좋은 반응들이 나와 이대로 규약을 픽스하기로했고, PM에게 보고해 승인을 받았다.
<br><br/></p>
<h2 id="✔️-협업회고">✔️ 협업회고</h2>
<p><br><br/></p>
<h3 id="1-실무-협업방식-경험이-지닌-가치">1. 실무 협업방식 경험이 지닌 가치</h3>
<p>이제껏 5인이하의 소규모 인원들이랑만 협업을하다가, 실제 회사처럼 대규모 조직체계로 협업을 진행해보니 되게 혼란스러웠다.</p>
<p>많은 사람들 사이에 둘러싸여 회의방에 있으니 기도 빨리고, 어느샌가 소극적이고 조심스러운 태도를 취하고 있는 나를 발견할 수 있었다. </p>
<p>당황과 혼란의 연속이었지만, 시간이지나 그 당시를 떠올려보니 실제 회사의 분위기를 느껴볼 수 있는 나름의 신선한 경험이었구나 싶었다. </p>
<p>&quot;실제 회사에 들어가기전에 이러한 협업을 해볼 수 있을까?&quot;라는 생각에 이번 협업이 더욱 가치있게 느껴졌으며, 그 속에서 일어나는 여러 일들을 잘 관찰해 많은 교훈들을 얻어야겠다는 다짐도 하게된 것 같다.</p>
<h3 id="2-조직에-대한-이해">2. 조직에 대한 이해</h3>
<p>&#39;조직&#39;이라는 단어만큼이나 &#39;회사&#39;라는 단어와 잘 어울리는 단어는 없다고 생각했다.</p>
<p>그런데, 막상 이번 협업에 들어가니 이 말이 더욱 생생하게 다가왔다.
<br><br/></p>
<ul>
<li>PM과 팀장의 힘은 강하지만 그만큼 엄청난 책임이 따른다는 것 </li>
<li>PM같은 경우는 수뇌부들과 팀장들의 정중앙에 위치하기에 많은 부담감을 가진다는 것</li>
<li>직급이 말단으로 갈수록 권력은 없지만 시키는대로만 움직이면 되기에 마음은 편하다는 것</li>
</ul>
<p>드라마, 경험담에서만 보거나 들었던 것들을 당장 부트캠프 협업내에서 하루만에 다 느낄수 있었다. </p>
<p>또한, 조직이 원활하게 돌아가기 위해서는 서로간의 &#39;소통&#39;이 아주 중요하다는 것도 깨달았다. </p>
<p>당장 TF팀 내부에서 짠 규약을 만일 PM에게 보고하지 않았다면, 우리의 업무방식을 PM 입장에서는 고려하지 않고 업무지시를 내렸을 것이라는 생각을하니 머리가 어지러웠다.</p>
<p><br><br/></p>
<p>앞으로 프로젝트 협업을 진행하는 동안 또 어떤 회고감들이 생길지 무척 궁금하다!</p>
<p>협업 2일차 회고글도 조만간 포스팅하겠다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Animation] interpolatingSpring]]></title>
            <link>https://velog.io/@alpha-kwhn/Animation-interpolatingSpring</link>
            <guid>https://velog.io/@alpha-kwhn/Animation-interpolatingSpring</guid>
            <pubDate>Mon, 26 Dec 2022 15:39:32 GMT</pubDate>
            <description><![CDATA[<h2 id="0-공부배경">0. 공부배경</h2>
<p>앱의 SplashView를 구현하는 방식의 일환으로 애니메이션 효과를 적용해보면 어떨까라는 생각이 들어서 여러 리서치 자료를 찾던 중 ìnterpolatingSpring 이라는 것을 알게되었다.</p>
<p>일단 해당 애니메이션은 SwiftUI의 View에 Spring 효과를 입히는 역할을 수행한다.</p>
<p>팀원들과 함께 만들던 앱의 캐릭터(귀여운 곰돌이)가 SplashView에서 Spring 처럼 가볍게 튕겨져 나오면 깜찍하고 괜찮겠다는 생각이들어서 채택을 결심하였다.</p>
<hr>
<h2 id="1-공식문서">1. 공식문서</h2>
<p>원하는 메서드를 사용하기 위해서는 공식문서를 꼭 읽어봐야겠죠..?</p>
<p>이번에도 어김없이 바로 검색해서 읽으러가봤습니다</p>
<blockquote>
<p><strong>interpolatingSpring(mass:stiffness:damping:initialVelocity:)</strong></p>
<p>An interpolating spring animation that uses a damped spring model to produce values in the range [0, 1] that are then used to interpolate within the [from, to] range of the animated property. Preserves velocity across overlapping animations by adding the effects of each animation.</p>
</blockquote>
<p><strong>감쇠 스프링 모델을 사용하여 애니메이션 속성의 [from, to] 범위 내에서 보간하는 데 사용되는 [0, 1] 범위의 값을 생성하는 보간 스프링 애니메이션입니다. 각 애니메이션의 효과를 추가하여 겹치는 애니메이션에서 속도를 유지한다.</strong></p>
<p>겉으로 정의만 읽어봤을 때는 대충 감쇠 스프링효과를 준다~ 정도로 밖에 이해가 되지 않았다. </p>
<p>하지만 이정도 정보만으로도 내가 해당 애니메이션을 사용할 명분은 충분했다.
(희망 애니메이션 구현효과와 정확히 일치하니까)</p>
<pre><code class="language-swift">static func interpolatingSpring(
    mass: Double = 1.0,
    stiffness: Double,
    damping: Double,
    initialVelocity: Double = 0.0
) -&gt; Animation
</code></pre>
<ul>
<li><p>mass</p>
<p>용수철에 달린 물체의 질량이라고 생각하면 됨. </p>
<p>무거운 물체가 달려있을수록 스프링이 진동하는 시간이 길어지고 느려지듯이 
mass 값이 커지면 그만큼 진동시간이 증가하게된다.
<br><br/></p>
</li>
</ul>
<ul>
<li><p>stiffness</p>
<p>애니메이션의 빠르기를 의미함
<br><br/></p>
</li>
<li><p>damping</p>
<p>스프링 애니메이션의 탄성마찰력에 해당한다</p>
<p>damping 값이 높아질수록 스프링 애니메이션의 탄성은 떨어진다.
<br><br/></p>
<ul>
<li>initialVelocity</li>
</ul>
<p>애니메이션이 변경되는 속도를 의미한다</p>
<p>공식문서 정의에 명시된 [0, 1] 사이의 값에 해당한다.</p>
</li>
</ul>
<p> <br><br/></p>
<p>매개변수까지 읽어보니까 대충 어떻게 조작할지 감이 잡힐 수 있었다.</p>
<p>내가 원하는 SplashView를 구성하기 위해서는 아래와 같은 조건이 필요했는데, 문서를 읽은 후에 이를 위해서 어떤 값을 조작해야할 지 감을 잡게 되었다.
 <br><br/></p>
<blockquote>
<ol>
<li>SplashView는 너무 오래 시간을 잡아먹으면 안됨
=&gt; <strong>stiffness를 크게 잡는다</strong></li>
</ol>
</blockquote>
<ol start="2">
<li>View 객체가 스프링 효과로 진동하는  시간이 너무 길면 안됨
=&gt; <strong>mass를 작게하고, damping을 높게 설정한다</strong></li>
</ol>
<p>세부적인 디테일은 위와 같은 플랜을 가지고 코드구현에 들어간 후에 값을 여러번 변경해가며 정하기로 마음먹었다.</p>
<hr>
<h2 id="2-코드구현">2. 코드구현</h2>
<pre><code class="language-swift">@State private var mass: Double = 2
@State private var stiffness: Double = 100
@State private var damping: Double = 13
@State private var initialVelocity: Double = 2
@State private var moveBear = false
@State private var logoOpacity: Double = 0.0

VStack{
  ZStack {
      Image(&quot;SplashText&quot;)
          .offset(y: -180)
          .opacity(logoOpacity)
  }

  ZStack {
      Image(&quot;santabear&quot;)
        .resizable()
        .frame(width:300, height: 200)
        .offset(y: moveBear ? 500 : 100)                   
        .animation(Animation.interpolatingSpring(mass: mass, 
        stiffness: stiffness, damping: damping, initialVelocity: 
        initialVelocity))
        .onAppear(){
            moveBear.toggle()
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
                withAnimation(.easeIn(duration: 1.2)) {
                    initialVelocity = 4
                }
            }
            DispatchQueue.main.asyncAfter(deadline: .now() + 1.4) {
                withAnimation(.easeIn(duration: 1.0)) {
                    moveBear.toggle()
                }
            }
            DispatchQueue.main.asyncAfter(deadline: .now() + 2.4) {
                withAnimation(.easeIn(duration: 0.6)) {
                    logoOpacity = 0.5
                }
            }
            DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
                withAnimation(.easeIn(duration: 1.0)) {
                    logoOpacity = 1
                }
            }
    }
}</code></pre>
<p>코드의 동작과정은 아래와 같다.</p>
<ol>
<li><p>SplashView가 켜지면 santabear 이미지를 보여줄지 말지를 알려주는 movebear 상태변수 값이 true로 토글되면서 화면상 y축 500의 위치에 나타난다.</p>
</li>
<li><p>시작으로부터 0.2초 후에는 애니메이션이 변경되는 속도인 initialVelocity 값을 4로 늘린채 1.2초 동안 애니메이션을 진행한다.</p>
</li>
<li><p>시작으로부터 1.4초 후엔 movebear 값이 false로 토글되면서 offset 삼항연산식에 적힌 위치로(y축 100) santabear 이미지가 이동하게 된다. </p>
</li>
<li><p>시작으로부터 2.4초 후엔 앱 로고의 투명도 값인 logoOpacity가 0에서 0.5까지 증가하는 애니메이션이 0.6초 동안 진행된다.
(안보이던 앱 로고가 희미하게 보이게 됨)</p>
</li>
<li><p>시작으로부터 3초 후엔 앱 로고의 투명도 값인 logoOpacity가 0.5에서 1까지 증가하는 애니메이션이 1.0초 동안 진행된다.
(희미하게 보이던 앱 로고가 또렷하게 보이게 됨)</p>
</li>
</ol>
<hr>
<h2 id="3-결과화면">3. 결과화면</h2>
<p>위 코드를 바탕으로 코드를 실행하면 아래와 같은 애니메이션 SplashView를 볼 수 있게 된다.</p>
<p>곰돌이 위의 나무는 그냥 이미지를 덧붙인 것이고, 눈 내리는 효과는 또다른 레퍼런스를 참고하여 제작하였다.</p>
<p>눈 효과 애니메이션은 추후에 따로 포스팅을 진행하겠다!</p>
<p>(곰돌이 가와~~이)</p>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/c1a76ef9-086a-455d-be39-307b28d04ab9/image.gif" alt=""></p>
<hr>
<h2 id="참고링크">참고링크</h2>
<p><a href="https://medium.com/@amosgyamfi/learning-swiftui-spring-animations-the-basics-and-beyond-4fb032212487">https://medium.com/@amosgyamfi/learning-swiftui-spring-animations-the-basics-and-beyond-4fb032212487</a></p>
<p><a href="https://developer.apple.com/documentation/swiftui/animation/interpolatingspring(mass:stiffness:damping:initialvelocity:)">https://developer.apple.com/documentation/swiftui/animation/interpolatingspring(mass:stiffness:damping:initialvelocity:)</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[iOS 앱 HTTP 통신 오류 해결]]></title>
            <link>https://velog.io/@alpha-kwhn/iOS-%EC%95%B1-HTTP-%ED%86%B5%EC%8B%A0-%EC%98%A4%EB%A5%98-%ED%95%B4%EA%B2%B0</link>
            <guid>https://velog.io/@alpha-kwhn/iOS-%EC%95%B1-HTTP-%ED%86%B5%EC%8B%A0-%EC%98%A4%EB%A5%98-%ED%95%B4%EA%B2%B0</guid>
            <pubDate>Sun, 04 Dec 2022 14:30:07 GMT</pubDate>
            <description><![CDATA[<h2 id="문제상황">문제상황</h2>
<p>데이터 API를 가져와서 앱의 화면에 보여주는 실습을 하던 중 API 아래의 사진과 같이 데이터가 아예 불러와지지 않고 네트워크 관련 에러문구가 지속해서 뜨는 문제를 겪게 되었다.</p>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/71531322-2168-4897-9dc2-0110c32c795f/image.png" alt=""></p>
<hr>
<h2 id="원인찾기">원인찾기</h2>
<p>처음에는 json 파일을 decode하는 과정에서 문제가 있다고 판단하고 정상적으로 작동했던 뷰의 코드를 가져와 그대로 사용해보았지만 문제는 해결되지 않았다. </p>
<p>그래서 나는 이 문제의 원인은 API Key의 문제 혹은 API의 URL 자체의 문제라고 판단했다.</p>
<h3 id="1-api-key의-문제인가">1. API Key의 문제인가?</h3>
<p>API Key의 문제인지 알아보기 위해서는 웹 상에서도 API 주소에 접속했을 때 데이터가 잘 뜨는지 확인하면 알 수 있다.</p>
<p>따라서, 나는 코드에서 사용한 API 주소를 즉시 웹 상에 cmd + C/V하여 접속해보았다.</p>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/0968a3e4-2665-4570-83f8-fbe475f751dc/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/ab18b3bf-d6c0-49e1-9b41-0f5d145979b8/image.png" alt=""></p>
<p>첫 번째 사진에 나와 있는 API 주소로 접속했더니 두 번째 사진에 보이는 것처럼 데이터가 멀쩡히 출력된 것을 확인할 수 있었다.</p>
<p>이로써 <strong>API Key에는 문제가 없음</strong>이 확실해졌다.</p>
<h3 id="2-url-자체의-문제인가">2. URL 자체의 문제인가?</h3>
<p>실습 코드에서 사용한 API 주소의 문제인지 확인해보기 위해, 본 json 코드를 바탕으로 mocki에서 임의 API 주소를 만들어서 코드에 적용시켜보았다.</p>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/27c396b9-afea-41fc-9706-2e78fe971b24/image.png" alt=""></p>
<p>mocki를 통해 위와 같은 API 주소를 발급받았고 코드를 돌려보았다.</p>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/88da26e2-2cc2-492b-89e9-b89e6f12e537/image.png" alt=""></p>
<p>바뀐 API 주소로 코드를 돌려보니까 위와 같이 정상적으로 동작하는 것을 확인할 수 있었다.</p>
<p>이를 통해, 처음에 사용했던 API 주소에 문제가 있었음을 알 수 있었다. </p>
<hr>
<h2 id="해결법-찾기">해결법 찾기</h2>
<p>우선 Mocki에서 생성한 Mock API와 본래의 API는 분명 같은 데이터를 담고 있는데 어째서 차이를 보였던 것인지 먼저 알아볼필요가 있다고 생각해 이 둘의 차이점에 대해 알아보았다. </p>
<h3 id="mock-api란">Mock API란?</h3>
<blockquote>
<p><strong>Mock API는 실제로 REST API가 구축되어 있지 않더라도, 있는 것처럼 테스트 환경을 만들어줌</strong></p>
</blockquote>
<p> API의 흉내만 낼 뿐이기에 테스트 용이 아닌 프로덕션 레벨에서는 사용이 불가능하며 API 준비가 덜 된 상태에서 개발을 진행할 시에 사용하기 좋다는 장점이 있다고 한다.</p>
<p> 실제 현업에서는 백엔드 팀이 API 서버를 아직 개발하지 못했을 때, 프론트 개발팀이 API로 뷰를 구성해야 할 때 임시용으로 사용한다고 한다. </p>
<p> Mocki외에도 Postman 등도 활용하여 Mock API를 생성하기도 한다.</p>
<h3 id="ats-정책-위반">ATS 정책 위반</h3>
<p><a href="https://www.hahwul.com/2019/03/11/ios-app-http-app-trasport-security/">https://www.hahwul.com/2019/03/11/ios-app-http-app-trasport-security/</a></p>
<p> 끊임없는 구글링과 팀원들의 도움 덕에 위의 해결 링크를 찾아서 문제를 해결해냈다!!</p>
<p> 현 문제의 <strong>ATS 정책 위반</strong>이라고 한다.</p>
<p> 애초에 코드로 해결할 수 없는 문제였다는 점에서 뭔가 허무했다..
 (코드에 쏟은 내 시간...)</p>
<h4 id="ats란">ATS란?</h4>
<blockquote>
<p>iOS 9 버전 이후부터 적용된 개인정보보호 기능이고 Xcode7 버전 이상에서 앱 생성 시 기본값으로 가져가게 되는 보안 정책이다.</p>
</blockquote>
<p>보안 이슈로 도입된 ATS 때문에 결과적으로 HTTP와의 통신이 Xcode에서는 기본적으로 불가능하다는 것이 위의 링크와 ATS의 정의에 대해 알아본 나의 생각이었다.</p>
<p>HTTP와의 통신을 위해서는 결국엔 Xcode상에서 특수한 조취를 취해야하며, 그 방법은 위 링크에 잘 나와 있어서 쉽게 문제를 해결해 나갈 수 있었다.</p>
<hr>
<h2 id="문제해결">문제해결</h2>
<ol>
<li>Info list에 들어가서 HTTP와의 통신을 위한 설정을 해준다.</li>
</ol>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/697aea1a-a642-48bf-805a-e03fccb9e637/image.png" alt=""></p>
<p>Info list에서 App Transport Security Settings (ATS settings)를 key에 추가해주고 Allow Arbitary Loads를 YES로 값설정 해줌으로써 HTTP 통신이 가능해지게끔 해줌</p>
<ol start="2">
<li>본래 사용하고자 했던 API 주소를 다시 살려서 코드를 실행해본다</li>
</ol>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/d6c74f10-e958-4374-83aa-7c14732ee00a/image.png" alt=""></p>
<p>그 결과 위의 사진처럼 결과가 잘 나옴을 확인할 수 있었다.</p>
<hr>
<p>API를 통해 데이터를 불러오는 것은 앱을 제작하는데에 있어서 매우매우 중요한 작업이다.</p>
<p>그런 의미에서 이번 문제 해결과정은 굉장히 의미있는 배움이라는 생각이든다.</p>
<p>API 호출에 대한 막연한 두려움이 있었는데 조금은 그 두려움이 사라진거 같아서 좋다!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Error] Generic struct 'ForEach' requires that 'Infos' conform to 'Hashable' 오류 해결]]></title>
            <link>https://velog.io/@alpha-kwhn/Error-Generic-struct-ForEach-requires-that-Infos-conform-to-Hashable-%EC%98%A4%EB%A5%98-%ED%95%B4%EA%B2%B0</link>
            <guid>https://velog.io/@alpha-kwhn/Error-Generic-struct-ForEach-requires-that-Infos-conform-to-Hashable-%EC%98%A4%EB%A5%98-%ED%95%B4%EA%B2%B0</guid>
            <pubDate>Thu, 24 Nov 2022 18:06:38 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/d4a6618c-104d-4b61-9fd0-62f2146a4e9f/image.png" alt=""></p>
<p>날씨정보에 관한 API를 통해 날씨정보를 화면에 출력하고자 하던 중 위와 같은 오류를 접했는데 1시간이나 시간을 들인 끝에 해결할 수 있었다.</p>
<p>평소에도 자주 접했던 오류였던지라 이번 기회에 확실히 <strong>오류의 원인과 정확한 해결법</strong>을 정리해보고자 trouble shooting 게시글을 작성하게되었다.</p>
<hr>
<h3 id="--코드-살펴보기">- 코드 살펴보기</h3>
<pre><code class="language-swift">struct WeatherView: View {
    var weatherWebService: WeatherWebService = WeatherWebService()
    var url: String =
    &quot;https://api.openweathermap.org/data/2.5/forecast?q=seoul&amp;appid=6976ce3140a4a0d4cce84e76d77271c7&quot;

    @State private var weathers: [Infos] = []

    var body: some View {
        List {
        //문제의 구문
            ForEach(weathers, id: \.self) { item in
                HStack {
                    Text(&quot;\(item.main.temp)&quot;)
                }
            }
        }
        .onAppear {
            Task {
                 do {
                     weathers = try await weatherWebService.fetchData(url: url)
                } catch {
                    print(&quot;\(error)&quot;)
                    return
                }
            }
        }
    }
}</code></pre>
<p>다음은 에러가 발생했던 코드이다. 맥락의 이해를 위해 그냥 에러가 발생한 구조체 전체를 가져왔다.</p>
<p>코드에 대해 간략히 설명하자면</p>
<blockquote>
<ol>
<li><code>url</code> 변수의 api주소를 Task 구문 안에서 decode하여 <code>weathers</code> 상태 프로퍼티에 <code>[Infos]</code> 타입의 데이터를 넣어주고</li>
</ol>
</blockquote>
<blockquote>
<ol start="2">
<li>해당 <code>weathers</code> 변수 (Infos 객체의 배열)를 ForEach 문을 통해 순회하며 <code>item.main.temp</code> 값 (기온정보)을 차례대로 List에 출력하는 형태였다.</li>
</ol>
</blockquote>
<p>(구조체의 자세한 정보는 뒤에 나오는 코드를 참고)</p>
<hr>
<h3 id="--원인-탐색과정">- 원인 탐색과정</h3>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/b225be11-eae3-435e-b8b8-48c4a438868c/image.png" alt=""></p>
<p>처음에는 평상시에 분명 자주 봤던 오류였기에 코딩을 하다보면 자연스럽게 해결될 것이라고 막연하게 생각했다.</p>
<p>그래서, 오류문구를 그대로 해석하여 기존에 Codable 프로토콜만 채택하던 Infos 구조체가 Hashable 프로토콜도 채택하게끔 처리해주었다.</p>
<pre><code class="language-swift">struct Infos: Codable, Hashable {
    let dt: Int
    let main: MainClass
    let weather: [Weather]
    let clouds: Clouds
    let wind: Wind
    let visibility: Int
    let pop: Double
    let sys: Sys
    let dtTxt: String
    let rain: Rain?

    enum CodingKeys: String, CodingKey, Hashable {
        case dt, main, weather, clouds, wind, visibility, pop, sys
        case dtTxt = &quot;dt_txt&quot;
        case rain
    }
}</code></pre>
<p>이렇게 코드를 수정하면 문제가 해결될 줄 알았다...분명히..</p>
<p>하지만, 여기서 또다른 오류가 발생하였다. </p>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/e3e13c1a-9aec-49c3-aa05-36073fd79f59/image.png" alt=""></p>
<p>Hashable 프로토콜을 채택했더니,, 이번에는 Infos 구조체가 Equatable 프로토콜에 순응하지 않는다는 오류가 떴다.</p>
<p>순간 머리가 하얘졌지만 침착하고 내가 여기서 지금 무엇을 해야 할지 곰곰히 생각해보았다.</p>
<p>예전에도 똑같은 오류를 겪었다가 해결했던거 같았는데 그 당시엔 어떻게 해결했는지 기억이나지 않아서 너무 아쉬웠다. </p>
<p>또다른 오류 문구가 떴기에 일단은 무작정 해석을 해보고 해석한대로 Equatable 프로토콜을 채택해보기도 했지만, 해결이 되지 않아서 결국 구글링을 하게 되었다.</p>
<p>Equatable을 왜 사용하는지 알아봤더니 다음과 같은 정보를 얻을 수 있었다. </p>
<blockquote>
<p>** Equatable은 타입끼리 비교연산을 하기 위해 필수적으로 구현되어야 함 **</p>
</blockquote>
<p>위 정보를 통해 나는 어느 정도 정답을 얻을 수 있었다.</p>
<p>Infos 타입의 값들끼리 비교를 할 수 있어야하는데 현재 그것이 불가능하다는 상태인 것이다. </p>
<p>그러면 이를 해결하기 위해서는 어떻게 해야할까?</p>
<p>해답은 Hashable 프로토콜 채택에 있었다. </p>
<p>모든 데이터 타입들은 자신과 같은 타입의 값들과 비교를 하기 위해서 값 자신이 Hashable한 값이어야한다.</p>
<p>우리가 아는 String, Int와 같은 원시타입들은 애초에 Hashable한 타입으로 설정되어있기에 Hashable 프로토콜을 채택하지 않아도 상관없었지만, 본 코드에서는 타입의 대상이 구조체이기 새로이 Hashable선언을 해주어야 Equatable이 만족된다는 것이다.</p>
<blockquote>
<p><strong>근데, Info 구조체에 Hashable 프로토콜 채택하지 않았나..?</strong></p>
</blockquote>
<p>맞다, Hashable 프로토콜을 채택한 것은 사실이다.</p>
<p>하지만, 채택했음에도 오류가 떴던 이유는 Infos 구조체 내부를 살펴보면 바로 알 수 있다.</p>
<pre><code class="language-swift">struct Infos: Codable, Hashable {
    let dt: Int
    let main: MainClass
    let weather: [Weather]
    let clouds: Clouds
    let wind: Wind
    let visibility: Int
    let pop: Double
    let sys: Sys
    let dtTxt: String
    let rain: Rain?

    enum CodingKeys: String, CodingKey, Hashable {
        case dt, main, weather, clouds, wind, visibility, pop, sys
        case dtTxt = &quot;dt_txt&quot;
        case rain
    }
}</code></pre>
<p>위에 코드가 있지만, 보기 편하도록 다시 한번 코드를 가져왔다. </p>
<p>Infos 구조체 내부를 자세히 들여다보면 main, clouds, wind, sys, rain 등의 프로퍼티들이 있고, 이들은 각각 MainClass, Clouds, Wind, Sys, Rain과 같은 만들어진 타입(구조체 형태)을 타입으로 가진다.</p>
<p>그리고 이들의 타입 값들을 비교가능하게하기 위해서는 MainClass, Clouds, Wind, Sys, Rain 구조체들도 모두 Hashable해야 함을 의미한다.</p>
<blockquote>
<p><strong>결론 : MainClass, Clouds, Wind, Sys, Rain 구조체에도 Hashable 프로토콜을 채택해주자&quot;</strong></p>
</blockquote>
<hr>
<h3 id="--문제해결">- 문제해결</h3>
<pre><code class="language-swift">struct MainClass: Codable, Hashable {
    let temp, feelsLike, tempMin, tempMax: Double
    let pressure, seaLevel, grndLevel, humidity: Int
    let tempKf: Double

    enum CodingKeys: String, CodingKey, Hashable {
        case temp
        case feelsLike = &quot;feels_like&quot;
        case tempMin = &quot;temp_min&quot;
        case tempMax = &quot;temp_max&quot;
        case pressure
        case seaLevel = &quot;sea_level&quot;
        case grndLevel = &quot;grnd_level&quot;
        case humidity
        case tempKf = &quot;temp_kf&quot;
    }
}

// MARK: - Rain
struct Rain: Codable, Hashable {
    let the3H: Double

    enum CodingKeys: String, CodingKey, Hashable {
        case the3H = &quot;3h&quot;
    }
}

// MARK: - Sys
struct Sys: Codable, Hashable {
    let pod: Pod
}

enum Pod: String, Codable, Hashable {
    case d = &quot;d&quot;
    case n = &quot;n&quot;
}

// MARK: - Weather
struct Weather: Codable, Hashable {
    let id: Int
    let main: MainEnum
    let weatherDescription, icon: String

    enum CodingKeys: String, CodingKey {
        case id, main
        case weatherDescription = &quot;description&quot;
        case icon
    }
}

enum MainEnum: String, Codable, Hashable {
    case clear = &quot;Clear&quot;
    case clouds = &quot;Clouds&quot;
    case rain = &quot;Rain&quot;
}

// MARK: - Wind
struct Wind: Codable, Hashable {
    let speed: Double
    let deg: Int
    let gust: Double
}</code></pre>
<p>Hashable 프로토콜 채택이 필요한 모든 구조체에 Hashable 프로토콜을 채택해주었다. </p>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/709c164e-5f18-4814-ab67-0f6272e339d7/image.png" alt=""></p>
<p>그리고 그 결과 ForEach 문에서 오류가 사라졌음을 확인할 수 있었다.</p>
<hr>
<p><strong>참고링크</strong> </p>
<p><a href="https://zeddios.tistory.com/498">https://zeddios.tistory.com/498</a>
<a href="https://babbab2.tistory.com/148">https://babbab2.tistory.com/148</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[협업 툴] Figma(1)]]></title>
            <link>https://velog.io/@alpha-kwhn/%ED%98%91%EC%97%85-%ED%88%B4-Figma1</link>
            <guid>https://velog.io/@alpha-kwhn/%ED%98%91%EC%97%85-%ED%88%B4-Figma1</guid>
            <pubDate>Sat, 19 Nov 2022 07:36:06 GMT</pubDate>
            <description><![CDATA[<p>ProtoTyping 작업을 할 때, Figma라는 UI 작성 협업 툴을 처음 접하게 되었다.</p>
<p>기능 조작과 구성들에 대한 이해가 부족한 상태에서 작업을 하다보니 남들보다 작업 속도가 느려졌다.</p>
<p>어찌저찌 ProtoTyping을 끝냈지만 내 스스로한테 아쉬움이 많이 남았었다.</p>
<p>그래서 ProtoTyping이 끝난 후에 따로 Figma에 대한 공부를 별도로 진행하게 되었다.</p>
<hr>
<h3 id="1-좌측-상단-툴">1. 좌측 상단 툴</h3>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/11da2300-18c5-40cf-a957-b0e2face7898/image.png" alt=""></p>
<p>Move, Frame, Shape, Pen, Text, Resources, Handling, Comment</p>
<ul>
<li><p>Move : 가장 많이 쓰이는 부분, 그냥 메인이라고 생각하면 편했다</p>
<pre><code>   기본적인 뷰의 설정/조작을 할 수 있음</code></pre></li>
<li><p>Frame : UI를 짜기 위한 배경틀을 생성할 때 사용했다</p>
</li>
<li><p>Shape : UI를 구성하기 위한 도형을 생성할 때 사용했다</p>
</li>
<li><p>Pen : 요소를 직접 만들거나, 직선/곡선을 그릴 때 사용</p>
</li>
<li><p>Text : 텍스트 박스 생성</p>
</li>
<li><p>Resources : UI에 넣을 이미지를 검색할 때 사용</p>
</li>
<li><p>Handling : 창을 움직일 때 사용 (별로 사용 안함)</p>
</li>
<li><p>Comment : 주석</p>
</li>
</ul>
<h3 id="2-우측-툴">2. 우측 툴</h3>
<ul>
<li>정렬
<img src="https://velog.velcdn.com/images/alpha-kwhn/post/d9e16895-fb59-47fe-8a76-be18f912824d/image.png" alt=""></li>
</ul>
<p>좌, 중앙, 우측, 상단, 중앙, 하단 등 6가지의 기준으로 뷰를 정렬해준다.</p>
<ul>
<li>뷰 형태 및 위치 조작
<img src="https://velog.velcdn.com/images/alpha-kwhn/post/0574e98c-629c-4721-93f8-5528b4b9526f/image.png" alt=""></li>
</ul>
<p>X: X축 좌표
Y: Y축 좌표
W: 너비
H: 높이
각도와 CornerRadius</p>
<p>** Shift를 누르고 키보드 위/아래를 누르면 10단위로 수치를 바꿀 수 있음**</p>
<ul>
<li>위치 고정</li>
</ul>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/4874c22e-21e5-4733-b06f-08a2777a6c97/image.png" alt=""></p>
<p>Frame의 크기에 구애받지 않게, 뷰의 고정된 위치를 잡아주는 부분이다</p>
<p>현 상태에서 뷰의 길이를 늘려도, 해당 뷰는 항상 좌측/하단 에 위치가 고정되어 있을 것이다</p>
<ul>
<li>뷰의 스타일 조작</li>
</ul>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/faec1faa-a969-4e35-a847-79cf349c96d2/image.png" alt=""></p>
<p>왼쪽은 뷰의 스타일 조작 (보이는 방식)
오른쪽은 뷰의 Opacity(투명도) 조작</p>
<ul>
<li>Fill</li>
</ul>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/86da2510-291f-428b-a4b7-71760f5d00d0/image.png" alt=""></p>
<p>뷰를 채울 색상 선택
눈 표시로 색 노출/숨기기 여부 선택 가능
+를 누르면 색상 추가, -를 누르면 색상 삭제
%를 통해 해당 색의 비율을 조절 가능 (주로 2개이상의 색을 섞을 때 사용)</p>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/a0c88a8d-8e6f-4159-8e11-0786f808b34e/image.png" alt=""></p>
<p>추가로, Fill 상단의 메뉴 버튼을 누르고, +를 누르면 선택된 색상에 별명을 붙여줄 수 있다</p>
<ul>
<li>Stroke</li>
</ul>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/96a54225-8589-4f26-9136-0ac5129ba52e/image.png" alt=""></p>
<p>뷰의 테두리 설정에 관한 부분
테두리 색상 및 비율 선택
노출여부
테두리 추가 및 삭제
테두리 두께 조절
테두리 영역 설정
테두리 위치 설정(내부, 중앙, 외부)</p>
<ul>
<li>Export</li>
</ul>
<p>선택된 뷰를 이미지 파일로 만들어 다운받을 수 있음</p>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/7320aa5b-db68-4a2a-bb28-204f8db20de0/image.png" alt=""></p>
<p>개인적으로 프로토타입핑을 할 때 이 기능을 몰라서 엄청 고생을 했었다.
그래서 전체 프레임을 Export해서 짤라 썼었는데 이 기능을 알았더라면,, 덜 고생할 수 있지 않았을까 싶었다.</p>
<p>이제라도 알아서 다행인 기능인듯</p>
<hr>
<h3 id="실무-팁">실무 팁</h3>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/800883c3-554b-4545-a064-f4ba435dca53/image.png" alt=""></p>
<p>위처럼 UI 요소 앞에 특수 기호를 넣어서 팀원들에게 
해당 요소가 중요하다는 것을 표시하거나, 별도로 이것만 처리를 해달라는 소통의 의미로 쓰이는 경우가 있다고 함</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SwiftUI] 내비게이션 뷰]]></title>
            <link>https://velog.io/@alpha-kwhn/SwiftUI-%EB%82%B4%EB%B9%84%EA%B2%8C%EC%9D%B4%EC%85%98-%EB%B7%B0</link>
            <guid>https://velog.io/@alpha-kwhn/SwiftUI-%EB%82%B4%EB%B9%84%EA%B2%8C%EC%9D%B4%EC%85%98-%EB%B7%B0</guid>
            <pubDate>Thu, 17 Nov 2022 04:11:50 GMT</pubDate>
            <description><![CDATA[<blockquote>
<h4 id="내비게이션-스택을-이용해-콘텐츠-뷰들을-관리하는-컨테이너-뷰">내비게이션 스택을 이용해 콘텐츠 뷰들을 관리하는 컨테이너 뷰</h4>
</blockquote>
<p>스타일에 따라 <strong>UINavigationController</strong> 또는 <strong>UISplitViewController</strong>의 역할을 수행함</p>
<p>콘텐츠 뷰를 스택처럼 감싸주면 된다.</p>
<pre><code>NavigationView {
    Image(&quot;SwiftUI&quot;)
}</code></pre><ul>
<li>네비게이션 바 타이틀</li>
</ul>
<pre><code>NavigationView {
    Image(&quot;SwiftUI&quot;)
        .navigationBarTitle(&quot;내비게이션 바 타이틀&quot;)
}</code></pre><p>추가로 displayMode 설정도 가능하다.</p>
<p>내비게이션 바 타이틀은 꼭 내비게이션 뷰 안에서 사용해줘야 함</p>
<pre><code>.navigationBarTitle(&quot;내비게이션 바 타이틀&quot;)
//automatic - 기본값
.navigationBarTitle(&quot;내비게이션 바 타이틀&quot;, displayMode: .large)
.navigationBarTitle(&quot;내비게이션 바 타이틀&quot;, displayMode: .inline)
</code></pre><p><img src="blob:https://velog.io/55d92e59-0734-4a0e-88a4-f1ad78713184" alt="내비게이션 바"></p>
<ul>
<li>내비게이션 바 아이템 </li>
</ul>
<p>UIBarButtonItem의 역할을 수행함</p>
<p>각 아이템을 버튼으로 정의하여 navigationBarItems 수식어에 전달</p>
<pre><code>let leadingItem = Button(action : { print(&quot;Leading item tapped&quot;) }) {
    Image(systemName: &quot;bell&quot;).imageScale(.large)
}

let trailingItem = Button(action : { print(&quot;Trailing&quot;) }) {
    Image(systemName: &quot;gear&quot;).imageScale(.large)
}
return NavigationView {
    Image(&quot;SwiftUI&quot;)
        .navigationBarItems(leading: leadingItem, trailing: trailingItem)
        .navigationBarTitle(&quot;내비게이션 바 아이템&quot;)
}</code></pre><p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/e52d6130-5b69-4e02-8556-c366c5dad32a/image.jpeg" alt="내비게이션 바 아이템"></p>
<p>내비게이션 바 아이템은 HStack을 사용해서 여러개를 함께 넣어줄 수도 있다.<br><br/></p>
<ul>
<li>내비게이션 링크</li>
</ul>
<p>지정한 목적지로 이동할 수 있도록 만들어진 버튼</p>
<p>뷰를 눌렀을 때 또는 미리 지정된 특정 조건을 만족했을 때 화면을 전환함</p>
<p>내비게이션 스택에 뷰를 추가하여 내비게이션 계층 구조를 형성하는 데 사용</p>
<pre><code>NavigationView {
    NavigationLink(destination: Text(&quot;Destination View&quot;))     {
    Image(&quot;SwiftUI&quot;)
  }
  .navigationBarTitle(&quot;내비게이션 링크&quot;)
}</code></pre><p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/873e8273-ec63-425b-a532-754fc776756e/image.jpeg" alt="내비게이션 링크"></p>
<p>내비게이션 링크에서도 버튼과 동일하게 이미지 랜더링 모드가 template으로 지정되어 원본 색상 정보를 잃어버릴 수도 있음</p>
<p>따라서, 버튼에서처럼 랜더링 모드를 지정하거나 PlainButtonStyle을 적용하여 본래 이미지 모습으로 돌릴 수 있음</p>
<pre><code>NavigationLink(destination: Text(&quot;Destination View&quot;)) {
    Image(&quot;SwiftUI&quot;)
        .renderingMode(.original)
}
.buttonStyle(PlainButtonStyle())</code></pre><p>랜더링 모드를 .original로 하면 원본 색상 유지가 가능
.template으로 지정하면 원본 색상 정보 상실</p>
<p>위 사진은 .template으로 랜더링 되어있어서 원본 색상 정보가 없어진 상태임<br><br/></p>
<ul>
<li>Hidden 수식어</li>
</ul>
<p>필요에 따라 내비게이션 바 또는 뒤로 가기 버튼을 숨길 수도 있다.</p>
<pre><code>func navigationBarHidden(_hidden : Bool) -&gt; some View</code></pre><pre><code>NavigationView {
    .navigationBarTitle(&quot;내비게이션 바 히든&quot;)
    .navigationBarHidden(true)
}</code></pre><p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/b02cad07-b874-4e71-bbcf-bb236d10aec4/image.jpeg" alt="내비게이션 바 히든"></p>
<p>navigationBarBackButtonHidden 함수도 있는데, 이는 내비게이션 바에서 뒤로 가기 버튼을 숨기는 기능을 한다.<br><br/></p>
<ul>
<li>Navigation ViewStyle</li>
</ul>
<p>총 3가지의 스타일을 제공하며 navigationViewStyle 수식어를 이용해 원하는 스타일을 명시적으로 적용할 수 있다.</p>
<p><img src="blob:https://velog.io/170510fd-b4ca-40f1-8ddf-f6e130b3d53f" alt="내비게이션 뷰 스타일"></p>
<p>StackNavigationViewStyle : 첫째 뷰만 인식하고 나머지를 무시
DoubleColumnNavigationStyle : 첫째 뷰, 마지막 뷰만 인식</p>
<p>앞서 다뤘던 예제들은 모두 StackNavigationViewStyle에 해당함<br><br/></p>
<ul>
<li>DoubleColumnNavigationStyle</li>
</ul>
<pre><code>NavigationView {
    VStack(spacing: 20) {
        NavigationLink(destination: Text(&quot;디테일 뷰 영역&quot;).font(.largeTitle)) {
        Text(&quot;마스터 뷰 메뉴1&quot;).font(.title)
        }
        NavigationLink(destination: Text(&quot;디테일 뷰 영역&quot;).font(.largeTitle)) {
        Text(&quot;마스터 뷰 메뉴2&quot;).font(.title)
        }
   }
   .navigationBarTitle(&quot;네비게이션 뷰 스타일&quot;)

   Text(&quot;디테일 뷰&quot;).font(.largeTitle)
}</code></pre><p>&lt;세로모드&gt;
<img src="https://velog.velcdn.com/images/alpha-kwhn/post/611ae5a1-ea86-46b2-99a2-61eac0c91d17/image.png" alt=""></p>
<p>세로모드로 볼 때엔 Stack 내비게이션 스타일 때와 별 차이가 없어보임<br><br/></p>
<p>&lt;가로모드&gt;
<img src="https://velog.velcdn.com/images/alpha-kwhn/post/fe459cbe-6bc6-4059-85f7-fd32edb9aa39/image.png" alt=""></p>
<p>가로모드가 되면 좀 달라지는 것을 확인할 수 있다.</p>
<p>일단 내비게이션 바와 내비게이션 링크 버튼이 안보임</p>
<p>이들은, 가로상태에서 화면 좌측끝단-&gt;오른쪽 방향으로 밀면 나타난다.</p>
<p>또한, 내비게이션 링크 버튼 눌러도 창이 전환되지 않고, 옆에 그대로 뜨게 된다.</p>
<p>본 예제 기종은 아이폰 11프로맥스인데, 이 기종이 가로 모드일 때 사이즈 클래스가 Regular에 해당하기에 이러한 UI를 가지게 된다.</p>
<pre><code>NavigationView { ... }
    .navigationViewStyle(StackNavigationStyle())</code></pre><p>내비게이션 뷰 스타일은 다음과 같이 내비게이션 뷰 밖에서 지정해준다.
<br><br/></p>
<ul>
<li>List</li>
</ul>
<blockquote>
<h4 id="하나의-열에-여러-개의-행으로-표현되는-ui를-구성해-다중-데이터를-쉽게-나열할-수-있도록-구성된-뷰">하나의 열에 여러 개의 행으로 표현되는 UI를 구성해 다중 데이터를 쉽게 나열할 수 있도록 구성된 뷰</h4>
</blockquote>
<p>SwiftUI의 대표적인 예시이며</p>
<p>VStack와 자칫하면 헷갈릴 가능성이 높다</p>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/dd81f153-70b8-4e59-a883-eadd7811e7e5/image.jpeg" alt=""></p>
<p>VStack은 단순히 세로 방향으로 뷰를 배치하지만, 리스트는 구분선과 같은 미리 정의된 UI를 통해 반복되는 뷰를 보기 쉽게 만들어준다.</p>
<pre><code>List {
    Text(&quot;1&quot;)
    Text(&quot;2&quot;)
    ...
    Text(&quot;10&quot;)
}</code></pre><p>여담으로 리스트에서 뷰를 11개이상 넣으려고 할 시엔 오류가 발생한다.
<br><br/></p>
<ul>
<li>정적 콘텐츠</li>
</ul>
<pre><code>List {
    Text(&quot;List&quot;).font(.largeTitle)
    Image(&quot;SwiftUI&quot;)
    Circle().frame(width: 100, heigh: 100)
    Color(.red).frame(width: 100, height: 100)
}</code></pre><p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/9a8d9c17-4f6a-4ead-97cf-8b40338c6697/image.jpeg" alt=""></p>
<ul>
<li>동적 콘텐츠</li>
</ul>
<ol>
<li>Range &lt; Int &gt;<pre><code>List(0...&lt;100) {
 Text(&quot;\($0)&quot;)
}</code></pre>본 코드는 0~99까지의 값을 출력해주는 리스트이다.</li>
</ol>
<p>여기서 범위 연산자는 (..&lt;)만 사용이 가능하다.<br><br/></p>
<ol start="2">
<li><p>RandomAccessCollection</p>
<p>RandomAccessCollection 프로토콜을 준수하는 데이터를 제공하는 것임</p>
<p>이 경우엔 데이터의 각 요소들을 구분하고 식별할 수 있도록 반드시 다음 2가지 방법 중 하나를 택해 id 값을 제공해야만 한다.</p>
<p>2.1 id 식별자 지정</p>
<p>id로 사용할 값을 직접 인수로 제공</p>
<p>id 매개변수엔 Hashable 프로토콜을 준수하는 프로퍼티 지정 가능</p>
<p>만일 데이터 타입 자체가 Hashable을 준수한다면 간단히 self라고 입력할 수도 있다.</p>
</li>
</ol>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/74a84628-8943-4faf-b8ba-e9b9c5671672/image.jpeg" alt=""></p>
<p>   2.2 identifier 프로토콜 채택
   <img src="https://velog.velcdn.com/images/alpha-kwhn/post/81263e79-47f1-4c1e-8c51-ee663f54c88d/image.jpeg" alt=""></p>
<ul>
<li>정적 콘텐츠와 동적 콘텐츠의 조합<br><br/></li>
</ul>
<ol>
<li>ForEach</li>
</ol>
<p>리스트처럼 id로 식별할 수 있는 데이터를 받아서 동적으로 뷰를 생성</p>
<p>전달받는 매개변수도 RandomAccessCollection 프로토콜이나 Range&lt; Int &gt; 타입을 사용한다</p>
<pre><code>List {
    ForEach(0..&lt;50) {
        Text(&quot;\(%0)&quot;)
    }
}

List(0..&lt;50) {
    Text(&quot;\($0)&quot;)
}</code></pre><p>위 코드들의 결과는 같지만, ForEach를 활용하면 정적 + 동적 컨텐츠를 만들 수 있어서 좋다.</p>
<pre><code>let fruits = [&quot;사과&quot;, &quot;배&quot;, &quot;포도&quot;, &quot;바나나&quot;]
let drinks = [&quot;물&quot;,&quot;우유&quot;, &quot;탄산수&quot;]
var body: some View {
    List {
        Text(&quot;Fruits&quot;).font(.largeTitle)
        ForEach(fruits, id: \.self) {
            Text($0)
        }

        Text(&quot;Drinks&quot;).font(.largeTitle)
        ForEach(drinks, id: \.self) {
            Text($0)
        }
  }
 }
}      </code></pre><p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/2bea82d8-5644-4c49-81e5-77bdb114cfa7/image.jpeg" alt=""></p>
<ul>
<li>섹션</li>
</ul>
<p>리스트는 섹션을 이용해 데잍터를 쉽게 그룹화하는 것도 가능하다</p>
<pre><code>struct Section&lt;Parent, Content, Footer&gt; { }</code></pre><p>섹션에는 헤더와 푸터를 생략하거나 추가할 수 있고, 둘 중 하나만 사용할 수도 있다.</p>
<pre><code>var body: some View {
    let titles = [&quot;Fruits&quot;, &quot;Drinks&quot;]
    let data = [fruits, drinks]
    return List {
        ForEach(data.indices) { index in
            Section(
                header: Text(titles[index]).font(.title),
                footer: HStack { Spacer(); Text(&quot;\(data[index].count)건&quot;) }
                ForEach(data[index], id: \.self) {
                    Text($0)
                }
              }
            }
          }
      }</code></pre><ul>
<li>ListStyle</li>
</ul>
<p>리스트에서 상황에 맞는 스타일을 적용하는 방법
<img src="https://velog.velcdn.com/images/alpha-kwhn/post/b6220a9d-1018-490a-ab85-1e3d3c33676c/image.png" alt=""></p>
<p>지금까지 살펴봤던 예제들은 모두 PlainListStyle에 해당하는 것이었음</p>
<p>1.GroupedListStyle</p>
<pre><code>List { ... }
    .lifeStyle(GroupedListStyle())</code></pre><p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/1e4ba51d-2d42-460e-a191-03267780424b/image.png" alt=""></p>
<p>섹션이 그룹별로 명확히 나눴음을 확인할 수 있음</p>
<p>이와 유사하게 insetGroupedStyle도 존재한다.</p>
<p>한눈에 차이를 살표보면 아래와 같다.</p>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/afed4983-8d4f-4323-9365-9ae2101806ca/image.png" alt=""></p>
<p>위는 grouped, 아래는 insetGrouped 스타일이 적용된 상태이다.</p>
<p>기기마다 다른 사이즈 클래스를 가지기 때문에 사용되는 스타일이 위처럼 다르다.</p>
<p>기기의 사이즈 클래스로 인해 자동으로 지정되는 리스트 스타일을 강제적으로 변경도 가능하다.</p>
<pre><code>List { ... }
    .listStyle(GroupedListStyle())
    .environment(\.horizontalSizeClass, .regular)</code></pre><p>위처럼 코드를 통해 가로일 때의 environment를 .regular로 설정하면 바꿀 수 있다.<br><br/></p>
<ul>
<li>지오매트리 리더</li>
</ul>
<blockquote>
<h4 id="자식-뷰에-부모-뷰와-기기에-대한-크기-및-좌표계-정보를-전달하는-기능을-수행하는-컨테이너-뷰">자식 뷰에 부모 뷰와 기기에 대한 크기 및 좌표계 정보를 전달하는 기능을 수행하는 컨테이너 뷰</h4>
</blockquote>
<pre><code>init(@ViewBuilder content: @escaping (GeometryProxy) -&gt; Content)</code></pre><p>여기서 content 매개변수는 지오메트리 프록시 타입의 정보를 받아 콘텐츠를 정의하는 함수를 전달한다.</p>
<p>content 매개 변수는 뷰 빌더 속성이 선언되어 있어 뷰를 나열하는 것만으로도 사용할 수 있다.</p>
<p>이때 뷰가 배열되는 방식은 ZStack으로 이뤄진다.</p>
<p>지오매트리 리더에 자식 뷰가 하나만 있을 때는 가운데 정렬
두 개 이상이 사용되면 최상단을 기준으로 배치
<img src="https://velog.velcdn.com/images/alpha-kwhn/post/41072980-a50c-42fb-92c6-2641f14a81fd/image.jpeg" alt="">
<img src="https://velog.velcdn.com/images/alpha-kwhn/post/df13eebc-e9cb-407b-8d1a-94a02665ccfa/image.png" alt=""></p>
<p>지오메트리 리더에 크기를 지정해주지 않으면 화면 전체 크기만큼 확장하게 된다.
<br><br/></p>
<ul>
<li>지오메트리 프록시</li>
</ul>
<p>지오메트리 프록시는 두 개의 프로퍼티와 하나의 메서드, 하나의 첨자를 제공하여 지오메트리 리더의 레이아웃 정보를 자식 뷰에 제공할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/842a4e80-dc1d-4d85-8d6d-f55c4f3a4c0a/image.png" alt=""></p>
<ul>
<li>size, SafeAreaInsets</li>
</ul>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/0ea602be-7f3e-4f74-9378-a0009cb3da1a/image.png" alt="">
<img src="https://velog.velcdn.com/images/alpha-kwhn/post/092bced6-0276-4ace-8ca7-4bb4c68c8b18/image.png" alt=""></p>
<ul>
<li><p>Frame</p>
<p>지오메트리 프록시는 프레임에 대한 정보도 제공하는데, 여기서 프레임은 단순히 그 자신의 CGRect값을 전달하는 것이 아니라 CoordinateSpace라는 열거형 타입이 가진 세가지 값 중 하나를 지정하면 그 좌표 공간에 관한 정보를 반환한다.</p>
<p>global : 화면 전체 영역을 지준으로 한 좌표 정보
local : 지오메트리 리더의 bounds를 기준으로 한 좌표 정보
named : 명시적으로 이름을 할당한 공간을 기준으로 한 좌표 정보</p>
<pre><code>var body : some View {
  HStack {
      Rectangle().fill(Color.yellow).frame(Width:30)

      VStack {
          Rectangle().fill(Color.blue).frame(height: 200)

          GeometryReader {
              self.contents(geometry: $0)
              }
              .background(Color.green)
              .border(Color.red, width: 4)
         }
         .coordinateSpace(name: &quot;VStackCS&quot;)
       }
       .coordinateSpace(name: &quot;HStackCS&quot;)
    }

    func contents(geometry g: GeometryProxy) -&gt; some View {
    VStack {
        Text(&quot;Local&quot;).bold()
      Text(stringFormat(for: g.frame(in: .local).origin))
          .padding(.bottom)

      Text(&quot;Global&quot;).bold()
      Text(stringFormat(for: g.frame(in: .global).origin))
          .padding(.bottom)

      Text(&quot;Global&quot;).bold()
      Text(stringFormat(for: g.frame(int: .global).origin))
          .padding(.bottom)

      Text(&quot;Named VStackCS&quot;).bold()
      Text(stringFormat(for: g.frame(in: .named(&quot;VStackCS&quot;).origin))
          .padding(.bottom)

      Text(&quot;Named HStackCS&quot;).bold()
      Text(stringFormat(for: g.frame(in: .named(&quot;HStackCS&quot;)).origin))
      }
    }

    func stringFormat(for print: CGPoint) -&gt; String {
        String(format: &quot;(x: %f, y: %f)&quot;, arguments: [point.x, point.y])
  }</code></pre></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[UIKit] MVC Pattern & Life Cycle]]></title>
            <link>https://velog.io/@alpha-kwhn/UIKit-MVC-Pattern-Life-Cycle</link>
            <guid>https://velog.io/@alpha-kwhn/UIKit-MVC-Pattern-Life-Cycle</guid>
            <pubDate>Sat, 12 Nov 2022 09:30:30 GMT</pubDate>
            <description><![CDATA[<h3 id="--mvc-pattern">- MVC Pattern</h3>
<p>Model - View - Controller의 앞글자를 따서 이름이 지어짐</p>
<p>Model : 앱의 데이터 및 비즈니스 로직을 관리
View : 데이터의 시각적 표현을 제공
Controller : 모델과 뷰 객체 사이의 다리 역할을 수행 (적절한 타이밍에 데이터를 이동시킴)</p>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/8841920f-371d-4ef1-ba54-b32751a89b0b/image.png" alt=""></p>
<p>AppDelegate : 앱 전반의 동작에 관여
SceneDelegate : Scene의 동작에 관여</p>
<p>ViewController : 앱과 Scene 위에서 실제로 표현될 여러 뷰에 대한 상태와 변화를 담당</p>
<ul>
<li>뷰를 제어하기 위한 객체 존재 -&gt; 이 객체를 통해 클래스 내부에 뷰의 상태나 기능 제어 가능</li>
<li>UIViewController를 상속 받았으며, 뷰 로딩이 완료됐을 때 시스템에 의해 자동으로 호출되는 viewDidLoad와 같은 메서드가 정의되어 있다. 
(Custom 가능)</li>
</ul>
<p>storyboard (Main, LaunchScreen) : 앱의 인터페이스 담당</p>
<ul>
<li>컨트롤러에 의해 조작되고, 각 뷰는 인터페이스 빌더를 통해 만들어진다.</li>
<li>여러 뷰들의 흐름을 보여준다</li>
<li>각각의 뷰를 미리볼 수 있고, Assistant창을 통해 뷰의 흐름, 기능파악 등을 할 수 있다.</li>
<li>UI를 그리는 곳
(Custom 가능)</li>
</ul>
<p>Info.plist : 앱의 동작 직전에 앱의 정보를 받아옴</p>
<hr>
<p>뷰와 모델의 상호의존성을 없애고, 컨트롤러가 뷰와 모델의 중간다리 역할 수행하는 아래의 그림이 
MVC 모델의 이상적인 형태일 것이다.</p>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/2ad81671-de96-4d75-b0b5-d0e14fc72e3b/image.png" alt=""></p>
<p>하지만, 실상은 조금 다르다</p>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/aecd82ca-3942-4046-807d-d2f5ec3e7758/image.png" alt=""></p>
<p>실제로는 View와 ViewController의 결합성이 너무 강하다.</p>
<p>View, Controller가 거의 모든 일을 담당해버리고 Controller가 View의 LifeCycle에 관여하기 때문에 이들의 결합성을 약화시키기도 힘들다.</p>
<p>이 상태에서 프로젝트의 규모가 커질수록 Controller가 비대해지고 내부구조가 복잡해져서 유지보수가 힘들어진다.</p>
<p>이러한 MVC 패턴의 문제점을 해결하기 위해 MVVM, VIPER 패턴 등이 등장했다.</p>
<hr>
<h3 id="--ios-app-life-cycle">- iOS App Life Cycle</h3>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/40f3293a-9e28-4fe7-8234-d70e0a6c3f4d/image.png" alt=""></p>
<h4 id="--uiapplicationmain">- UIApplicationMain</h4>
<p><strong>(공식문서)</strong></p>
<p><code>UIApplicationMain</code> </p>
<blockquote>
<p>어플리케이션 객체와 이에 대한 Delegate를 생성하고, Event Cycle을 만드는 함수</p>
</blockquote>
<pre><code class="language-swift">func UIApplicationMain(
    argc: Int32,
    argv: UnsafeMutablePointer&lt;UnsafeMutablePointer&lt;CChar&gt;?&gt;,
    principalClassName: String?,
    delegateClassName: String?
) -&gt; Int32</code></pre>
<ul>
<li><p>argc : argv의 count에 해당함, main에 상응하는 parameter</p>
</li>
<li><p>argv : 인자 리스트 변수, main에 상응하는 parameter</p>
</li>
<li><p>principalClassName : UIApplication 클래스의 이름
=&gt;  UIApplicationMain이 실행되면 UIApplication 객체가 싱글톤 패턴으로 하나가 생성됨</p>
</li>
<li><p>delegateClassName : application delegate가 인스턴스화되는 클래스의 이름</p>
</li>
</ul>
<p>반환 타입이 Int32이긴 하지만, 사용자가 iOS App을 exit하지 않는 이상 정수 반환 값이 지정되어도 앱은 절대 종료되지 않는다는 특징이 있다.</p>
<h3 id="요약">요약</h3>
<ul>
<li>UIApplicationMain은 주 클래스에서 application 객체를 인스턴스화한다.</li>
<li>주어진 클래스로부터 delegate를 인스턴스화하고 세팅한다.</li>
<li>이벤트 루프를 설정함 (application run loop, processing events)</li>
<li>만일 Info.plist에 load되어져야 하는 main nib file이 있다면, <code>NSMainNibFile</code> key와 적절한 nib file 명을 포함시켜주어서 해당 nib file을 UIApplicationMain이 load 할 수 있도록 해준다.</li>
</ul>
<p>사실상 UIApplicationMain은</p>
<p>앱 객체 생성 프로세스 핸들링, UI와 기능을 읽어 구현, 이벤트 루프 실행</p>
<p>이 모든 것을 다 하기 때문에 앱 그 자체로 볼 수 있다.</p>
<hr>
<h3 id="앱-실행-과정">앱 실행 과정</h3>
<blockquote>
<p>App Start -&gt; UIApplicationMain 실행 -&gt; UIApplication 생성 -&gt; AppDelegate 생성 -&gt; 해당 클래스에 있는 application 메소드를 실행시켜 개발자가 써 놓은 코드 실행</p>
</blockquote>
<ul>
<li>AppDelegate </li>
</ul>
<p><strong>UIApplication의 권한을 위임받아</strong> 커스텀 코드와 상호작용하여 <strong>코드를 실제 뷰와 컨트롤러로 보여지게, 그리고 동작하게 한다.</strong></p>
<ul>
<li>EventLoop</li>
</ul>
<p>앱이 꺼지기 직전까지 쭉 이벤트 루프를 돌면서 뷰를 생성하고, 동작하게 함.
앱의 여러 뷰와 각각의 뷰를 제어하는 컨트롤러가 사용자와 상호작용하는 것으로 볼 수 있음.</p>
<hr>
<h3 id="앱-종료-과정">앱 종료 과정</h3>
<blockquote>
<p>이벤트 루프 실행 -&gt; AppDelegate의 applicationWillTermintate 실행 -&gt; 앱 종료</p>
</blockquote>
<p>앱이 꺼지기 직전까지는 이벤트 루프가 실행
종료직전에 AppDelegate의 applicationWillTerminate 메소드가 실행
해당 메소드 안에 적혀 있는 커스텀 코드에 따라 종료 직전 처리해야 할 일들을 모두 완료
앱이 최종적으로 종료됨</p>
<hr>
<p>참고링크 : <a href="https://2unbini.github.io/%F0%9F%93%82%20all/swift/UIKit-2/">https://2unbini.github.io/%F0%9F%93%82%20all/swift/UIKit-2/</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[M1 Mac Cocoapod Install Error (XCode 14.1 ver)]]></title>
            <link>https://velog.io/@alpha-kwhn/M1-Mac-Cocoapod-Install-Error-XCode-14.1-ver</link>
            <guid>https://velog.io/@alpha-kwhn/M1-Mac-Cocoapod-Install-Error-XCode-14.1-ver</guid>
            <pubDate>Sat, 12 Nov 2022 02:57:43 GMT</pubDate>
            <description><![CDATA[<h3 id="cocoapods이란">Cocoapods이란?</h3>
<ul>
<li>Swift 및 Objc 언어 환경 프로젝트이 의존성을 관리해주는 도구</li>
</ul>
<hr>
<p>설치가 안되어있어서 나의 맥북에 설치를 진행했다.</p>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/8648ec77-56b5-44d5-a86f-386536a7d98b/image.png" alt=""></p>
<p><code>sudo gem install cocoapods</code> 명령어를 입력하였고 그 결과 설치가 되었다.
<img src="https://velog.velcdn.com/images/alpha-kwhn/post/578fbfcc-53b5-45b3-a4ca-953ec345b011/image.png" alt=""></p>
<p>cocoapod이 설치되었으니, 원하는 프로젝트 파일에 접근하여 cocoapod를 연동시키는 과정을 진행했다.
<code>pod init</code>  명령어를 입력했는데,, 갑자기 에러문구가 떴다.</p>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/9bcfc438-cf05-483a-92fa-f5400678ad0a/image.png" alt=""></p>
<p>이 문제를 해결하기 위해 에러코드를 복사하여 구글링을 하였다.</p>
<p>검색을 해보니, M1 칩 맥북에서 흔히 발생하는 Cocoapod 에러라고 한다.</p>
<p>이를 해결하기 위해서는 </p>
<ol>
<li><p>Rosetta로 Terminal 열기</p>
</li>
<li><p>XCode를 13 버전으로 낮춰주기 (14에서는 pod install 불가능)</p>
</li>
<li><p><code>sudo arch -x86_64 gem install cocoapods</code> 와 같은 명령어를 통해 arm64가 아닌 x86_64 아키텍쳐로 cocoapods를 설치해야 한다.</p>
<p>위 방법들을 쓴 결과 아래와 같이 문제가 해결된 모습을 볼 수 있었다.</p>
</li>
</ol>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/eb86ac5f-0ae3-4006-80d2-fd26f58bd59a/image.png" alt=""></p>
<p>보면 오른쪽 XCode Inspector에 Project Format이 13.0으로 설정되어 있고</p>
<p>x86_64 아키텍처에서 cocoapods를 설치하고 init하여서 성공적으로 프로젝트 폴더에 Podfile을 생성했음을 확인할 수 있었다.</p>
<p>1, 3번 과정을 실행해도 2번 (XCode version 낮추기)을 실행하지 않으면 설치가 안되었는데, 이를 미루어보아 XCode의 버전 설정이 가장 중요한 과정임을 알 수 있었다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[GitHub] Repository에서 특정 branch만 clone 실패 해결과정]]></title>
            <link>https://velog.io/@alpha-kwhn/GitHub-Repository%EC%97%90%EC%84%9C-%ED%8A%B9%EC%A0%95-branch%EB%A7%8C-clone-%EC%8B%A4%ED%8C%A8-%ED%95%B4%EA%B2%B0%EA%B3%BC%EC%A0%95</link>
            <guid>https://velog.io/@alpha-kwhn/GitHub-Repository%EC%97%90%EC%84%9C-%ED%8A%B9%EC%A0%95-branch%EB%A7%8C-clone-%EC%8B%A4%ED%8C%A8-%ED%95%B4%EA%B2%B0%EA%B3%BC%EC%A0%95</guid>
            <pubDate>Tue, 25 Oct 2022 16:26:50 GMT</pubDate>
            <description><![CDATA[<p>부트캠프 팀 레포지토리에서 내가 만든 branch를 내 맥북으로 클론하고 싶었는데 그 과정에서 어려움을 겪었다.</p>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/9d1bad30-19f6-42fc-9937-298da2eddba3/image.png" alt=""></p>
<p>기존에 사용하던 방법은 아래의 명령어였다.</p>
<pre><code>git clone 저장소주소</code></pre><p>그런데 막상 클론하고 난 파일을 보니 main에 올려져 있는 파일들이 clone 된 것을 확인할 수 있었다.</p>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/6a8da22f-1da5-4811-9dfb-0e2f2d67c6e5/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/0c3b06c4-8b4d-4a97-8bcd-bcadf059c0f9/image.png" alt=""></p>
<p>제대로 브랜치가 clone 되었더라면 이런화면이 떠야하는데..</p>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/a4c1bab8-5e74-4242-b6ea-178ffa09bff5/image.png" alt=""></p>
<p>ContentVeiw()를 프리뷰 캔버스로 실행했을 때 main 브랜치에 올려진 코드의 실행화면이 나타났다.
(나중에 코드를 확인해보니 내 코드 아닌것도 확인)</p>
<p>기존에 쓰던 명령어말고 다른 명령어를 사용해야겠다는 것을 느꼈고, 그래서 자료를 찾아보았더니 운좋게 알아낼 수 있었다.
(참고링크 : <a href="https://info-lab.tistory.com/m/60">https://info-lab.tistory.com/m/60</a>)</p>
<p>특정 repository의 main이 아닌 특정 branch를 clone하고 싶으면 아래와 같은 명령어를 입력해야한다.</p>
<pre><code>git clone -b branch이름 저장소주소</code></pre><p>본 명령어를 치고 엔터를 누르면 끝날줄 알았는데, 그런데 갑자기 아래의 문구가 떴다
<img src="https://velog.velcdn.com/images/alpha-kwhn/post/98aaa94f-e646-4c59-be81-b1f23c51152b/image.png" alt=""></p>
<p>&quot;리모트의 kwan 브랜치가 없다&quot;라는 단어를 보았을 때, 현재 git의 remote 저장소가 내가 원하는 저장소로 지정이 안되어 있다는 느낌을 받았다.</p>
<p>그래서 나는 신속히 현재 연결된 원격저장소가 무엇인지 확인해보았다.</p>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/420e5482-a155-4b92-8873-91d627bac05e/image.png" alt=""></p>
<pre><code>git remote -v</code></pre><p>현재 연결된 remote 저장소를 확인하기위해 위와 같은 명령어를 입력했다.</p>
<p>터미널을 보니 내가 원하는 roundingRound-swiftui-20221021-team02.git remote 저장소가 아닌 BootCamp.git remote 저장소에 연결이 되어 있음을 확인할 수 있었다.</p>
<p>따라서 나는 remote 저장소 연결을 변경하는 작업을 수행해야했다.</p>
<pre><code>git remote set-url origin 저장소주소</code></pre><p>방법을 찾아보다가 위 명령어를 사용하면 해결이 된다고 들어서 입력해보았다.
(참고링크: <a href="https://webisfree.com/2020-04-14/%5Bgit%5D-git-remote-repository-%EB%B3%80%EA%B2%BD%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95">https://webisfree.com/2020-04-14/[git]-git-remote-repository-%EB%B3%80%EA%B2%BD%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95</a>)</p>
<p>그 결과 clone이 정상적으로 실행된 것을 확인할 수 있었다.
XCode에서도 나의 branch 이름이 명확히 떴고, ContentView()의 출력 화면도 내가 짠 화면대로 잘 나왔다.!</p>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/191ad3d2-31d6-4ea2-8acd-0ab005d58841/image.png" alt=""><img src="https://velog.velcdn.com/images/alpha-kwhn/post/2af0dcf4-6115-4235-bc57-8e9610df8b8b/image.png" alt=""></p>
<p>git repository 원하는 branch clone하기
git remote repository 변경하기 </p>
<p>위 두가지를 이번 경험을 통해 제대로 알게되었다.
앞으로 유사한 문제를 마주하게 되었을때는 잘 해결할 수 있을것 같다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Objective-C ]]></title>
            <link>https://velog.io/@alpha-kwhn/Objective-C</link>
            <guid>https://velog.io/@alpha-kwhn/Objective-C</guid>
            <pubDate>Sun, 09 Oct 2022 08:46:46 GMT</pubDate>
            <description><![CDATA[<h4 id="20221006">2022.10.06</h4>
<p>Swift의 조상님(?)인 Objective0-C 언어를 부트캠프에서 배워보게되었다.</p>
<p>앞으로 자주 쓸 언어는 아니지만, 그래도 iOS 개발로 진출을 한다면 가끔씩 마주칠 수도 있는 언어이기에 집중해서 공부를 해보도록 하겠다..!</p>
<hr>
<h2 id="📌-개요brbr">📌 개요<br><br/></h2>
<h3 id="--역사-및-특징brbr">- 역사 및 특징<br></br></h3>
<p>Object-C 언어는 1980년대 초 <strong>브래드 콕스가 설계</strong>한 언어이며, 아래의 특징을 가진다.</p>
<blockquote>
<h4 id="smalltalk-80-언어-기반">SmallTalk-80 언어 기반</h4>
</blockquote>
<h4 id="c언어-위에-있는-계층정layered-구조">C언어 위에 있는 계층정(layered) 구조</h4>
<h4 id="c언어를-확장하여-객체를-생성하고-다룰-수-있는-새-언어">C언어를 확장하여 &#39;객체&#39;를 생성하고 다룰 수 있는 새 언어</h4>
<p>Objective-C는 캡슐화, 데이터 은닉, 계승, 다형성 등의 특징을 지니는 <strong>객체 지향 언어</strong>이다.</p>
<p>1988년에 NeXT Software는 Objective-C언어로 NeXTSTEP 운영체제 개발환경과 라이브러리를 개발하였고, NeXT는 추후에 애플에 인수된다.</p>
<p>그렇게 <strong>NeXT가 인수되면서 Mac OS X와 iPhone OS 앱 개발의 기본언어는 자연스레 Objective-C가 되었다</strong>.</p>
<p>하지만, 시대가 변하면서 Objective-C언어의 불편함에 많은 iOS 개발자들이 힘들어했으며 새로운 언어 등장 붐이 일면서 애플도 Swift라는 언어를 개발했다.</p>
<p>애플이 <strong>iOS 개발 언어를 Swift로 바꾸기 시작하면서, Objective-C는 개발에서 더 이상 쓰이지 않는 일이 많아졌다.</strong></p>
<p>실제로 <strong>Objective-C의 마지막 최신버전 발표는 2007</strong>년 이후 나오지 않고 있다.</p>
<p>대세에서는 밀렸으나 과거에 Objective-C로 만들었던 코드들이 남아있기도 하고, <strong>Swift도 결국엔 Objective-C를 바탕으로 만들어졌기에 여전히 Objective-C의 가치는 살아있다</strong>.<br><br/></p>
<hr>
<h2 id="📌-프로그램-구조brbr">📌 프로그램 구조<br><br/></h2>
<p>Objective-C 프로그램은 기본적으로 다음 부분으로 구성된다.</p>
<ul>
<li><h4 id="전처리기-명령">전처리기 명령</h4>
</li>
<li><h4 id="인터페이스">인터페이스</h4>
</li>
<li><h4 id="구현">구현</h4>
</li>
<li><h4 id="메소드">메소드</h4>
</li>
<li><h4 id="변수">변수</h4>
</li>
<li><h4 id="진술-및-표현">진술 및 표현</h4>
</li>
<li><h4 id="주석">주석</h4>
</li>
</ul>
<p>&quot;Hello World&quot;를 출력하는 기본 예제코드를 살펴보면서 구조에 대해 정확히 파악해보자.</p>
<pre><code class="language-swift">#import &lt;Foundation/Foundation.h&gt;

@interface SampleClass : NSObject
- (void) sampleMethod;
@end

@implementation SampleClass
-(void)sampleMethod {
    NSLog(@&quot;Hello World!\n&quot;);
}
@end

int main() {
    SampleClass *sampleClass = [[SampleClass alloc]init];
    [sampleClass sampleMethod];
    return 0;
}</code></pre>
<p><br><br/></p>
<h4 id="1-전처리기-명령">1) 전처리기 명령</h4>
<pre><code class="language-swift">#import &lt;Foundation/Foundation.h&gt;</code></pre>
<p>프로그램의 첫 번째 줄은 전처리기 명령부이다.
컴파일 되기 전에 처리해야할 명령을 넣는 부분이다.</p>
<p>본 코드에서는 컴파일러가 컴파일을 시작하기 전에 Foundation.h 파일을 포함하라고 지시한다. <br><br/></p>
<h4 id="2-인터페이스-선언">2) 인터페이스 선언</h4>
<pre><code class="language-swift">@interface SampleClass : NSObject
- (void) sampleMethod;
@end</code></pre>
<p>Objective-C에서는 인터페이스란 것을 생성한다.
클래스를 선언하고, 그 안에서 쓰이는 메서드를 선언해준다.</p>
<p>@implementation - @end로 시작과 끝을 꼭 알려주어야하며, NSObject 클래스를 꼭 상속해줘야한다. </p>
<p>NSObject 클래스는 런타임 시스템에 대한 인터페이스 역할을 하는 &#39;루트 클래스&#39;이다.</p>
<p>또한, 메서드를 선언할 때 앞에 -, + 등을 붙인다.</p>
<p>앞에 -가 붙는 경우는 Swift에서 func 키워드를 이용한 일반적인 인스턴스 메서드를 선언하는 경우라고 생각하면된다.</p>
<p>그리고 +가 붙는 경우는 class func 키워드를 이용한 Swift에서의 타입 메서드를 선언하는 경우라고 생각하면 된다.<br><br/></p>
<h4 id="3-구현">3) 구현</h4>
<pre><code class="language-swift">@implementation SampleClass
-(void)sampleMethod {
    NSLog(@&quot;Hello World!\n&quot;);
}
@end</code></pre>
<p>인터페이스 파트에서 선언한 클래스의 메서드를 구현해주는 부분이다.</p>
<p>@implementation - @end로 구현부의 시작과 끝을 꼭 표시해줘야한다. </p>
<p>내부 구현은 Objective-C 문법에 따라 코딩하면 된다.<br><br/></p>
<h4 id="4-main-함수">4) main 함수</h4>
<pre><code class="language-swift">int main() {
    SampleClass *sampleClass = [[SampleClass alloc]init];
    [sampleClass sampleMethod];
    return 0;
}</code></pre>
<p>Objective-C에서 main()은 프로그램이 실행되는 주요 함수이다.</p>
<p>이 부분도 구현부와 마찬가지로, Objective-C 문법에 따라 코드를 작성해주면 된다.</p>
<p>[[SampleClass alloc]init];은 클래스 인스턴스를 선언해주는 주요 코드</p>
<p>[samplecClass sampleMethod];는 인스턴스를 통해 메서드를 호출하는 주요 코드이다.</p>
<hr>
<h2 id="📌-데이터-타입brbr">📌 데이터 타입<br><br/></h2>
<p>Objective-C의 타입은 다음과 같이 분류할 수 있다.<br><br/></p>
<ul>
<li><h4 id="기본-타입">기본 타입</h4>
<p>산술타입이며 정수 및 부동 소수점 타입으로 구성된다.</p>
</li>
<li><h4 id="열거형">열거형</h4>
<p>산술타입이며 프로그램 전체에서 특정 불연속 정수 값만 할당할 수 있는 변수를 정의</p>
</li>
</ul>
<ul>
<li><h4 id="타입-무효">타입 무효</h4>
형식 지정자 void는 사용할 수 있는 값이 없음을 나타냄</li>
</ul>
<ul>
<li><h4 id="파생-타입">파생 타입</h4>
포인터 타입, 배열 타입, 구조 타입, 통합 타입 및 함수 타입이 포함됨<br><br/></li>
</ul>
<p>Swift 타입과의 주된 타입이라고 한다면 Int, Double이 기본 타입이라는 것이다. </p>
<p>Swift에서의 Int, Double은 구조체에 해당하기 때문이다.</p>
<hr>
<h3 id="--기본-타입brbr">- 기본 타입<br><br/></h3>
<ul>
<li><h4 id="정수타입integer-typesbrbr">정수타입(Integer Types)<br><br/></h4>
<p>아래 표는 저장 크기와 값 범위가 있는 표준 정수 타입에 대한 세부 정보를 제공한다. 
<img src="blob:https://velog.io/dd6b9b7d-4042-4cdf-bec7-4362893bceb5" alt="정수타입">
저장 크기와 종류는 Swift와 유사하다. </p>
<p>한가지 유의할 점이라면, Objective-C에서의 <strong>char은 1 byte 크기의 유니코드가 아닌 &#39;아스키코드&#39;를 말한다.</strong><br><br/></p>
</li>
</ul>
<ul>
<li><h4 id="부동소수점-타입floating-point-typesbrbr">부동소수점 타입(Floating-Point Types)<br><br/></h4>
아래 표는 저장 크기와 값 범위 및 정밀도가 있는 표준 부동 소수점 타입에 대한 세부 정부를 제공한다.
<img src="https://velog.velcdn.com/images/alpha-kwhn/post/7a98d3a9-9345-4796-a9ee-1e8e9b4ebc79/image.png" alt="부동소수점 타입">
이 또한, 저장 크기와 종류가 Swift와 유사하다.
<br><br/></li>
</ul>
<h3 id="--열거형brbr">- 열거형<br><br/></h3>
<p>Swift와 마찬가지로 <code>enum</code> 키워드를 활용하여 열거형을 정의한다.</p>
<pre><code class="language-swift">enum month {
    january = 1, february, march, april, 
    may, june, july, august, september, october, 
    november, december
};</code></pre>
<p>위 코드는 month라는 열거형 타입을 선언한 코드이다.</p>
<p>이렇게 선언한 타입으로 변수를 만들어서 해당 열거형 타입 내의 값들에 접근할 수 있게 된다.</p>
<p>열거형 타입의 변수를 정의하는 방법은 아래와 같다.</p>
<pre><code class="language-swift">enum month vars, wars;
vars = january;
wars = december;</code></pre>
<p>정의된 변수에는 열거형 내에 선언된 값들 (january, february....)만 들어올 수 있다.</p>
<pre><code class="language-swift">#import &lt;Foundation/Foundation.h&gt;


int main(int argc, const char * argv[])
{

    enum month { january = 1, february, march, april, may, june, july, august, september, october, november, december };

    enum month amonth;         
    int days;

    NSLog (@&quot;Enter month number: &quot;); 
    scanf (&quot;%i&quot;, &amp;amonth);

    switch (amonth) { 
        case january:
        case march: 
        case may:
        case july:
        case august: 
        case october: 
        case december:
            days = 31;
            break; 
        case april: 
        case june:
        case september: 
        case november:
            days = 30;
            break; 
        case february:
            days = 28;
            break; 
        default:
            NSLog (@&quot;bad month number&quot;); days = 0;
            break;
    }
    if ( days != 0 )
        NSLog (@&quot;Number of days is %i&quot;, days);
    if ( amonth == february )
        NSLog (@&quot;...or 29 if it&#39;s a leap year&quot;);

    return 0;
} </code></pre>
<p><br><br/></p>
<h3 id="--타입무효voidbrbr">- 타입무효(void)<br><br/></h3>
<p>void 타입은 사용 가능한 값이 없음을 지정하며, 아래와 같은 상황에서 사용된다.</p>
<p><img src="blob:https://velog.io/366ff27b-ef84-48ab-9112-d19f9d9b1010" alt="void타입"><br><br/></p>
<h3 id="--파생타입derived-typesbrbr">- 파생타입(Derived types)<br><br/></h3>
<ul>
<li><h4 id="배열-arraybrbr">배열 (Array)<br><br/></h4>
<blockquote>
<h4 id="같은-타입의-요소들을-순차적으로-저장하는-고정크기의-컬렉션">같은 타입의 요소들을 순차적으로 저장하는 고정크기의 컬렉션</h4>
</blockquote>
<p>배열 변수 선언 후 숫자를 사용하여 표현하며, 배열 특정 요소는 인덱스에 의해 엑세스가 가능함.</p>
<p>가장 낮은 주소는 첫 번째 요소, 가장 높은 주소는 마지막 요소이다.</p>
<p>배열의 선언법과 초기화 방법은 아래와 같다.</p>
<pre><code class="language-swift">타입 배열이름 [크기];
double balance[10] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 
8.0, 9.0, 10.0};

double ssef[] = {2.2, 3.3};
NSLog(@&quot;1번째 요소값 = %f\n&quot;, ssef[1]);
//3.3 출력</code></pre>
<p>배열의 size는 0보다 큰 정수 상수, type은 유효한 Objective-C 데이터 유형(int, double 등등)만 가능하다.</p>
<p> 또한, 배열의 초기화시에 대괄호에 숫자를 넣어 size를 지정해 줄 수 있으며, 대괄호 안에 숫자를 넣지 않으면 중괄호에 선언된 값들 개수만큼 크기가 자동으로 설정된다.</p>
<p>아래는 배열을 활용한 예제 코드이다.</p>
<pre><code class="language-swift">#import &lt;Foundation/Foundation.h&gt;
int main(int argc, const char * argv[]) {
  @autoreleasepool {

      int myArray[10];
      int i, j;

      for (i=0; i&lt;10; i++) {
           myArray[i] = i + 100;
      }

      for (j = 0; j &lt; 10; j++) {
          NSLog(@&quot;Element[%d] = %d\n&quot;, j, myArray[j]);
      }
  }
  return 0;
}</code></pre>
<p>추가로 위 코드에서 @autorelease는 프로그램의 최고 메모리 사용량을 줄여주는 역할을 한다고 한다.
(주로 loop 문에서 많이 쓰인다)</p>
<p>또한, 배열은 아래와 같이 다양한 형태로 존재할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/3ecfb2fc-ca88-4b55-8911-71fb53cfa101/image.png" alt="배열"></p>
</li>
<li><h4 id="포인터-pointerbrbr">포인터 (Pointer)<br><br/></h4>
<blockquote>
<h4 id="변수의-메모리-위치를-값으로-가지는-변수">변수의 메모리 위치를 값으로 가지는 변수</h4>
</blockquote>
<p>포인터의 선언 방식은 아래와 같다.</p>
<pre><code class="language-swift">type *var-name;</code></pre>
<p>여기서 type에는 Int, Double 등과 같은 유효한 데이터 타입이 와야한다.</p>
<p>var-name은 포인터 변수의 이름을 의미한다.</p>
<p>아래는 포인터를 활용한 예제 코드들이다.</p>
<pre><code class="language-swift">#import &lt;Foundation/Foundation.h&gt;
int main(int argc, const char * argv[]) {
  int age = 13;
  double height = 145.32;

  //변수에 담긴 값을 출력
  NSLog(@&quot;age : %d&quot;, age);
  NSLog(@&quot;height : %f&quot;, height);

  //변수가 위치한 메모리 안에서의 주소
  NSLog(@&quot;address of age : %x&quot;, &amp;age);
  NSLog(@&quot;address of height : %x&quot;, &amp;height);

  //포인터 정보 -&gt; 해당 데이터의 메모리 주소 + 메모리를 차지하는 크기
  //토지대장 느낌
  return 0;
}
//13, 145.320000
// 6fdff3ac, 6fdff3a0 (16진수로 표현된 메모리 주소)</code></pre>
<pre><code class="language-swift">#import &lt;Foundation/Foundation.h&gt;
int main(int argc, const char * argv[]) {
  int age = 17;

  // 변수 age의 주소를 확인해서, int 타입이 담길 거라고 생각하는 포인터 변수 만들기
  int *addressOfAge = &amp;age;

  NSLog(@&quot;age는 %p 주소에 위치했습니다.&quot;, addressOfAge);
  NSLog(@&quot;age 변수의 메모리 크기 %zu 바이트입니다.&quot;, sizeof(age));
  NSLog(@&quot;int의 메모리 크기 %zu 바이트입니다.&quot;, sizeof(int));
  NSLog(@&quot;처음 %p 주소에 가보니 %d 값이 들어있습니다.&quot;, addressOfAge, *addressOfAge);
  //0X16fdff3ac
  //0X16fdff3ac, 17

</code></pre>
</li>
</ul>
<pre><code>addressOfAge = 32;
//오류나는 문장 -&gt; 포인터 타입 아닌 Int 타입이 들어가기 때문에 

*addressOfAge = 32;
//옳은 문장 -&gt;

NSLog(@&quot;다시 %p 주소에 가보니 %d 값이 들어있습니다.&quot;, addressOfAge, *addressOfAge);
NSLog(@&quot;%p를 담은 데이터의 포인터정보의 메모리 크기 %zu 바이트입니다.&quot;, infoOfAge, sizeof(infoOfAge));
NSLog(@&quot;int를 담은 데이터의 포인터정보 크기는 %zu 바이트입니다.&quot;, sizeof(int*));

//SampleClass의 인스턴스를 만들어서 그 메모리의 위치정보를 SampleClass클래스에 맞춘 포인터 변수 
// sampleClass에 할당함
// 클래스에 의해 만들어지는 인스턴스는 무조건 포인터 단위로 관리해야만 활용 가능함.
SampleClass *sampleClass = [[SampleClass alloc] init];
//alloc, init에 의해 모두 주소값이 반환됨

//sampleClass 포인터 정보가 가르키는 인스턴스 데이터를 찾아가서
//데이터에 명시된 sayHello 메소드를 실행하라
[sampleClass sayHello];

return 0;</code></pre><p>}  </p>
<pre><code> 위 코드를 통해 살펴볼 수 있는 포인터의 특성들은 아래와 같다.

   #### -특정 변수의 메모리 주소는 `앰퍼서더(&amp;)` 로 접근한다.

  #### - 메모리주소는 16진수 값으로 표현되기에 `%p` 뿐만 아니라 `%x` 로 출력할 수 있다.

  #### - 포인터 변수에 담긴 메모리 주소에 담긴 값에 접근할 땐 포인터 변수 앞에 `*` 을 붙인다.

  #### - size에 대응하는 형식지정자는 `%zu` 이다.

  #### - 포인터를 통해 출력한 주소 값의 크기는 주소에 담긴 값의 타입과 상관없이 항상 8byte이다.
  #### (주소 값은 16진수로 표현되기 때문이다)&lt;br&gt;&lt;br/&gt;


 Objective-C에서는 **포인터에 할당할 정확한 주소가 없는 경우 포인터 변수에 NULL 값을 할당** 할 수도 있는데, 우리는 이를 `NULL 포인터` 라고 부른다.

 NULL 포인터는 **메모리 주소 값으로 0**을 가지는데, 이는 **포인터가 액세스 가능한 메모리 위치를 가리키도록 의도되지 않았음을 의미**한다. 

  NULL 포인터를 공부하면서 개인적으로 Swift에서의 nil과 굉장히 헷갈렸는데 둘의 차이점을 살펴보면 아래와 같다.&lt;br&gt;&lt;br/&gt;

   |NULL|nil|
   |:---:|:---:|
   |주소가 없음을 의미|내용이 없음을 의미|
   &lt;br&gt;&lt;br/&gt;


 포인터는 아래에 적힌 다양한 형태들로 존재할 수 있다. 
 ![포인터](https://velog.velcdn.com/images/alpha-kwhn/post/7ad64858-37ca-411a-9f87-bf8178d4ffe8/image.png)

----

## 📌 변수와 상수&lt;br&gt;&lt;br/&gt;


변수와 상수의 개념은 Swift, C 등 다른 프로그래밍 언어와 동일하며, 선언 방식도 비슷하다. 

그렇기에 본 포스팅에선 가볍게 살펴보는 정도로만 변수와 상수 개념을 다루겠다.&lt;br&gt;&lt;br/&gt;


### - 변수
&gt;    #### 변수 : 값을 저장하는 저장 영역에 주어진 이름, 변경이 가능

아래는 변수를 선언 및 출력하는 예제코드이다.

```swift
#import &lt;Foundation/Foundation.h&gt;

// Variable declaration:
extern int a, b;
extern int c;
extern float f;

int main () {
  /* variable definition: */
  int a, b;
  int c;
  float f;

  /* actual initialization */
  a = 10;
  b = 20;

  c = a + b;
  NSLog(@&quot;value of c : %d \n&quot;, c);

  f = 70.0/3.0;
  NSLog(@&quot;value of f : %f \n&quot;, f);

  return 0;
}</code></pre><p>여기서 <code>extern</code> 은 <strong>어느 곳에서나 변수를 선언할 수 있다는 것을 의미</strong>하는 키워드이다. </p>
<p>변수를 선언할 때 <strong>등호 왼쪽에 위치한 메모리 위치를 참조하는 표현식</strong>을 <code>lvalue</code> 라고 한다.</p>
<p>변수를 선언할 때 <strong>등호 오른쪽에 위치한 메모리의 일부 주소에 저장된 데이터 값</strong>을 <code>rvalue</code> 라고 한다.<br><br/></p>
<h3 id="--상수">- 상수</h3>
<blockquote>
<h4 id="상수--프로그램이-실행-중에-변경할-수-없는-고정-값">상수 : 프로그램이 실행 중에 변경할 수 없는 고정 값</h4>
</blockquote>
<p>상수는 정수, 문자, 부동 소수점 또는 문자열 리터럴과 같은 기본 데이터 유형 중 하나일 수 있으며, 열거형 상수도 있다.</p>
<p>이때 리터럴이란, 해당 타입의 원형(타입의 값 그자체)을 말한다.<br><br/></p>
<ul>
<li><h4 id="정수-리터럴">정수 리터럴</h4>
<p><strong>정수 리터럴은 10/8/16진수 상수일 수 있고, 기수를 접두사로 지정</strong>한다.
(0 : 8진수 접두사, 0x : 16진수 접두사, 10진수는 접두사 없음)</p>
<p>또한, <strong>unsigned와 long에 대해 U와 L의 조합인 접미사도 가질 수 있다.</strong>
(U와 L은 소문자도 될 수 있다)</p>
<p>아래는 정수 리터럴의 몇가지 예시이다.</p>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/54e06ea2-66ec-403c-8bef-3ae3f452a5f7/image.png" alt="정수 리터럴"></p>
<ul>
<li><h4 id="부동-소수점-리터럴">부동 소수점 리터럴</h4>
</li>
</ul>
<p>부동 소수점 리터럴에는 <strong>정수 부분, 소수점, 소수 부분 및 지수 부분</strong>이 있다.</p>
<p>나타내는 방법은 <strong>소수점 형식과 지수 형식이 있다</strong>.</p>
<p><strong>소수점 형식을 사용하여 나타낼 때는 소수점, 지수 또는 둘 다를 포함</strong>해야 함.</p>
<p><strong>지수 형식을 사용하여 나타낼 때는 정수 부분, 소수 부분 또는 둘 다를 포함</strong>해야 함.</p>
<p><strong>부호가 있는 지수는 e 또는 E로 시작</strong>한다. </p>
<p>아래는 부동 소수점 리터럴의 몇가지 예시이다.</p>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/13365a2a-d05d-4800-a792-a4ccc1869e78/image.png" alt="부동 소수점 리터럴"></p>
</li>
</ul>
<ul>
<li><h4 id="문자-리터럴">문자 리터럴</h4>
<p>문자 리터럴은 <code>작은 따옴표(&#39;)</code> 에 묶여 있으며 char 유형의 단순 변수에 저장이 가능하다. </p>
<p>일반문자(&#39;x&#39;), 이스케이프 시퀀스(&#39;\t&#39;), 범용문자(&#39;\u02C0&#39;)이 있다.</p>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/d6d9a5eb-c74c-4132-b661-622aabdbb2b7/image.png" alt="문자 리터럴"></p>
</li>
</ul>
<ul>
<li><h4 id="문자열-리터럴">문자열 리터럴</h4>
<p>문자열 리터럴 또는 상수는 <code>큰 따옴표(&quot;&quot;)</code> 로 묶인다.</p>
<p>문자열에는 문자 리터럴들이 포함된다.</p>
<p> <img src="https://velog.velcdn.com/images/alpha-kwhn/post/aeac0a7e-3f90-4190-82ef-8a322ed0fa86/image.png" alt="문자열 리터럴"></p>
<ul>
<li><h4 id="상수-정의법brbr">상수 정의법<br><br/></h4>
</li>
</ul>
<h4 id="1-define">1. #define</h4>
<pre><code class="language-swift">#define identifier value</code></pre>
<p>컴파일 시점에 코드의 모든 identifier를 value로 바꿔버리는 방식으로 상수를 정의한다.</p>
<p>전통적인 C언어에서는 많이 쓰이지만, Objective-C에서는 사용이 지양된다.<br><br/></p>
<h4 id="2-const-키워드">2. const 키워드</h4>
<pre><code class="language-swift">const type variable = value;

#import &lt;Foundation/Foundation.h&gt;

int main() {
   const int LENGTH = 10;
  const int WIDTH = 5;
  const char NEWLINE = &quot;\n&quot;;
  int area;

  area = LENGTH * WIDTH;
  NSLog(@&quot;value of area : %d&quot;, area);
  NSLog(@&quot;%c&quot;, NEWLINE);

  return 0;
}</code></pre>
<p>const 키워드를 이용해 상수를 정의하면 코드 작동 중에 선언이 이루어지기 때문에, #define 보다 안전하다.</p>
<p>Objective-C에서는 const 키워드 사용을 권장한다. </p>
<p>그리고 Objective-C에서 상수이름은 대문자로 해야한다.</p>
</li>
</ul>
<hr>
<h2 id="📌-반복문과-조건문brbr">📌 반복문과 조건문<br><br/></h2>
<p> 반복문과 조건문도 상수와 변수처럼 다른 언어들과 특성이 비슷하다.</p>
<p> 따라서, 반복문과 조건문에 관한 간단한 코드예제들만 살펴보고 넘어가겠다.<br><br/></p>
<h3 id="--반복문-loopsbrbr">- 반복문 (Loops)<br><br/></h3>
<p> Objective-C에서 사용할 수 있는 반복문의 종류는 아래와 같다.<br><br/></p>
<blockquote>
<h4 id="--while문">- while문</h4>
<h4 id="--for문">- for문</h4>
<h4 id="--dowhile문">- do...while문</h4>
</blockquote>
<p> 그리고 이러한 반복문은 다음과 같은 제어문도 지원한다.</p>
<blockquote>
<h4 id="--break">- break</h4>
<h4 id="--continue">- continue</h4>
</blockquote>
<p> <br><br/></p>
<ul>
<li><h4 id="while-문">while 문</h4>
<pre><code class="language-swift">#import &lt;Foundation/Foundation.h&gt;

int main ()
{
 int a = 10;

 while( a &lt; 20) {
     NSLog(@&quot;value of a: %d\n&quot;, a);
     a++;

     if (a &gt; 15) {
         break;
     }
 }
}</code></pre>
<p>while 옆의 소괄호 안의 조건이 true인 경우에 한해 계속해서 반복문이 돌아간다.</p>
<p>하지만, a가 15이상이 된다면 break 제어문에 걸리게 된다.</p>
<p>여기서 <code>break</code> 는 <strong>반복문에서 탈출하라는 것을 의미</strong>한다.<br><br/></p>
</li>
</ul>
<ul>
<li><h4 id="do-while문">do-while문</h4>
<pre><code class="language-swift">#import &lt;Foundation/Foundation.h&gt;
int main ()
{
 int a = 10;

 do {
     if( a == 15 ) {
         a = a + 1;
         continue;
     }
     NSLog(@&quot;value of a: %d\n&quot;, a);
     a++;
 }while( a &lt; 20 );

 return 0;
}</code></pre>
<p>do-while문의 가장 큰 특징은, <strong>while 옆의 조건이 true든지 false든지 간에 do 중괄호 안에 들어있는 구문을 일단 먼저 실행</strong>한다는 것이다. </p>
<p>만일 <strong>do에 있는 구문이 실행되었는데, while 옆의 조건이 false이게 된다면, do-while 반복문은 종료</strong>된다.</p>
<p>그리고 코드 중간에 <code>continue</code> 라는 제어문이 있는데, 이는 <strong>continue 이후에 나오는 나머지 코드들을 건너뛰고 위의 즉시 조건을 다시 테스트</strong>하게끔 한다.</p>
<p>Swift의 repeat-while과 거의 흡사한 형식이다.<br><br/></p>
<ul>
<li><h4 id="for문">for문</h4>
</li>
</ul>
<pre><code class="language-swift">#import &lt;Foundation/Foundation.h&gt;

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        int n, number, triangularNumber;
        NSLog(@&quot;Whata&amp;number);
     triangularNumber = 0;
        
     for(n=1; n &lt;= number; ++n)
            triangularNumber += n;
        
     NSLog(@&quot;NUMBER %i is %i\n&quot;, number, triangularNumber);
    }
    return 0;
}</code></pre>
<p>C언어의 for문과 형식이 똑같다.<br><br/>
<br><br/></p>
</li>
</ul>
<p>for 옆 소괄호에는 (초기화 된 값, 값 조건, 증감여부)를 알려주어서 <strong>초기화 된 값이 값 조건을 만족하지 못 할때까지 반복문이 실행</strong>된다.<br><br/></p>
<p> 좀 더 반복문을 응용해보면, Objective-C에서는 이러한 <strong>반복문들을 중첩시켜서 중첩반복문도 생성할 수 있게 해준다</strong>.
 <br><br/></p>
<h3 id="--조건문-decision-makingbrbr">- 조건문 (Decision Making)<br><br/></h3>
<p> Objective-C에서는 다음과 같은 조건문들이 있다.<br><br/></p>
<blockquote>
<h4 id="--if문">- if문</h4>
<h4 id="--ifelse문">- if...else문</h4>
<h4 id="--switch문">- switch문</h4>
</blockquote>
<p> <br><br/></p>
<ul>
<li><h4 id="if--if-else-문">if &amp; if-else 문</h4>
<pre><code class="language-swift">#import &lt;Foundation/Foundation.h&gt;

int main ()
{
  int a = 30;

  if(a &lt; 20) {
      NSLog(@&quot;a는 20보다 작습니다.&quot;);
  } else if (a &lt; 40) {
      NSLog(@&quot;a는 40보다 작고 20보다 크거나 같습니다.&quot;);
  } else {
      NSLog(@&quot;a는 40보다 크거나 같습니다.&quot;);
  }

  NSLog(@&quot;a는 %d입니다.&quot;, a);

  return 0;
}</code></pre>
</li>
<li><h4 id="switch-문">switch 문</h4>
<pre><code class="language-swift">#import &lt;Foundation/Foundation.h&gt;
int main ()
{
  char grade = &#39;B&#39;;

  switch(grade) {
      case &#39;A&#39;:
          NSLog(@&quot;잘함&quot;);
          break;
      case &#39;B&#39;:
          NSLog(@&quot;적당&quot;);
          break;
      case &#39;C&#39;:
          NSLog(@&quot;섭섭&quot;);
          break;
      case &#39;D&#39;:
          NSLog(@&quot;재수강&quot;);
          break;
      case &#39;F&#39;:
          NSLog(@&quot;자퇴는 능지순&quot;);
          break;
      default:
          NSLog(@&quot;??&quot;);
          break;
  }

  NSLog(@&quot;학점은 %c&quot;, grade);

  return 0;
}</code></pre>
<p>switch 옆 소괄호 안의 값(grade)에 따라 해당 값에 대응되는 case 안의 구문을 실행한다. </p>
<p>switch문의 <strong>case 구문을 작성할 때는 break;를 반드시 적어줘야한다.</strong></p>
<p>break;를 적어주지 않으면 switch문이 멈추지 않고 계속 실행되기 때문이다.</p>
<p>** Swift는 break;를 적지 않아도 한 번 실행하면 바로 switch문이 끝났다는 점에서 차이가 있다**고 볼 수 있다.</p>
</li>
</ul>
<hr>
<h2 id="📌-함수brbr">📌 함수<br><br/></h2>
<blockquote>
<h4 id="작업을-함께-수행하는-명령문의-그룹">작업을 함께 수행하는 명령문의 그룹</h4>
</blockquote>
<p><br><br/></p>
<h3 id="--함수-정의하기">- 함수 정의하기</h3>
<pre><code class="language-swift">- (리턴타입) 메서드이름:(인수타입1) 인자이름1 결합인수2:(인수타입2)... {
    //함수내용
}</code></pre>
<ul>
<li><h4 id="리턴타입--함수가-반환하는-값의-타입">리턴타입 : 함수가 반환하는 값의 타입</h4>
</li>
<li><h4 id="메서드이름--메서드의-실제-이름">메서드이름 : 메서드의 실제 이름</h4>
</li>
<li><h4 id="인수--자리-표시자-함수가-호출될-때-값이-전달되는-곳">인수 : 자리 표시자, 함수가 호출될 때 값이 전달되는 곳</h4>
</li>
<li><h4 id="결합-인수--함수를-호출하는-동안-읽기-쉽고-명확하게-하기-위한-것">결합 인수 : 함수를 호출하는 동안 읽기 쉽고 명확하게 하기 위한 것</h4>
</li>
<li><h4 id="메서드-본문--메서드가-수행하는-작업을-수행하는-명령문-모음brbr">메서드 본문 : 메서드가 수행하는 작업을 수행하는 명령문 모음&lt;<br><br/></h4>
</li>
</ul>
<p>아래는 함수 선언 및 구현의 예제코드이다.<br><br/></p>
<pre><code class="language-swift">#import &lt;Foundation/Foundation.h&gt;
@interface SampleClass:NSObject
/* method declaration */
- (int)max:(int)num1 andNum2:(int)num2;
@end

@implementation SampleClass
/* method returning the max between two numbers */
- (int)max:(int)num1 andNum2:(int)num2 {
 /* local variable declaration */
 int result;

 if (num1 &gt; num2) {
 result = num1;
 } else {
 result = num2;
 }

 return result;
}
@end</code></pre>
<p><br><br/></p>
<h3 id="--함수-호출하기brbr">- 함수 호출하기<br><br/></h3>
<p>함수에 정의된 작업을 수행하고 싶으면 해당 함수를 직접 호출해야 한다.</p>
<p>Objective-C에서 함수 호출은 다음과 같은 방식으로 할 수 있다.<br><br/></p>
<pre><code class="language-swift">[인스턴스이름 메서드:인자1 결합인자2:인자2..];</code></pre>
<p>아래는 함수 호출에 관련된 예제코드이다.<br><br/></p>
<pre><code class="language-swift">int main () {

 /* local variable definition */
 int a = 100;
 int b = 200;
 int ret;

 SampleClass *sampleClass = [[SampleClass alloc]init];
 /* calling a method to get max value */
 ret = [sampleClass max:a andNum2:b];

 NSLog(@&quot;Max value is : %d\n&quot;, ret );
 return 0;
}</code></pre>
<p><br><br/></p>
<h3 id="--함수의-인수brbr">- 함수의 인수<br><br/></h3>
<p>함수를 호출하는 동안 인수를 함수에 전달하는 방법은 2가지가 있다.</p>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/62bc56e5-0256-40be-8a2e-ec336ceef0fe/image.png" alt="함수의 인수"></p>
<p>Objective-C는 이 둘 중에서 Call by value를 사용해 인수를 전달한다.</p>
<p>Call by value는 <strong>함수 내의 코드가 함수를 호출하는 데 사용되는 인수를 변경할 수 없음</strong>을 의미한다.</p>
<hr>
<h2 id="📌-블록brbr">📌 블록<br><br/></h2>
<blockquote>
<h4 id="클로저의-조상">클로저의 &#39;조상&#39;</h4>
</blockquote>
<p>Objective-C 클래스는 관련동작과 데이터를 결합하는 개체를 정의한다.</p>
<p>하지만, 때로는 메서드 모음이 아닌 단일 작업이나 동작 단위를 나타내는 것이 합리적이다.</p>
<p>이럴때 쓰기 좋은 것이 바로 &#39;블록&#39;이다.</p>
<p>블록을 사용하면 <strong>값인 것처럼 메서드나 함수에 전달할 수 있는 고유한 코드 세그먼트를 만들 수 있다.</strong><br><br/></p>
<h3 id="--블록-선언-및-호출brbr">- 블록 선언 및 호출<br><br/></h3>
<pre><code class="language-swift">returntype (^blockName)(argumentType)= ^{};
//선언방식

void (^simpleBlock)(void) = ^{
    NSLog(@&quot;This is a block&quot;);
};
//구현

simpleBlock();
//호출</code></pre>
<p>블록은 아래와 같이 함수와 마찬가지로 인수를 사용하고 값을 반환할 수 있다.</p>
<pre><code class="language-swift">double (^multiplyTwoValues)(double, double) = ^(double firstValue,
double secondValue) {
    return firstValue * secondValue;
};

double result = multiplyTwoValues(2,4);
NSLog(@&quot;The result is %f&quot;, result);

// 타입이름 (^이름) (파라미터) = ^(인수) { 내용};</code></pre>
<hr>
<h2 id="📌-숫자brbr">📌 숫자<br><br/></h2>
<blockquote>
<h4 id="기본-데이터-유형을-객체-형태로-저장하기-위한-방법">기본 데이터 유형을 객체 형태로 저장하기 위한 방법</h4>
</blockquote>
<p>Objective-C에서는 NSNumber를 통해 기본 데이터 유형을 객체 형태로 저장할 수 있게끔 해준다.</p>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/2a7bbc64-03c5-40a4-9673-b31664444f26/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/4bad64a7-841b-43e6-abcd-508651598643/image.png" alt=""></p>
<p>아래는 위의 NSNumber 메서드를 활용한 예제코드이다.</p>
<pre><code class="language-swift">@interface SampleClass : NSObject
//Foundation이 제공하는 NSObject를 상속받은 SampleClass는 이러한 내용을 구현함
- (NSNumber *) multiplyA: (NSNumber *)a withB:(NSNumber *)b;
@end
//매개변수로 double, float이 올수도 있음
//NSNumber를 활용하면 해결가능(Foundation에서 제공)


//SampleClass의 구체적인 내용은 다음과 같습니다.
@implementation SampleClass
    - (NSNumber *)multiplyA:(NSNumber *)a withB:(NSNumber *)b {
    //NSNumber 타입으로 받은 a, b로부터 float 값들을 꺼내서 곱셈한 후
    //NSNumber로 다시 만들어 반환함        
        float number1 = [a floatValue]; //NSNumber -&gt; float 으로 변환됨
        float number2 = [a floatValue];
        float product = number1 * number2;

        //결과를 NSNumber로 다시 만들어 반환 -&gt; numberWithFloat 활용
        NSNumber *result = [NSNumber numberWithFloat:product];
        return result;
}
@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSLog(@&quot;Hello, world!&quot;);

        SampleClass *sampleClass = [[SampleClass alloc] init];
//객체를 생성하는 코드[[객체 alloc]init]
        //swift였다면.. var sampleClass: SampleClass = SampleClass()

        NSNumber *a = [NSNumber numberWithFloat:10.5];
        NSNumber *b = [NSNumber numberWithFloat:10.0];
        //float-&gt;NSNumber 객체로 만들어준다
        NSNumber *result = [sampleClass multiplyA:a withB:b];

        //결과의 NSNumber로부터 NSString을 만들어 활용 및 출력
        NSString *resultString = [result stringValue];
        NSLog(@&quot;The product is %@&quot;, resultString);
    return 0;
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Swift] 상속 (1)]]></title>
            <link>https://velog.io/@alpha-kwhn/Swift-%EC%83%81%EC%86%8D-1</link>
            <guid>https://velog.io/@alpha-kwhn/Swift-%EC%83%81%EC%86%8D-1</guid>
            <pubDate>Mon, 03 Oct 2022 18:05:49 GMT</pubDate>
            <description><![CDATA[<h4 id="20220928">2022.09.28</h4>
<p>저번에 배운 클래스 개념에서 좀 더 심화된 내용인 &#39;상속&#39;에 대한 학습정리를 본 포스팅을 통해 해보고자 한다😎</p>
<p>타 객체지향언어(C++, JAVA) 에서도 배웠어서 익숙한 개념이지만, 처음부터 다시 배운다는 마음가짐으로 하나하나 학습해보겠다👊</p>
<hr>
<h2 id="📌-상속이란❓brbr">📌 상속이란❓<br></br></h2>
<h3 id="--정의">- 정의</h3>
<blockquote>
<h4 id="특정-클래스로부터-파생되어-새로운-기능을-추가하는-것">특정 클래스로부터 파생되어 새로운 기능을 추가하는 것</h4>
</blockquote>
<p>상속은 Swift의 <strong>다른 타입과 확실하게 구별되는 클래스만의 고유한 특징</strong>이다.</p>
<p>클래스가 다른 클래스로부터 상속될 때 <strong>상속하는 클래스를 &#39;하위(자식) 클래스(subclass)&#39;</strong> 라고 하고 <strong>상속된 클래스를 &#39;상위(부모) 클래스(superclass)&#39;</strong>라고 한다. </p>
<p>서브클래스는 슈퍼클래스로부터 물려받은 메서드를 호출할 수 있고 프로퍼티에 접근이 가능하다. </p>
<p>또한, 슈퍼클래스로부터 물려받은 메서드, 프로퍼티, 서브스크립트 등을 자신만의 내용으로 재정의할 수도 있다. <br><br/></p>
<h3 id="--상속-선언하기">- 상속 선언하기</h3>
<p>클래스의 상속은 다음과 같은 구문을 통해 이뤄진다.</p>
<pre><code class="language-swift">class 클래스 이름 : 부모클래스 이름 {
    프로퍼티 &amp; 메서드들
}</code></pre>
<p>예시 코드를 통해 이를 어떻게 활용했는지 더욱 자세히 알아보자.</p>
<pre><code class="language-swift">class Student: Person {
    var grade: String = &quot;F&quot;

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

let yagom: Person = Person()
yagom.name = &quot;yagom&quot;
yagom.age = 99
print(yagom.introduction)
yagom.speak()

let jay: Student = Student()
jay.name = &quot;jay&quot;
jay.grade = &quot;A&quot;
print(jay.introduction)
jay.speak()
jay.study()</code></pre>
<p>상속하는 클래스 Student 뒤에 <code>콜론(:)</code> 을 붙이고 그 뒤에 상속된 클래스를 적어줌으로써 상속을 선언해준다.</p>
<p>또한, 서브클래스로 생성한 인스턴스는 부모클래스의 프로퍼티 접근과 메서드 호출이 가능하므로 아래의 코드들은 모두 정상적으로 실행된다.</p>
<hr>
<h2 id="📌-재정의-overridingbrbr">📌 재정의 (Overriding)<br></br></h2>
<h3 id="--정의-1">- 정의</h3>
<blockquote>
<h4 id="상위-클래스에서-상속될-특성을-하위-클래스에서-재정의-하는-것">상위 클래스에서 상속될 특성을 하위 클래스에서 &#39;재정의&#39; 하는 것</h4>
</blockquote>
<p>여기서 말하는 &#39;특성&#39;이란 인스턴스 메서드, 타입 메서드, 인스턴스 프로퍼티, 타입 프로퍼티, 서브스크립트 등을 말한다.<br><br/></p>
<h3 id="--선언하기brbr">- 선언하기<br></br></h3>
<p>재정의는 상속받은 특성들의 새로운 정의 앞에 <code>override</code> 라는 키워드를 붙임으로써 선언이 가능하다.</p>
<p><code>override</code> 키워드는 스위프트 컴파일러가 조상클래스에 해당 특성이 있는지 확인하는 역할을 한다. </p>
<p>만일 <strong>조상클래스에 재정의할 해당 특성이 없다면 컴파일 오류가 발생</strong>하게 된다.</p>
<p><code>override</code> 를 활용하여 재정의 구문을 작성해보면 아래와 같다.</p>
<pre><code class="language-swift">override func someMethod() { }</code></pre>
<h3 id="--super-키워드brbr">- super 키워드<br></br></h3>
<blockquote>
<h4 id="자식클래스에서-재정의가-이뤄졌을때-부모클래스의-특성을-자식클래스에서-사용하고-싶을-때-사용함">자식클래스에서 재정의가 이뤄졌을때, 부모클래스의 특성을 자식클래스에서 사용하고 싶을 때 사용함</h4>
</blockquote>
<p>자식클래스의 부모클래스 특성 재정의 과정에서, 부모클래스 특성의 사용이 필요한 경우에 자주 쓰인다.</p>
<p>활용예제를 살펴보면 아래와 같다.</p>
<pre><code class="language-swift">class SavingAccount: BankAccount {
    var interestRate: Float = 0.0

    func calculateInterest() -&gt; Float {
        return interestRate * accountBalance
    }

    override func displayBalance() {
        super.displayBalance()
        print(&quot;Prevailing interest rate is \(interestRate)&quot;)
   }
}</code></pre>
<p>displayBalance 메서드를 재정의하는 과정에서 super 키워드를 이용하여 부모클래스(BankAccount)에 있는 displayBalance 메서드를 호출하였음을 확인할 수 있다.<br><br/></p>
<h3 id="--메서드-재정의-brbr">- 메서드 재정의 <br><br/></h3>
<p>상속된 인스턴스 또는 타입 메서드를 재정의하여 하위 클래스 내에서 용도에 맞도록 재정의할 수 있다.</p>
<pre><code class="language-swift">class Vehicle {
    func makeNoise() {
        print(&quot;gogo&quot;)
    }
}

class Train: Vehicle {
    override func makeNoise() {
        print(&quot;choo choo&quot;)
    }
}

let train = Train()
train.makeNoise() //choo choo</code></pre>
<p>Vehicle 클래스를 상속한 Train 이라는 클래스가 생성되었고, 그 과정에서 makeNoise 메서드도 재정의가 이뤄졌다.</p>
<p>따라서 Train 인스턴스를 생성하고 거기서 makeNoise 메서드를 호출한다면, 하위클래스인 Train에서 재정의된 makeNoise 메서드가 호출됨을 확인할 수 있다.<br></br></p>
<h3 id="--프로퍼티-재정의brbr">- 프로퍼티 재정의<br><br/></h3>
<p>메서드와 마찬가지로 프로퍼티 또한 부모클래스로부터 상속받은 인스턴스 프로퍼티나 타입 프로퍼티를 자식클래스에서 용도에 맞게 재정의할 수 있다.</p>
<p>단, <strong>저장 프로퍼티는 재정의가 불가능</strong>하며 <strong>재정의가 가능한 것은 접근자(getter), 설정자(setter), 프로퍼티 감시자(property observer)</strong>가 있다. <br><br/></p>
<ul>
<li><p>연산 프로퍼티 재정의</p>
<p>설정자/접근자가 모두 존재하는 프로퍼티를 접근자만 존재하게끔 재정의할 수 없다.</p>
<p>하지만, 접근자만 존재했던 프로퍼티에 설정자를 추가 해주거나 접근자의 내용을 수정하는 식의 재정의는 가능하다.</p>
<p>아래의 코드를 통해 연산 프로퍼티 재정의가 실제로 어떻게 이뤄지는지 살펴보자.</p>
<pre><code class="language-swift">class Person {
    var name: String = &quot;&quot;
    var age: Int = 0
    var koreanAge: Int {
        return self.age + 1
    }

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

}

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

    override var introduction: String {
        return super.introduction + &quot; &quot; + &quot;학점: \(self.grade)&quot;
    }

    override var koreanAge: Int {
        get {
            return super.koreanAge
        }

        set {
            self.age = newValue - 1
        }
   }
}</code></pre>
<p>Person 클래스의 introduction 프로퍼티는 Student 클래스에서 내용이 수정됨으로써 재정의가 이뤄졌음을 확인할 수 있다. </p>
<p>참고로, 연산 프로퍼티가 읽기 전용일 경우에는 get 메서드를 생략하고 return 구문만 집어넣어도 상관이 없다.</p>
<p>Person 클래스의 koreanAge 프로퍼티는 읽기전용 프로퍼티였는데, set 메서드가 추가됨으로써 읽기/쓰기가 모두 가능한 프로퍼티로 재정의 되었음을 확인할 수 있다.<br></br></p>
</li>
</ul>
<p><del>프로퍼티 감시자에 관한 개념은 아직 학습을 하지 않았으므로 추후 별도로 포스팅 하겠다.</del></p>
<hr>
<p>이번 포스팅에서는 상속의 기본적인 개념과 사용 예제들을 위주로 살펴보았다.</p>
<p>상속에 관한 더욱 많은 내용들이 존재하지만 아직 추가학습을 하지 않았다.</p>
<p>빠른 시일내에, 추가적인 공부를 진행하여 2편도 작성하겠다 🥹</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Swift] 프로퍼티 (1)]]></title>
            <link>https://velog.io/@alpha-kwhn/Swift-%ED%94%84%EB%A1%9C%ED%8D%BC%ED%8B%B0</link>
            <guid>https://velog.io/@alpha-kwhn/Swift-%ED%94%84%EB%A1%9C%ED%8D%BC%ED%8B%B0</guid>
            <pubDate>Sun, 02 Oct 2022 16:40:39 GMT</pubDate>
            <description><![CDATA[<h4 id="20220927">2022.09.27</h4>
<p>부트캠프에서 클래스를 공부하면서 &#39;프로퍼티&#39;라는 개념을 알게 되었다.</p>
<p>대충 어떤 느낌인지는 알겠으나, 더욱 깊이 공부할 가치가 있다고 느껴져서 이렇게 포스팅을 하게 되었다 💻</p>
<p>머릿속에 중구난방으로 떠도는 개념들을 이번 기회에 잘 정리하여, 추후 개념이 헷갈리거나 기억이 안날때 참고할 수 있는 자료를 만든다고 생각하고 잘 정리해보자!</p>
<hr>
<h2 id="📌-프로퍼티란-무엇인가brbr">📌 프로퍼티란 무엇인가<br><br/></h2>
<h3 id="--정의">- 정의</h3>
<blockquote>
<h4 id="특정-클래스-구조체-열거형-등에-관련된-값">특정 클래스, 구조체, 열거형 등에 관련된 <strong>&#39;값&#39;</strong></h4>
</blockquote>
<p>프로퍼티는 크게 3가지로 나눌 수 있다.</p>
<h4 id="--저장-프로퍼티-stored-property">- 저장 프로퍼티 (Stored Property)</h4>
<h4 id="--연산-프로퍼티-computed-property">- 연산 프로퍼티 (Computed Property)</h4>
<h4 id="--타입-프로퍼티-type-property">- 타입 프로퍼티 (Type Property)</h4>
<p>본 포스팅에서는 위 3가지 프로퍼티들을 하나하나 살펴볼 예정이다.</p>
<hr>
<h2 id="📌-저장-프로퍼티-stored-propertybrbr">📌 저장 프로퍼티 (Stored Property)<br></br></h2>
<h3 id="--저장-프로퍼티란❓">- 저장 프로퍼티란❓</h3>
<blockquote>
<h4 id="특정-클래스-구조체-인스턴스의-변수-또는-상수에-담기는-값">특정 클래스, 구조체 인스턴스의 변수 또는 상수에 담기는 &#39;값&#39;</h4>
</blockquote>
<p>쉽게 설명하자면, 클래스나 구조체 내부에 선언된 변수/상수라고 생각하면 된다.</p>
<p>한가지 특징이 있다면, <strong>열거형은 저장 프로퍼티를 가지지 않는다.</strong><br><br/></p>
<h3 id="--저장-프로퍼티-선언-및-초기값-지정brbr">- 저장 프로퍼티 선언 및 초기값 지정<br><br/></h3>
<p>다음은 저장 프로퍼티를 선언한 예시 코드이다.</p>
<pre><code class="language-swift">class BankAccount {
    var accountBalance: Float
    var accountNumber: Int
    let fees: Float = 25.00 //프로퍼티에 기본값 할당

    init(accountBalance: Float, accountNumber: Int) {
        self.accountBalance = accountBalance
        self.accountNumber = accountNumber
 }
 //이니셜라이저를 통한 초깃값 할당

 struct CoordinatePoint {
     var x: Int
    var y: Int
 }

 let yagomPoint: CoordinatePoint = CoordinatePoint(x: 10, y: 5)</code></pre>
<p>예시코드에서는 클래스와 구조체의 경우를 나누어서 저장 프로퍼티를 선언하고 초기값을 부여하는 작업을 하였다.</p>
<p>코드 상으로는 비슷해보이지만, 클래스와 구조체는 결정적인 한 가지 차이가 존재한다. </p>
<p>그 차이점은 바로 <strong>&#39;이니셜라이저의 자동제공 여부&#39;</strong>이다.</p>
<p>클래스의 경우에는 <strong>저장 프로퍼티에 맞는 이니셜라이저를 자동으로 제공하지 않는다.</strong></p>
<p>따라서, 저장 프로퍼티에 기본값을 부여하지 않으면 별도의 이니셜라이저 정의를 통해 초깃값을 제공하여야 한다.</p>
<p>왜냐하면 <strong>클래스에서는 저장 프로퍼티가 옵셔널이 아닌 이상 이니셜라이저를 통해 초기화를 시켜주거나 기본값을 지정해주어야하기 때문</strong>이다. </p>
<p>반면, 구조체의 경우에는 <strong>저장 프로퍼티에 맞는 이니셜라이저를 자동으로 제공한다.</strong></p>
<p>따라서, 저장 프로퍼티에 기본값을 부여하지 않아도 별도의 이니셜라이저 정의없이 초깃값 설정이 가능하다.<br><br/></p>
<h3 id="--지연-저장-프로퍼티brbr">- 지연 저장 프로퍼티<br><br/></h3>
<p><strong>처음 접근될 때까지 초기값이 계산되지 않는 프로퍼티</strong>를 말한다.</p>
<p>타입의 인스턴스 초기화가 완료된 후에도 초기값이 없을 수 있으므로 <strong>지연 저장 프로퍼티는 <code>var</code> 키워드를 사용하여 변수로 선언하여야 한다</strong>는 특징이 있다.</p>
<p>왜냐하면 <strong>상수는 인스턴스 초기화가 완료되기 전에 항상 값을 가지고 있어야 하기 때문</strong>이다.</p>
<p>지연 저장 프로퍼티는 다음과 같은 상황에서 주로 쓰인다고 한다.</p>
<blockquote>
<h4 id="--복잡한-클래스에-불필요한-초기화를-피하기-위해">- 복잡한 클래스에 불필요한 초기화를 피하기 위해</h4>
</blockquote>
<h4 id="--인스턴스의-초기화가-완료될-때까지-값을-알-수-없는-외부-요인에-인해-초기값이-달라질-때">- 인스턴스의 초기화가 완료될 때까지 값을 알 수 없는 외부 요인에 인해 초기값이 달라질 때</h4>
<p>지연 저장 프로퍼티는 코드에서 어떻게 사용되는지 아래 예제 코드를 통해 쉽게 이해해보자, 지연 저장 프로퍼티는 <code>lazy</code> 라는 키워드로 선언할 수 있다. </p>
<pre><code class="language-swift">class DataImporter {
    var filename = &quot;data.txt&quot;
}

class DataManager {
    lazy var importer = DataImporter()
    var data = [String]()
}

let manager = DataManager()
manager.data.append(&quot;Some data&quot;)
manager.data.append(&quot;Some more data&quot;)
print(manager.importer.filename)
</code></pre>
<p>DataManager 클래스의 importer 라는 프로퍼티는 DataImporter 클래스 인스턴스를 값으로 가진다.</p>
<p>하지만, importer는 <code>lazy</code> 키워드로 선언된 지연 저장 프로퍼티이다. </p>
<p>따라서, DataManager 클래스 내부에서 importer는 최초 접근이 이뤄지기 전까지 DataImporter 클래스의 인스턴스를 할당 받을 수 없다.</p>
<p>importer 프로퍼티의 최초 접근은 코드의 마지막 줄 <code>manager.importer.filename</code> 를 통해 이뤄진다.</p>
<p>이렇게 최초 접근이 이뤄진다면, DataImporter 클래스의 인스턴스가 생성되고 importer 프로퍼티로의 할당이 이루어진다. </p>
<p>만일, importer가 지연 저장 프로퍼티로 선언되지 않았다면 어떻게 되었을까?</p>
<p>그런 경우에는, 만일 코드 상에서 importer 프로퍼티가 사용되지 않았을 때를 생각해보면 된다. </p>
<p>importer 프로퍼티를 지연 저장 프로퍼티로 선언하지 않는다면, 사용되지도 않는 프로퍼티에 굳이 DataImporter 인스턴스를 할당하게 됨으로써 쓸 때 없는 메모리 소모가 발생할 것이다. </p>
<p>이를 통해 우리는 <strong>지연 저장 프로퍼티가 불필요한 공간 낭비를 줄일 수 있다</strong>는 것을 알 수 있다.</p>
<hr>
<h2 id="📌-연산-프로퍼티-stored-propertybrbr">📌 연산 프로퍼티 (Stored Property)<br></br></h2>
<h3 id="--연산-프로퍼티란-❓brbr">- 연산 프로퍼티란 ❓<br></br></h3>
<blockquote>
<h4 id="클래스-구조체-열거형-타입에서-특정-상태에-따른-값을-연산하는-프로퍼티">클래스, 구조체, 열거형 타입에서 &#39;특정 상태에 따른 값을 연산&#39;하는 프로퍼티</h4>
</blockquote>
<p>프로퍼티에 대해 공부하면서 가장 이해가 힘들었던 부분이 바로 <strong>&#39;연산 프로퍼티&#39;</strong> 였던 것 같다. </p>
<p>정의에 따르면 타입에 관련된 &#39;값&#39;이 프로퍼티라고 앞서 언급한 바 있다.</p>
<p>그런데 연산 프로퍼티는 <strong>&#39;실제 값을 저장하는 프로퍼티가 아니다&#39;</strong>라는 점에서 프로퍼티의 본래 정의와 모순된다고 느껴졌기 때문이다. </p>
<p>실제로 앱 스쿨 강사님께서도 연산 프로퍼티는 메서드의 색채가 짙다고 하셨다.</p>
<p>그래서 나도 그냥 연산 프로퍼티는 &#39;값&#39;을 다루는 것일 뿐, 사실상 메서드라고 보는 것이 맞다고 받아들이기로 했다,,,😕</p>
<p>실제로 연산 프로퍼티의 기능을 메소드로 구현할 수 있지만, 가독성과 역할의 명확한 표현 등을 이유로 이렇게 프로퍼티 형식으로 사용하고 있다고 한다.</p>
<p>연산 프로퍼티는 아래의 2가지 요소로 구성이 된다고 한다.</p>
<ul>
<li>접근자 (getter)</li>
<li>설정자 (setter)</li>
</ul>
<p>또한, 저장 프로퍼티와는 다르게 <strong>열거형도 가질 수 있다</strong>는 특징이 있었다.<br></br></p>
<h3 id="--접근자-getterbrbr">- 접근자 (getter)<br></br></h3>
<blockquote>
<h4 id="인스턴스-내외부의-값을-연산하여-적절한-값을-돌려줌">인스턴스 내/외부의 값을 연산하여 적절한 값을 돌려줌</h4>
</blockquote>
<p>저장 프로퍼티를 특정 목적에 맞게 연산하여 return 해주는 역할을 한다.
(값을 돌려주는 역할인만큼 return 구문을 필수로 사용해야 함)<br></br></p>
<h3 id="--설정자-setter">- 설정자 (setter)</h3>
<blockquote>
<h4 id="전달받은-인자를-목적에-맞게-연산한다">전달받은 인자를 목적에 맞게 연산한다</h4>
</blockquote>
<p>파라미터로 전달받은 인자를 특정 목적에 맞게끔 연산하고 저장해주는 역할을 한다.<br><br/></p>
<h3 id="--연산-프로퍼티-선언-brbr">- 연산 프로퍼티 선언 <br><br/></h3>
<p>아래의 예시 코드를 살펴보면서 연산 프로퍼티를 어떻게 선언하는지 알아보자.</p>
<pre><code class="language-swift">struct CoordinatePoint {
    var x: Int
    var y: Int
    //저장 프로퍼티 선언 (기본값 설정 x인 상태)

    var oppositePoint: CoordinatePoint {
        //접근자 (getter)
        get {
            return CoordinatePoint(x:-x, y:-y)
        }
        //설정자 (setter)
        set(opposite) {
            x = -opposite.x
            y = -opposite.y
        //전달 받은 인자를 바탕으로 연산 수행
        }
    }
}

var yagomPosition: CoordinatePoint = CoordinatePoint(x: 10, y: 20)
//구조체 인스턴스 -&gt; 이니셜라이저 선언 없이 매개변수로 바로 인스턴스 생성 가능
print(yagomPosition)
//10, 20
print(yagomPosition.oppositePoint)
//get의 반환 값에 따라 -10, -20 출력
yagomPosition.oppositePoint = CoordinatePoint(x:15, y:10)
//x, y값을 인자로 넣어주었으므로 인자 값을 바탕으로 set의 연산과정 수행
print(yagomPosition)
//get의 반환 값에 따라 -15, -10 출력</code></pre>
<p><code>var oppositePoint: CoordinatePoint</code> 와 같은 형식으로 연산 프로퍼티를 선언하였다.</p>
<p>연산 프로퍼티는 값을 저장하는 것이 아닌 계산을 하는 것이기 때문에 타입 추론이 적용되지 않는다.</p>
<p>따라서, 꼭 <strong>연산 프로퍼티를 선언할 때 타입을 반드시 명시</strong>해야한다. </p>
<p>또한, <strong>연산 프로퍼티를 사용하기 위해서는 반드시 읽고 쓸 수 있는 저장 프로티가 존재</strong>해야 하며, 계산을 통해 반환되는 값이 고정적이지 않기 때문에 <strong>무조건 연산 프로퍼티는 <code>var</code> 키워드를 통해 변수로 선언</strong>해주어야 한다.<br><br/></p>
<h3 id="--읽기-전용-연산-프로퍼티brbr">- 읽기 전용 연산 프로퍼티<br><br/></h3>
<blockquote>
<h4 id="연산-프로퍼티에서-접근자만-존재하고-설정자가-존재하지-않을-경우">연산 프로퍼티에서 접근자만 존재하고, 설정자가 존재하지 않을 경우</h4>
</blockquote>
<p>연산 프로퍼티에서 접근자(getter)는 필수이지만, 설정자(setter)는 선택적으로 사용한다.</p>
<p>따라서, 필요에 따라 별도의 값 설정이 필요가 없는 경우에는 설정자를 생략할 수 있다.</p>
<pre><code class="language-swift">struct CoordinatePoint {
    var x: Int
    var y: Int
    //저장 프로퍼티 선언 (기본값 설정 x인 상태)

    var oppositePoint: CoordinatePoint {
        //접근자 (getter) 만 사용
        get {
            return CoordinatePoint(x:-x, y:-y)
        }
    }
}</code></pre>
<h3 id="--설정자-매개변수-생략">- 설정자 매개변수 생략</h3>
<pre><code class="language-swift">set(opposite) {
           x = -opposite.x
        y = -opposite.y
 }</code></pre>
<p>위의 코드는 opposite라는 매개변수를 통해 저장 프로퍼티 x, y 값을 새롭게 설정해주는 설정자를 선언한 것이다.</p>
<p>Swift의 연산 프로퍼티에서는 매개변수 없이 설정자를 작성할 수도 있다.</p>
<p>매개변수 없이 작성한 설정자는 아래와 같다.</p>
<pre><code class="language-swift">set {
    x = -newValue.x
}</code></pre>
<p>이 때, 여기서 newValue는 매개변수(opposite)을 의미한다.</p>
<p>set 옆에 소괄호로 매개변수를 작성하지 않고, newValue를 매개변수라고 생각하며 코드를 적어준다고 이해하면 편하다.</p>
<p>Swift의 이러한 기능은 사용자로 하여금 코드를 좀 더 편하게 작성할 수 있게끔 도와준다.</p>
<hr>
<h2 id="📌-self-프로퍼티brbr">📌 self 프로퍼티<br><br/></h2>
<blockquote>
<h4 id="자기-자신을-가리키는-프로퍼티">자기 자신을 가리키는 프로퍼티</h4>
</blockquote>
<p>모든 인스턴스는 암시적으로 생성된 self 프로퍼티를 갖는다.</p>
<p>self 프로퍼티는 주로 <strong>인스턴스를 더 명확히 지칭하고 싶을 때 사용</strong>하는데, 대표적인 예로 <strong>메서드의 매개변수 이름이 인스턴스 프로퍼티의 이름과 같은 경우</strong>가 있다. </p>
<pre><code class="language-swift">class LevelClass {
    var level: Int = 0

    func jumpLevel(to level: Int) {
        print(&quot;Jump to \(level)&quot;)
        self.level = level
    }
}</code></pre>
<p>위 코드를 보면 jumpLevel 메서드의 매개변수 이름과 Levelclass 클래스의 인스턴스 프로퍼티의 이름이 모두 level로 같은 것을 확인할 수 있다.</p>
<p>이렇게 되면 level 이라는 프로퍼티에 매개변수 level의 인자 값을 넣어줄 때 서로의 정체가 헷갈려지는 상황이 벌어질 수도 있다.</p>
<pre><code class="language-swift">level = level</code></pre>
<p>물론 좌측의 level이 누가 봐도 인스턴스 프로퍼티임을 알 수 있지만, 이러한 코드 자체가 혼란을 야기하는 것은 사실이다. </p>
<p>따라서, self 프로퍼티를 앞에 붙여서 자신이 인스턴스 프로퍼티라는 사실을 확실하게 명시해주는 것이 <strong>가독성 측면에서 좋다</strong>.</p>
<p>추가로 <strong>self 프로퍼티는 값 타입 인스턴스 자체의 값을 치환할 수 있다</strong>는 특징도 가진다.
(클래스는 참조 타입이므로 불가능, 구조체와 열거형은 값 타입이므로 가능)</p>
<pre><code class="language-swift">class LevelClass {
    var level: Int = 0

    func reset() {
        self = LevelClass()
    }
}</code></pre>
<hr>
<p>클래스에 관한 다양한 개념들이 있지만, 양이 너무 방대해 이번 포스팅에서는 그 중 일부만 정리하게 되었다. </p>
<p>추가적인 내용들은 포스팅 2편에서 이어서 정리해 볼 생각이다.</p>
<ul>
<li>프로퍼티의 정의</li>
<li>저장 프로퍼티</li>
<li>저장 프로퍼티 초기화 및 기본값 설정</li>
<li>지연 저장 프로퍼티</li>
<li>연산 프로퍼티(접근자/설정자)</li>
<li>self 프로퍼티</li>
</ul>
<p>위에서 나열한 오늘의 학습 내용들을 머릿속으로 잘 정리해야겠다 👀  </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Swift] 클래스 ]]></title>
            <link>https://velog.io/@alpha-kwhn/Swift-%ED%81%B4%EB%9E%98%EC%8A%A4-1</link>
            <guid>https://velog.io/@alpha-kwhn/Swift-%ED%81%B4%EB%9E%98%EC%8A%A4-1</guid>
            <pubDate>Sat, 01 Oct 2022 06:47:25 GMT</pubDate>
            <description><![CDATA[<h4 id="20220927">2022.09.27</h4>
<p>당일 앱 스쿨에서 배운 <strong>&#39;클래스&#39;</strong>에 관한 지식을 복습하고자 포스팅을 하게 되었다. 복습 스터디를 통해서 지식정리를 어느정도 하였지만, 본 회고를 통해 더욱 확실하게 지식들을 내 것으로 만들어보자👀</p>
<hr>
<h2 id="📌-클래스와-객체지향언어">📌 클래스와 객체지향언어</h2>
<h3 id="--객체지향언어의-등장">- 객체지향언어의 등장</h3>
<p>세상에 모든 것은 &#39;객체&#39;라고 생각하는 사람들이 등장하고, 이러한** 객체들 사이의 상호작용으로 프로그램이 동작한다<strong>는 개념에서 나오게된 언어가 바로 <span style="color:red"></strong>&#39;객체지향언어&#39;**</span>이다.</p>
<p>그러면, 객체언어라고 하면 될 것이지 왜 굳이 객체&#39;지향&#39;언어라고 하는 걸까?</p>
<p>그 이유는 바로, 객체언어를 만들기 위해서 절차지향 언어를 사용했다는 점 때문이다. </p>
<p>따라서, &#39;객체&#39;라는 단어 뒤에 &#39;지향&#39;이라는 단어를 붙이게되었다.</p>
<h3 id="--클래스란❓">- 클래스란❓</h3>
<blockquote>
<h4 id="특정-역할을-수행하는-객체를-정의하는-타입">&#39;특정 역할을 수행하는 객체를 정의하는 타입&#39;</h4>
</blockquote>
<p>&#39;객체지향언어&#39;의 핵심인 <span style ="color:red"><strong>객체를 생성해내는 틀</strong></span>이라고 쉽게 이해할 수 있겠다.</p>
<p>클래스는 <code>캡슐화</code> <code>다형성</code> <code>상속</code> 이라는 3가지 특성을 가지며, 특정 역할을 수행하는 메서드와 프로퍼티로 구성된다.</p>
<p><strong>프로퍼티</strong>는 또다른 말로 &#39;인스턴스 변수&#39;라고 하며, <strong>클래스 내의 캡슐화된 데이터를 말한다.</strong></p>
<p>여기서 <strong>&#39;데이터 캡슐화&#39;</strong>란 <span style ="color:red">클래스에 저장되고 접근될 수 있는 데이터는 오직 해당 클래스 내에 정의된 메서드만을 통해서 가능하다</span>는 것을 말한다.
(객체지향 프로그래밍의 핵심 목적이라고 한다)</p>
<hr>
<h2 id="📌-클래스-선언과-객체생성">📌 클래스 선언과 객체생성</h2>
<h3 id="--클래스의-선언">- 클래스의 선언</h3>
<p><code>class</code> 키워드를 사용하여 아래와 같이 클래스를 선언할 수 있다.</p>
<pre><code class="language-swift">class BankAccount {
    var accountBalance: Float = 0
    var accountNumber: Int = 0
    //프로퍼티

    func displayBalalnce() {
        print(&quot;Number \(accountBalance)&quot;)
    }
    //인스턴스 메서드

    class func getMaxBalance() -&gt; Float {
        return 100000.00
    }
    //타입 메서드</code></pre>
<p>클래스의 이름은 대문자로 시작한다는 것이 특징이다.</p>
<p>클래스 내부의 프로퍼티와 인스턴스 메서드를 정의하는 방법은 일반적인 변수/상수/함수를 선언하는 것과 동일한 방식이다.</p>
<p>위 코드를 보면 마지막에 <code>class func</code> 로 선언된 타입 메서드를 정의하는 부분이 있다.</p>
<p>개인적으로 인스턴스 메서드랑 타입 메서드가 처음 들었을 때 많이 헷갈렸는데, 그래서 둘의 차이를 간략하게 정리해보았다.</p>
<table>
<thead>
<tr>
<th align="center"></th>
<th align="center">인스턴스 메서드</th>
<th align="center">타입 메서드</th>
</tr>
</thead>
<tbody><tr>
<td align="center">정의</td>
<td align="center">특정 타입의 &#39;<strong>인스턴스</strong>&#39;에서 호출하는 메소드</td>
<td align="center"><strong>타입 자체에서 호출</strong>되는 메소드</td>
</tr>
<tr>
<td align="center">선언 키워드</td>
<td align="center"><code>func</code></td>
<td align="center"><code>static func</code></td>
</tr>
</tbody></table>
<p>타입이 클래스인 경우에는 예외적으로 static 대신 class를 앞에 붙인다.</p>
<h3 id="--객체-생성-및-메서드와-프로퍼티-접근">- 객체 생성 및 메서드와 프로퍼티 접근</h3>
<p>위의 클래스 선언문을 바탕으로 객체를 생성하는 방법은 아래와 같다.</p>
<pre><code class="language-swift">let people: BankAccount = BankAccount()</code></pre>
<p>클래스의 객체를 선언할 때는, 클래스 선언 때와 달리 <strong>소문자</strong>로 시작해야한다.</p>
<p>추후, 다른 포스팅에서 설명하겠지만 <strong>클래스의 인스턴스(객체)는 참조 타입이므로 상수로 선언하더라도 내부 프로퍼티 값 변경이 가능</strong>하다.</p>
<pre><code class="language-swift">people.accountBalance //프로퍼티 접근
people.displayBalance() //메서드 접근
BankAccount.getMaxBalance() // 타입 메서드 접근(인스턴스가 아닌 타입(여기선 클래스)을 통해)</code></pre>
<p>인스턴스 프로퍼티와 메서드에 접근하기 위해서, 인스턴스 뒤에 <code>.(점 표기법)</code>을 붙인다.</p>
<p>타입 메서드도 마찬가지로 <code>.</code>을 통해 접근이 가능하다
(단, 인스턴스가 아닌 타입을 통해 접근)</p>
<hr>
<h2 id="📌-클래스의-인스턴스-초기화-및-소멸">📌 클래스의 인스턴스 초기화 및 소멸</h2>
<h3 id="--클래스-인스턴스-초기화">- 클래스 인스턴스 초기화</h3>
<p>인스턴스 생성시에 초기화가 필요할 수도 있는데, 이럴 때 이니셜라이저를 
<code>init()</code> 메서드를 사용한다. </p>
<pre><code class="language-swift">init() {
    temperature = 32.0
}</code></pre>
<p>가장 기본적인 init() 메서드를 선언하는 형식은 위와 같으며, init() 내에서 클래스 내부의 저장 프로퍼티를 초기화시킬 수 있다.</p>
<p>하지만, 만일 <strong>프로퍼티 선언 시에 초기화</strong>를 해버리거나 <strong>이니셜라이저에 매개변수가 없는 경우</strong>라면 <strong>이니셜라이저는 생략이 가능</strong>하다.
(이런 경우를 <code>기본 초기화 구문</code> 이라고 한다)</p>
<p>그렇다면, 만일 매개변수가 있는 이니셜라이저가 필요하다면 어떻게 해야할까?</p>
<p>그럴경우에는, 무조건 이니셜라이저를 아래와 같은 형식으로 직접 선언해주어야 한다.</p>
<pre><code class="language-swift">init(_ kelvin: Double) {
    temperature = kelvin - 273.15
}</code></pre>
<p>위 코드에서 이니셜라이저의 매개변수로 들어간 kelvin을 우리는 <code>초기화 파라미터</code> 라고 한다.</p>
<p>초기화 파라미터를 사용함으로써, 프로퍼티의 초기화를 사용자화 할 수 있게 된다.</p>
<p>또한, 초기화 파라미터를 사용함으로써 <strong>프로퍼티의 초기화를 클래스 인스턴스가 생성되는 시점으로 설정</strong>할 수 있게 된다. </p>
<p>아래의 코드 예시를 통해 <strong>클래스 인스턴스 초기화</strong>에 관한 개념을 정리해보자</p>
<pre><code class="language-swift">class BankAccount {
    var accountBalance: Float = 0
    var accountNumber: Int = 0

    init(number: Int, balance: Float) {
        accountNumber = number
        accountBalance = balance
    }

    func displayBalance() {
        print(&quot;Number \(accountBalance)&quot;)
        print(&quot;Current balance is \(accountNumber)&quot;)
    }
}

var account1: BankAccount = BankAccount(number: 12312312, balance: 400.54)
//인스턴스 생성 시점에 프로퍼티 초기화</code></pre>
<hr>
<h3 id="--클래스-인스턴스-소멸하기">- 클래스 인스턴스 소멸하기</h3>
<p>클래스의 인스턴스가 더 이상 필요가 없을 때, 해당 인스턴스는 Swift의 런타임 시스템에 의해 없어진다. </p>
<p>허나, 이렇게 인스턴스가 사라지기 직전에 반드시 해야 할 정리 작업이 있다면 이를 어떻게 명시해주어야 할까?</p>
<p>이럴 때 사용하는 것이 바로 <strong>소멸자 구현</strong> 이다.</p>
<p>클래스에서 소멸자를 구현할 때는 <code>deinit</code> 이라는  키워드를 사용한다. </p>
<p>소멸자의 구현은 아래와 같은 형식으로 할 수 있다.</p>
<pre><code class="language-swift">deinit {
    //인스턴스가 사라지기 전에 수행할 작업
 }</code></pre>
<p>deinit을 적용하여 위에서 우리가 배운 지식들을 적용하여 온전한 하나의 클래스를 선언해보면 아래와 같을 것이다.</p>
<pre><code class="language-swift">class BankAccount {
    var accountBalance: Float = 0
    var accountNumber: Int = 0
    //인스턴스 프로퍼티

    init(number: Int, balance: Float) {
        accountNumber = number
        accountBalance = balance
    }
    //이니셜라이저 

    deinit {
        print(&quot;프로그램을 종료합니다&quot;)
    }
    //소멸자 

    func displayBalance() {
        print(&quot;Number \(accountBalance)&quot;)
        print(&quot;Current balance is \(accountNumber)&quot;)
    }
    //인스턴스 메서드

    class func getMaxBalance() -&gt; Float {
        return 100000.00
    }
    //타입 메서드
}

var account1: BankAccount = BankAccount(number: 12312312, balance: 400.54)
//인스턴스 생성 시점에 프로퍼티 초기화

account1.accountBalance //프로퍼티 접근
account1.displayBalance() //메서드 접근
BankAccount.getMaxBalance() // 타입 메서드 접근(인스턴스가 아닌 타입(여기선 클래스)을 통해)
</code></pre>
<hr>
<p>오늘 공부한 클래스의 기본개념 이외에도 클래스에 관한 더 많은 내용들이 있지만, 이들은 나중에 따로 다뤄볼 예정이다
(상속개념)</p>
<p>본 포스팅을 통해 아래의 개념들을 확실히 이해할 수 있었다 😀</p>
<ul>
<li>클래스의 선언</li>
<li>인스턴스 생성</li>
<li>인스턴스 초기화 &amp; 소멸</li>
<li>인스턴스를 통한 메서드 &amp; 프로퍼티 접근  (점 표기법)</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Swift] 함수]]></title>
            <link>https://velog.io/@alpha-kwhn/Swift-%ED%95%A8%EC%88%98</link>
            <guid>https://velog.io/@alpha-kwhn/Swift-%ED%95%A8%EC%88%98</guid>
            <pubDate>Mon, 26 Sep 2022 16:14:10 GMT</pubDate>
            <description><![CDATA[<h4 id="20220924">2022.09.24</h4>
<p>클로저 공부를 하다가, 함수에서 배웠던 용어들과 개념들이 살짝 기억이 나지 않아 추가 공부가 필요할 것 같다는 생각이 들었다.</p>
<p>차근차근 복습을 하며 기억을 상기시켜보자,,</p>
<hr>
<h2 id="📌-함수란">📌 함수란?</h2>
<blockquote>
<h4 id="특정-작업을-수행하는-코드-모음-형태">&#39;특정 작업을 수행하는 코드 모음 형태&#39;</h4>
</blockquote>
<p>Swift에서 함수는 <span style="color:red"><strong>함수 호출을 단순화 하기위해 기본값을 제공</strong></span>할 수 있으며 함수가 <span style="color:red"><strong>실행을 완료하면 전달된 변수를 수정하는 입출력 파라미터로 전달</strong></span>될 수 있다.</p>
<p>평소 <strong>메서드</strong>와 <strong>함수</strong>가 대체 무슨 차이인지에 대해 궁금했는데
그 둘을 다음과 같은 차이가 있다고 한다.</p>
<blockquote>
<h4 id="메서드">메서드</h4>
<p>구조체/클래스 등 특정 타입에 연관되어 사용하는 함수를 말함</p>
<h4 id="함수">함수</h4>
<p>모듈 전체에서 전역적으로 사용할 수 있는 함수를 말함</p>
</blockquote>
<hr>
<h2 id="📌-함수의-정의와-호출">📌 함수의 정의와 호출</h2>
<p>파이썬에서와 마찬가지로 Swift에서도 함수는 <code>func</code> 키워드를 사용해 정의하는데, 구문의 형식은 아래와 같다.</p>
<pre><code>func 함수이름 (매개변수...) -&gt; 반환 타입 {
    실행구문
    return 반환 값
}</code></pre><pre><code class="language-swift">func hello(name: String) -&gt; String {
    return &quot;Hello \(name)!&quot;
}

let helloJenny: String = hello(name: &quot;Jenny&quot;)
print(helloJenny)

func introduce(name: String) -&gt; String {
    &quot;제 이름은 &quot; + name + &quot;입니다&quot;
}

let introduceJenny: String = introduce(name: &quot;Jenny&quot;)
print(introduceJenny)</code></pre>
<hr>
<h2 id="📌-함수의-매개변수와-반환값">📌 함수의 매개변수와 반환값</h2>
<p>매개변수와 반환값이 어떻게 되는가에 따라 함수는 다양한 종류로 나뉜다.</p>
<blockquote>
<h4 id="1-매개변수가-없는-함수">1. 매개변수가 없는 함수</h4>
<h4 id="2-매개변수가-있는-함수">2. 매개변수가 있는 함수</h4>
<h4 id="3-반환값이-없는-함수">3. 반환값이 없는 함수</h4>
<h4 id="4-반환값이-있는-함수">4. 반환값이 있는 함수</h4>
</blockquote>
<ul>
<li>매개변수가 없는 함수</li>
</ul>
<p>함수에 매개변수 값이 없음, 하지만 함수는 어떠한 매개변수가 없더라도 함수의 이름 뒤에 <code>소괄호()</code> 가 필요하다.</p>
<p>함수는 입력 매개변수 정의를 요구하지 않음.</p>
<pre><code class="language-swift">func sayHelloWorld() -&gt; String {
    return &quot;hello, world&quot;
}
print(sayHelloWorld())</code></pre>
<ul>
<li>매개변수가 있는 함수</li>
</ul>
<p>함수는 함수의 소괄호 내에 콤마로 구분하여 여러개의 입력 매개변수를 가질 수 있다.</p>
<p>매개변수가 있는 함수의 경우에는, 소괄호 안에 적절한 매개변수 이름을 붙여주고 <code>콜론(:)</code>을 적은 후 전달인자를 보내준다.</p>
<p>이 때, 매개변수가 예시코드처럼 여러 개일 경우에는 <code>쉼표(,)</code> 로 구분해준다.</p>
<pre><code class="language-swift">func greet(person: String, alreadyGreeted: Bool) -&gt; String {
    if alreadyGreeted {
        return greetAgain(person: person)
    } else {
        return greet(person: person)
    }
}
print(greet(person: &quot;Tim&quot;, alreadyGreeted: true))</code></pre>
<ul>
<li>반환 값이 없는 함수</li>
</ul>
<p>함수는 반환 타입 정의를 요구하지 않는다.</p>
<p>반환 값이 없는 함수의 경우엔 <code>-&gt; (반환 타입)</code> 을 표기하지 않음</p>
<pre><code class="language-swift">func greet(person: String) {
    print(&quot;Hello, \(person)!&quot;)
}
greet(person: &quot;Dave&quot;)
// Prints &quot;Hello, Dave!&quot;</code></pre>
<p>사실, 엄밀히 따지면 반환 값은 존재하긴 한다.</p>
<p>단지, 반환타입이 정의되지 않아 <code>Void</code> 타입이 반환되기 때문에 *<em>표기가 되지 않은 것 뿐이다. *</em></p>
<ul>
<li>반환 값이 있는 함수</li>
</ul>
<p>매개변수 선언부 옆에 <code>-&gt; (반환타입)</code> 과 같은 구문을 작성하여 반환 값이 있음을 표시한다.</p>
<pre><code class="language-swift">func minMax(array: [Int]) -&gt; (min: Int, max: Int) {
    var currentMin = array[0]
    var currentMax = array[0]
    for value in array[1..&lt;array.count] {
        if value &lt; currentMin {
            currentMin = value
        } else if value &gt; currentMax {
            currentMax = value
        }
    }
    return (currentMin, currentMax)
}</code></pre>
<p>만일, 위의 예시코드처럼 함수가 여러 개의 반환값을 가진다면 그 함수는 최종적으로 <code>튜플</code> 을 반환할 것이다.</p>
<p>반환 값 속의 min, max는 함수의 반환 값 조회 시에 이름으로 접근할 수 있도록 라벨링 된 것이다.</p>
<hr>
<h2 id="📌-전달인자-레이블과-암시적-반환">📌 전달인자 레이블과 암시적 반환</h2>
<h3 id="--전달인자-레이블">- 전달인자 레이블</h3>
<p>Swift에서는 함수의 매개변수 이름과 더불어 <code>전달인자 레이블</code> 을 지정해줄 수 있다.</p>
<p>전달인자 레이블은 함수 외부에서 매개변수의 역할을 좀 더 명확히 할 수 있게 해준다.</p>
<p>사용 시에는 매개변수 이름 앞에 한 칸을 띄운 후 전달인자 레이블을 지정해준다. </p>
<p>전달인자 레이블을 포함한 전체적인 함수 작성 구문을 정리해보면 아래와 같을 것이다.</p>
<pre><code>func 함수 이름(전달인자 레이블 매개변수 타입, 전달인자 레이블 매개변수 이름:
    매개변수 타입...) -&gt; 반환 타입 {
    실행 구문
    return 반환 값
}</code></pre><pre><code class="language-Swift">func sayHello(from myName:String, to name: String) -&gt; String {
    return &quot;Hello \(name)! I&#39;m \(myName)&quot;
    }

    print(sayHello(from: &quot;yagom&quot;, to: &quot;Jenny&quot;))</code></pre>
<p>전달인자 레이블을 활용한 예시 코드를 보면 한가지 특징을 볼 수 있다.</p>
<p>바로, 함수 내부에서는 매개변수 이름이 사용가능하나, 전달인자 레이블은 사용하지 못한다는 점이다.
그리고 함수를 호출할 때는 매개변수 이름을 사용할 수 없지만, 전달인자 레이블은 사용이 가능하다.</p>
<p>만일 전달인자 레이블을 사용하고 싶지 않다면 <code>와일드카드 식별자(_)</code> 를 대신 사용하면 된다.</p>
<p>또한, 함수 이름은 같지만 전달인자 레이블을 다르게 하여 함수 오버로딩 기능을 사용할 수 있다는 특징도 있다.</p>
<h3 id="--암시적-반환을-가진-함수">- 암시적 반환을 가진 함수</h3>
<p>함수의 전체 내용이 한줄로 표현되어있다면 함수는 맹목적으로 표현식을 반환한다. 즉, <code>return</code> 키워드가 없어도 반환이 가능하다는 것이다.</p>
<pre><code class="language-swift">func greeting(for person: String) -&gt; String {
    &quot;Hello, &quot; + person + &quot;!&quot;
}
print(greeting(for: &quot;Dave&quot;))
// Prints &quot;Hello, Dave!&quot;

func anotherGreeting(for person: String) -&gt; String {
    return &quot;Hello, &quot; + person + &quot;!&quot;
}
print(anotherGreeting(for: &quot;Dave&quot;))
// Prints &quot;Hello, Dave!&quot;</code></pre>
<hr>
<h2 id="📌-매개변수-기본값과-가변입출력-매개변수">📌 매개변수 기본값과 가변/입출력 매개변수</h2>
<h3 id="--매개변수-기본값">- 매개변수 기본값</h3>
<p>Swift의 함수에서 매개변수는 기본값을 가질 수 있다.</p>
<p>이말인 즉슨, 함수 호출 시에 매개변수가 전달되지 않는다면 해당 매개변수의 기본 값이 자동으로 전달된다는 뜻이다. </p>
<pre><code>func sayHello(_ name: String, times: Int = 3) -&gt; String {
    var result: String = &quot;&quot;

    for _ in 0..&lt;times {
        result += &quot;Hello \(name)!&quot; + &quot; &quot;
    }
    return result
}

print(sayHello(&quot;Joe&quot;, times: 2)) // 기본 값이 변경되어 그 크기 만큼 반복문 실행
print(sayHello(&quot;Hana&quot;) // 기본값의 크기만큼 반복문 실행 </code></pre><p>책에서는 가급적이면 기본값이 없는 매개변수를 기본값이 있는 매개변수 앞에 사용하라고 권장한다고 적혀있기도 했다 (참고!)</p>
<h3 id="--가변-매개변수">- 가변 매개변수</h3>
<p>매개변수로 몇 개의 값이 들어올지 모를 때 활용하는 것이 바로 <code>가변 매개변수</code> 이다.</p>
<p>가변 매개변수는 0개 이상의 값을 받아올 수 있으며, 배열처럼 활용이 가능하다.</p>
<p>또한, 함수마다 가변 매개변수는 1개만 가질 수 있다.</p>
<pre><code class="language-swift">func sayHelloToFriends(me: String, friends names: String...) -&gt; String {
    var result: String = &quot;&quot;

    for friend in names {
        result += &quot;Hello \(friend)!&quot; + &quot; &quot;
    }

    result += &quot;I&#39;m &quot; + me + &quot;!&quot;
    return result
}

print(sayHelloToFriends(me: &quot;yagom&quot;, friends: &quot;Johansson&quot;, &quot;Jay&quot;, &quot;Wizplan&quot;)) //여러 개의 값을 가변 매개변수는 포함이 가능하다
print(sayHelloToFriends(me: &quot;yagom&quot;)) //가변 매개변수 0개 값 포함시</code></pre>
<h3 id="--입출력-매개변수-inout-매개변수">- 입출력 매개변수 (inout 매개변수)</h3>
<p>위의 예시코드처럼 함수의 전달인자로 값을 전달할 때는 보통 <code>값을 복사</code>해서 전달한다.</p>
<p>하지만, 만일 <span style="color:red"><strong>값이 아닌 참조를 전달</strong></span>하고 싶을 때는 어떻게 할까?</p>
<p>그런 경우에 사용하는 것이 바로 <code>입출력 매개변수</code> 이다.</p>
<p>입출력(inout) 매개변수를 이용하여 값 타입 데이터의 참조를 전달인자로 보내면 함수 내부에서 참조하여 원래 값을 변경하는 방식으로 동작이 이루어진다.</p>
<p>요약하면 아래와 같다.</p>
<blockquote>
<h4 id="1-함수-호출-시-전달인자의-값을-복사">1. 함수 호출 시, 전달인자의 값을 복사</h4>
<h4 id="2-해당-전달인자의-값을-변경하면-1에서-복사한-것을-함수-내부에서-변경">2. 해당 전달인자의 값을 변경하면 1에서 복사한 것을 함수 내부에서 변경</h4>
<h4 id="3-함수를-반환하는-시점에-2에서-변경된-값을-원래의-매개변수에-할당">3. 함수를 반환하는 시점에 2에서 변경된 값을 원래의 매개변수에 할당</h4>
</blockquote>
<p>물론, 이러면 함수 외부의 값에 어떤 영향을 줄지 모르기 때문에 <strong>함수형 프로그래밍 패러다임에서는 지양하는 패턴이다.</strong></p>
<p>참조는 inout 매개변수로 전달될 변수 또는 상수 앞에 <code>앰퍼샌드(&amp;)</code> 를 붙여서 표현한다.</p>
<pre><code class="language-swift">var numbers: [Int] = [1, 2, 3]

func nonReferenceParameter(_ arr: [Int]) {
    var copiedArr: [Int] = arr
    copiedArr[1] = 1
}

func referenceParameter(_ arr : inout [Int]) {
    arr[1] = 1
}

nonReferenceParameter(numbers)
print(numbers[1]) //2 값이 안바뀜 참조가 없었기 때문

referenceParameter(&amp;numbers)
print(numbers[1]) //1 값이 바뀜 참조가 있었기 때문(&amp;)</code></pre>
<p>입출력(inout) 매개변수는 기본값을 가질 수 없으며, 가변 매개변수로 사용될 수도 없다.</p>
<p>또한 상수는 변경될 수 없으므로 입출력 매개변수의 전달인자로 사용이 불가능하다.</p>
<p>입출력(inout) 매개변수는 잘 사용하면 문제가 없지만, 잘못 사용하면 메모리 안전을 위협한다.</p>
<hr>
<h2 id="📌-데이터-타입으로서의-함수">📌 데이터 타입으로서의 함수</h2>
<p>함수는 일급 객체이기에, <span style="color:red"><strong>매개변수 타입과 반환 타입으로 구성된 하나의 타입</strong></span>으로 사용할 수 있다.</p>
<p>함수의 데이터 타입은 받게 될 매개변수의 데이터 타입과 반환될 데이터 타입을 조합하여 결정된다. </p>
<pre><code class="language-swift">func sayHello(name: String, times: Int) -&gt; String {
// ...
}</code></pre>
<p>위의 코드를 예시로 들면, 함수의 타입은 (String, Int) -&gt; String이라고 할 수 있을 것이다. </p>
<p>함수를 데이터 타입으로 사용할 수 있다는 것은 꽤나 의미가 큰 것이, 이러한 특성 때문에 함수를 전달인자로 받을 수도, 반환 값으로 돌려줄 수도 있다는 의미이다. </p>
<p>아래의 코드를 보면 더욱 이해가 쉬울 것이다.</p>
<pre><code class="language-swift">func orderStarbucks() -&gt; String {
  print(&quot;스타벅스 주문&quot;)
  return &quot;카라멜마끼야또&quot;
}

func orderMegaCoffee() -&gt; String {
  print(&quot;메가커피 주문&quot;)
  return &quot;꿀아메리카노&quot;fu
}

func orderHollys() -&gt; Int {
  print(&quot;할리스 주문&quot;)
  // return &quot;바닐라딜라이트&quot;
  return 100
}

var orderCafe: () -&gt; String = orderStarbucks
print(&quot;손님 주문하신 \(orderCafe()) 나왔습니다&quot;)
orderCafe = orderMegaCoffee
print(&quot;손님 주문하신 \(orderCafe()) 나왔습니다&quot;)
let orderCafeNumber = orderHollys
print(&quot;\(orderCafeNumber()) 번째손님, 커피 나왔습니다&quot;)</code></pre>
<p>함수는 데이터 타입으로 사용할 수 있다는 특징 때문에 변수, 상수에 함수를 할당이 가능해 다음과 같은 코드를 작성할 수 있었다.</p>
<pre><code class="language-swift">func inchesToFeet(_ inches: Float) -&gt; Float {
    return inches * 0.833333
 }

 func inchesToYards(_ inches: Float) -&gt; Float {
     return inches * 0.0277778
 }
 let toFeet = inchesToFeet
 let toYards = inchesToYards


 func outputConvertion(_ converterFunc: (Float)-&gt;Float, value: Float) {
     let result = convertFunc(value)
    print(&quot;Result of convertion is \(result)&quot;)

func decideFunction(_ feet:Bool) -&gt; (Float) -&gt; Float {
    if feet {
        return toFeet
    } else {
        return toYards
    }</code></pre>
<p>위의 예제코드는 함수가 매개변수로 함수를 받았을 경우와 함수가 함수를 반환값으로 가지는 경우를 모두 나타낸 코드이다.</p>
<p>outputConvertion 함수의 매개변수 convertFunc는 Float를 매개변수로 입력받아 Float 타입 값을 반환하는 함수를 값으로 입력받으므로, 선언부에 타입을 작성할 때 (Float) -&gt; Float로 함수 매개변수의 타입을 작성한다.</p>
<p>decideFunction 함수는 Boolean 값을 매개변수로 받고
Float 값을 매개변수로 입력받아 Float 타입의 값을 반환하는 함수를 반환하므로, 선언부에 타입을 작성할 때 (Float) -&gt; Float로 함수 반환 타입을 작성한다.</p>
<hr>
<p>앞으로 함수에 관한 개념이 가물가물 할 때마다 본 포스팅을 다시 한번 읽어볼 것이며, 부족한 점이 또 생긴다면 포스팅을 업그레이드 시킬 예정이다😃</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[2.1 Swift 훑어보기 (1)]]]></title>
            <link>https://velog.io/@alpha-kwhn/2.1-Swift-%ED%9B%91%EC%96%B4%EB%B3%B4%EA%B8%B0-1</link>
            <guid>https://velog.io/@alpha-kwhn/2.1-Swift-%ED%9B%91%EC%96%B4%EB%B3%B4%EA%B8%B0-1</guid>
            <pubDate>Fri, 23 Sep 2022 16:05:35 GMT</pubDate>
            <description><![CDATA[<h4 id="20220919">2022.09.19</h4>
<p>Swift 언어 공부의 첫 걸음을 뗐다.</p>
<p>전반적으로 무슨 내용을 배울지 학생들에게 알려주기 위해 강사님께서는 Swift 공식문서를 읽어보는 시간을 준비하셨다.
한글로 번역된 Swift 공식문서의 링크는 아래와 같다.</p>
<p><code>https://bbiguduk.gitbook.io/swift</code></p>
<p>여담이지만, 수업 중 iOS 앱 개발이 프론트엔드에 가깝다 볼 수 있다고 강사님께서 말씀해주셨다. </p>
<p>평소에 iOS 앱 개발에도 백엔드/프론트 엔드가 명확히 나누어져 있는지 궁금했는데, 강사님의 말씀을 들어보니 확실히 프론트엔드의 색채가 짙다는 것을 느낄 수 있었다
(앞으로 나는 앱 프론트개발 쪽으로 이해하면 되겠군,,,👀)</p>
<hr>
<h3 id="변수와-상수">변수와 상수</h3>
<p>스위프트 둘러보기 문서에서 가장 먼저 기술되어 있던 내용은 <code>변수</code> 와 <code>상수</code> 에 관한 내용이었다.</p>
<pre><code class="language-swift">import Foundation

let myConstant = 42
var myVariable = 50
myVariable = 51</code></pre>
<h4 id="📌-point">📌 Point</h4>
<ul>
<li>변수 선언은 <code>var</code> 키워드를 이용</li>
<li>상수 선언은 <code>let</code> 키워드를 이용</li>
<li>변수는 한 번 저장된 값이 언제든지 바뀔 수 있음</li>
<li>상수는 한 번 저장된 값을, 선언부 이외의 줄에서 바꿀 수 없음</li>
</ul>
<hr>
<h3 id="타입">타입</h3>
<p>변수와 상수에 관한 설명이 끝나고 다음 내용을 읽어보기 전에, 강사님께서 Swift 언어에서의 원시타입 종류들을 정리해주셨다.</p>
<blockquote>
<h4 id="원시타입-primitive-type">원시타입 (Primitive Type)</h4>
<h4 id="숫자--int-float-double">숫자 : Int, Float, Double</h4>
<h4 id="불리언--bool">불리언 : Bool</h4>
<h4 id="텍스트--string-character">텍스트 : String, Character</h4>
<h4 id="컬렉션--arrayt-dictionarykhashable-v-setthashalbe">컬렉션 : Array<T>, Dictionary&lt;K:Hashable, V&gt;, Set&lt;T:Hashalbe&gt;</h4>
</blockquote>
<p> 원시언어는 단어에서도 유추할 수 있듯이, Swift에서 기본이되는 타입이며 구조체이다.</p>
<h4 id="--숫자-타입">- 숫자 타입</h4>
<ul>
<li><h4 id="정수--int-uint0양수만-표현">정수 : Int, UInt(0~양수만 표현)</h4>
</li>
<li><h4 id="부동-소수점-수">부동 소수점 수</h4>
<ul>
<li>Float : 32비트</li>
<li>Double : 64비트</li>
<li>Float80 : 80비트<pre><code class="language-swift">let implicitInteger = 70
let implicitDouble = 70.0
let explicitDouble: Double = 70</code></pre>
</li>
</ul>
</li>
</ul>
<h4 id="--불리언-타입">- 불리언 타입</h4>
<p>  참/거짓을 처리하는 목적의 데이터 타입
  true/false로 각각 참/거짓 지정이 가능하다</p>
<h4 id="--텍스트-타입">- 텍스트 타입</h4>
<ul>
<li><p>character : 단순한 유니코드 1글자</p>
<ul>
<li>String : 문자열, 유니코드 문자 여러개가 합쳐진 형태(문자들의 집합)</li>
</ul>
<p>character, String 모두 큰따옴표(&quot;&quot;)를 사용한다는 특징이 있으며, 구성하는 문자들은 모두 유니코드 표에 근거한 문자들이어야 한다.</p>
<p>여러줄의 문자열을 선언할 때는 &quot;&quot;&quot;을 사용한다.</p>
<p>추가로 아래 코드 중간에 <code>\  (apple)</code> 와 같은 출력 형식을 볼 수 있는데,
우리는 이를 <code>&#39;문자열 보간법&#39;</code> 이라고 한다
<code>문자열 보간법</code> 을 활용하면 <strong>소괄호 안의 변수나 상수를 손쉽게 문자열로 바꿀 수 있다</strong></p>
<pre><code class="language-swift">let quotation = &quot;&quot;&quot;
I said &quot;I have \(apple) apples.&quot;
And then I said &quot;I have \(apples + orange) pieces of fruit.&quot;
&quot;&quot;&quot;</code></pre>
</li>
</ul>
<h4 id="--컬렉션-타입">- 컬렉션 타입</h4>
<ul>
<li>배열 
<span style="color:red">순서가 있는 요소들의 모음</span>
Array<T>로 타입 정의
(T : 배열에 포함될 요소의 타입)
<br><br/><ul>
<li>딕셔너리
<span style="color:red">순서가 없는 키-값 쌍</span>의 모음
값은 구조체, 클래스 포함 어떤 값이든 가능
키도 어떤 타입이든 될 수 있지만, 고유해야 한다
<br><br/></li>
</ul>
</li>
<li>집합
특정 타입의 요소들을 포함한다 (배열과 유사)
<span style="color:red">순서를 갖지 않고</span>, 값들은 <span style="color:red">고유</span>해야 한다</li>
</ul>
<pre><code class="language-swift">  var arrayOfInts: Array&lt;Int&gt;
  var arrayOfInts: [Int]
  //배열의 선언법

  var dictionaryOfCapitalsByCountry: Dictionary&lt;String, String&gt;
  //딕셔너리 선언법
  var dictionaryOfCapitalsByCountry: [String : String]
  //키를 통해 값을 불러옴

  var winningLotteryNumbers: Set&lt;Int&gt;
  // 집합 선언법

  let emptyArray: [String] = []
  let emptyDictionary: [String: Float] = [:]
  //배열과 딕셔너리의 초기화 구문
</code></pre>
<hr>
<h3 id="서브스크립트">서브스크립트</h3>
<h4 id="배열과-딕셔너리에-접근하는-단축법">배열과 딕셔너리에 접근하는 단축법</h4>
<blockquote>
<p>  대괄호 ([ ])를 사용하여 배열과 딕셔너리를 생성하고 대괄호 안에 인덱스 또는 키를 작성하여 해당 요소에 접근한다 </p>
</blockquote>
<pre><code class="language-swift">let secondElement = countingUp[1]
//배열에 편리하게 접근할 수 있게 해주는 방법

var fruits: Array&lt;String&gt; = [
        &quot;strawberries&quot;, 
        &quot;limes&quot;, 
        &quot;tangerines&quot;
]
//문자열 타입의 리터럴이 콤마로 싸여서 대괄호에 나열되어 있으면 &quot;문자열 배열&quot;

fruits[1] = &quot;grapes&quot;
print(&quot;\(fruits)&quot;)
//[&quot;strawberries&quot;, &quot;grapes&quot;, &quot;tangerines&quot;]

fruits.append(&quot;blueberries&quot;)
//배열에서 인덱스 추가하기 -&gt; append 문법을 사용한다

var occupations: [String: String] = [
          &quot;Malcolm&quot;: &quot;Captain&quot;, //key : value
          &quot;Kaylee&quot;: &quot;Mechanic&quot;,
]

occupations[&quot;Jayne&quot;] = &quot;Public Relations&quot;
//딕셔너리 선언 및 키:값 추가

occupations[&quot;Malcolm&quot;] = &quot;Public Relations&quot;
//딕셔너리 키의 값 교체 -&gt; 새로운 키:값 쌍이 생성되는 것 x, 변경 o
print(&quot;\(occupations)&quot;)

//[&quot;Kaylee&quot;: &quot;Mechanic&quot;, &quot;Jayne&quot;:&quot;Public Relations&quot;, &quot;Malcolm&quot;: &quot;Public Relations&quot;]</code></pre>
<h4 id="📌-point-1">📌 Point</h4>
<ul>
<li>배열은 인덱스를 이용해 값에 접근</li>
<li>딕셔너리는 키 값을 이용해 값에 접근</li>
<li>append를 이용해 배열에 값 추가</li>
<li>키 값을 활용해 딕셔너리로 값을 수정할 수 있다</li>
</ul>
<hr>
<p>Swift 언어를 배웠던 첫 시간이었는데, 되게 많은 내용들이 슉슉 지나가서 정신이 없었다</p>
<p> 기존에 배웠던 프로그래밍언어와 견주어 보면 형식적 측면 말고는 대충 일맥상통하는 면이 꽤 있었다</p>
<p>  부트캠프에 참여한 모든 인원들이 함께 이해할 수 있어야 하기에 강사님께서 되게 기초적인 내용도 깊게 파서 가르치셨고, 이런 점은 전공자인 나 입장에서도 모르고 지나쳤던 부분들을 바로잡을 수 있게 도와주어서 매우 유익하게 다가왔다.</p>
<p> 다음 시간에도 파이팅🔥</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[1. Swift 소개와 Design Thinking]]]></title>
            <link>https://velog.io/@alpha-kwhn/1.1-Swift-%EC%86%8C%EA%B0%9C%EC%99%80-Design-Thinking</link>
            <guid>https://velog.io/@alpha-kwhn/1.1-Swift-%EC%86%8C%EA%B0%9C%EC%99%80-Design-Thinking</guid>
            <pubDate>Fri, 23 Sep 2022 13:59:52 GMT</pubDate>
            <description><![CDATA[<h4 id="20220916">2022.09.16</h4>
<p>OT도 끝났겠다, 이제 본격적으로 강사님과의 수업이 시작되었다
(23주간의 09:00-18:00 생활 시작...😢)</p>
<p>첫 수업의 주제는 아래와 같았다</p>
<blockquote>
<ul>
<li><strong>Swift 언어 소개</strong></li>
<li><strong>Design Thinking 기법 소개</strong></li>
</ul>
</blockquote>
<p>아무래도 첫 시간인 만큼, <strong>입문</strong>에 초점을 두신 것 같았다
강사님께서 재밌게 강의를 해주셔서 유튜브 보듯이 들었던 것 같음😎</p>
<hr>
<h2 id="⏰-오전-수업">⏰ 오전 수업</h2>
<p>오전 수업은 Swift 언어 소개 강의로 진행되었다</p>
<p>Swift를 만든 회사가 애플인 만큼, 오늘도 어김없이 Apple의 역사에 관한 내용이 등장했다!</p>
<p>아는 사람들은 알겠지만, 스티브 잡스는 한 때 애플에서 쫓겨난 적이 있었다</p>
<p>쫓겨난 잡스는 그 후에 애플을 퇴사한 일부 엔지니어들과 함께 NeXT라는 회사를 설립한다🏢</p>
<hr>
<h3 id="next-설립부터-애플로의-복귀까지">NeXT 설립부터 애플로의 복귀까지</h3>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/b591e273-7932-4017-a774-532ae9571819/image.png" alt="스티브잡스가 애플을 나오고 세웠던 NeXT"></p>
<p>NeXT의 주요 생산품은 워크스테이션이었다
수치해석 프로그램인 매스매티카를 탑재했던만큼, 그당시 CERN과 같은 연구기관들에서 다량으로 NeXT의 워크스테이션을 구매했었다고 한다</p>
<p>하지만, 가정용 컴퓨터들이 빠르게 고성능화 되어갔고 그에 따라 NeXT의 워크스테이션 매출은 죽어갔다</p>
<p>그렇다면 잡스가 나간 애플은 어땠을까?</p>
<p>애플도 꾸준히 고성능 Macintosh를 출시하며, 시장에 발맞춰 나갔으나 마이크로소프트의 Windows95 운영체제가 출시된 이후에 위기를 맞이하게된다</p>
<p>애플의 Mac OS는 경쟁사인 마이크로소프트에 비해 뒤쳐지기 시작했고, 이를 해결하기 위해 NeXT를 인수하였다
(당시 NeXT의 운영체제인 NeXTSTEP을 가지기 위해)</p>
<p>이렇게 잡스는 애플에 다시 복귀하게 되었고, 그 후 애플의 행보는 우리가 잘 아는 아이팟, 아이폰, 아이패드 등의 제품들을 만들어냄으로써 최고의 회사로 성장했다</p>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/88a51221-8281-46a0-ada9-460024bfb885/image.png" alt="아이팟에서 아이폰까지"></p>
<hr>
<h3 id="objective-c-그리고-swift">Objective-C 그리고 Swift</h3>
<p>c언어에 객체지향기능이 추가된 언어라고 이해하면 된다
1984년부터 시작된 검증된 언어로써, 이름에서도 유추할 수 있듯이 C언어 기반한 문법체계를 갖추고 있다.</p>
<p>하지만, 메모리를 건드리는 C언어의 특성상 오류 수정이 어렵고, 2006년 2.0 버전 공개 이후 업데이트가 없어서 현 시점으로써는 미래도 암울한 언어로 남아있다.</p>
<p>따라서, Objective-C를 쓰던 애플은 iOS 개발자들의 편의를 고려해 Swift라는 언어를 개발했다.</p>
<p>Swift의 특징을 설명하자면 다음 3가지로 요약할 수 있다 </p>
<blockquote>
<ul>
<li><h4 id="safe안정성--엄격한-문법을-적용해-실수-방지">Safe(<em>안정성</em>) : 엄격한 문법을 적용해 실수 방지</h4>
</li>
</ul>
</blockquote>
<ul>
<li><h4 id="fast신속성--c언어-수준과-동등한-성능을-목표">Fast(<em>신속성</em>) : C언어 수준과 동등한 성능을 목표</h4>
</li>
<li><h4 id="expressive더-나은-표현성--개발자들이-원하는-현대적이고-세련된-문법-지원">Expressive(<em>더 나은 표현성</em>) : 개발자들이 원하는 현대적이고 세련된 문법 지원</h4>
</li>
</ul>
<p>그 외에도 아래와 같은 특징도 가진다</p>
<ul>
<li>컴파일러 언어임에도 불구하고 Playground를 통한 결과 확인이 가능</li>
<li>ARC를 통한 효율적 메모리 관리</li>
<li>소괄호와 세미콜론 생략이 가능하다는 자유도 높은 문법 스타일</li>
</ul>
<hr>
<h2 id="☀️-오후-수업">☀️ 오후 수업</h2>
<p>오후에는 Design Thinking에 관한 수업이 진행되었다</p>
<p><img src="https://velog.velcdn.com/images/alpha-kwhn/post/5820a807-6793-4574-ae43-fc1feec550d5/image.png" alt="Design Thinking 절차"></p>
<p>본격 수업의 진행에 앞서, 미국 하버드대학(정확히 기억은 안남..)의 Design School에 관한 짧은 영상과 한 유명 앱 개발자의 특강을 보여주셨다.</p>
<p>앱 개발자에게 꼭 필요한 사고법이라고 알려주신만큼 유심히 영상을 보았다.</p>
<hr>
<h3 id="공감과-문제정의의-중요성">공감과 문제정의의 중요성</h3>
<blockquote>
<h4 id="도움을-주고자하는-사람들에-대한-공감">&#39;도움을 주고자하는 사람들에 대한 공감&#39;</h4>
</blockquote>
<h4 id="진짜-해결이-필요한-문제이며-많은-가치-창출이-가능한가">&#39;진짜 해결이 필요한 문제이며 많은 가치 창출이 가능한가?&#39;</h4>
<p>Design Thinking에는 여러 과정이 있었는데, 영상 속 강의자 분께서는 그 중에서 &#39;공감&#39;과 &#39;문제정의&#39;과정이 제일 중요하다고 강조하셨다.</p>
<p>영상이 끝난 후 강사님의 말씀도 이와 마찬가지였으며, 이러한 사고법을 체험해보기 위해 회고 조원들끼리 팀 활동을 하는 시간을 주셨다.</p>
<p>팀 활동 내용은 다음과 같았다.</p>
<blockquote>
<h4 id="1-각자-생각한-앱-아이디어를-간략히-정의하기">1. 각자 생각한 앱 아이디어를 간략히 정의하기</h4>
<h4 id="2-내-앱을-사용할-사용자가-누군지-생각해보고-해당-사용자의-특성을-다른-조원들이-정의">2. 내 앱을 사용할 사용자가 누군지 생각해보고, 해당 사용자의 특성을 다른 조원들이 정의</h4>
<h4 id="3-조원들이-생각한-사용자의-특성에-맞추어-개선된-앱-아이디어를-정의">3. 조원들이 생각한 사용자의 특성에 맞추어 개선된 앱 아이디어를 정의</h4>
</blockquote>
<p>생각보다 어려운 활동이었는데, 조원들이 정의한 앱 사용자의 특성을 활용해 개선된 앱 아이디어를 정의하는 것이 가장 어려웠던 것 같다.
(너무 오래걸려서, 내 아이디어는 아쉽게 시간 이슈로 활동을 진행하지 못함,,,😢)</p>
<p>이렇게 첫 수업도 알차게 마무리되었다. 
앞으로도 오늘처럼 재미 있게 수업이 진행되었으면 좋겠다,,,👀</p>
]]></description>
        </item>
    </channel>
</rss>