<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>이동건의 이유있는 코드</title>
    <link>https://baked-corn.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Wed, 1 Jul 2026 00:53:40 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>군옥수수수</managingEditor>
    <image>
      <title>이동건의 이유있는 코드</title>
      <url>https://tistory1.daumcdn.net/tistory/2745885/attach/16bb46387f83459ab3015eaa1429bea8</url>
      <link>https://baked-corn.tistory.com</link>
    </image>
    <item>
      <title>블로그를 이전하였습니다.</title>
      <link>https://baked-corn.tistory.com/139</link>
      <description>&lt;h2&gt;&lt;br /&gt;&lt;/h2&gt;&lt;h2&gt;&lt;br /&gt;&lt;/h2&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;h2 style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;블로그를&amp;nbsp;&lt;a href=&quot;http://protocorn93.github.io&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;http://protocorn93.github.io&lt;/a&gt;&amp;nbsp;로 이전하였습니다!&amp;nbsp;&lt;/span&gt;&lt;/h2&gt;&lt;h2 style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;font-weight: normal;&quot;&gt;많은 방문과 피드백 부탁드리겠습니다.  &lt;/span&gt;&lt;/h2&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>기록</category>
      <author>군옥수수수</author>
      <guid isPermaLink="true">https://baked-corn.tistory.com/139</guid>
      <comments>https://baked-corn.tistory.com/139#entry139comment</comments>
      <pubDate>Fri, 2 Nov 2018 16:18:39 +0900</pubDate>
    </item>
    <item>
      <title>[Project] GitBingo</title>
      <link>https://baked-corn.tistory.com/138</link>
      <description>&lt;article class=&quot;markdown-body&quot;&gt;
&lt;h2&gt;&lt;a href=&quot;https://itunes.apple.com/kr/app/gitbingo/id1435428800?l=en&amp;amp;mt=8&quot;&gt;GitBingo (깃빙고)&lt;/a&gt;&lt;/h2&gt;
&lt;blockquote&gt;&lt;p&gt;App Icon by &lt;a href=&quot;https://github.com/snowjang24&quot;&gt;snowJang24&lt;/a&gt;, App Name by &lt;a href=&quot;https://github.com/nailerHeum&quot;&gt;nailerHeum&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;1일 1커밋을 실천하려는 개발자들을 위한 어플리케이션&lt;/strong&gt;&lt;/p&gt;
&lt;h4&gt;기능&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;실시간 Contribution 확인 가능&lt;/li&gt;
&lt;li&gt;원하는 시간에 알람을 받아 금일 커밋을 진행하였는지 확인 가능&lt;/li&gt;
&lt;li&gt;투데이 익스텐션 타겟을 사용해 위젯에서 이번주 커밋 정보와 알람 등록 시간을 확인 가능&lt;/li&gt;

&lt;/ol&gt;
&lt;h4&gt;사용한 기술&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Swift4&lt;/code&gt;, &lt;code&gt;Xcode9&lt;/code&gt;, &lt;code&gt;UserNotifications&lt;/code&gt;, &lt;code&gt;Error Handling&lt;/code&gt;, &lt;code&gt;Localizing&lt;/code&gt;, &lt;code&gt;Networking&lt;/code&gt;, &lt;code&gt;UIApplicationShortCuts&lt;/code&gt;, &lt;code&gt;Today Extensions&lt;/code&gt;, &lt;code&gt;SwiftLint&lt;/code&gt;, &lt;code&gt;Unit Test&lt;/code&gt;&lt;/li&gt;

&lt;/ul&gt;
&lt;h4&gt;사용한 아키텍쳐&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Delegation&lt;/code&gt;, &lt;code&gt;Singleton&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;시도한 아키텍쳐 : &lt;code&gt;MVP&lt;/code&gt;&lt;/li&gt;

&lt;/ul&gt;
&lt;h4&gt;공부한 내용 정리&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;App Extension Programming Guide for iOS&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://ehdrjsdlzzzz.github.io/2018/10/03/App-Extension-Programming-Guide-1/&quot;&gt;Essential&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ehdrjsdlzzzz.github.io/2018/10/09/App-Extension-Programming-Guide-2/&quot;&gt;Essential - Handling Common Scenarios&lt;/a&gt;&lt;/li&gt;

&lt;/ul&gt;
&lt;/li&gt;

&lt;/ul&gt;
&lt;h4&gt;사용한 라이브러리&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/tid-kijyun/Kanna&quot;&gt;&lt;code&gt;Kanna&lt;/code&gt;&lt;/a&gt; - &lt;a href=&quot;https://github.com/users/ehdrjsdlzzzz/contributions&quot; target=&quot;_blank&quot; class=&quot;url&quot;&gt;https://github.com/users/ehdrjsdlzzzz/contributions&lt;/a&gt; 로부터 HTML을 파싱해오기 위해 사용&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/SVProgressHUD/SVProgressHUD&quot;&gt;&lt;code&gt;SVProgressHUD&lt;/code&gt;&lt;/a&gt; - Indicator와 함께 코멘트를 사용하기 위해 사용&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/realm/SwiftLint&quot;&gt;&lt;code&gt;SwiftLint&lt;/code&gt;&lt;/a&gt; - Swift 스타일과 컨벤션을 지키기 위해&lt;/li&gt;

&lt;/ul&gt;
&lt;h4&gt;문제점&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;웹 브라우저에선 00:00 이후 다음 날 컨트리뷰션 도트를 바로 확인 가능하지만 앱에선 GMT 시간 차로 오전 9시가 되어서야 그날의 도트를 받아올 수 있음.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;이 문제를 해결하기 위해 많은 노력을 해보았으나 해결하지 못함&lt;/li&gt;
&lt;li&gt;확인해본 결과 모바일 크롬이나 사파리에서도 동일한 이슈가 발생한 것으로 모바일에서 요청한 것에 대한 깃헙 서버의 응답에 이슈가 있는 것으로 판단하였음.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;

&lt;/article&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>Project</category>
      <category>IOS</category>
      <author>군옥수수수</author>
      <guid isPermaLink="true">https://baked-corn.tistory.com/138</guid>
      <comments>https://baked-corn.tistory.com/138#entry138comment</comments>
      <pubDate>Thu, 6 Sep 2018 14:45:25 +0900</pubDate>
    </item>
    <item>
      <title>App Programming Guide for iOS -Introduction,Expected App Behaviors</title>
      <link>https://baked-corn.tistory.com/137</link>
      <description>&lt;article class=&quot;markdown-body&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-size: 18pt;&quot;&gt;&lt;b&gt;[ios] App Programming Guide for iOS - Introduction,Expected App Behaviors&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 18pt;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Xcode로부터 생성된 모든 프로젝트는 생성 그 즉시 시뮬레이터나 디바이스에서 실행이 가능합니다. 하지만 이렇게 단순히 실행이 된다는 이유 하나만으론 앱 스토에 배포될 준비가 되었다 할 수 없습니다. 모든 앱은 사용자에게 좋은 사용 경험을 보장할만한 어느 정도 수준의 &lt;strong&gt;customization&lt;/strong&gt;이 필요합니다. 이러한 customization의 범위는 앱의 아이콘부터 앱의 설계 수준까지 다양합니다. 이번 챕터에선 모든 앱에서 처리해야하는 동작과 계획 과정 초기에 고려해야할 것들에 대해 설명합니다. &lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;훌륭한 사용자 경험 전달을 보장하기 위해서 앱은  iOS와 함께 동작해야 합니다. 훌륭한 사용자 경험이란 단지 디자인뿐만 아니라 더 많은 요소들을 함축적으로 내포합니다. 앱의 사용자는 앱이 빠른 속도로 반응하고 적은 전력만을 사용하기를 기대합니다. 앱은 모든 최신 iOS 기기를 지원해야하며 현재 사용되고 있는 기기에서 최적화된 것처럼 보여야 합니다. &lt;/p&gt;
&lt;h4&gt;At a Glance&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Apps Are Expected to Support Key Features&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;시스템은 모든 앱이 앱 아이콘이나 앱의 기능을 나타내는 정보와 같이 특정 리소스와 설정 데이터들을 갖고 있을 것이라고 간주합니다. Xcode를 통해 프로젝트를 생성한다면 몇몇의 정보는 기본적으로 주어지지만 추가적인 리소스 파일이나 앱의 기능의 명시는 앱이 배포되기 전에 반드시 설정해주어야 합니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt; &lt;a href=&quot;https://developer.apple.com/library/archive/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/ExpectedAppBehaviors/ExpectedAppBehaviors.html#//apple_ref/doc/uid/TP40007072-CH3-SW2&quot;&gt;Expected App Behaviors&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Apps Follow Well-Defined Execution Paths&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;사용자가 앱을 실행한 시점부터 종료하는 시점까지 앱은 잘 정의된 실행 단계(경로)를 따라야 합니다. 앱의 생명주기 동안 앱은 foreground와 background를 오갈 수 있고, 종료된 후 재실행될 수 있으며, 또한 잠시 수면 상태에 돌입할 수 있습니다. 이렇게 새로운 상태로 변환될 때 마다 앱의 상태에 대한 기대는 달라집니다. foreground 상태의 앱은 거의 모든 것을 할 수 있지만 background에선 최소한의 행위만을 해야 합니다. 개발자는 이러한 상태 변화를 활용하여 앱의 동작을 적절하게 조정할 수 있습니다. &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;a href=&quot;https://developer.apple.com/library/archive/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/TheAppLifeCycle/TheAppLifeCycle.html#//apple_ref/doc/uid/TP40007072-CH2-SW1&quot;&gt;The App Life Cycle&lt;/a&gt;, &lt;a href=&quot;https://developer.apple.com/library/archive/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/StrategiesforHandlingAppStateTransitions/StrategiesforHandlingAppStateTransitions.html#//apple_ref/doc/uid/TP40007072-CH8-SW1&quot;&gt;Strategies for Handling App State Transitions&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;App Must Run Efficiently in a Multitasking Enviornment&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;사용자에게 베터리 Life는 성능, 반응 속도, 훌륭한 사용자 경험만큼 중요합니다. 앱의 베터리 사용량을 축소시킨다면 사용자는 해당 앱을 재충전 없이 하루종일 사용할 수 있겠지만, 빠른 앱 런칭 속도와 앱의 동작 속도또한 그만큼 중요합니다. iOS의 멀티태스킹 환경은 사용자가 기대하는 반응 속도나 사용자 경험을 희생시킬 필요 없이 좋은 베터리 Life를 제공합니다. 하지만 이를 위해선 앱이 시스템이 정의하고 제공하는 행위들을 수행해야 합니다. &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt; &lt;a href=&quot;https://developer.apple.com/library/archive/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html#//apple_ref/doc/uid/TP40007072-CH4-SW1&quot;&gt;Background Execution&lt;/a&gt;, &lt;a href=&quot;https://developer.apple.com/library/archive/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/StrategiesforHandlingAppStateTransitions/StrategiesforHandlingAppStateTransitions.html#//apple_ref/doc/uid/TP40007072-CH8-SW1&quot;&gt;Strategies for Handling App State Transitions&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Communication Between Apps Follows Specific Pathways&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;보안성의 목적으로 iOS 앱들은 각각의 샌드박스에서 실행되며 다른 앱과의 제한된 상호작용만 허용됩니다. 시스템 상의 다른 앱들과 통신을 하고 싶다면 특별한 방법이 존재합니다. &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt; &lt;a href=&quot;https://developer.apple.com/library/archive/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/Inter-AppCommunication/Inter-AppCommunication.html#//apple_ref/doc/uid/TP40007072-CH6-SW2&quot;&gt;Inter-App Communication&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Performance Tuning is Important for Apps&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;앱에 의해 수행되는 모든 작업은 그에 맞는 에너지 비용이 따르기 마련입니다. 사용자의 베터리를 많이 잡아먹는 앱은 부정적인 사용자 경험을 제공하고 이는 앱의 삭제로 이어지기 됩니다. 그렇기 때문에 작업에 따른 비용을 항상 인지하고 있어야 하며 시스템이 제공하는 에너지 절전 기능을 활용해야 합니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;a href=&quot;https://developer.apple.com/library/archive/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/PerformanceTips/PerformanceTips.html#//apple_ref/doc/uid/TP40007072-CH7-SW1&quot;&gt;Performance Tips&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h4&gt;Providing the Required Resources&lt;/h4&gt;
&lt;p&gt;모든 앱은 디바이스 위에서 실행되기 위해선 다음 목록에 해당하는 리소스와 메타데이터들을 반드시 포함해야 합니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;An information property-list file&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Info.plist&lt;/code&gt;는 시스템이 앱과 상호작용할 때 필요로 하는 메타데이터를 포함하고 있습니다. Xcode는 프로젝트의 생성 시 초기 설정에 맞게 자동으로 이 파일을 생성해줍니다. 이 파일은 제작하는 프로젝트의 특성에 따라 직접 수정할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.apple.com/library/archive/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/ExpectedAppBehaviors/ExpectedAppBehaviors.html#//apple_ref/doc/uid/TP40007072-CH3-SW5&quot;&gt;The Information Property List File&lt;/a&gt;&lt;/li&gt;

&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A declaration of the app's required capabilites&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;모든 앱은 앱 동작에 필요한 하드웨어 기능들을 반드시 명시해주어야 합니다. 앱스토어는 이 정보를 이용하여 해당 앱이 사용자(앱스토에서 앱을 받으려는 사람)의 디바이스에서 동작할 수 있는지 없는지를 결정합니다. 역시 제작하는 프로젝트의 특성에 따라 직접 수정할 수 있습니다. &lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.apple.com/library/archive/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/ExpectedAppBehaviors/ExpectedAppBehaviors.html#//apple_ref/doc/uid/TP40007072-CH3-SW4&quot;&gt;Declaring the Required Device Capabilities&lt;/a&gt;&lt;/li&gt;

&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;One or more icons&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;앱의 아이콘은 시스템에 의해 사용자의 홈 화면에서 확인할 수 있습니다. 또한 설정 앱에서 다른 버전의 앱 아이콘을 설정할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.apple.com/library/archive/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/ExpectedAppBehaviors/ExpectedAppBehaviors.html#//apple_ref/doc/uid/TP40007072-CH3-SW1&quot;&gt;App Icons&lt;/a&gt;&lt;/li&gt;

&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;One or more launch images&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;앱이 시작되고 앱의 UI가 준비될 때 까지 시스템은 임시로 launch image를 사용자에게 보여줍니다. launch image를 통해 사용자는 앱이 실행 중이고 곧 메인 화면으로 진입할 것이라는 것을 알 수 있습니다. 앱은 반드시 하나 이상의 launch image를 갖고 있어야 하며 다양한 시나리오에 맞춰 다양한 launch image를 사용할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.apple.com/library/archive/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/ExpectedAppBehaviors/ExpectedAppBehaviors.html#//apple_ref/doc/uid/TP40007072-CH3-SW3&quot;&gt;App Launch (Default) Images&lt;/a&gt;&lt;/li&gt;

&lt;/ul&gt;
&lt;/li&gt;

&lt;/ul&gt;
&lt;hr&gt;
&lt;h4&gt;The App Bundle&lt;/h4&gt;
&lt;p&gt;iOS 앱을 빌드하면 Xcode 이를 &lt;strong&gt;번들(bundle)&lt;/strong&gt;이라는 것으로 포장합니다. 번들은 하나의 디렉토리로 관련된 리소스들을 한 장소에 그룹지어 놓은 것을 의미합니다. iOS 앱 번들은 앱의 실행 파일과 앱 아이콘, 이미지 파일, 지역화된 컨텐츠와 같은 리소스 파일들을 포함하고 있습니다. 다음 테이블 표는 설명을 위한 전형적인 iOS 앱인 MyApp의 앱 번들에 포함되는 컨텐츠들을 설명합니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;이 예제는 설명을 위한 목적으로 몇몇 파일은 여러분들의 앱 번들에 없을 수 있습니다. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;figure&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;File&lt;/th&gt;&lt;th&gt;Example&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;App executable&lt;/td&gt;&lt;td&gt;&lt;code&gt;MyApp&lt;/code&gt;&lt;/td&gt;&lt;td&gt;실행 가능 파일은 앱의 컴파일 된 코드를 포함합니다. 실행 가능 파일의 이름은 앱의 이름에서 &lt;code&gt;.app&lt;/code&gt; 확장자를 뺀 것과 동일합니다. &lt;strong&gt;[필수]&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;The information property list file&lt;/td&gt;&lt;td&gt;&lt;code&gt;Info.plist&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;Info.plist&lt;/code&gt; 파일은 앱의 설정 정보를 포함하고 있으며 시스템은 이 정보를 사용하여 해당 앱과 어떻게 상호작용할지를 결정합니다. 이 파일명은 반드시 &lt;code&gt;Info.plist&lt;/code&gt;이어야 합니다. &lt;strong&gt;[필수]&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;App icons&lt;/td&gt;&lt;td&gt;&lt;code&gt;Icon.png&lt;/code&gt; &lt;code&gt;Icon@2x.png&lt;/code&gt;&lt;/td&gt;&lt;td&gt;홈 화면에서 앱을 나타내는 아이콘 &lt;strong&gt;[필수]&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Launch Images&lt;/td&gt;&lt;td&gt;&lt;code&gt;Default.png&lt;/code&gt;&lt;/td&gt;&lt;td&gt;앱의 실행 준비동안 사용자에게 보여지는 이미지로 앱이 UI를 보여줄 준비가 되면 사라지고 UI가 나타납니다. 최소한 한 개 이상의 이미지가 요구 됩니다. &lt;strong&gt;[필수]&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Storyboard files (or nib files)&lt;/td&gt;&lt;td&gt;&lt;code&gt;Main.storyboard&lt;/code&gt;&lt;/td&gt;&lt;td&gt;스토리보드 파일은 앱이 디바이스 화면에 보여주는 뷰나 뷰 컨트롤러들을 포함합니다. 뷰 컨트롤러는 뷰들을 묶어 정렬하고 이들을 화면에 보여주는 역할을 합니다. 또한 스토리보드는 한 세트의 뷰들에서 다른 세트의 뷰들로의 전환 작업(&lt;strong&gt;Segue&lt;/strong&gt;)에도 관여합니다. 메인 스토리보드 파일의 이름은 Xcode에 의해 프로젝트 생성시 자동으로 결정되는데 &lt;code&gt;Info.plist&lt;/code&gt;에서 이를 변경해줄 수 있습니다. nib 파일을 사용하는 프로젝트에서도 마찬가지 입니다. 스토리보드 파일의 사용은 필수는 아니지만 권장됩니다.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Settings bundle&lt;/td&gt;&lt;td&gt;&lt;code&gt;Settings.bundle&lt;/code&gt;&lt;/td&gt;&lt;td&gt;만일 디바이스의 설정 앱에서 앱의 설정이 보여지길 원한다면 설정 번들을 반드시 포함시켜야 합니다. 이 번들은 선택 사항입니다.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Nonlocalized resource files&lt;/td&gt;&lt;td&gt;&lt;code&gt;sun.png&lt;/code&gt;&lt;/td&gt;&lt;td&gt;이미지, 사운드, 동영상과 같이 지역화되지 않은 파일이라 합니다. 이러한 모든 파일들은 앱 번들에 상단에 위치해야 합니다.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Subdirectories for localized resources&lt;/td&gt;&lt;td&gt;&lt;code&gt;en.lproj&lt;/code&gt; &lt;code&gt;fr.lproj&lt;/code&gt;&lt;/td&gt;&lt;td&gt;지역화된 리소스들은 반드시 &lt;code&gt;.lproj&lt;/code&gt; 접미사를 갖는 언어 별 프로젝트 디렉토리에 위치해야 합니다. iOS 앱은 국제화되어야 하며 지원하는 언어 별 &lt;code&gt;.lproj&lt;/code&gt; 디렉토리를 갖고 있어야 합니다.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;
&lt;/table&gt;&lt;/figure&gt;
&lt;blockquote&gt;&lt;p&gt;iOS 앱은 &lt;code&gt;Resource&lt;/code&gt;라는 이름의 사용자 정의 디렉토리는 생성할 수 없습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h4&gt;Supporting User Privacy&lt;/h4&gt;
&lt;p&gt;사용자의 개인정보를 다루기 위한 설계는 매우 중요합니다. 대부분의 iOS 디바이스에는 사용자가 외부나 다른 앱에 노출시키고 싶지 않은 민감한 데이터들을 갖고 있습니다. 만일 앱이 사용자 정보에 부적절한 방식으로 접근하거나 사용한다면 사용자는 해당 앱을 그 즉시 삭제할 것입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;이러한 사용자나 디바이스의 정보에 접근 사용자의 승낙하에 이루어져야 합니다. 게다가 사용자와 디바이스의 정보를 보호하는데 적당한 단계를 거쳐야 하며 데이터의 사용은 투명하게 이루어져야 합니다. 다음은 이러한 민간한 데이터에 접근할 때 취할 수 있는 행동의 좋은 예제들입니다. &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;정부나 산업계의 가이드라인을 따른다.&lt;/li&gt;
&lt;li&gt;iOS 시스템 허가 설정에 의해 보호되고 있는 민감한 데이터에 접근 허가 요청은 앱이 해당 데이터를 필요로 하는 그 순간에 이루어져야 합니다. 이렇게 민감한 데이터에 접근을 요청할 때는 왜 필요하며 어떻게 사용할지에 대한 적절한 문구를 &lt;code&gt;Info.plist&lt;/code&gt;에 해당 데이터 사용 요청 권한 문구에 명시해주어야 합니다. iOS 시스템 허가 설정에 해당하는 데이터는 위치, 연락처, 캘린더, 추억, 사진, 미디어 등이 있습니다. 사용자가 데이터의 접근을 허가하지 않는 상황에서도 합당한 대체 행위를 제공해야 합니다. &lt;/li&gt;
&lt;li&gt;데이터가 어떻게 사용되는지에 대해 투명하게 공개되어야 합니다. 예를 들어 앱스토에 앱을 배포할 때 데이터 사용 정책에 대한 URL을 메타데이터에 포함시킬 수 있습니다. 또한 앱의 설명에서 이러한 민감한 데이터 사용 정책에 대해 기술할 수도 있습니다. &lt;/li&gt;
&lt;li&gt;사용자나 디바이스에 정보에 대한 권한은 전적으로 사용자에게 있어야 합니다. 사용자가 언제든지 데이터 접근에 대해 거부할 수 있어야 합니다. &lt;/li&gt;
&lt;li&gt;작업을 수행하기 위한 최소한의 데이터만을 요청하고 사용해야 합니다. 불필요하거나 추후에 사용할 것 같다는 이유와 같이 명백한 이유 없는 불필요한 데이터의 요청이나 수집은 하지 말아야 합니다. &lt;/li&gt;
&lt;li&gt;앱에서 수집하려는 사용자나 디바이스 데이터는 적절한 단계를 거쳐 보호되어야 합니다. 앱 자체에서 이러한 정보들을 저장하려면 iOS의 데이터 보호 기능들을 사용하여 암호화된 데이터들을 저장해야 합니다. 사용자나 디바이스의 정보를 네트워크를 통해 전송하기 위해서는 App Transport Security를 사용해야 합니다. &lt;/li&gt;
&lt;li&gt;앱이 오디오 입력을 지원하는 경우 실제로 녹음을 시작하는 시점에 녹음을 위한 오디오 세션을 구성해야 합니다. 녹음을 시작할 때 사용자에게 이를 알리고 녹음을 중지할 수 있는 옵션도 제공해야 합니다.&lt;/li&gt;

&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;참고자료&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.apple.com/library/archive/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/ExpectedAppBehaviors/ExpectedAppBehaviors.html#//apple_ref/doc/uid/TP40007072-CH3-SW4&quot;&gt;App Programming Guide for iOS&lt;/a&gt;&lt;/li&gt;

&lt;/ol&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;/article&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>Swift + iOS/iOS</category>
      <category>IOS</category>
      <category>Swift</category>
      <author>군옥수수수</author>
      <guid isPermaLink="true">https://baked-corn.tistory.com/137</guid>
      <comments>https://baked-corn.tistory.com/137#entry137comment</comments>
      <pubDate>Thu, 16 Aug 2018 12:21:31 +0900</pubDate>
    </item>
    <item>
      <title>[Swift] Swift에서 정규표현식 사용하기</title>
      <link>https://baked-corn.tistory.com/136</link>
      <description>&lt;article class=&quot;markdown-body&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-size: 18pt;&quot;&gt;&lt;b&gt;[Swift] Swift에서 정규표현식 사용하기&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-size: 18pt;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;저는 지금까지 텍스트 필드 위에 입력되는 사용자의 입력이나 텍스트 덩어리에서 원하는 패턴의 값을 뽑아내거나 검증을 할 때 항상 모든 경우에 대해 &lt;code&gt;if-else&lt;/code&gt; 와 같은 조건문을 이용하였습니다. &lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;하지만 이렇게 조건문으로 모든 것을 해결하려하니 코드의 가독성, 효율성이 떨어질 뿐만 아니라 시간도 꽤나 소모되는 경우가 허다했습니다. 그러던 와중 매번 나랑은 관계없다고 생각한 정규표현식을 사용하고 느낀 편리함을 기록해보고자 이렇게 글을 작성하게 되었습니다. 그럼 바로 시작해보도록 하겠습니다. &lt;/p&gt;
&lt;hr&gt;
&lt;h4&gt;NSRegularExpression&lt;/h4&gt;
&lt;p&gt;먼저 Swift에서 정규표현식을 사용하여 패턴을 검증하기 위해선 &lt;code&gt;NSRegularExpression&lt;/code&gt;을 사용해야 합니다. 앞에 &lt;code&gt;NS-&lt;/code&gt;가 붙어있다는 사실만으로도 &lt;code&gt;NSRegularExpression&lt;/code&gt;이 Objective-C로 작성되어 있다는 것을 알 수 있습니다. &lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;먼저 이를 직접 사용해보면서 어떤 식으로 사용하는지에 대해 알아보도록 하겠습니다. &lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;예제의 상황은 이렇습니다. 사용자가 입력한 다음의 텍스트로부터 &lt;code&gt;#&lt;/code&gt;가 접두어로 있는, 즉 해시태그에 해당하는 문자들을 뽑아보도록 하겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&lt;i&gt;&quot;I made this wonderful pic last #christmas... #instagram #nofilter #snow #fun&quot;&lt;/i&gt;&lt;/code&gt;&lt;/p&gt; &lt;br&gt;
&lt;p&gt;&lt;strong&gt;Pattern&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;우리가 뽑아낼 단어는 접두어로 &lt;code&gt;#&lt;/code&gt;를 갖는 단어들입니다. 이러한 단어들을 뽑아내기 위한 정규표현식은 &lt;code&gt;#[a-z0-9]+&lt;/code&gt; 입니다. 이게 무엇을 의미할까요? &lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;[]&lt;/code&gt; 안에 특정 패턴이 어떠한 종류의 값을 갖는지에 대해 값의 범위(range)를 표현해주어야 합니다. 해시태그로 &lt;code&gt;#&lt;/code&gt; 뒤에 알파벳과 숫자를 갖는 패턴으로는 &lt;code&gt;#[a-z0-9]&lt;/code&gt;가 됩니다.&lt;/li&gt;
&lt;li&gt;그렇다면 &lt;code&gt;+&lt;/code&gt;는 무엇일까요? 이는 바로 특정 범위에 해당하는 문자들이 한개 혹은 그 이상 존재한다는 의미입니다. 만일 &lt;code&gt;+&lt;/code&gt; 가 붙지 않았다면 &lt;code&gt;#5&lt;/code&gt; 와 같이 &lt;code&gt;#&lt;/code&gt; 뒤 한개의 문자만 있는 해시태그만 찾아낼 것입니다. &lt;/li&gt;

&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;&lt;b&gt;NSRegularExpression&lt;/b&gt;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;그럼 이제 본격적으로 &lt;code&gt;NSRegularExpression&lt;/code&gt;을 사용해보도록 하겠습니다. 위에서 정의한 &lt;code&gt;#[a-z0-9]+&lt;/code&gt; 의 패턴을 갖는 인스턴스는 다음과 같이 생성할 수 있습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot; lang=&quot;swift&quot;&gt;let regex = try? NSRegularExpression(pattern: &quot;#[a-z0-9]+&quot;, options: .caseInsensitive)
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;code&gt;.caseInsenstive&lt;/code&gt; 란 단어 그대로 case, 즉 uppsercase, lowercase에 둔감하다는 의미로 대소문자를 구분하지 않는다는 옵션입니다. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;이렇게 우리는 하나의 정규 표현식 패턴을 갖는 거름망을 만든 것이라고 보면 됩니다. 그럼 이제 텍스트를 이 거름망에 통과시켜 보도록 하겠습니다. &lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot; lang=&quot;swift&quot;&gt;let text = &quot;I made this wonderful pic last #christmas... #instagram #nofilter #snow #fun&quot;

let textToNS = text as NSString 
regex.matches(in: text, options: [], range: NSRange(location: 0, length: textToNS.length))
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;in:&lt;/code&gt; 에는 검사할 텍스트를 넣어줍니다. &lt;/li&gt;
&lt;li&gt;&lt;code&gt;range:&lt;/code&gt; 에는 검사할 텍스트의 범위를 정해줍니다. 하지만 코드에서 &lt;code&gt;String&lt;/code&gt; 을 &lt;code&gt;NSString&lt;/code&gt; 으로 캐스팅하여 넣어준 것을 확인할 수 있습니다. 이는 &lt;code&gt;NSRegularExpression&lt;/code&gt;이 &lt;code&gt;NSRange&lt;/code&gt;를 인자로 받기 때문인데 &lt;code&gt;NSRange&lt;/code&gt;를 받는 이유는 기본적으로 Objective-C와 Swift에서 문자열을 처리하는 방법이 다르기 때문입니다. &lt;/li&gt;

&lt;/ul&gt;
&lt;p&gt;이렇게 &lt;code&gt;matches&lt;/code&gt;를 통해 우리는 거름망을 통과시킨 결과를 얻을 수 있는데 그 결과 타입은 &lt;code&gt;[NSTextCheckingResult]&lt;/code&gt;입니다. 그리고 &lt;code&gt;NSTextCheckResult&lt;/code&gt;는 검사를 원하는 텍스트에서 거름망의 패턴과 일치하는 부분 텍스트가 있다면 해당 부분 텍스트의 범위를 &lt;code&gt;NSRange&lt;/code&gt;의 형태로 반환하고 &lt;code&gt;NSTextCheckResult&lt;/code&gt;는 이를 &lt;code&gt;range&lt;/code&gt; 프로퍼티로 갖고 있습니다. &lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot; lang=&quot;swift&quot;&gt;regex.matches(in: self, options: [], range: NSRange(location: 0, length: string.length)).map {
    string.substring(with: $0.range)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt; 그렇다면 우리는 그렇게 나온 일치하는 부분 텍스트의 범위(&lt;code&gt;NSRange&lt;/code&gt;)를 통해 부분 텍스트들을 원본에서 뽑아낼 수 있습니다.  그렇게 결과로는 &lt;code&gt;[&quot;christmas&quot;, &quot;instagram&quot;, &quot;nofilter&quot;, &quot;snow&quot;, &quot;fun&quot;]&lt;/code&gt;가 나오게 됩니다. &lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;이렇게  정규 표현식을 사용한다면 보다 쉽게 텍스트로부터 원하는 패턴의 값들을 뽑아낼 수 있습니다. 다음은 제가 사용하기 위해 공부해 본 정규 표현식입니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;&quot;[a-z0-9]+&quot;(?=:)&lt;/code&gt; : json 키-값 쌍에서 키를 찾아주는 정규 표현식입니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;(?, ... )&lt;/code&gt; : 이는 전방 탐색 문법으로 &lt;code&gt;...&lt;/code&gt;에 오는 패턴 앞을 검사합니다. 저는 이 부분에 &lt;code&gt;:&lt;/code&gt; 를 넣었으니. 모든 텍스트에서 &lt;code&gt;:&lt;/code&gt; 앞을 검사하게 됩니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&quot;[a-z0-9]+&quot;&lt;/code&gt; : &lt;code&gt;:&lt;/code&gt; 앞에  &lt;code&gt;&quot;&quot;&lt;/code&gt; 안에 들어있는 즉 문자나 숫자를 포함하는 문자열이 존재하는지 검사하기 위한 조건입니다. 이렇게 되면 우리는 json 키-값 쌍에서 키를 찾아낼 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;NSRegularExpression&lt;/code&gt;에서 사용할 때 주의할 점은 &lt;code&gt;&quot;&quot;&lt;/code&gt; 안에 위의 표현식이 들어가기 때문에 반드시 &lt;code&gt;\&quot;&lt;/code&gt;처리를 해주어야 합니다. &lt;code&gt;in: &quot;\&quot;[a-z0-9]+\&quot;(?=)&quot;&lt;/code&gt;&lt;/li&gt;

&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,20}&lt;/code&gt; : 이메일의 형식 검사&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;사용자가 이메일을 입력했을 때 유효한 이메일인지 검사하는 패턴입니다.&lt;/li&gt;

&lt;/ol&gt;
&lt;/li&gt;

&lt;/ol&gt;
&lt;hr&gt;
&lt;h4&gt;마무리&lt;/h4&gt;
&lt;p&gt;이외에도 우리는 수 많은 정규 표현식을 사용할 수 있습니다. 그 문법은 굉장히 무궁무진합니다. 그렇기 때문에 이들을 적절히 사용한다면 왠만한 패턴의 텍스트들을 모두 뽑아낼 수 있을 것입니다. &lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;오늘은 이렇게 Swift에서 정규 표현식을 사용하는 방법에 대해 공부했습니다. 정규 표현식의 문법을 마음대로 사용할 수준은 아직은 아니지만 기회가 있을 때마다 적극적으로 사용하며 이를 익힐 수 있도록 해야겠습니다. &lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;이런 정규 표현식은 구글에 검색해보면 일종의 치트 시트 형식으로 많이 사용하는 문법들을 정리해 놓은 pdf 파일이나 블로그 글들을 쉽게 접할 수 있습니다. 이들과 정규 표현식을 사용해 볼 수 있는 각종 사이트들을 활용한다면 왠만한 패턴들은 뽑아내실 수 있을 겁니다. 감사합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;참고자료&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://learnappmaking.com/regular-expressions-swift-string/&quot;&gt;How to Find Strings With Regular Expressions in Swift&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://regex101.com&quot;&gt;regex101&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.cbs.dtu.dk/courses/27610/regular-expressions-cheat-sheet-v2.pdf&quot;&gt;Regex Cheat Sheet&lt;/a&gt;&lt;/li&gt;

&lt;/ol&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;/article&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>Swift + iOS/Swift</category>
      <category>NSRegularExpression</category>
      <category>regex</category>
      <category>Swift</category>
      <category>스위프트</category>
      <category>정규표현식</category>
      <author>군옥수수수</author>
      <guid isPermaLink="true">https://baked-corn.tistory.com/136</guid>
      <comments>https://baked-corn.tistory.com/136#entry136comment</comments>
      <pubDate>Sat, 11 Aug 2018 07:31:52 +0900</pubDate>
    </item>
    <item>
      <title>[ios] Xcode에서 Unit Test를 해보다</title>
      <link>https://baked-corn.tistory.com/135</link>
      <description>&lt;article class=&quot;markdown-body&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-size: 18pt;&quot;&gt;&lt;b&gt;[ios] Xcode에서 Unit Test를 해보다&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 18pt;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;안녕하세요. 오늘은 프로그래밍 공부를 시작하면서 처음으로 테스팅이라는 것을 해본 경험을 기록해보고자 이렇게 글을 작성하게 되었습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;사실 TDD, 유닛 테스트 등 여러 테스팅에 관련된 이야기를 들어만 봤을 뿐 이것을 해볼 시도도 하지 않았고 그렇게 중요하게 생각도 하지 않았습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;하지만 Let us: Go! 2018 밋업에서도 주제로 언급이 되었었고 연사분께서 하신 말씀 중 새로운 것을 두려워하고, 낯선 것을 두려워하기 때문에 TDD를 팀에 도입하기 힘들다는 말씀에 저 스스로 너무나 부끄러웠습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;하지만 다행히 저또한 해볼 수 있는 기회가 생겨서 굉장히 초보적이고 거창한 테스팅 코드는 아니지만 이를 통해 나름 뿌듯한 경험을 하게 되어 이렇게 글까지 작성하게 되었습니다. &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;물론 어느정도 찾아보고 공부를 한 후 글을 작성하는 것이지만 이는 저의 단순한 경험기이고 명확하지 않은 의미 전달과 잘못된 정보가 내포되어 있을 수 있습니다. 이점 양해 부탁드리며 많은 피드백 역시 부탁드리겠습니다. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h4&gt;&lt;a href=&quot;https://developer.apple.com/library/archive/documentation/DeveloperTools/Conceptual/testing_with_xcode/chapters/01-introduction.html#//apple_ref/doc/uid/TP40014132&quot;&gt;Testing with Xcode&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;먼저 저는 개발자 문서를 가장 먼저 찾아보았습니다. 그리고 이곳에서 설명하는 내용 중 제가 이해하게 된 부분을 먼저 간략하게 정리해보려 합니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;이 부분에서는 테스팅의 방법론이나, 좋은 테스팅 코드를 작성하는 법 등이 아닌 단순히 테스팅의 목적, Xcode에서 테스트 코드를 작성하는 방법과 각 메뉴, 메소드들의 역할들에 대해서만 이해하였습니다. &lt;/p&gt;
&lt;h4&gt;테스팅 준비하기&lt;/h4&gt;
&lt;p&gt;먼저 유닛 테스트를 진행하기 위해서는 테스트 타겟을 생성해야 하고 현재 프로젝트와 연결시켜주어야 합니다. 이를 위해서는 두 가지 방법이 존재합니다. &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;1. 프로젝트 생성시 함께 만들기&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;프로젝트를 생성하실 때 &lt;code&gt;Include Unit Test&lt;/code&gt;와 &lt;code&gt;Include UI Tests&lt;/code&gt; 항목을 선택하시게 되면 테스트 코드의 뼈대가 포함된 프로젝트를 함께 생성하실 수 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;2. 추후에 만들어 포함시키기&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;만일 항목을 선택하지 않고 프로젝트를 생성하였다면 다음과 같은 방법으로 테스트 코드를 만들어 포함시킬 수 있습니다.&lt;/p&gt;&lt;p&gt;먼저 &lt;code&gt;Navigator&lt;/code&gt;의 왼쪽에서 여섯 번째 항목으로 들어간 후 하단의 &lt;code&gt;+&lt;/code&gt; 버튼을 눌러 추가할 수 있습니다. &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;만일 유닛 테스트 타겟을 생성한다면 다음과 같이 &lt;code&gt;Target to be Tested&lt;/code&gt; 항목에서 테스트할 프로젝트를 선택해주어야 합니다. 이것이 끝이 아니라 마지막으로 테스트의 대상이 되는 프로젝트의 파일들에서 테스트 타겟을 타겟 맴버쉽으로 포함시켜야 합니다. 그래야 테스트 타겟에서 테스트의 대상이 되는 모듈에 접근이 가능하기 때문입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 522px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/992234405B53375107&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F992234405B53375107&quot; width=&quot;522&quot; height=&quot;174&quot; filename=&quot;스크린샷 2018-07-21 오후 6.58.06.png&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt; 부끄러운 사실이지만 저는 이것조차 하지 못해 굉장히 해맸습니다....!!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;간단한 테스트 코드 작성해보기&lt;/h4&gt;
&lt;p&gt;이렇게 테스트 타겟을 생성하게 되면 이와 함께 테스트 클래스가 생성됩니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;/article&gt;
&lt;script src=&quot;https://gist.github.com/ehdrjsdlzzzz/32966b24919e3fd14573cc7e59ce7977.js&quot;&gt;&lt;/script&gt;
&lt;article class=&quot;markdown-body&quot;&gt;
&lt;p&gt;먼저  &lt;strong&gt;&lt;code&gt;setUp&lt;/code&gt; 메소드&lt;/strong&gt;부터 살펴보면 이 메소드에서는 이 테스트 클래스에서 진행되는 모든 테스트 케이스에서 공통으로 필요로 하는 행위들을 정의해줍니다. 즉 클래스 안에 속하는 테스트 메소드들이 호출되기 전 항상 &lt;code&gt;setUp&lt;/code&gt; 메소드가 호출되는 것입니다. &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;예를 들자면 각 테스트 케이스에서 필요한 객체를 이곳에서 생성해줄 수 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그 다음으로는 &lt;strong&gt;&lt;code&gt;tearDown&lt;/code&gt; 메소드&lt;/strong&gt;입니다. &lt;code&gt;setUp&lt;/code&gt; 메소드와 유사하지만 그 반대로 모든 테스트 케이스 메소드들이 종료된 후 호출되는 메소드로 &lt;code&gt;setUp&lt;/code&gt;에서 생성되고 테스트 메소드에서 사용된 것들을 정리해주고 해제할 필요가 있을 때 해당 내용들을 &lt;code&gt;tearDown&lt;/code&gt;에 작성해주면 됩니다. &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그럼 테스트 메소드를 작성해볼까요? &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;테스트 메소드는 &lt;code&gt;test&lt;/code&gt; 접두어를 붙인 메소드로 이런 접두어가 붙은 메소드 옆에는 다이아몬드 모양이 생기고 우리는 그 버튼을 눌러 테스팅을 진행할 수 있습니다. 그리고 &lt;strong&gt;각 케이스는 하나의 메소드로 분리하여 작성&lt;/strong&gt;해야 합니다. &lt;strong&gt;테스트 메소드도 메소드로 하나의 기능만을 수행해야하기 때문에 하나의 테스트 메소드 안에 여러 케이스를 넣는 것은 올바른 방법이 아닙니다.&lt;/strong&gt; &lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;그리고 우리는 &lt;code&gt;XCTAssert...&lt;/code&gt; 계열 메소드를 사용하여 기대 값과 실제 결과 값을 비교하여 테스트 수행 결과를 확인할 수 있습니다. &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;code&gt;XCTAsset&lt;/code&gt; 계열 메소드는 &lt;a href=&quot;https://developer.apple.com/documentation/xctest&quot;&gt;공식 문서&lt;/a&gt;에서 확인해보실 수 있습니다. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;br /&gt;
&lt;/article&gt;
&lt;script src=&quot;https://gist.github.com/ehdrjsdlzzzz/8701f169ed648448f35dbae22d963870.js&quot;&gt;&lt;/script&gt;
&lt;article class=&quot;markdown-body&quot;&gt;
&lt;p&gt;만일 &lt;code&gt;pow(3)&lt;/code&gt; 의 결과가 9가 아니라면, 즉 기대 값과 테스트의 대상이 되는 메소드의 결과 값이 같다면 &lt;code&gt;XCTAssertEqual&lt;/code&gt; 메소드를 무사히 통과하겠지만 그렇지 않다면 테스트에 &lt;code&gt;fail&lt;/code&gt; 했다는 안내와 함께 &lt;code&gt;결과 값이 올바르지 않습니다.&lt;/code&gt;라는 문구가 함께 출력될 것입니다. &lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;저는 이러한 테스팅을 하는 &lt;strong&gt;방법&lt;/strong&gt;도 방법이지만 &lt;strong&gt;좋은&lt;/strong&gt; 테스팅, &lt;strong&gt;올바른&lt;/strong&gt; 테스팅에 대해 궁금하였습니다. 여러 글들을 보아도 테스팅에 대한 경험이 전무하기 때문에 와닿지는 않았지만 &quot;이런거구나~&quot; 정도의 감만 익히는 수준으로 글들을 빠르게 읽어갔습니다. &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그리고 제가 이해한 것들을 바탕으로 좋은 테스팅과 올바른 테스팅에 대해 간략하게 정리해보았습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;FIRST&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;F&lt;/strong&gt;ast - 테스팅은 빠르게 동작해야 한다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;I&lt;/strong&gt;ndependent / &lt;strong&gt;I&lt;/strong&gt;solated - 독립적이어야 한다. &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;R&lt;/strong&gt;epeatable - 동일한 인풋의 테스팅의 결과는 항상 동일해야 한다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;S&lt;/strong&gt;elf-Validating - 테스트는 완벽히 자동화되어야 한다. 그 결과 자체로 성공과 실패를 알 수 있어야 한다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;T&lt;/strong&gt;imely - 이상적인 테스트 코드는 테스트할 코드를 작성하기 전 작성되어야 한다.&lt;/li&gt;

&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Given, When, Then&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Given, When, Then으로 섹션을 나누어 작성하는 습관을 기르자&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Given - 입력 값을 제공&lt;/li&gt;
&lt;li&gt;When - 입력 값을 사용해 테스트의 대상이 되는 메소드를 실행&lt;/li&gt;
&lt;li&gt;Then - 결과 값을 증명 (기대값과 비교)&lt;/li&gt;

&lt;/ol&gt;
&lt;p&gt;위의 예시에 이를 적용한다면 다음과 같습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;/article&gt;
&lt;script src=&quot;https://gist.github.com/ehdrjsdlzzzz/5f7976128b2d706559274427b27dff92.js&quot;&gt;&lt;/script&gt;
&lt;article class=&quot;markdown-body&quot;&gt;
&lt;p&gt;&lt;strong&gt;Asynchronous Test&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;비동기 코드에 대한 테스팅은 대체로 느리기 때문에 보다 빠른 테스트 코드와 분리시켜야 한다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Fail Faster&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;테스트를 진행하다보면 당연히 실패하는 케이스도 있습니다. 하지만 그 실패하는 케이스는 되도록 빠르게 결과를 내뱉어야 합니다. 이게 무슨 뜻인지는 코드를 통해 살펴보도록 하겠습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;/article&gt;
&lt;script src=&quot;https://gist.github.com/ehdrjsdlzzzz/f6ae0ae1a1471c9b446fa76a0cb05b22.js&quot;&gt;&lt;/script&gt;
&lt;article class=&quot;markdown-body&quot;&gt;
&lt;p&gt;여기서 요청(request)에 대한 기대 응답을 5초동안 기다리는 것이 아닌 그 결과가 나오는 즉시 실패에 대한 결과를 보여주는 것입니다. &lt;/p&gt;
&lt;hr&gt;
&lt;h4&gt;마무리&lt;/h4&gt;
&lt;p&gt;테스팅에 대한 많은 얘기들이 오고가는 글들이 존재합니다. 하지만 이제 막 테스트를 처음 해본 저에게는 아직 와닿지 않는다거나 하는 글들이 많았습니다. 하지만 확실히 왜 테스트 코드를 작성하고 이를 적극 도입하려는 움직임이 생기는지는 조금씩 이해가 가기 시작하였습니다. &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;미래에 이 글을 보게 된다면 웃음이 날 정도로 기초적이고 당연하며 올바르지 않은 내용이 담겨있을 수 있는 글이지만 이 글을 시작으로 테스트에 보다 더 적극적이고 열린 마음으로 임해야겠습니다. 감사합니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;굉장히 두서 없는 글이지만 혹여나 틀린 정보가 있다면 많은 피드백 부탁드리겠습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;/article&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>Swift + iOS/iOS</category>
      <category>IOS</category>
      <category>Swift</category>
      <category>unit test</category>
      <category>Xcode</category>
      <category>스위프트</category>
      <category>테스팅</category>
      <author>군옥수수수</author>
      <guid isPermaLink="true">https://baked-corn.tistory.com/135</guid>
      <comments>https://baked-corn.tistory.com/135#entry135comment</comments>
      <pubDate>Sat, 21 Jul 2018 22:46:12 +0900</pubDate>
    </item>
    <item>
      <title>[iOS Boostcourse] 동시성과 병렬성 그리고 비동기 프로그래밍</title>
      <link>https://baked-corn.tistory.com/134</link>
      <description>&lt;article class=&quot;markdown-body&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-size: 18pt;&quot;&gt;&lt;b&gt;[iOS Boostcourse] 동시성과 병렬성 그리고 비동기 프로그래밍&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 18pt;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;이전에 운영체제 과목을 수강하면서 공부했던 내용입니다. 당시에도 굉장히 비중있게 공부했던 부분이라 이번 부스트코스를 통해 다시 공부를 하게 되어 이를 간단하게 요약하고 정리해보는 시간을 갖게 되었습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;iOS에서 동시성 프로그래밍에 대해 살펴보기 전 먼저 알아야할 개념들부터 정리해보도록 하겠습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;프로세스&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;  하나의 프로그램이 메모리 상에서 &lt;strong&gt;실행&lt;/strong&gt;되는 작업 단위입니다. &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;스레드&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;  하나의 프로세스 내에서 실행되는 &lt;strong&gt;작업흐름의 단위&lt;/strong&gt;로 프로세스가 시작하는 동시에 동작하는 스레드를  메인 스레드라하고 이외의 추가로 생성되는 스레드를 서브 스레드라 부릅니다. 보통 하나의 프로세스는 하나의 스레드를 갖지만 둘 이상의 스레드를 동시에 실행할 수도 있고 이를 우리는 &lt;strong&gt;멀티스레딩&lt;/strong&gt;이라고 합니다.&lt;/p&gt;&lt;p&gt;그럼 이제 비동기, 동시성 그리고 병렬성에 대해 정리해보도록 하겠습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;비동기 프로그래밍&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;  비동기 프로그래밍이란 프로그램의 주 실행 흐름에서 특정 작업을 위해 프로그램이 멈추고 해당 작업이 끝날 때까지 기다리는 것이 아니라 해당 작업은 별도의 공간에 맡겨둔 뒤 결과를 기다리지 않고 주 실행 흐름을 방해하지 않고 그대로 흐름을 이어가도록 가능케 하는 병렬처리 방식입니다. &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;동시성 프로그래밍&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;  말 그대로 동시에 여러 프로그램을 돌리는 것이 아닌 그렇게 보이게끔 하는 기법으로 시간을 분할하여 스레드들에게 서로 번갈아가며 제공하여 실행되게끔 하는 방식입니다. 코어에 상관 없이 실행 가능한 기법으로 싱글 코어에서도 멀티스레딩을 가능케 합니다. &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;병렬성 프로그래밍&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;  동시성 프로그래밍과 다르게 동시에 돌아가는 것처럼 보이는 것이 아닌 실제로 동시에 실행되는 것을 의미합니다! 멀티 코어에서 멀티 스레드를 동작시키는 방식으로 데이터 병렬성과 작업 병렬성으로 나뉘게 됩니다. &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;데이터 병렬성 - 처리해야 할 데이터를 나누어 나누어진 데이터들을 병렬 처리하여 작업을 빠르게 수행하는 기법&lt;/li&gt;
&lt;li&gt;작업 병렬성 - 서로 다른 작업을 병렬 처리하는 기법&lt;/li&gt;

&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;동시성과 병렬성 차이&lt;/strong&gt;&lt;/p&gt;&lt;p&gt; 동시성 프로그래밍과 병렬성 프로그래밍 모두 비동기적으로 구현할 수 있습니다. 하지만 둘은 다음과 같은 차이가 존재합니다.&lt;/p&gt;
&lt;figure&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;&amp;nbsp;&lt;/th&gt;&lt;th&gt;동시성&lt;/th&gt;&lt;th&gt;병렬성&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;개념&lt;/td&gt;&lt;td&gt;논리적&lt;/td&gt;&lt;td&gt;물리적&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;동작 가능 환경&lt;/td&gt;&lt;td&gt;싱글코어, 멀티 코어&lt;/td&gt;&lt;td&gt;멀티 코어&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;
&lt;/table&gt;&lt;/figure&gt;
&lt;blockquote&gt;&lt;p&gt;병렬성 프로그래밍은 멀티 코어 환경에서만 동작 가능합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;이젠 iOS에서 동시성 프로그래밍을 어떻게 지원하는지에 대해 알아보도록 하겠습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h4&gt;OperationQueue? DispatchQueue ?&lt;/h4&gt;
&lt;p&gt;저는 사실 iOS 공부를 하면서 Concurrency한 작업을 진행할 때 &lt;code&gt;DispatchQueue&lt;/code&gt;만을 사용해왔습니다. 사실 어떠한 이유가 있어서 이것을 사용했다기보단 제가 독학을 하면서 보고 공부한 유투버들이나 예제에서 모두 &lt;code&gt;DispatchQueue&lt;/code&gt;를 사용했었기 때문입니다. &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;하지만 이번에 부스트코스를 통해 학습을 진행하면서 &lt;code&gt;OperationQueue&lt;/code&gt;에 대해 알게 되었고 이 둘에 어떠한 차이점이 있는지 궁금하였습니다. &lt;/p&gt;&lt;p&gt;그래서 이 둘의 차이점에 대해 공부를 해보았고 이 둘의 차이점에 대해 보다 확실히 이해하게 되었습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;이 둘의 차이점에 대해 쉽게 설명된 글이 있어 &lt;a href=&quot;https://cocoacasts.com/choosing-between-nsoperation-and-grand-central-dispatch&quot;&gt;해당 글&lt;/a&gt;을 인용해 둘의 차이점을 간략하게 소개하겠습니다. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;code&gt;Operation&lt;/code&gt;과 &lt;code&gt;OperationQueue&lt;/code&gt;는 &lt;code&gt;NSOperation&lt;/code&gt;과 &lt;code&gt;NSOperationQueue&lt;/code&gt;로 iOS2에서 처음으로 소개되었고, Grand Central Dispatch 줄여서 GCD는 iOS4에서 처음으로 소개되었습니다. 이 둘은 동시성을 지원하기 위해 작업 단위를 캡슐화하여 실행에 넘기는 동작을 하도록 설계되었습니다. 이렇게 두 api의 목적이 같기 때문에 개발자들은 종종 어느 것을 사용해야 하는지 헷갈려 하기도 합니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;언제 어떤 api를 사용해야 하는지 설명하기 전에 이 둘의 주요 차이점에 대해 먼저 이야기 해보도록 하겠습니다. &lt;/p&gt;
&lt;h4&gt;What Sets Them Apart&lt;/h4&gt;
&lt;p&gt;애플은 &lt;code&gt;Operation&lt;/code&gt;이 GCD 위에서 동작하게끔 설계하였습니다. 그러므로 &lt;code&gt;Operation&lt;/code&gt;은 GCD를 상위 수준으로 추상화한 api라고 할 수 있습니다. 즉 &lt;code&gt;Operation&lt;/code&gt;을 사용하는 것은 은연중에 GCD를 사용하는 것과 같습니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;GCD는 시스템의 유닉스 레벨의 수준에서 직접적으로 상호작용하는 저수준의 C api입니다. 반면 &lt;code&gt;Operation&lt;/code&gt;은 Objective-C api입니다. 그렇기 때문에 &lt;code&gt;Operation&lt;/code&gt;은 보다 저수준에서 동작하는 GCD보다 상대적으로 느릴 수 밖에 없습니다.&lt;/p&gt;
&lt;h4&gt;Benefits of Operation&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;Operation&lt;/code&gt;이 GCD 위에서 만들어졌다는 사실에 &lt;code&gt;Operation&lt;/code&gt;만이 제공하는 것이 무엇이 있는지 궁금하실 겁니다. 이러한 몇 가지 차이점으로 인한 이점은 &lt;code&gt;Opertation&lt;/code&gt;을 선택하도록 하는 요소가 되기도 합니다. &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Dependencies&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;code&gt;Operation&lt;/code&gt;은 의존성을 제공합니다. 의존성을 제공한다는 것은 개발자가 일련의 작업에 순서를 정할수 있다는 것을 의미하고 하나의 작업이 다른 작업에 의존성을 갖고 있다면 이 작업은 해당 작업들이 모두 끝난 후에 작업을 시작할 수 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Observable&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;code&gt;Operation&lt;/code&gt;과 &lt;code&gt;OperationQueue&lt;/code&gt; 클래스는 KVO를 통해 관찰될 수 있는 프로퍼티를 제공합니다. 이러한 사실로 우리는 작업들의 상태를 모니터링할 수 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Pause, Cancel, Resume&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;code&gt;Operation&lt;/code&gt;들은 정지,취소 그리고 재시작될 수 있습니다. GCD에 작업을 할당한다면 해당 작업에 대한 어떠한 통제권도 갖지 못합니다. 이러한 관점에서 &lt;code&gt;Operation&lt;/code&gt;이 보다 작업의 Life cycle에 대한 유연함을 제공한다는 것을 알 수 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;단 작업을 대기열에 추가한 것 자체는 되돌릴 수 없습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Control&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;code&gt;OperationQueue&lt;/code&gt; 역시 &lt;code&gt;DispatchQueue&lt;/code&gt;에 비해 몇 가지 이점을 갖고 있는데요. 그 예로는 대기열에 들어갈 수 있는 작업의 숫자를 지정함으로써 동시에 수행될 수 있는 작업의 수를 지정할 수 있습니다. 이를 통해 동시에 실행되는 작업의 갯수와 이들의 순서를 조작할 수 있습니다. &lt;/p&gt;
&lt;h4&gt;When to Use Which&lt;/h4&gt;
&lt;p&gt;일반적으로 애플은 개발자들에게 보다 고수준의 추상화된 api를 사용할 것을 권장합니다. 즉 &lt;code&gt;Operation&lt;/code&gt;을 보다 권장하는 것이죠. &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그렇다면 애플은 왜 보다 고수준의 api를 사용할 것을 권장하는 것일까요? 애플은 새로운 iOS 버전의 출시마다 운영체제의 효율을 증가시키기 위해 프레임워크와 라이브러리를 최적화하는 작업을 수행합니다. 이러한 작업은 보통 저수준의 api의 영향을 주곤 합니다. 심지어 이러한 저수준의 api 위에 존재하는 고수준의 api도 이러한 작업에 영향을 받곤 합니다. &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그렇다면 GCD의 사용을 지양햐야 하는 것일까요? 이는 개발자의 선택에 따릅니다. 많은 개발자들이 GCD를 사용하기도 하고 &lt;code&gt;Operation&lt;/code&gt;과 GCD를 같이 사용하기도 합니다.&lt;/p&gt;
&lt;h4&gt;When to Use &lt;code&gt;Operation&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;위에서 언급한 의존성을 이용한 작업의 순서를 결정할 수 있는 점이 GCD에게는 없는 강력한 이점 중 하나입니다. 즉 어떠한 작업들의 순서를 지정해줄 필요가 있다면 &lt;code&gt;Operation&lt;/code&gt;을 사용하는 것이 바람직합니다.  하지만 짧은 시간안에 수십개의 작업을 생성하야할 경우에는 &lt;code&gt;Operation&lt;/code&gt;의 내재된 오버헤드로 인한 성능 문제로 이어질 수 있습니다.&lt;br /&gt;&lt;/p&gt;
&lt;h4&gt;When to Use GCD&lt;/h4&gt;
&lt;p&gt;GCD는 &lt;code&gt;Operation&lt;/code&gt;을 사용하여 일련의 작업들을 수행하기 위한 코드에 비해 적은 양의 코드로도 같은 행위를 할 수 있습니다. GCD가 순서가 아예 없는 것은 아닙니다. 기본적으로 GCD는 FIFO 형태의 하나의 작업 대기열을 갖고 있기 때문에 들어온 순서대로 작업을 처리할 수 있습니다. 또한 이들을 들어온 순서에 상관없이 Concurrent하게 작업을 진행할 수도 있습니다. 이렇게 특정 작업의 순서를 지정해주는 것처럼 &lt;code&gt;Operation&lt;/code&gt;이 갖고 있는 이점을 사용하는 것이 아니라면 GCD를 사용해도 무방합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h4&gt;마무리&lt;/h4&gt;
&lt;p&gt;오늘은 이렇게 iOS에서 동시성 프로그래밍을 지원하는 api에 대해 살펴보았고 그들의 차이점도 같이 살펴보았습니다. 오늘은 간략하게 다른 블로그의 글을 번역하고 이를 요약한 것이어서 내용을 가볍게 훑어보기에는 좋았습니다. 하지만 가볍게 이해하는 것은 잘못된 지식으로 이어질 수 있기 때문에 다음에는 &lt;a href=&quot;https://developer.apple.com/library/archive/documentation/General/Conceptual/ConcurrencyProgrammingGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40008091-CH1-SW1&quot;&gt;Concurrency Programming Guide&lt;/a&gt; 문서를 정독해보고 이를 통해 보다 개념을 확실히 하고 학습한 내용을 정리해보는 시간을 갖도록 하겠습니다. 감사합니다. &lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;참고자료&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://www.edwith.org/boostcourse-ios/lecture/16866/&quot;&gt;[Edwith] 동시성 프로그래밍과 비동기 프로그래밍&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://cocoacasts.com/choosing-between-nsoperation-and-grand-central-dispatch&quot;&gt;Choosing between NSOperation and Grand Central Dispatch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt; &lt;a href=&quot;https://www.quora.com/What-is-the-difference-in-GCD-and-NSOperation&quot;&gt;What is Difference in GCD and NSOperation? &lt;/a&gt;&lt;/li&gt;

&lt;/ol&gt;
&lt;/article&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>Swift + iOS/Edwith-Boostcourse</category>
      <category>boostcourse</category>
      <category>edwith</category>
      <category>IOS</category>
      <category>부스트코스</category>
      <author>군옥수수수</author>
      <guid isPermaLink="true">https://baked-corn.tistory.com/134</guid>
      <comments>https://baked-corn.tistory.com/134#entry134comment</comments>
      <pubDate>Wed, 18 Jul 2018 14:52:37 +0900</pubDate>
    </item>
    <item>
      <title>[Swift] 프로토콜과 제네릭 그리고 열거형</title>
      <link>https://baked-corn.tistory.com/133</link>
      <description>&lt;article class=&quot;markdown-body&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-size: 18pt;&quot;&gt;&lt;b&gt;[Swift] 프로토콜과 제네릭 그리고 열거형&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-size: 18pt;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Swift를 활용한 프로그램 설계 규칙에 있어서 메소드 인터페이스가 동일하면 프로토콜을 활용하고 로직은 동일하나 타입만 다르다면 제네릭을 활용하는 것이 좋은 설계 규칙 중 하나로 뽑힙니다. 오늘은 &lt;strong&gt;프로토콜(Protocol)&lt;/strong&gt;과 &lt;strong&gt;제네릭(Generics)&lt;/strong&gt;을 같이 사용해보고 이를 통해 배운점을 기록해보고자 합니다. &lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;다음은 프로토콜에 관해 제가 작성한 포스팅들입니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://baked-corn.tistory.com/24?category=718234&quot;&gt;Protocol [1]&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://baked-corn.tistory.com/26?category=718234&quot;&gt;Protocol [2]&lt;/a&gt;&lt;/li&gt;

&lt;/ul&gt;
&lt;p&gt;다음은 제네릭을 사용해 iOS에서 코드를 줄여본 경험을 작성한 포스팅입니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://baked-corn.tistory.com/127?category=718235&quot;&gt;[ios] 제네릭을 이용해 코드 중복 제거하기&lt;/a&gt;&lt;/li&gt;

&lt;/ul&gt;
&lt;blockquote&gt;&lt;p&gt; 프로토콜과 제너릭에 대한 기본적인 지식이 필요로 하는 포스팅입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h4&gt;프로토콜(Protocol) 과 제네릭(Generics)&lt;/h4&gt;
&lt;p&gt;인터페이스가 동일하다면 프로토콜로 이를 묶어서 추후에 같은 인터페이스를 필요로 하는 타입에 통일된 인터페이스를 제공할 수 있습니다. 그 안의 로직은 다양할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그리고 구현 로직은 완전 동일하지만 타입만 다르다면 우리는 이것을 제네릭을 이용해 코드의 중복을 방지할 수 있습니다. 프로토콜에 대한 지식이 있으신 분들은 &lt;strong&gt;프로토콜도 하나의 타입&lt;/strong&gt;이라는 것도 알고 계실 겁니다. 그래서 저는 이 둘을 활용한다면 보다 코드를 추상화할 수 있고 중복을 제거할 수 있을 것이라고 생각하여 이 둘을 함께 사용해보았습니다. &lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;저는 같은 분류에 속하나 서로 다른 성격(&lt;strong&gt;타입&lt;/strong&gt;)을 갖는 두 &lt;code&gt;enum&lt;/code&gt;을 하나의 분류라는 의미에서 동일한 프로토콜을 준수하도록 하였습니다. 그리고 같은 분류 속에서 속하는 이 둘은 동일한 로직을 갖기 때문에 이 둘을 제네릭을 활용하여 코드의 중복을 제거해보고자 하였습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h4&gt;Implementation&lt;/h4&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;
&lt;/article&gt;
&lt;script src=&quot;https://gist.github.com/ehdrjsdlzzzz/32ada176916c14d4e234824bd1c6c1e4.js&quot;&gt;&lt;/script&gt;
&lt;article class=&quot;markdown-body&quot;&gt;
&lt;p&gt;&lt;code&gt;enum&lt;/code&gt; 타입을 추후에 제네릭으로 묶어 사용하기 위해 &lt;code&gt;GroupProtocol&lt;/code&gt;은 &lt;code&gt;RawReresentable&lt;/code&gt;을 체택합니다. 그리고 &lt;code&gt;GroupProtocol&lt;/code&gt;을 준수하는 두 &lt;code&gt;enum&lt;/code&gt; 타입은 &lt;code&gt;RawRepresentable&lt;/code&gt;을 이미 준수하고 있는 타입이기 때문에 따로 &lt;code&gt;RawRepresentable&lt;/code&gt; 프로토콜을 추가로 구현해주지 않아도 됩니다. &lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.apple.com/documentation/swift/rawrepresentable&quot;&gt;RawRepresentable&lt;/a&gt;&lt;/li&gt;

&lt;/ul&gt;
&lt;p&gt;그리고 이 &lt;code&gt;enum&lt;/code&gt;들의 동일한 로직을 제네릭으로 묶어 놓은 구조체를 다음과 같이 작성하였습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;/article&gt;
&lt;script src=&quot;https://gist.github.com/ehdrjsdlzzzz/420fd2868af91455404b8a46e0177351.js&quot;&gt;&lt;/script&gt;
&lt;article class=&quot;markdown-body&quot;&gt;
&lt;p&gt;&lt;code&gt;AEntity&lt;/code&gt;와 &lt;code&gt;BEntity&lt;/code&gt; 모두 &lt;code&gt;RawValue&lt;/code&gt;가 &lt;code&gt;String&lt;/code&gt; 이므로 이들의 로직을 묶어준 &lt;code&gt;ConmonLogic&lt;/code&gt; 에서 사용하게 될 &lt;code&gt;T&lt;/code&gt; 는 &lt;code&gt;RawValue&lt;/code&gt;가 &lt;code&gt;String&lt;/code&gt; 인 타입에 한정해야 합니다. 이렇게 구조체를 정의할 때 타입이 한정된 &lt;code&gt;T&lt;/code&gt;는 구조체 안에서 따로 어떠한 제한을 걸어 사용할 필요 없이 바로 사용할 수 있게 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;이렇게 &lt;code&gt;T&lt;/code&gt;는 &lt;code&gt;RawRepresentable&lt;/code&gt;을 체택한 &lt;code&gt;GroupProtocol&lt;/code&gt;을 체택하였으므로 &lt;code&gt;T&lt;/code&gt;를 반환하는 메소드를 다음과 같이 작성할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;/article&gt;
&lt;script src=&quot;https://gist.github.com/ehdrjsdlzzzz/ef69497e6ee24fce8f2a8b83137abd66.js&quot;&gt;&lt;/script&gt;
&lt;article class=&quot;markdown-body&quot;&gt;
&lt;p&gt;여기서 &lt;code&gt;T&lt;/code&gt;를 생성할 때 사용되는 &lt;code&gt;rawValue&lt;/code&gt;인 &lt;code&gt;something&lt;/code&gt;은 무슨 타입이 될까요? 바로 &lt;code&gt;String&lt;/code&gt; 입니다. 다른 타입이 될 순 없습니다. 왜냐하면 &lt;code&gt;CommonLogic&lt;/code&gt; 구조체를 정의할 때 &lt;code&gt;T&lt;/code&gt;의  &lt;code&gt;RawValue&lt;/code&gt; 타입을 &lt;code&gt;String&lt;/code&gt;으로 한정해주었기 때문입니다.&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그리고 만일 프로토콜 내부에서 &lt;code&gt;associatedtype&lt;/code&gt;이 선언되어 있거나 &lt;code&gt;Self&lt;/code&gt;가 사용된다면 그 프로토콜은 제네릭의 한정 프로토콜으로만 사용할 수 있습니다. 그 뜻이 무엇인지 코드로 살펴보도록 하겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;/article&gt;
&lt;script src=&quot;https://gist.github.com/ehdrjsdlzzzz/677c3b88919c094c0b0544f1f5327779.js&quot;&gt;&lt;/script&gt;
&lt;article class=&quot;markdown-body&quot;&gt;
&lt;p&gt;위와 같이 &lt;code&gt;GroupProtocol&lt;/code&gt;을 준수하는 타입 그 자체를 의미하는 &lt;code&gt;Self&lt;/code&gt;가 &lt;code&gt;GroupProtocol&lt;/code&gt; 안에서 사용된다면 다음과 같은 상황에서 에러 메시지를 볼 수 있을 것입니다. &lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;code&gt;Self&lt;/code&gt; 키워드는 공식 문서에서 다음과 같이 설명하고 있습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;a href=&quot;https://docs.swift.org/swift-book/ReferenceManual/Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-ID374&quot;&gt;&lt;i&gt;In that context,&amp;nbsp;&lt;code&gt;Self&lt;/code&gt;&amp;nbsp;refers to the eventual type that conforms to the protocol.&lt;/i&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/article&gt;
&lt;br /&gt;
&lt;script src=&quot;https://gist.github.com/ehdrjsdlzzzz/e860eb1fd3cbb58f0df00b82c020f856.js&quot;&gt;&lt;/script&gt;
&lt;article class=&quot;markdown-body&quot;&gt;
&lt;p&gt;이렇게 &lt;code&gt;GroupProtocol&lt;/code&gt;을 직접적으로 사용할 수 없기 때문에 우리는 코드를 다음과 같이 수정해주어야 합니다.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;/article&gt;
&lt;script src=&quot;https://gist.github.com/ehdrjsdlzzzz/cf90fb4d071d9ffa4c4aa47fc69fe2ef.js&quot;&gt;&lt;/script&gt;
&lt;article class=&quot;markdown-body&quot;&gt;
&lt;hr&gt;
&lt;h4&gt;마무리&lt;/h4&gt;
&lt;p&gt;제네릭을 사용하는 것은 아직 많이 낯섭니다. 그렇기 때문에 사용할 때마다 에러 메시지와 마주치게 되지만 이러한 에러들을 수정해나가게 되면서 제네릭의 강력함에 매번 놀라곤 합니다. 제네릭을 보다 적극적으로 활용하여 코드를 깨끗하게 유지하는 습관을 들여야 할 것 같습니다. 감사합니다. &lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;참고자료&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.swift.org/swift-book/LanguageGuide/Enumerations.html&quot;&gt;Enumerations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.swift.org/swift-book/LanguageGuide/Generics.html&quot;&gt;Generics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.hackingwithswift.com/example-code/language/how-to-fix-the-error-protocol-can-only-be-used-as-a-generic-constraint-because-it-has-self-or-associated-type-requirements&quot;&gt;How to fix the error Protocol  can only be used as a generic constraint because it has Self or associated type requirements&lt;/a&gt;&lt;/li&gt;

&lt;/ol&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;/article&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>Swift + iOS/Swift</category>
      <category>enum</category>
      <category>Enumeration</category>
      <category>Generics</category>
      <category>IOS</category>
      <category>Protocol</category>
      <category>Swift</category>
      <category>스위프트</category>
      <category>열거형</category>
      <category>제네릭</category>
      <category>프로토콜</category>
      <author>군옥수수수</author>
      <guid isPermaLink="true">https://baked-corn.tistory.com/133</guid>
      <comments>https://baked-corn.tistory.com/133#entry133comment</comments>
      <pubDate>Fri, 13 Jul 2018 12:00:34 +0900</pubDate>
    </item>
    <item>
      <title>[ios] UIViewController LifeCycle - 추가</title>
      <link>https://baked-corn.tistory.com/132</link>
      <description>&lt;article class=&quot;markdown-body&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-size: 18pt;&quot;&gt;&lt;b&gt;[ios] UIViewController LifeCycle - 추가&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 18pt;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;안녕하세요. 오늘은 다시 기본으로 돌아가 개념을 확실히 다잡기 위해 이전에 다루었 &lt;a href=&quot;http://baked-corn.tistory.com/32?category=718235&quot;&gt;UIViewController LifeCycle&lt;/a&gt; 글에 내용을 조금 더 추가해보았습니다. &lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;기존의 글에서는 단순히 &lt;code&gt;UIViewController&lt;/code&gt;의 Life Cycle 관련 메소드들을 소개하는 수준이었습니다. 오늘은 &lt;code&gt;UINavigationController&lt;/code&gt; 위에서 &lt;code&gt;UIViewController&lt;/code&gt;들을 호출해가며 실제로 서로 다른 &lt;code&gt;UIViewController&lt;/code&gt;들의 메소드들이 어떠한 순서로 호출되는지 살펴보도록 하겠습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;먼저 &lt;code&gt;UINavigationController&lt;/code&gt;는 루트 뷰 컨트롤러를 하나 갖고 있습니다. &lt;code&gt;UINavigationController&lt;/code&gt;에서 뷰 컨트롤러들의 Life Cycle은 어떻게 돌아갈까요?&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;루트 뷰 컨트롤러에서는 &lt;code&gt;viewWillDisappear&lt;/code&gt;가 호출될 것 같고...! 올라오는 뷰 컨트롤러에서는 나타나는 &lt;code&gt;viewWillAppear&lt;/code&gt;가 호출될 것 같은데 정확한 이들 메소드의 호출 순서는 어떻게 될까요?&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;이를 이해하기 위해서는 &lt;code&gt;UINavigationController&lt;/code&gt;는 기본적으로 &lt;strong&gt;스택 (Stack)&lt;/strong&gt;의 자료구조로 뷰 컨트롤러를 관리한다는 사실을 알고 있어야 합니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 600px; width: 600px; height: 313px;; height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99CC10485B3F5BFA0E&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99CC10485B3F5BFA0E&quot; width=&quot;600&quot; height=&quot;313&quot; filename=&quot;UINavigationController.png&quot; filemime=&quot;image/jpeg&quot; style=&quot;width: 600px; height: 313px;&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;이렇게 &lt;code&gt;UINavigationController&lt;/code&gt; 안의 뷰 컨트롤러들은 &lt;strong&gt;팝(Pop)&lt;/strong&gt;되기 전까지 메모리에서 사라지지 않습니다. 그 말인즉슨 팝이 되야 메모리에서 사라진다는 것이고 그제서야 &lt;code&gt;deinit&lt;/code&gt; 메소드가 호출됩니다. &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그럼 이제 본격적으로 푸시되고 팝 될때 두 뷰 컨트롤러는 어떤 단계를 어떤 순서로 서로 충돌되지 않게끔 자신들의 뷰를 화면에 띄우고 사라지는지 직접 다이어그램으로 살펴보도록 하겠습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;직접 메소드들을 호출해가며 확인하시는게 이해하는데 도움이 되실 것입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;먼저 푸시되는 상황을 살펴보겠습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;i&gt;&lt;span style=&quot;font-size: 9pt;&quot;&gt;push&lt;/span&gt;&lt;/i&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 600px; width: 600px; height: 582px;; height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99D748435B3F5C1201&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99D748435B3F5C1201&quot; width=&quot;600&quot; height=&quot;582&quot; filename=&quot;PushViewController.png&quot; filemime=&quot;image/jpeg&quot; style=&quot;width: 600px; height: 582px;&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;&lt;br /&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;code&gt;UIViewController-1&lt;/code&gt;이 먼저 보이는 뷰 컨트롤러고 이는 &lt;code&gt;init&lt;/code&gt; 부터 &lt;code&gt;viewDidAppear&lt;/code&gt;까지 위에 나열된 순서대로 메소드들을 호출해가며 화면에 나타납니다. 그리고 여기서 푸시를 하게 되면 그 위로 &lt;code&gt;UIViewController-2&lt;/code&gt;가 올라오게 됩니다. 이때 푸시 될 &lt;code&gt;UIViewController-2&lt;/code&gt;를 메모리에서 불러오는 작업을 먼저 수행합니다. 그 과정이 바로 &lt;code&gt;init&lt;/code&gt; 부터 &lt;code&gt;viewDidLoad&lt;/code&gt;까지입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;지금까지는 단순히 메모리로부터 불러오고 이들을 조합하고 위치를 조정하는 단계였고 아직 화면에 보이는 상태는 아닙니다. 그리고 사라질 &lt;code&gt;UIViewController-1&lt;/code&gt;가 &quot;사라질 것이다&quot;라는 메소드를 호출하고 &lt;code&gt;UIViewController-2&lt;/code&gt;는 &quot;나타날 것이다&quot;라는 메소드를 호출합니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;마지막으로 &lt;code&gt;UIViewController-1&lt;/code&gt;이 &quot;사라졌다&quot; 라는 메소드를 호출하고 이를 확인 후 &lt;code&gt;UIViewController-2&lt;/code&gt;도 &quot;나타났다&quot;라는 메소드를 호출할 것입니다. &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;이렇게 서로 메소드를 교차하며 호출하여 충돌을 피해서 화면에서 사라지고 화면에서 나타나게 되는 것입니다. &lt;strong&gt;여기서 주목해야할 것은 &lt;code&gt;UIViewController-1&lt;/code&gt;의 &lt;code&gt;deinit&lt;/code&gt; 메소드가 호출되지 않는다는 것입니다. 왜냐하면 단순히 가려진 것이지 메모리에서 사라진 것은 아니기 때문입니다.&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;그렇다면 팝이 될 때는 어떨까요?&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;i&gt;&lt;span style=&quot;font-size: 9pt;&quot;&gt;pop&lt;/span&gt;&lt;/i&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 600px; width: 600px; height: 351px;; height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99ABC9495B3F5C240A&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99ABC9495B3F5C240A&quot; width=&quot;600&quot; height=&quot;351&quot; filename=&quot;PopViewController.png&quot; filemime=&quot;image/jpeg&quot; style=&quot;width: 600px; height: 351px;&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;&lt;br /&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;역시 사라지는 쪽에서 &quot;사라질 것&quot; 이라고 의사를 내비치는 것입니다. 그리고 위와 같은 순서로 메소드들이 호출되며 역시 팝이 되는 상황도 충돌을 피하며 사라지고 나타나는 것입니다. &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;여기서 주목해야할 점은 &lt;strong&gt;&lt;code&gt;UIViewController-2&lt;/code&gt;는 &lt;code&gt;UINavigationController&lt;/code&gt;의 스택 안에서&amp;nbsp;벗어나는 팝 연산이고 메모리에서 사라지기 때문에 &lt;code&gt;deinit&lt;/code&gt; 메소드가 호출된다는 점입니다.&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;그리고 이전 포스팅에서 &lt;code&gt;loadView&lt;/code&gt;가 호출되는 시점에서 &lt;code&gt;IBOutlet&lt;/code&gt;과 &lt;code&gt;IBAction&lt;/code&gt;들이 생성되고 연결된다고 언급했습니다.이 역시 직접 메소드들을 호출해가며 확인해보았습니다. 그 결과는 다음과 같습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 365px; width: 365px; height: 600px;; height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99D75C505B3F5C7A21&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99D75C505B3F5C7A21&quot; width=&quot;365&quot; height=&quot;600&quot; filename=&quot;스크린샷 2018-07-03 오후 2.09.54.jpg&quot; filemime=&quot;image/jpeg&quot; style=&quot;width: 365px; height: 600px;&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;hr&gt;
&lt;h4&gt;마무리&lt;/h4&gt;
&lt;p&gt;오늘은 이렇게 예전에 학습했고 포스팅까지 했던 UIViewController의 LifeCycle을 다시 살펴보고 직접 호출해가며 개념을 다잡는 시간을 가졌습니다. 감사합니다.&lt;/p&gt;
&lt;/article&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>Swift + iOS/iOS</category>
      <category>IOS</category>
      <category>Swift</category>
      <category>UINavigationController</category>
      <category>UIViewController</category>
      <category>스위프트</category>
      <author>군옥수수수</author>
      <guid isPermaLink="true">https://baked-corn.tistory.com/132</guid>
      <comments>https://baked-corn.tistory.com/132#entry132comment</comments>
      <pubDate>Fri, 6 Jul 2018 21:13:22 +0900</pubDate>
    </item>
    <item>
      <title>[Swift] Functor and Monad in Swift</title>
      <link>https://baked-corn.tistory.com/131</link>
      <description>&lt;article class=&quot;markdown-body&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-size: 18pt;&quot;&gt;&lt;b&gt;[Swift] Functor and Monad in Swift&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-size: 18pt;&quot;&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Swift의 Monad를 소개하기 위해 작성된 포스팅으로 Monad를 단독으로 다루는 것보다 Functor와 함께 이야기하는 것이 이해에 도움이 된다고 생각하여 Functor와 Monad를 이해하기 위한 몇몇 개념과 함께 이들을 알아보도록 하겠습니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h4&gt;Context&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;컨텍스트(Context)&lt;/strong&gt;와 &lt;strong&gt;컨텐트(Content)&lt;/strong&gt;의 관계는 다음과 같습니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;img src=&quot;https://cdn-images-1.medium.com/max/1600/0*V08xYU6Ru7K8q8kE.jpg&quot;&gt;&lt;/p&gt;&lt;p&gt;컨텍스트는 컨텐트를 담고있는 형태로 &lt;strong&gt;옵셔널(Optional)&lt;/strong&gt;을 예로 들면 &lt;code&gt;Optional(2)&lt;/code&gt;에서 &lt;code&gt;Optional&lt;/code&gt;은 컨텍스트가 &lt;code&gt;2&lt;/code&gt; 는 컨텐트가 됩니다. 만일 옵셔널안에 값이 존재하지 않는다면 컨텍스트만 존재하는 꼴이 되겠죠.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;이렇게 컨텍스트는 무언가를 담고있는 것을 의미합니다. 이렇게 무엇을 담고있다는 의미에서 &lt;strong&gt;컨테이너(Container)&lt;/strong&gt; 역시 컨텍스트의 일종으로 볼 수 있습니다. 그럼 그 컨테이너를 살펴보도록 하겠습니다.&lt;/p&gt;
&lt;h4&gt;Container&lt;/h4&gt;
&lt;p&gt;우리가 흔히 사용하는 자료구조인 &lt;code&gt;Array&lt;/code&gt;, &lt;code&gt;Set&lt;/code&gt; 그리고 &lt;code&gt;Dictionary&lt;/code&gt;와 같은 자료구조들도 일종의 컨테이너라고 할 수 있습니다. 이들은 한 개 이상의 원소를 가질 수 있는 컨테이너들로 쉽게 컨테이너라는 개념이 연상될 것입니다. 하지만 이들만이 컨테이너라고 할 수 있을까요?&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;위에서 언급했던 옵셔널도 컨텍스트의 일종이라고 하였습니다. 그렇다면 옵셔널은 컨테이너이기도 할까요? 그렇습니다. 옵셔널도 컨테이너의 한 종류로 그 컨테이너 안에는 값이 존재할 수도 존재하지 않을 수도 있습니다. 즉 두 가지의 경우를 담고 있는 컨테이너라고 이해할 수 있습니다.&lt;/p&gt;
&lt;h4&gt;Map&lt;/h4&gt;
&lt;p&gt;우리는 컨테이너에 &lt;strong&gt;매핑(Mapping)&lt;/strong&gt;이라는 연산을 수행할 수 있습니다. 매핑을 굳이 직역하자면 사상이라 할 수 있습니다.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;컨테이너의 원소 값 각각에 특정한 변형을 적용하는 것을 변형을 사상한다고 표현할 수 있습니다.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;다음은 이러한 매핑 연산의 예시입니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[1, 2, 3, 4] --- [2,4,6,8]
[&quot;1&quot;, &quot;2&quot;, &quot;3&quot;] --- [1, 2, 3]
[&quot;Harry&quot;, &quot;Joe&quot;, &quot;David&quot;] --- [&quot;My name is Harry&quot;, &quot;My name is Joe&quot;, &quot;My name is David&quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이런 매핑은 내부 원소의 값의 변형만 일어납니다. 그 원소를 담고있는 컨테이너의 변형은 일어나지 않습니다. 그말인즉슨 &lt;code&gt;Array&lt;/code&gt;에 매핑 연산을 진행하였다고 &lt;code&gt;Array&lt;/code&gt;가 &lt;code&gt;Dictionary&lt;/code&gt;가 되는 컨테이너의 변형은 일어나지 않는다는 것입니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;이렇게 값에 변형을 매핑할 수 있는 모든 것들을 &lt;strong&gt;Functor&lt;/strong&gt;라고 합니다. 그렇다면 Functor는 컨테이너와 같은 의미일까요? 이에 대해서는 같다는 것이 지배적인 의견인 것 같으나 완전히 같지는 않다는 의견도 존재합니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://bartoszmilewski.com/2014/01/14/functors-are-containers/&quot;&gt;Functors are Containers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gist.github.com/jwiegley/8571782&quot;&gt;Functors are not Containers&lt;/a&gt;&lt;/li&gt;

&lt;/ul&gt;
&lt;h4&gt;Functor&lt;/h4&gt;
&lt;p&gt;Functor는 위에서 언급했듯이 변형을 사상할 수 있는 모든 것들을 말합니다. 이렇게 Functor에서 매핑 연산이 일어나는 과정을 다이어그램으로 표현하자면 다음과 같습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;img src=&quot;http://adit.io/imgs/functors/fmap_just.png&quot;&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;여기서 주목해야 할 점은 매핑으로 변형된 값은 다시 Functor로 감싼 후 반환된다는 것입니다.&lt;/strong&gt; 그리고 Swift에서 매핑의 대표적인 메소드가 바로 &lt;code&gt;map&lt;/code&gt; 입니다. &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그리고 저는 Functor로써의 옵셔널에 주목해보려 합니다. 옵셔널 역시 내장 메소드로 &lt;code&gt;map&lt;/code&gt;을 갖고 있습니다. 옵셔널에서 &lt;code&gt;map&lt;/code&gt; 메소드를 지원하지 않는다고 가정해보도록 하겠습니다. 그리고 서버로부터 데이터를 받아와 이를 &lt;code&gt;UILabel&lt;/code&gt;에 출력해주고자 할 때 우리는 다음과 비슷한 코드로 이를 구현할 것입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;/article&gt;
&lt;script src=&quot;https://gist.github.com/ehdrjsdlzzzz/d4339fe2761592b709409744ee2e1021.js&quot;&gt;&lt;/script&gt;
&lt;article class=&quot;markdown-body&quot;&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;단순히 이름을 출력해주는 것인데 &lt;code&gt;if-let&lt;/code&gt; 이나 &lt;code&gt;guard-let&lt;/code&gt; 과 같은 코드 때문에 코드가 길어지게 되죠. 하지만 옵셔널도 Functor로써 &lt;code&gt;map&lt;/code&gt; 메소드를 지원하기 때문에 우리는 다음과 같이 코드를 길이를 줄일 수 있습니다.&lt;/p&gt;
&lt;/article&gt;
&lt;script src=&quot;https://gist.github.com/ehdrjsdlzzzz/1c183d1bd379e621e91ff2414f22bcbd.js&quot;&gt;&lt;/script&gt;
&lt;article class=&quot;markdown-body&quot;&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그럼 대체 &lt;code&gt;map&lt;/code&gt; 메소드가 어떻게 구현되어 있기에 이러한 코드가 가능한 것일까요? 이를 이해하기 위해선 옵셔널이 어떻게 동작하는지 알고 있어야 합니다. 옵셔널은 다음과 같이 &lt;code&gt;enum&lt;/code&gt;을 사용하여 구현되어 있습니다.&lt;/p&gt;
&lt;/article&gt;
&lt;script src=&quot;https://gist.github.com/ehdrjsdlzzzz/2da820c5b6549414cd4b2c8ea231f5b4.js&quot;&gt;&lt;/script&gt;
&lt;article class=&quot;markdown-body&quot;&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;값이 있는 경우와 없는 경우로 나뉘어 있죠. 옵셔널의 &lt;code&gt;map&lt;/code&gt; 메소드도 역시 &lt;code&gt;enum&lt;/code&gt;을 활용하였습니다. 코드로 살펴보겠습니다. &lt;/p&gt;
&lt;/article&gt;
&lt;script src=&quot;https://gist.github.com/ehdrjsdlzzzz/a0ed8ec4315aa3a2ffdfb554a3183bf0.js&quot;&gt;&lt;/script&gt;
&lt;article class=&quot;markdown-body&quot;&gt;
&lt;p&gt;옵셔널의 &lt;code&gt;map&lt;/code&gt; 메소드는 &lt;code&gt;Wrapped&lt;/code&gt; 타입을 파라미터로 받고 &lt;code&gt;U&lt;/code&gt; 타입을 반환하는 함수 &lt;code&gt;transform&lt;/code&gt;을 파라미터로 받습니다. 그리고 &lt;code&gt;map&lt;/code&gt; 메소드 자체는 &lt;code&gt;U?&lt;/code&gt; 타입을 반환합니다. &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그리고 &lt;code&gt;switch&lt;/code&gt; 문에서 &lt;code&gt;self&lt;/code&gt;, 즉 &lt;code&gt;map&lt;/code&gt; 메소드를 호출한 옵셔널 타입의 값을 검사하므로 &lt;code&gt;map&lt;/code&gt; 메소드를 호출한 옵셔널 컨텍스트 안에 값이 존재한다면 해당 값을 컨텍스트로부터 추출하여 파라미터로 받아온 &lt;code&gt;transform&lt;/code&gt; 함수에 넘겨 값을 처리합니다. &lt;code&gt;transform&lt;/code&gt; 메소드의 반환 결과는 &lt;code&gt;U&lt;/code&gt; 타입이지만 옵셔널 &lt;code&gt;map&lt;/code&gt;의 반환 타입이 &lt;code&gt;U?&lt;/code&gt; 이므로 컴파일러가 자동으로 &lt;code&gt;U?&lt;/code&gt;로 감싸 반환합니다. 반면에 &lt;code&gt;map&lt;/code&gt; 메소드를 호출한 옵셔널 타입의 변수에 값이 존재하지 않는다면 &lt;code&gt;nil&lt;/code&gt; 값을 반환하는 것입니다. &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그렇기 때문에 위의 예제에서 &lt;code&gt;userName&lt;/code&gt;이 &lt;code&gt;map&lt;/code&gt; 메소드를 호출하게 되면 다음과 같은 과정을 거치게 됩니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;userName&lt;/code&gt;에 값이 존재하는지 &lt;code&gt;switch&lt;/code&gt; 문을 통해 검사&lt;/li&gt;
&lt;li&gt;값이 존재하므로 이를 추출하여 파리미터로 넘어온 함수 &lt;code&gt;greeting(_:)&lt;/code&gt; 함수에 파라미터로 추출한 값을 넣는다.&lt;/li&gt;
&lt;li&gt;함수의 실행 결과로 &lt;code&gt;&quot;안녕하세요 \(name)님&quot;&lt;/code&gt;을 반환하고 &lt;code&gt;map&lt;/code&gt; 메소드는 이 결과를 &lt;code&gt;Optional(&quot;안녕하세요 \(name)님&quot;)&lt;/code&gt; 으로 반환&lt;/li&gt;
&lt;li&gt;결과가 &lt;code&gt;label.text&lt;/code&gt;에 담김. (&lt;code&gt;label.text&lt;/code&gt;의 타입은 &lt;code&gt;String?&lt;/code&gt;)&lt;/li&gt;

&lt;/ol&gt;
&lt;p&gt;그럼 위의 과정과 Functor에서 매핑이 진행되는 과정을 다시 한번 살펴보고 다음 코드를 봐주시기 바랍니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;/article&gt;
&lt;script src=&quot;https://gist.github.com/ehdrjsdlzzzz/d684fe4b7462e84d2486b3d5f1f1bf55.js&quot;&gt;&lt;/script&gt;
&lt;article class=&quot;markdown-body&quot;&gt;
&lt;p&gt;&lt;code&gt;number&lt;/code&gt;의 타입은 무엇일까요?&lt;/p&gt;&lt;p&gt;.&lt;/p&gt;&lt;p&gt;.&lt;/p&gt;&lt;p&gt;.&lt;/p&gt;&lt;p&gt;.&lt;/p&gt;&lt;p&gt;.&lt;/p&gt;&lt;p&gt;.&lt;/p&gt;&lt;p&gt;&lt;code&gt;Int?&lt;/code&gt; 라고 예상하셨나요? 틀렸습니다! &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;정답은 바로 &lt;code&gt;Int??&lt;/code&gt;로 &lt;code&gt;Optional&amp;lt;Optional&amp;lt;Int&amp;gt;&amp;gt;&lt;/code&gt;입니다. 이러한 과정이 나오게 된 과정을 살펴보기 전 명심해야할 것은 위에서 언급했던 &lt;i&gt;&lt;b&gt;&quot;여기서 주목해야 할 점은 매핑으로 변형된 값은 다시 Functor로 감싼 후 반환된다는 것입니다.&quot;&lt;/b&gt;&lt;/i&gt;  문장입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;예제에서 Functor는 옵셔널입니다. 그리고 &lt;code&gt;Int($0)&lt;/code&gt;의 반환 결과 역시 옵셔널 타입입니다. 즉 위의 다이어그램에서 &lt;strong&gt;Apply Function&lt;/strong&gt;의 결과로 옵셔널 타입의 값이 반환되고 그 값을 옵셔널 Functor안에 넣어 반환하기 때문에 최종 결과가 &lt;code&gt;Optional&amp;lt;Optional&amp;lt;Int&amp;gt;&amp;gt;&lt;/code&gt;가 되는 것입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;이를 코드로 옵셔널 &lt;code&gt;map&lt;/code&gt;의 코드와 함께 살펴보면 &lt;code&gt;Wrapped&lt;/code&gt; 타입은 &lt;code&gt;String&lt;/code&gt;이 됩니다. 그리고 &lt;code&gt;Int(_:)&lt;/code&gt; 의 반환 타입은 &lt;code&gt;Optional&amp;lt;Int&amp;gt;&lt;/code&gt; 타입이죠. 그리고 코드의 &lt;code&gt;transform&lt;/code&gt; 반환 타입이 &lt;code&gt;U&lt;/code&gt; 이므로 &lt;code&gt;U == Optional&amp;lt;Int&amp;gt;&lt;/code&gt; 관계를 갖는 것입니다. 그리고 &lt;code&gt;map&lt;/code&gt; 메소드의 최종 반환 타입이 &lt;code&gt;U?&lt;/code&gt; 이기 때문에 &lt;code&gt;U? == Optional&amp;lt;Optional&amp;lt;Int&amp;gt;&amp;gt;&lt;/code&gt;이므로 최종 반환 결과 값의 타입은 &lt;code&gt;Optional&amp;lt;Optional&amp;lt;Int&amp;gt;&amp;gt;&lt;/code&gt;가 되는 것입니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그렇다면 &lt;strong&gt;모나드(Monad)&lt;/strong&gt;란 무엇일까요?&lt;/p&gt;
&lt;hr&gt;
&lt;h4&gt;Monad&lt;/h4&gt;
&lt;p&gt;모나드는 Functor의 일종입니다. 모나드를 쉽게 설명하자면 &lt;code&gt;flatMap&lt;/code&gt; 연산이 가능한 모든 것들을 우리는 모나드라고 부를 수 있습니다. &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;모나드를 값이 있을 수도 있고 없을 수도 있는 상태의 컨텍스트를 갖는 Functor의 일종이라고 설명되곤 하는데 이 부분에 대해서는 아직 저 스스로 이해가 조금 더 필요한 것 같습니다. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;하지만 단순하게 생각해서 값이 있을 수도 없을 수도 있는 컨텍스트라하면 옵셔널은 단번에 따오릅니다. 맞습니다! 옵셔널도 모나드에 속합니다. 그리고 모나드를 다음과 같이 설명하기도 합니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;i&gt;&lt;b&gt;&quot; Monads apply a function that returns a wrapped value to a wrapped value. &quot;&lt;/b&gt;&lt;/i&gt;&lt;/p&gt;&lt;p&gt;저는 이를 &lt;b&gt;&lt;i&gt;&quot; 모나드는 포장된 값에 포장된 값을 반환하는 함수를 적용시킨다. &quot; &lt;/i&gt;&lt;/b&gt;라 이해를 하였습니다. &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그렇다면 먼저 옵셔널에서의  &lt;code&gt;flatMap&lt;/code&gt;과 &lt;code&gt;map&lt;/code&gt;의 코드를 함께 살펴보도록 하겠습니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;i&gt;&lt;span style=&quot;font-size: 8pt;&quot;&gt;map in Optional&lt;/span&gt;&lt;/i&gt; &lt;/p&gt;
&lt;/article&gt;
&lt;script src=&quot;https://gist.github.com/ehdrjsdlzzzz/ec9908bb535f287abbf734571d4bfed0.js&quot;&gt;&lt;/script&gt;
&lt;article class=&quot;markdown-body&quot;&gt;
&lt;p&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/p&gt;&lt;p&gt;&lt;i&gt;&lt;span style=&quot;font-size: 8pt;&quot;&gt;flatMap in Optional&lt;/span&gt;&lt;/i&gt;&lt;/p&gt;
&lt;/article&gt;
&lt;script src=&quot;https://gist.github.com/ehdrjsdlzzzz/6d05b153f7a92c2400f1baf3d009ac4f.js&quot;&gt;&lt;/script&gt;
&lt;article class=&quot;markdown-body&quot;&gt;
&lt;p&gt;둘의 차이점이 보이시나요? 바로 &lt;code&gt;transform&lt;/code&gt; 메소드의 반환 타입입니다.&lt;/p&gt;&lt;p&gt;그렇다면 다음의 코드에서 &lt;code&gt;mapResult&lt;/code&gt;와 &lt;code&gt;flatMapResult&lt;/code&gt;의 타입은 어떻게 될까요? &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;/article&gt;
&lt;script src=&quot;https://gist.github.com/ehdrjsdlzzzz/ee09ed86885d5c4a4135b9f3dc1c5403.js&quot;&gt;&lt;/script&gt;
&lt;article class=&quot;markdown-body&quot;&gt;
&lt;p&gt;.&lt;/p&gt;&lt;p&gt;.&lt;/p&gt;&lt;p&gt;.&lt;/p&gt;&lt;p&gt;.&lt;/p&gt;&lt;p&gt;.&lt;/p&gt;&lt;p&gt;.&lt;/p&gt;&lt;p&gt;결과는 다음과 같습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Optional&amp;lt;Optional&amp;lt;Int&amp;gt;&amp;gt;
Optional&amp;lt;Int&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;mapResult&lt;/code&gt;의 타입이 &lt;code&gt;Optional&amp;lt;Optional&amp;lt;Int&amp;gt;&amp;gt;&lt;/code&gt;인 이유는 위에서 살펴보았습니다. 그렇다면 &lt;code&gt;flatMapResult&lt;/code&gt;의 타입은 왜 &lt;code&gt;Optional&amp;lt;Int&amp;gt;&lt;/code&gt;일까요? &lt;code&gt;map&lt;/code&gt;과 &lt;code&gt;flatMap&lt;/code&gt;의 차이점은 &lt;code&gt;transform&lt;/code&gt; 메소드의 반환 타입이 다르다고 말씀드렸습니다. &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;예제의 &lt;code&gt;Int(_:)&lt;/code&gt; 의 반환 타입은 &lt;code&gt;Optional&amp;lt;Int&amp;gt;&lt;/code&gt; 입니다.그리고  &lt;code&gt;transform&lt;/code&gt; 의 반환 타입은 &lt;code&gt;U?&lt;/code&gt; 이기 때문에 &lt;code&gt;U? == Optional&amp;lt;Int&amp;gt;&lt;/code&gt;가 되는 것입니다. 마지막으로 &lt;code&gt;flatMap&lt;/code&gt;의 최종 결과 반환 타입은 &lt;code&gt;U?&lt;/code&gt;이기 때문에 &lt;code&gt;Optional&amp;lt;Int&amp;gt;&lt;/code&gt;가 되는 것입니다. 이렇게 &lt;strong&gt;&lt;em&gt;&quot; 모나드는 포장된 값에 포장된 값을 반환하는 함수를 적용시킨다. &quot;&lt;/em&gt;&lt;/strong&gt; 라는 뜻을 코드로써 어떻게 구현되어 있는지를 확인할 수 있었습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;한 번 더 예를 들어 다음과 같이 짝수라면 반으로 나누는 메소드와 이를 연속으로 호출한다면 그 모습은 다음과 같을 것입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;/article&gt;
&lt;script src=&quot;https://gist.github.com/ehdrjsdlzzzz/efd98485f98238f58b32d7f08e200682.js&quot;&gt;&lt;/script&gt;
&lt;article class=&quot;markdown-body&quot;&gt;
&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;img src=&quot;http://adit.io/imgs/functors/monad_chain.png&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Swift 4.1부터 &lt;code&gt;Array&lt;/code&gt;과 같이 Sequence한 원소를 갖는 컨테이너에서  &lt;code&gt;flatMap&lt;/code&gt;은 deprecated 되었고 &lt;code&gt;compactMap&lt;/code&gt;으로 대체되었습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;옵셔널이 아닌 모나드, 즉  &lt;code&gt;Array&lt;/code&gt;과 같이 여러 원소를 갖는 컨테이너에서 &lt;code&gt;compactMap&lt;/code&gt;은 내부 컨텍스트의 값도 추출할 수 있습니다. 이를 위해 &lt;code&gt;Array&lt;/code&gt;에서 적용되는 &lt;code&gt;compactMap&lt;/code&gt;에 대해 알아보도록 하겠습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;/article&gt;
&lt;script src=&quot;https://gist.github.com/ehdrjsdlzzzz/bcbde23467387a73e0216b9d5b3b65be.js&quot;&gt;&lt;/script&gt;
&lt;article class=&quot;markdown-body&quot;&gt;
&lt;p&gt;결과를 보시면 내부 컨텍스트의 값을 추출한다는 것을 단번에 이해하실 수 있으실 겁니다.&lt;/p&gt;&lt;p&gt;이를 이해하기 위해서는 &lt;code&gt;Array&lt;/code&gt; 에서의 &lt;code&gt;compactMap&lt;/code&gt;이 내부적으로 어떤 원리로 작동하는지 이해하고 있어야 합니다.&lt;/p&gt;
&lt;/article&gt;
&lt;script src=&quot;https://gist.github.com/ehdrjsdlzzzz/72eda0066ee558deb87b3e84ce41172a.js&quot;&gt;&lt;/script&gt;
&lt;article class=&quot;markdown-body&quot;&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;여러 원소를 갖는 모나드에서 &lt;code&gt;map&lt;/code&gt;은 단순히 클로저를 수행하고 결과를 그대로 반환하지만 위의 코드에서와 같이 &lt;code&gt;compactMap&lt;/code&gt;은 내부 컨텍스트 (예제에선 옵셔널)의 값을 추출하여 담아 반환합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h4&gt;마무리&lt;/h4&gt;
&lt;p&gt;사실 한 기업의 면접에서 &quot;모나드는 무엇인가요?&quot; 라는 질문을 받았었습니다. 하지만 스위프트를 처음 공부할 때 이해하기 힘들어 덮어두고 넘어갔던 내용이었던지라 식은땀을 한 바가지 흘렸었죠. 물론 면접의 결과는 물 보듯 뻔했습니다. &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그래서 &quot;제대로 이해하보자&quot; 라고 생각하고 이렇게 공부를 하고 기록을 해보았습니다. 사실 지금도 100% 이해했다고 하기는 힘들 것 같습니다. 하지만 어렴풋이 감이 생겼고 이를 지속적으로 발전시켜가도록 노력해야겠습니다. 감사합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;참고자료&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;http://www.mokacoding.com/blog/functor-applicative-monads-in-pictures&quot;&gt;Swift Functors, Applicatives, and Monads in Pictures&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://oaksong.github.io/2018/01/22/monad/&quot;&gt;모나드(Monad)와 함수 객체&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://soooprmx.com/archives/6025&quot;&gt;Functor의 개념과 Swift내의 functor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://swiftyjimmy.com/higher-order-functions-functor-monad/&quot;&gt;Higher-order functions, Functor and Monad in Swift&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://youtu.be/vVW5bkXQ138&quot;&gt;Elements of Functional Programming - Youtube&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://chris.eidhof.nl/post/monads-in-swift/&quot;&gt;Monads in Swift&lt;/a&gt;&lt;/li&gt;

&lt;/ol&gt;
&lt;/article&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>Swift + iOS/Swift</category>
      <category>context</category>
      <category>Functional Programming</category>
      <category>functor</category>
      <category>IOS</category>
      <category>monad</category>
      <category>Swift</category>
      <category>모나드</category>
      <category>스위프트</category>
      <category>함수객체</category>
      <category>함수형 프로그래밍</category>
      <author>군옥수수수</author>
      <guid isPermaLink="true">https://baked-corn.tistory.com/131</guid>
      <comments>https://baked-corn.tistory.com/131#entry131comment</comments>
      <pubDate>Thu, 5 Jul 2018 15:23:40 +0900</pubDate>
    </item>
    <item>
      <title>[ios] Handling UIKit Gestures</title>
      <link>https://baked-corn.tistory.com/130</link>
      <description>&lt;article class=&quot;markdown-body&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-size: 18pt;&quot;&gt;&lt;a href=&quot;https://developer.apple.com/documentation/uikit/touches_presses_and_gestures/handling_uikit_gestures&quot;&gt;Handling UIKit Gestures&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Gesture recognizer를 사용하는 것은 뷰에서 발생하는 Touch나 Press 이벤트를 다룰수 있는 가장 간단한 방법입니다. 어떤 뷰든간에 한 개 혹은 복수 개의 Gesture에 대한 recognizer를 붙일 수 있습니다. Gesture recognizer는 뷰 위에서 발생하는 일련의 패턴이 존재하는 이벤트들 ( Double-Tap, Swipe, Pinch 등등 )을 처리하기 위해 Target-Action 패턴을 사용하고 이벤트가 발생하면 Target 객체에 이러한 사실을 전달하여 해당 이벤트를 처리할 수 있는 액션 메소드를 호출합니다. &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://docs-assets.developer.apple.com/published/7c21d852b9/0c8c5e29-c846-4a16-988b-3d809eafbb6b.png&quot; width=&quot;80%&quot;&gt;&lt;/p&gt;&lt;p&gt;Gesture Recognizer에는 두 종류가 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;불연속 gesture recognizer&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;이벤트를 인식한 후 액션 메소드를 한번만 호출&lt;/li&gt;
&lt;li&gt;&lt;code&gt;UITapGestureRecognizer&lt;/code&gt;&lt;/li&gt;

&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;연속 gesture recognizer&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;최초 이벤트 인식 후 이벤트의 변화를 추적하며 액션 메소드를 변화에 맞춰 호출&lt;/li&gt;
&lt;li&gt;&lt;code&gt;UIPanGestureRecognizer&lt;/code&gt;&lt;/li&gt;

&lt;/ul&gt;
&lt;/li&gt;

&lt;/ul&gt;
&lt;h4&gt;Configuring a gesture recognizer&lt;/h4&gt;
&lt;p&gt;Gesture recognizer를 구성하기 위해서는&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;스토리보드에서 Gesture recognizer를 뷰 위에 드래그하여 올려 놓습니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;액션 메소드를 구현합니다.&lt;/p&gt;
&lt;/li&gt;&lt;li&gt;&lt;p&gt; 액션 메소드와 Gesture recognizer를 연결합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;/article&gt;
&lt;script src=&quot;https://gist.github.com/ehdrjsdlzzzz/6f01d60fa0bd9ce6b160f86176066679.js&quot;&gt;&lt;/script&gt;
&lt;article class=&quot;markdown-body&quot;&gt;


&lt;p&gt;코드로 이를 구현할 때는 &lt;code&gt;addGestureRecognizer(_:)&lt;/code&gt;를 사용합니다.&lt;/p&gt;
&lt;h4&gt;Responding to Gestures&lt;/h4&gt;
&lt;p&gt;액션 메소드를 통해 gesture를 적절히 처리해줍니다. 위에서 언급했듯이 불연속적 gesture는 버튼과 같이 한 번의 gesture에 대해 액션 메소드는 한번만 호출됩니다. 연속적 gesture에 대해서는 이벤트를 추적하고 이에 맞게 액션 메소드 역시 여러번 호출됩니다. &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;code&gt;UIGestureRecognizer&lt;/code&gt;에는 &lt;code&gt;state&lt;/code&gt;라는 프로퍼티가 있고 이를 활용하여 액션 메소드를 구성할 수 있습니다. 연속 Gesture recognzier에선 &lt;code&gt;.began&lt;/code&gt;, &lt;code&gt;.changed&lt;/code&gt;, &lt;code&gt;.ended&lt;/code&gt; 그리고 &lt;code&gt;.cancelled&lt;/code&gt; 를 사용할 수 있습니다. 예를 들어 &lt;code&gt;.changed&lt;/code&gt; 상태에선 뷰의 속성을 임의로 변경시키고 &lt;code&gt;.ended&lt;/code&gt;에서는 이를 확정 짓는 등의 행위를 할 수 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;/article&gt;
&lt;script src=&quot;https://gist.github.com/ehdrjsdlzzzz/e7e69f7f065349d024a4e4d927d25a56.js&quot;&gt;&lt;/script&gt;
&lt;article class=&quot;markdown-body&quot;&gt;
&lt;hr&gt;
&lt;h4&gt;&lt;a href=&quot;https://developer.apple.com/documentation/uikit/uigesturerecognizer&quot;&gt;UIGestureRecognizer&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Gesture recognizer는 gesture를 인식하는 로직과 그에 따른 행위를 분리시켜 놓습니다. 그리고 gesture를 인식하거나 인식하고 있는 gesture의 변화가 감지되면 해당 사실을 지정된 객체(Target Object)에 전달합니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;code&gt;UIGestureRecognizer&lt;/code&gt;의 서브 클래스들로는 다음 클래스들이 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;UITapGestureRecognizer&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;UIPinchGestureRecognizer&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;UIRotationGestureRecognizer&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;UISwipeGestureRecognizer&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;UIPanGestureRecognizer&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;UIScreenEdgePanGestureRecognizer&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;UILongPressGestureRecognizer&lt;/code&gt;&lt;/li&gt;

&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;UIGestureRecognizer&lt;/code&gt; 클래스는 위의 서브 클래스들에서 정의되는 공통되는 행위에 대해 정의하고 있습니다. 또한 &lt;code&gt;UIGestureRecognizerDelegate&lt;/code&gt; 프로토콜을 준수하고 있는 객체와도 상호작용이 가능하기 때문에 이들을 활용하여 보다 섬세한 행위들을 정의해줄 수 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;또한 액션 메소드로는 두 가지 유형을 사용할 수 있습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot; lang=&quot;swift&quot;&gt;@IBAction func myActionMethod()
@IBAction func myActionMethod(_ gesture: UIGestureRecognizer)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;두 번째 유형처럼 &lt;code&gt;UIGestureRecognizer&lt;/code&gt;나 그의 서브 클래스를 인자로 받는다면 gesture의 보다 상세한 정보들을 사용할 수 있습니다. 예를들어 &lt;code&gt;UIRotationGestureRecognizer&lt;/code&gt;에 대한 액션 메소드로 인자를 받는다면 회전 각도에 대한 정보를 알 수 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;이제 Gesture recognizer에서 중요한 부분에 대해 살펴보도록 하겠습니다. 그것은 바로 &lt;code&gt;addGestureRecognizer(_:)&lt;/code&gt; 메소드로 뷰와 관계를 갖는 &lt;strong&gt;&lt;i&gt;Gesture recognizer는 뷰의 &lt;a href=&quot;http://baked-corn.tistory.com/129&quot;&gt;Responder chain&lt;/a&gt;에 속하지 않는다는 것입니다.&lt;/i&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;터치 이벤트를 예를들어 설명하자면 만일 &lt;code&gt;UITapGestureRecognizer&lt;/code&gt;의 지정 객체인 뷰 위에서 터치가 발생하면 윈도우는 터치 이벤트를 해당 뷰로 전달하기 전에 먼저 Gesture recognizer로 전달합니다. &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;만일 등록한 Gesture recognizer와 맞지 않은 이벤트라면 해당 이벤트는 온전히 터치가 발생한 뷰로 전달됩니다. 하지만 Gesture recognizer에 맞는 gesture라면 해당 이벤트는 recognizer에 의해 처리가 되고 뷰로는 전달되지 않습니다. 이를 테스트해보기 위해 직접 코드를 작성해보았습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;버튼에 더블 탭 Gesture recognizer를 등록했을 경우입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;/article&gt;
&lt;script src=&quot;https://gist.github.com/ehdrjsdlzzzz/38e5c88540ba7e666ecdbfe86a1f7e09.js&quot;&gt;&lt;/script&gt;
&lt;article class=&quot;markdown-body&quot;&gt;
&lt;p&gt;버튼을 한번만 클릭하면 결과물은 다음과 같습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;UIRESPONDER : Button Touch Began
UIRESPONDER : Button Touch Ended
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;당연한 결과물이죠? 터치 이벤트는 등록된 Gesture recognizer의 패턴과 일치하지 않으므로 터치 이벤트는 온전하게 뷰로 전달이 됩니다. 하지만 더블 클릭을 하면 어떻게 될까요?&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;UIRESPONDER : Button Touch Began
UIGestureRecognizer : UITapGestureRecognizer
UIRESPONDER : Button Touch Cancelld
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;터치가 일어나면 우선 손가락이 화면에 처음 접촉한 순간에 대한 이벤트는 정상적으로 전달이 됩니다. 그렇기 때문에 &lt;code&gt;touchesBegan&lt;/code&gt; 메소드는 정상적으로 호출이 되는 것입니다. 하지만 그 후 더블 클릭이 일어나면 (빠르게 같은 좌표에 대한 손가락의 접촉과 때어짐이 두번 발생) 이에 대한 이벤트는 &lt;code&gt;doubleTapGesture&lt;/code&gt;로 전달이 되어 처리가 되고 &lt;code&gt;UIResponder&lt;/code&gt;로 전달되어야 하는 이벤트는 취소 처리가 되는 것입니다. &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;이런 이벤트 전달의 흐름은 &lt;code&gt;UIGestureRecognizer&lt;/code&gt;의 프로피티인  &lt;code&gt;cancelsTouchesInView&lt;/code&gt;, &lt;code&gt;delaysTouchesBegan&lt;/code&gt; 그리고 &lt;code&gt;delaysTouchesEnded&lt;/code&gt; 값에 의해 결정됩니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;code&gt;&lt;b&gt;&lt;span style=&quot;font-size: 12pt;&quot;&gt;cancelsTouchesInView&lt;/span&gt;&lt;/b&gt;&lt;/code&gt; - &lt;code&gt;Bool&lt;/code&gt; 타입의 프로퍼티로 default 값은 &lt;code&gt;true&lt;/code&gt;입니다. Gesture Recognizer가 gesture를 인식하면 나머지 터치 정보들을 뷰로 전달하지 않고 이전에 전달된 터치들은 취소됩니다. (&lt;code&gt;touchesCancelled&lt;/code&gt;) 하지만 만일 이 값을 &lt;code&gt;false&lt;/code&gt;로 할당한다면 gesture를 인신한 후에도 터치 정보를 뷰에 전달하게 됩니다. 이를 코드와 출력 결과물로 살펴보도록 하겠습니다.&lt;/p&gt;
&lt;/article&gt;
&lt;script src=&quot;https://gist.github.com/ehdrjsdlzzzz/193a7bbb4de91390310ced2c9dbd1984.js&quot;&gt;&lt;/script&gt;
&lt;article class=&quot;markdown-body&quot;&gt;
&lt;p&gt;&lt;code&gt;UIGestureRecognizer&lt;/code&gt; 의 &lt;code&gt;cancelsTouchesInView&lt;/code&gt; 프로퍼티는 기본적으로 &lt;code&gt;true&lt;/code&gt;이기 때문에 이에 대한 출력 결과물은 다음과 같습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;UIRESPONDER : Button Touch Began
UIGestureRecognizer : UITapGestureRecognizer
UIRESPONDER : Button Touch Cancelld
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;하지만 &lt;code&gt;singleTapGesture.cancelsTouchesInView = false&lt;/code&gt; 코드를 작성하면 결과물은 다음과 같습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;UIRESPONDER : Button Touch Began
UIGestureRecognizer : UITapGestureRecognizer
UIRESPONDER : Button Touch Ended
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;터치가 끝났다는 정보가 뷰로 전달되었다는 것을 확인할 수 있습니다. &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;code&gt;&lt;b&gt;&lt;span style=&quot;font-size: 12pt;&quot;&gt;delaysTouchesBegan&lt;/span&gt;&lt;/b&gt;&lt;/code&gt; - &lt;code&gt;Bool&lt;/code&gt; 타입의 프로퍼티로 직역하자면 터치 최초 발생 이벤트 전달을 늦춘다는 의미입니다. defatult 값은 &lt;code&gt;false&lt;/code&gt;입니다. default 값이 &lt;code&gt;false&lt;/code&gt;이기 때문에 터치가 최초 발생한 순간 해당 gesture가 recognizer의 패턴과 하는 것과 무관하게 터치 시작 이벤트가 뷰로 전달되고 &lt;code&gt;touchesBegan&lt;/code&gt; 메소드가 호출됩니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;UIRESPONDER : Button Touch Began
UIGestureRecognizer : UITapGestureRecognizer
UIRESPONDER : Button Touch Cancelld
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;하지만 값이 &lt;code&gt;true&lt;/code&gt;라면 recognizer가 패턴을 검사하는 동안에는 터치의 최초 발생 이벤트를 뷰로 전달하지 않고 보류합니다. 그리고 gesture가 recognizer의 패턴과 일치된다고 판단되면 해당 이벤트는 버려지고 (discard) 뷰로 전달되지 않습니다. 이렇게 애초에 최초 터치 이벤트조차 뷰로 전달되지 않으니 &lt;code&gt;touchesCancelled&lt;/code&gt;도 호출되지 않는 것입니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;UIGestureRecognizer : UITapGestureRecognizer 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;하지만 어디까지나 delay (지연)이기 때문에 &lt;code&gt;singleTapGesture&lt;/code&gt;가 올라가있는 뷰 위에서 손가락을 최초 터치 후 때지 않고 기다리면 터치의 시작 이벤트는 뷰로 전달되고 &lt;code&gt;touchesBegan&lt;/code&gt; 메소드는 호출됩니다. &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;code&gt;&lt;b&gt;&lt;span style=&quot;font-size: 12pt;&quot;&gt;delaysTouchesEnded&lt;/span&gt;&lt;/b&gt;&lt;/code&gt; - &lt;code&gt;delaysTouchesBegan&lt;/code&gt;과 유사한 역할의 프로퍼티로 터치가 끝난 순간의 이벤트 전달을 지연시킬 것인지를 결정하는 프로퍼티입니다. 하지만 &lt;code&gt;delaysTouchesBegan&lt;/code&gt;과 다르게 default 값은 &lt;code&gt;true&lt;/code&gt;입니다. 이 프로퍼티를 사용해보기 위해 저는 더블 탭을 인지하는 &lt;code&gt;doubleTapGesture&lt;/code&gt;를 사용하였습니다. 결과는 제가 기대한 것과는 약간 달랐습니다.&lt;/p&gt;
&lt;/article&gt;
&lt;script src=&quot;https://gist.github.com/ehdrjsdlzzzz/1506b2769bcab219005b7e09b771d2f2.js&quot;&gt;&lt;/script&gt;
&lt;article class=&quot;markdown-body&quot;&gt;
&lt;p&gt;이와 같이 코드를 작성하면 저는 &lt;code&gt;singleTapGesture&lt;/code&gt; 와 마찬가지로 &lt;code&gt;touchesEnded&lt;/code&gt; 가 정상적으로 호출될 것으로 예상하였으나 결과물은 다음과 같았습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;UIRESPONDER : Button Touch Began
UIGestureRecognizer : UITapGestureRecognizer
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;그리고 버튼은 눌려진 상태를 유지하고 있었습니다. 즉 터치 종료 이벤트가 전달되지 않았다는 것입니다. 물론 그렇다고 취소된 것도 아닌 것이죠. 하지만 &lt;code&gt;delaysTouchesEnded&lt;/code&gt;의 공식 문서에는 다음과 같이 설명되어 있었습니다. &lt;/p&gt;&lt;p&gt;&lt;i&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/i&gt;&lt;/p&gt;&lt;p&gt;&lt;i&gt;&lt;b&gt;Set this property to&amp;nbsp;&lt;code&gt;false&lt;/code&gt;&amp;nbsp;to have touch objects in the&amp;nbsp;&lt;a href=&quot;https://developer.apple.com/documentation/uikit/uitouch/phase/ended&quot;&gt;&lt;code&gt;UITouch.Phase.ended&lt;/code&gt;&lt;/a&gt;&amp;nbsp;delivered to the view while the gesture recognizer is analyzing the same touches.&lt;/b&gt;&lt;/i&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;&lt;br /&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;저는 더블 탭이 문서에서 언급하는 &lt;em&gt;same touches&lt;/em&gt; 라고 이해를 하고 &lt;code&gt;delaysTouchesEnded = false&lt;/code&gt; 코드를 추가로 작성해주었고 그제서야 원하는 출력 결과물을 얻을 수 있었습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;UIRESPONDER : Button Touch Began
UIRESPONDER : Button Touch Ended
UIRESPONDER : Button Touch Began
UIGestureRecognizer : UITapGestureRecognizer
UIRESPONDER : Button Touch Ended
&lt;/code&gt;&lt;/pre&gt;



&lt;h4&gt;Subclassing Notes&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;UIGestureRecognizer&lt;/code&gt; 를 상속받아 자신만의 Gesture recognizer를 만들 수 있습니다. 기본적으로 Gesture recognizer는 상태(&lt;code&gt;UIGestureRecognizer.State&lt;/code&gt;)에 따른 행동을 취하는데 이러한 상태는 State machine에 의해 결정됩니다. 그렇기 때문에 &lt;code&gt;UIGestureRecognizer&lt;/code&gt;를 상속받아 무엇을 만들 때 이런 상태 변화에 대한 정의를 명확히 해주어야 합니다. State machine에 대해서는 밑에서 보다 자세히 다루어볼 것이기 때문에 간단히만 살펴보도록 하겠습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;일단 연속적 gesture와 비연속적 gesture의 상태 변화 과정에는 차이가 있습니다. 우선 연속적, 비연속적 gesture와 상관없이 모든 gesture는 이벤트를 처리할 준비가 되었다는 &lt;code&gt;UIGestureRecognizer.State.possible&lt;/code&gt; 상태로부터 시작합니다. &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그리고 비연속적 gesture는 gesture 인식 성공 여부(&lt;code&gt;recognized&lt;/code&gt;)에 따라 &lt;code&gt;UIGestureRecognizer.State.ended&lt;/code&gt;인지 &lt;code&gt;UIGestureRecognizer.State.failed&lt;/code&gt; 나뉘고 인식에 성공하면 Target object에 액션 메시지를 보냅니다. &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;연속적 gesture는 조금 더 다양한 상태의 변화를 가질 수 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Possible ——&amp;gt; Began ——&amp;gt; [Changed] ——&amp;gt; Cancelled&lt;/li&gt;
&lt;li&gt;Possible ——&amp;gt; Began ——&amp;gt; [Changed] ——&amp;gt; Ended&lt;/li&gt;

&lt;/ul&gt;
&lt;p&gt;[Changed] 상태는 일어나지 않을 수도 있으며 Cancelled 혹은 Ended 상태 전에 여러번 발생할 수도 있습니다. 그리고 매 상태 변화마다 Target object에 액션 메시지를 보냅니다.&lt;/p&gt;&lt;p&gt;&amp;nbsp; &lt;/p&gt;&lt;p&gt;이렇게 &lt;code&gt;UIGestureRecognizer&lt;/code&gt;를 사용하고 이해하며 이를 상속받아 자신만의 Gesture recognizer를 만들어 사용하기 위해서는 위에서 언급했던 State machine에 대한 이해가 필요합니다. &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;그리고 이외에도 &lt;code&gt;UIGestureRecognizer&lt;/code&gt; 서브 클래스에서 반드시 재정의해주어야 하는 메소드는 &lt;a href=&quot;https://developer.apple.com/documentation/uikit/uigesturerecognizer#1658520&quot;&gt;공식 문서&lt;/a&gt;에 명시되어 있습니다. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h4&gt;&lt;a href=&quot;https://developer.apple.com/documentation/uikit/touches_presses_and_gestures/implementing_a_custom_gesture_recognizer/about_the_gesture_recognizer_state_machine&quot;&gt;About the Gesture Recognizer State Machine&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Gesture recognizer는 기본적으로 State machine에 의해 동작합니다. 이런 State machine은 몇몇 중요한 행위에 대해 결정을 하는 역할을 합니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;연속적 Gesture recognizer가 &lt;code&gt;UIGestureRecognizer.State.began&lt;/code&gt; 상태로 들어갈 수 있는지 여부&lt;/li&gt;
&lt;li&gt;비연속적 Gesture recognizer가 &lt;code&gt;UIGestureRecognizer.State.ended&lt;/code&gt; 상태로 들어갈 수 있는지 여부&lt;/li&gt;
&lt;li&gt;Gesture recognizer와 연결된 액션 메소드를 언제 호출할 것인지&lt;/li&gt;

&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;UIGestureRecognizer&lt;/code&gt; 를 상속받아 직접 클래스를 작성한다면 적절한 시점에 State machine을 갱신해주어야 합니다. 그리고 최종 상태인 &lt;code&gt;UIGestureRecognizer.State.ended&lt;/code&gt; , &lt;code&gt;UIGestureRecognizer.State.failed&lt;/code&gt;, &lt;code&gt;UIGestureRecognizer.State.cancelled&lt;/code&gt;에 다다른 이후 UIKit은 Gesture recognizer를 초기화하고 상태를초기 상태인 &lt;code&gt;UIGestureRecognizer.State.possible&lt;/code&gt; 상태로 되돌립니다. &lt;/p&gt;
&lt;h4&gt;Managing State Transitions for a Discrete Gesture Recognizer&lt;/h4&gt;
&lt;p&gt;비연속적 Gesture recognizer를 구현한다면 &lt;code&gt;state&lt;/code&gt; 프로퍼티의 값의 선택지는 &lt;code&gt;UIGestureRecognizer.State.ended&lt;/code&gt; 와 &lt;code&gt;UIGestureRecognizer.State.failed&lt;/code&gt; 두 가지가 됩니다. 만일 직접 만든 recognizer의 gesture와 들어온 gesture가 일치한다면 &lt;code&gt;.ended&lt;/code&gt;로 그렇지 않다면 &lt;code&gt;.failed&lt;/code&gt;로 변경시켜주어야 합니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;https://docs-assets.developer.apple.com/published/7c21d852b9/9ce946b4-9661-4a40-86bc-2f78abf3a8b1.png&quot; width=&quot;50%&quot;&gt;&lt;/p&gt;&lt;p&gt;인식에 성공하여 &lt;code&gt;.ended&lt;/code&gt; 상태로 변경한다면 UIKit은 연결된 객체의 액션 메소드를 호출합니다. &lt;code&gt;.failed&lt;/code&gt;라면 어느 것도 호출하지 않습니다. &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;비연속적 gesture recognizer를 구현해보는 공식 문서입니다.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://developer.apple.com/documentation/uikit/touches_presses_and_gestures/implementing_a_custom_gesture_recognizer/implementing_a_discrete_gesture_recognizer?changes=_4&quot;&gt;Implementing a Discrete Gesture Recognizer&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;Managing State Transitions for a Continuous Gesture Recognizer&lt;/h4&gt;
&lt;p&gt;연속적 gesture recognizer에서 상태의 변화에는 크게 세 가지 종류로 나눠볼 수 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;최초 이벤트에 따라 &lt;code&gt;UIGestureRecognizer.State.began&lt;/code&gt; 이나 &lt;code&gt;UIGestureRecognizer.State.failed&lt;/code&gt;로의 상태 변화&lt;/li&gt;
&lt;li&gt;그 이후 이벤트에 따라 &lt;code&gt;UIGestureRecognizer.State.began&lt;/code&gt; 에서 &lt;code&gt;UIGestureRecognizer.State.changed&lt;/code&gt;나 &lt;code&gt;UIGestureRecognizer.State.failed&lt;/code&gt;로의 상태 변화&lt;/li&gt;
&lt;li&gt;마지막 이벤트에 따라 &lt;code&gt;UIGestureRecognizer.State.ended&lt;/code&gt;로의 상태 변화&lt;/li&gt;

&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://docs-assets.developer.apple.com/published/7c21d852b9/86fa3739-c97b-44cc-b51d-0215697660b7.png&quot; width=&quot;100%&quot;&gt;&lt;/p&gt;&lt;p&gt;흐름대로 따라가면서 살펴보도록 하겠습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;먼저 &lt;code&gt;.possible&lt;/code&gt; 상태에서 gesture가 들어오고 recognizer의 패턴과 일치하는지 검사를 합니다. 일치한다면 &lt;code&gt;.began&lt;/code&gt; 으로 상태를 갱신합니다. 만일 패턴과 일치하지 않는다면 즉시 &lt;code&gt;.failed&lt;/code&gt; 상태로 변경해야합니다. UIKit은 한번에 하나의 Gesture recognizer만 메시지를 보내도록 허용하기 때문에 &lt;code&gt;.failed&lt;/code&gt; 상태로 보내야 다른 Gesture recognizer들에게 그들의 gesture를 처리할 수 있는 기회가 돌아갑니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;이렇게 초기 패턴이 일치하여 &lt;code&gt;.began&lt;/code&gt; 상태로 들어가면 이후의 이벤트들은 &lt;code&gt;.changed&lt;/code&gt;로 상태를 갱신합니다. 이미 &lt;code&gt;.changed&lt;/code&gt; 상태여도 상태의 변화를 같은 값으로 갱신시키는데 이는 &lt;code&gt;.changed&lt;/code&gt; 상태와 연관된 액션 메소드를 지속적으로 호출시키기 위함입니다. &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그리고 정상적으로 gesture의 일련의 과정이 정상적으로 종료되면 &lt;code&gt;.ended&lt;/code&gt; 상태로 갱신되고 그렇지 않으면 &lt;code&gt;.cancelled&lt;/code&gt; 상태로 갱신됩니다.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;연속적 gesture recognizer를 구현해보는 공식 문서입니다.&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://developer.apple.com/documentation/uikit/touches_presses_and_gestures/implementing_a_custom_gesture_recognizer/implementing_a_continuous_gesture_recognizer?changes=_4&quot;&gt;Implementing a Continuous Gesture Recognizer&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;Handling Cancellation&lt;/h4&gt;
&lt;p&gt;gesture의 취소 행위는 전화가 걸려오는 상황과 같은 시스템 이벤트에 의해 방해되었을 때 자동으로 발생합니다. 또한 이러한 취소 행위를 직접 코드로 구현할 수도 있습니다. 이러한 취소 행위는 recognizer를 만든 사람이 의도하지 않은 작업들이 발생하는 것을 막아주는 역할을 합니다. &lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;시스템이 gesture를 취소하고나면 UIKit은 &lt;code&gt;touchesCancelled&lt;/code&gt; 나 &lt;code&gt;pressesCancelled&lt;/code&gt; 메소드를 호출합니다. 이러한 gesture 취소 행위가 일어나면 위에서 언급했듯이 &lt;code&gt;UIGestureRecognizer.State.cancelled&lt;/code&gt;로 즉시 상태를 갱신시켜야 하며 이렇게 상태를 변경시켜야 UIKit이 액션 메소드를 호출할 수 있습니다.&lt;/p&gt;
&lt;h4&gt;Resetting the Gesture Recognizer State Machine&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;reset()&lt;/code&gt; 메소드를 구현하고 사용함으로써 구현한 Gesture recognizer의 상태를 초기 상태로 되돌릴 수 있습니다. 새로운 제스처가 발생하고 해당 이벤트를 전달하기 전이나 State machine의 상태가 &lt;code&gt;.cancelled&lt;/code&gt;, &lt;code&gt;.failed&lt;/code&gt;, &lt;code&gt;ended&lt;/code&gt; 일 경우 UIKit은 &lt;code&gt;reset()&lt;/code&gt; 를 호출하여 Gesture recognizer의 상태를 초기화할 뿐만 아니라 State machine을 &lt;code&gt;.possible&lt;/code&gt; 상태로 되돌리기도 합니다. 이렇게 &lt;code&gt;.possible&lt;/code&gt; 상태로 되돌려 놔야 새로운 이벤트를 받을 수 있기 때문입니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h4&gt;마무리&lt;/h4&gt;
&lt;p&gt;지난 시간 Responder Chain and Touch Event 포스팅에 이어 오늘은 이벤트를 다루는 다른 방법 중 하나인 &lt;code&gt;UIGestureRecognizer&lt;/code&gt;에 대해 전반적으로 공부해보았습니다. 가끔 &lt;code&gt;UIGestureRecognizer&lt;/code&gt;의 서브 클래스들을 사용하면서 원하는대로 동작을 안하는 경우가 있었는데 그 이유를 알게되는 계기가 되었습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;추후에는 &lt;code&gt;UIGestureRecognizer&lt;/code&gt; 를 직접 구현해보는 공식 문서를 공부해보고 이를 기록해보도록 하겠습니다. 감사합니다. &lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;참고자료&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.apple.com/documentation/&quot;&gt;Apple Developer Documentation&lt;/a&gt;&lt;/li&gt;

&lt;/ol&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;/article&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>Swift + iOS/iOS</category>
      <category>cancelsTouchesInView</category>
      <category>delaysTouchesBegan</category>
      <category>delaysTouchesEnded</category>
      <category>IOS</category>
      <category>Swift</category>
      <category>UIGestureRecognizer</category>
      <category>스위프트</category>
      <author>군옥수수수</author>
      <guid isPermaLink="true">https://baked-corn.tistory.com/130</guid>
      <comments>https://baked-corn.tistory.com/130#entry130comment</comments>
      <pubDate>Thu, 28 Jun 2018 15:53:46 +0900</pubDate>
    </item>
  </channel>
</rss>