<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>sanichdaniel의 iOS 개발 블로그</title>
    <link>https://sanichdaniel.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Mon, 25 May 2026 23:22:19 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>sanich8355</managingEditor>
    <item>
      <title>WWDC: The Layout Cycle</title>
      <link>https://sanichdaniel.tistory.com/51</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;The Layout Cycle&lt;/h3&gt;
&lt;p&gt;Layout은 Black Box일때가 많다.&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;뷰에 주어진 constrai&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;nt으로부터 뷰에 프레임이 할당되기까지의 과정에 대해 알아보자&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-filename=&quot;스크린샷 2020-12-06 오후 4.30.41.png&quot; data-origin-width=&quot;2344&quot; data-origin-height=&quot;1290&quot; width=&quot;522&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/y1nX4/btqPgHqKPVN/r7ikCJj91r1egoYfkLCwWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/y1nX4/btqPgHqKPVN/r7ikCJj91r1egoYfkLCwWK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/y1nX4/btqPgHqKPVN/r7ikCJj91r1egoYfkLCwWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fy1nX4%2FbtqPgHqKPVN%2Fr7ikCJj91r1egoYfkLCwWK%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-12-06 오후 4.30.41.png&quot; data-origin-width=&quot;2344&quot; data-origin-height=&quot;1290&quot; width=&quot;522&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;The Layout Cycle&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-filename=&quot;스크린샷 2020-12-06 오후 4.17.32.png&quot; data-origin-width=&quot;2834&quot; data-origin-height=&quot;1676&quot; width=&quot;527&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cKsx7o/btqPqmlw0Kq/f3wDzJLS9HxKbZSjz2fja0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cKsx7o/btqPqmlw0Kq/f3wDzJLS9HxKbZSjz2fja0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cKsx7o/btqPqmlw0Kq/f3wDzJLS9HxKbZSjz2fja0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcKsx7o%2FbtqPqmlw0Kq%2Ff3wDzJLS9HxKbZSjz2fja0%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-12-06 오후 4.17.32.png&quot; data-origin-width=&quot;2834&quot; data-origin-height=&quot;1676&quot; width=&quot;527&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. Application Run Loop 이 돈다&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. Constraint가 변한다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Constraint 변하는 상황들에는 아래의 예시들이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. activate or deactivate&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. setting constant or prioritiy&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. adding or removing views&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Constraint change가 발생하면 Layout Engine은 layout을 다시 계산한다&lt;/p&gt;
&lt;p&gt;뷰들은&lt;span&gt; 자신의 superview가 layout을 다시 그려야한다고 마킹하다 (&lt;/span&gt;&lt;b&gt;superview.setNeedsLayout()&lt;/b&gt;을 호출)&lt;br /&gt;이 과정이 deferred layout pass를 스케줄한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. deferred layout pass가 발생한다.&lt;/h3&gt;
&lt;p&gt;잘못 배치된 뷰들을 재배치해준다.&lt;/p&gt;
&lt;p&gt;여기서 layout의 constraint를 업데이트하고 뷰 들의 프레임을 다시 계산한다.&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;deferred layout pass를 스케줄 하고 싶다면 &lt;/span&gt;&lt;b&gt;setNeedsLayout&lt;/b&gt;이나&amp;nbsp; &lt;b&gt;setNeedUpdateConstraints&lt;/b&gt;를 호출해주면 된다.&lt;/p&gt;
&lt;p&gt;deferred layout pass는 2가지 단계를 거친다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;1. update pass&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;필요시, constraints를 업데이트한다&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;시스템은 뷰 계층을 돌며 뷰컨트롤러에 &lt;b&gt;updateViewConstraints&lt;/b&gt;를 호출하고 뷰에 &lt;b&gt;updateConstraints&lt;/b&gt;를 호출한다.&lt;/p&gt;
&lt;p&gt;만약 constraints 업데이트가 느리거나, 뷰가 불필요하게 바뀌는 퍼포먼스 이슈 발생하여 constraints를 일괄적으로 업데이트 하고 싶을때는 이 함수들을 오버라이드 할 수 있다. 하지만 지금까지 작업하며 오버라이드 한적이 한번도 없었고 WWDC나 아래 스택오버플로우 답글에서도 그때그때 컨스트레인트를 업데이트하는것을 추천한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;2. layout pass&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;필요시, 뷰의 프레임을 다시 재배치한다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;시스템은 뷰 계층을 돌며 레이아웃이 필요하다고 마킹된 뷰컨트롤러에 &lt;b&gt;viewWillLayoutSubviews&lt;/b&gt;를 호출하고, 뷰에 &lt;b&gt;layoutSubviews&lt;/b&gt;를 호출한다.&lt;/p&gt;
&lt;p&gt;이 함수들을 오버라이드하여 커스텀한 레이아웃을 줄 수 있으나, &lt;b&gt;레이아웃이 컨스트레인트 자체만으로 표현될수 없을때만&lt;/b&gt; 하는게 좋다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;자신의 subtree 바깥의 뷰를 invalidate하지 않는게 좋다&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이 과정에서 Layout Engine으로부터 서브뷰의 프레임을 복사해와 서브뷰들이 포지션된다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;출처&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.apple.com/videos/play/wwdc2015/219/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;developer.apple.com/videos/play/wwdc2015/219/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/AutolayoutPG/ModifyingConstraints.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;developer.apple.com/library/archive/documentation/UserExperience/Conceptual/AutolayoutPG/ModifyingConstraints.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://stackoverflow.com/questions/47823639/why-calling-setneedsupdateconstraints-isnt-needed-for-constraint-changes-or-ani&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;stackoverflow.com/questions/47823639/why-calling-setneedsupdateconstraints-isnt-needed-for-constraint-changes-or-ani\&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=xjArhdrqAn8&amp;amp;feature=youtu.be&amp;amp;t=20m00s&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;www.youtube.com/watch?v=xjArhdrqAn8&amp;amp;feature=youtu.be&amp;amp;t=20m00s&lt;/a&gt;&lt;/p&gt;</description>
      <author>sanich8355</author>
      <guid isPermaLink="true">https://sanichdaniel.tistory.com/51</guid>
      <comments>https://sanichdaniel.tistory.com/51#entry51comment</comments>
      <pubDate>Sun, 6 Dec 2020 16:07:48 +0900</pubDate>
    </item>
    <item>
      <title>nested function (중첩함수)</title>
      <link>https://sanichdaniel.tistory.com/50</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;마틴 파울러의 리팩토링을 읽다가 리팩토링 기법중 하나인 함수를 추출하기 단원을 읽다가,&lt;br /&gt;함수가 사용되는곳이 한곳에 불과하면 private 함수로 빼는것보다 중첩함수를 사용하는것이 유용하다는 글을 읽었다.&lt;br /&gt;중첩함수를 한번도 사용해본적이 없었기에 공부해보았다.&lt;/blockquote&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;중첩함수를 처음 보았을때는 낯설어서 못생겼다고 생각을 했었다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;하자만 공부해보니 중첩함수는 가독성과 캡슐화의 측면에서 이점이 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;가독성&lt;/h3&gt;
&lt;p&gt;private 함수는 클래스(또는 파일)에서 접근이 가능하다.&lt;/p&gt;
&lt;p&gt;하지만 중첩함수는 해당 함수안에서만 사용된다는것이 보장된다.&lt;/p&gt;
&lt;p&gt;public namespace를 줄이려고 private 키워드를 사용하듯, private namespace를 줄이기 위해 중첩함수를 사용해보자.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;캡슐화&lt;/h3&gt;
&lt;p&gt;중첩함수는 소속된 함수의 지역변수에 접근할수 있다.&lt;/p&gt;
&lt;p&gt;지역변수들을 인자로 전달할 필요가 없다&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;조심할점&lt;/h3&gt;
&lt;p&gt;순환참조!&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;출처&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://stackoverflow.com/questions/32968133/what-is-the-practical-use-of-nested-functions-in-swift&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;stackoverflow.com/questions/32968133/what-is-the-practical-use-of-nested-functions-in-swift&lt;/a&gt;&lt;/p&gt;</description>
      <category>swift</category>
      <author>sanich8355</author>
      <guid isPermaLink="true">https://sanichdaniel.tistory.com/50</guid>
      <comments>https://sanichdaniel.tistory.com/50#entry50comment</comments>
      <pubDate>Sun, 15 Nov 2020 14:37:15 +0900</pubDate>
    </item>
    <item>
      <title>WWDC: Better Apps with Value type</title>
      <link>https://sanichdaniel.tistory.com/44</link>
      <description>&lt;p&gt;value 타입에 관한 &lt;a href=&quot;https://developer.apple.com/videos/play/wwdc2016/419/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;WWDC&lt;/a&gt; 영상을 참고하여 새로알게된 사실들을 정리해보았다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;배경지식&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;value type vs reference type&amp;nbsp;&lt;/h4&gt;
&lt;p&gt;&lt;b&gt;value type&lt;/b&gt;: 값이 복사될때&lt;span&gt; (할당, 생성, 인자로 넘겨질때) 매번 독립적인 인스턴스를 만든다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;b&gt;reference type&lt;/b&gt;: 값이 복사될때 참조가 복사되고 인스턴스는 공유된다&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span&gt;heap stack 어디 저장되나&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;span&gt;Referenct 타입은 heap에 저장되고, 포인터(참조)는 stack에 저장된다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;value type이 class에 포함되거나 closure에 캡쳐되면 heap에 저장된다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;Reference 타입은 항상 heap에 저장, value 타입은 자신이 선언된곳에 저장된다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Local Reasoning&lt;/h2&gt;
&lt;p&gt;강의 초반에 Local Reasoning이란 term이 나온다.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Local Reasoning&lt;/b&gt;이란 한곳의 코드를 보면, 다른 곳의 코드와 어떻게 상호작용해야하는지 생각할 필요가 없는것을 말한다.&lt;/p&gt;
&lt;p&gt;팀에 처음 합류해서 코드를 볼때 아는 건 없고, 어떻게 코드들이 상호작용 되는지 몰라 몹시 혼란스러운 경험이 다들 있을것이다.&lt;/p&gt;
&lt;p&gt;Local Reasoning이 잘 되어있으면 처음 합류하는 사람도 이해하기 쉽고, 유지보수 하기가 쉽고, 작성하기 쉽고, 테스트 하기가 쉽다.&lt;/p&gt;
&lt;h2&gt;Value type for Local Reasoning&lt;/h2&gt;
&lt;h3&gt;1. Different variables are logically distinct&lt;/h3&gt;
&lt;p&gt;Reference 타입의 경우 인스턴스들은 하나의 데이터를 가지고 있다.&lt;/p&gt;
&lt;p&gt;따라서 다른곳에서 값이 수정될수도 있다. 이것은 Local Reasoning을 어렵게 한다.&lt;/p&gt;
&lt;p&gt;하지만 Value타입의 경우 각 변수들은 논리적으로 구별된다.&lt;/p&gt;
&lt;p&gt;하나의 value type 변수의 값을 mutate 한다고 다른 변수의 값에 영향을 끼치지 않는다.&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;2. Mutability when you want it&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;let을 붙여 외부에서 값 수정을 못하게 immutable하게 만들 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;값을 수정하고 싶을때만 var을 붙여주면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;내부에서 인스턴스 메서드를 통해 값을 수정하려면 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;mutating&lt;/span&gt; 키워드가 필요하다&lt;/p&gt;
&lt;h3&gt;&lt;span style=&quot;letter-spacing: normal;&quot;&gt;3. Copy is Cheap&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;지금까지 &lt;i&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;value type의 경우 매번 값이 복사되기에 비효율적이어서 커스텀 타입을 만들때 들고있을 변수들의 수가 적은 경우에만 value 타입을 써야한다&lt;/span&gt;&amp;nbsp;&lt;/span&gt;&lt;/i&gt;&lt;span style=&quot;color: #333333;&quot;&gt;라고 &lt;/span&gt;&lt;b&gt;잘못 &lt;/b&gt;알고 있었다. &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;하지만 WWDC에 따르면 copy의 값은 constant time이기에 싸다고 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;또한 내부적으로 copy-on-write 즉 값이 수정될때 copy가 실제로 일어나기에 더욱 값싸진다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;따라서 value 타입을 쓸수 있는 상황에서는 되도록 value 타입을 쓰자!&lt;/span&gt;&lt;/p&gt;</description>
      <category>swift</category>
      <author>sanich8355</author>
      <guid isPermaLink="true">https://sanichdaniel.tistory.com/44</guid>
      <comments>https://sanichdaniel.tistory.com/44#entry44comment</comments>
      <pubDate>Sun, 25 Oct 2020 17:18:09 +0900</pubDate>
    </item>
    <item>
      <title>expression, statement, literal</title>
      <link>https://sanichdaniel.tistory.com/43</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span&gt;expressions(수식)&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;span&gt;값을 리턴하는 코드&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1603345379956&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let someValue:Int = 12
if true &amp;amp;&amp;amp; false {
    print(&quot;This is false&quot;)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span&gt;여기에 들어간 expression은&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1603345406526&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let someValue:Int = 12
true &amp;amp;&amp;amp; false
&quot;This is false&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;statement(문장)&lt;/h3&gt;
&lt;p&gt;어떠한 작업을 수행하는 모든 문장&lt;/p&gt;
&lt;p&gt;Swift에서는 크게 3가지 종류로 statement를 구분한다&lt;/p&gt;
&lt;p&gt;expression은 값을 리턴하는 statement라 볼 수 있다&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;span&gt;1. simple statements&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;expression이나 선언&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;span&gt;2. compiler control statements&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;#if&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;3. control flow staements&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;if 문, guard문, for 문..&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;literal&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1603345936292&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;42               // Integer literal
3.14159          // Floating-point literal
&quot;Hello, world!&quot;  // String literal
true             // Boolean literal&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;literal은 자신만의 타입이 없다.&lt;/p&gt;
&lt;p&gt;대신, swift의 타입 추론이 literal의 타입을 추론한다.&lt;/p&gt;
&lt;p&gt;만약 적절한 타입정보를 얻을수 없다면, swift는 standard library에 나온 default literal type일것이라 추론한다.&lt;/p&gt;
&lt;p&gt;정수형 literal에 대한 default 타입은 Int이고, 소숫점 literal에 대한 default 타입은 Double이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;nil&lt;/b&gt; literal 같은 경우는 타입이 추론될수 없으니 아래와 같은 식은 불가능하다&lt;/p&gt;
&lt;pre id=&quot;code_1603346247520&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let a = nil&lt;/code&gt;&lt;/pre&gt;</description>
      <category>swift</category>
      <author>sanich8355</author>
      <guid isPermaLink="true">https://sanichdaniel.tistory.com/43</guid>
      <comments>https://sanichdaniel.tistory.com/43#entry43comment</comments>
      <pubDate>Sat, 24 Oct 2020 16:19:24 +0900</pubDate>
    </item>
    <item>
      <title>양방향 타입추론</title>
      <link>https://sanichdaniel.tistory.com/42</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;Swift의 타입추론은 양방향으로 이루어진다고 한다. 알아보자&lt;/blockquote&gt;
&lt;h3&gt;Bottom-up 타입 추론&lt;/h3&gt;
&lt;p&gt;타입 정보가 &lt;b&gt;leaf&lt;/b&gt;에서 &lt;b&gt;root&lt;/b&gt;으로 전달되는것&lt;/p&gt;
&lt;pre id=&quot;code_1603365822506&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var x = 0&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;literal 0을 보고 x의 타입을 Int로 추론한다. (정수의 literal의 기본 타입은 Int이다.)&lt;/p&gt;
&lt;p&gt;&lt;b&gt;leaf&lt;/b&gt;인 literal이 &lt;b&gt;root&lt;/b&gt;인 변수의 타입을 결정한다.&lt;/p&gt;
&lt;pre id=&quot;code_1603348149739&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let age = 26              // age is of type Int
let name = &quot;Toni&quot;         // name is of type String
let pair = (age, name)    // pair is of type (Int, String)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;pair 튜플의 타입은 (age, name)의 타입으로부터 결정이 된다.&lt;/p&gt;
&lt;p&gt;타입체커는 age, name을 코드에서 찾는다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;즉 root인 pair의 타입은 leaf에 해당하는 age, name의 literal의 타입 정보로부터 전달되는것.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;아래 트리는 위의 expression의 AST를 나타낸 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-filename=&quot;스크린샷 2020-10-22 오후 3.48.17.png&quot; data-origin-width=&quot;1096&quot; data-origin-height=&quot;674&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2pJNU/btqLvfFyCIT/bInRhBnRnvRmPrYh8fcmrk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2pJNU/btqLvfFyCIT/bInRhBnRnvRmPrYh8fcmrk/img.png&quot; data-alt=&quot;Abstract Syntax tree: 소스 코드를 컴퓨터가 이해할수 있는 트리구조로 변형시킨것. leaf에 해당하는 age, name으로부터 타입정보가 위로 전달되는것을 확인할수있다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2pJNU/btqLvfFyCIT/bInRhBnRnvRmPrYh8fcmrk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2pJNU%2FbtqLvfFyCIT%2FbInRhBnRnvRmPrYh8fcmrk%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-10-22 오후 3.48.17.png&quot; data-origin-width=&quot;1096&quot; data-origin-height=&quot;674&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Abstract Syntax tree: 소스 코드를 컴퓨터가 이해할수 있는 트리구조로 변형시킨것. leaf에 해당하는 age, name으로부터 타입정보가 위로 전달되는것을 확인할수있다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Top-down 타입 추론&lt;/h2&gt;
&lt;p&gt;Top-down은 반대로 &lt;b&gt;root&lt;/b&gt;에서 &lt;b&gt;leaf&lt;/b&gt;로 타입 정보가 전달된다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;4가지 케이스가 있다&lt;/p&gt;
&lt;p&gt;1. literal expression&lt;/p&gt;
&lt;p&gt;2. Implicit member &lt;span style=&quot;color: #333333;&quot;&gt;expression&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;3. 클로져&lt;/p&gt;
&lt;p&gt;4. 함수 호출 &lt;span style=&quot;color: #333333;&quot;&gt;expression&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Literal Expression&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1603363135547&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let y: Double = 2     // y is of type Double&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;정수 literal의 타입은 기본적으로 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;Int&lt;/span&gt;이다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;하지만 명시적으로 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;Double&lt;/span&gt;이라 타입을 적어주면, literal의 타입이 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;Double&lt;/span&gt;로 추론된다&lt;/p&gt;
&lt;p&gt;위의 예시에서, &lt;b&gt;root&lt;/b&gt;인 y의 타입 정보가 &lt;b&gt;leaf&lt;/b&gt;인 literal 2의 타입을 &lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;Double&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt; 로 결정지었다. (Top - down)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;배열 literal도 디폴트 타입이 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;Array&amp;lt;T&amp;gt;&lt;/span&gt;이나 Set이라 명시하면 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;Set&amp;lt;T&amp;gt;&lt;/span&gt; 타입을 얻을수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1603363312641&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let arr = [1, 2, 3]                 // arr is of type Array&amp;lt;Int&amp;gt;
let mySet: Set&amp;lt;Int&amp;gt; = [1, 2, 3]       // set is of type Set&amp;lt;Int&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위 예시에서도 &lt;b&gt;root&lt;/b&gt;인 mySet변수에 명시적으로 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;Set&lt;/span&gt; 타입을 주었기에, &lt;b&gt;leaf&lt;/b&gt;인 오른쪽 배열 literal의 타입도 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;Set&lt;/span&gt;으로 추론되었다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Implicit Member Expressions&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;타입의 멤버를 축약된 방식 dot &lt;b&gt;.&lt;/b&gt;&amp;nbsp;으로 접근하는걸 말한다&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;enum이나 타입 메서드를 접근할때 사용된다&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1603363774215&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;enum Season {
    case spring
    case summer
    case fall
    case winter
}

var season = Season.summer          // season is of type Season
season = .fall&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;season = .fall에서&lt;/p&gt;
&lt;p&gt;.fall을 축약된 형태로 접근할수 있는것도 season변수의 타입이 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;Season&lt;/span&gt;으로 위에서 결정되었기에 가능한것이다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;root(변수 season)의 타입정보가 leaf(literal .fall)로 전달되었다.&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Closures&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;클로져의 인자 타입과, 리턴 타입을 명시적으로 적어주지 않더라도, 클로져가 사용되는 문맥에서 타입이 자주 추론된다.&lt;/p&gt;
&lt;p&gt;아래에서 filter() 함수는 클로져를 인자로 받는다.&lt;/p&gt;
&lt;p&gt;클로져의 인자 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;n&lt;/span&gt;의 타입은 numbers 의 타입에 의해 추론된다&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1603364207786&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let numbers = [1, -2, 3]            // numbers is of type Array&amp;lt;Int&amp;gt;
let positiveNumbers = numbers.filter { n in n &amp;gt;= 0 }
print(positiveNumbers)              // [1, 3]

let numbers = [1.0, -2.0, 3.0]      // numbers is of type Array&amp;lt;Double&amp;gt;
let positiveNumbers = numbers.filter { n in n &amp;gt;= 0 }
print(positiveNumbers)              // [1.0, 3.0]&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Overload Resoulution&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;함수나 operator는 overload될수 있다.&lt;/p&gt;
&lt;p&gt;타입체커는 overload에서 어떤 함수를 사용할지 결정할때&lt;/p&gt;
&lt;p&gt;함수의 인자의 타입과, 함수가 호출된 문맥을 둘다 확인한다.&lt;/p&gt;
&lt;pre id=&quot;code_1603364498719&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;func f() -&amp;gt; Int {
    return 2
}

func f() -&amp;gt; String {
    return &quot;test&quot;
}

let x = f()                   // error: ambiguous use of 'f()'
let y: Int = f()              // Overload Resolution picks f: () -&amp;gt; Int
let z: String = f()           // Overload Resolution picks f: () -&amp;gt; String
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;x의 경우에는 어떤 함수를 사용할지 결정할수 없어 에러가 난다.&lt;/p&gt;
&lt;p&gt;하지만 y의 리턴타입은 Int가 와야하기에 첫번째 f() 함수를 사용하도록 결정이된다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;출처&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://tonisuter.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;tonisuter.com/&lt;/a&gt;&lt;/p&gt;</description>
      <category>swift</category>
      <author>sanich8355</author>
      <guid isPermaLink="true">https://sanichdaniel.tistory.com/42</guid>
      <comments>https://sanichdaniel.tistory.com/42#entry42comment</comments>
      <pubDate>Thu, 22 Oct 2020 14:39:22 +0900</pubDate>
    </item>
    <item>
      <title>Operator Overloading</title>
      <link>https://sanichdaniel.tistory.com/41</link>
      <description>&lt;h2&gt;Operator Overloading&lt;/h2&gt;
&lt;p&gt;Class, struct는 기존에 존재하는 operator에 대한 자신만의 구현을 제공할수 있다.&lt;/p&gt;
&lt;p&gt;이것을 operator overloading이라 한다.&lt;/p&gt;
&lt;p&gt;operator은 &lt;b&gt;+&lt;/b&gt;,&lt;b&gt; -&lt;/b&gt;,&lt;b&gt; *&lt;/b&gt;,&lt;b&gt; /&lt;/b&gt;,&lt;b&gt; %&lt;/b&gt;,&lt;b&gt; = &lt;/b&gt;같은 심볼들로 값을 체크하거나, 수정, 합치는데 사용된다&lt;/p&gt;
&lt;p&gt;함수를 사용하는것보다 더 간결하게 코드를 표현할수 있을때 사용된다&lt;/p&gt;
&lt;p&gt;Equatable 프로토콜 구현이 사실 operator overloading이었다!&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;출처&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.hackingwithswift.com/example-code/language/how-to-use-operator-overloading&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;www.hackingwithswift.com/example-code/language/how-to-use-operator-overloading&lt;/a&gt;&lt;/p&gt;</description>
      <category>swift</category>
      <author>sanich8355</author>
      <guid isPermaLink="true">https://sanichdaniel.tistory.com/41</guid>
      <comments>https://sanichdaniel.tistory.com/41#entry41comment</comments>
      <pubDate>Fri, 16 Oct 2020 20:42:20 +0900</pubDate>
    </item>
    <item>
      <title>빌드 타임 개선</title>
      <link>https://sanichdaniel.tistory.com/38</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;빌드 타임이 어디서 오래걸리는지 측정해보았다.&amp;nbsp;&lt;br /&gt;Build Settings의 &amp;ldquo;Swift Compiler - Custom Flags&amp;rdquo;, &amp;ldquo;Other Swift Flags&amp;rdquo; 에서&lt;br /&gt;-Xfrontend -warn-long-expression-type-checking=&amp;lt;limit&amp;gt; 옵션을 추가해주고 빌드해본 결과&lt;br /&gt;== 비교 연산자를 사용하는곳에서 warning이 많이 나왔다.&amp;nbsp;&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;비교 연산자 타입추론이 오래 걸리는 이유?&lt;/h2&gt;
&lt;p&gt;비교 연산자 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;==&lt;/span&gt; 은 수많은 곳에서 overload되는 operator이다. (overload: 같은 이름의 다른 메서드들)&lt;/p&gt;
&lt;p&gt;swift standard library에서만 73곳에서 overload되고 있고, 커스텀하게 만든 타입들에서도 자주 overload 된다.&lt;/p&gt;
&lt;p&gt;operator는 글로벌 함수처럼 호출되기에, 컴파일러는 모든 ==의 overload를 확인해야한다.&lt;/p&gt;
&lt;p&gt;즉 자주 overload 되는 모든 operator들에서는 비교연산자와 같은 퍼포먼스 이슈가 있을것으로 보인다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;개선방안&lt;/h2&gt;
&lt;p&gt;protocol extension의 메서드로 바꿔주기&lt;/p&gt;
&lt;pre id=&quot;code_1603373200749&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;extension Equatable {
   func equals(_ object: Self?) -&amp;gt; Bool {
      guard case object = self else { return false }
      return true
   }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;메서드인 경우 컴파일러가 타입추론하기 훨씬 쉽다.&lt;/p&gt;
&lt;p&gt;컴파일러는 메서드가 호출된 base 타입의 overload만 확인하면 되기 때문이다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;또한 내부적으론 패턴매칭을 이용하여 equality를 비교한다.&lt;/p&gt;
&lt;p&gt;패턴매칭은 내부적으로 ~= operator을 사용하는데, == 보단 일반적으로 적게 overload되기에 타입추론이 더 빠르다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;출처&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://forums.swift.org/t/swift-equality-operator-takes-long-time-to-type-check/41226/8&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;forums.swift.org/t/swift-equality-operator-takes-long-time-to-type-check/41226/8&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.swiftbysundell.com/articles/improving-swift-compile-times/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;www.swiftbysundell.com/articles/improving-swift-compile-times&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.cocoawithlove.com/blog/2016/07/12/type-checker-issues.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;www.cocoawithlove.com/blog/2016/07/12/type-checker-issues.html&lt;/a&gt;&lt;/p&gt;</description>
      <category>swift</category>
      <author>sanich8355</author>
      <guid isPermaLink="true">https://sanichdaniel.tistory.com/38</guid>
      <comments>https://sanichdaniel.tistory.com/38#entry38comment</comments>
      <pubDate>Wed, 14 Oct 2020 21:44:16 +0900</pubDate>
    </item>
    <item>
      <title>Pure functions in swift</title>
      <link>https://sanichdaniel.tistory.com/37</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Pure function 이란?&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 같은 인자라면, 같은 리턴 값 (외부에 의존하지 않는다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 사이드 이펙트가 없다&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;장점&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 재사용성, 테스트하기 쉬위짐&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 사이드 이펙트가 적음&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size16&quot;&gt;함수를 pure하게 만들기&lt;/h2&gt;
&lt;h3&gt;1. 값을 바꾸지 말고, 새로운 값을 리턴하자&lt;/h3&gt;
&lt;pre id=&quot;code_1602676807120&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;extension String {
    mutating func addSuffixIfNeeded(_ suffix: String) {
        guard !hasSuffix(suffix) else {
            return
        }

        append(suffix)
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 함수는 값을 &lt;b&gt;mutate &lt;/b&gt;하기에 pure 하지 않다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;mutable 값에만 호출할수 있게되고 더러운 &lt;i&gt;var muate assign &lt;/i&gt;코드가 필요해진다.&lt;/p&gt;
&lt;pre id=&quot;code_1602676938924&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var fileName = contentName
fileName.addSuffixIfNeeded(&quot;.md&quot;)
try save(content, inFileNamed: fileName)&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1602677018591&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;extension String {
    func addingSuffixIfNeeded(_ suffix: String) -&amp;gt; String {
        guard !hasSuffix(suffix) else {
            return self
        }

        return appending(suffix)
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;span style=&quot;color: #333333;&quot;&gt;2. 외부 값에 의존하지 말고, 인자로 받자&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1602677157036&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;func makeFailureHelpText() -&amp;gt; String {
    guard numberOfAttempts &amp;lt; 3 else {
        return &quot;Still can't log you in. Forgot your password?&quot;
    }
    
    return &quot;Invalid username/password. Please try again.&quot;
}

func makeFailureHelpText(numberOfAttempts: Int) -&amp;gt; String {
    guard numberOfAttempts &amp;lt; 3 else {
        return &quot;Still can't log you in. Forgot your password?&quot;
    }
    
    return &quot;Invalid username/password. Please try again.&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Purity 강제하기&lt;/h2&gt;
&lt;p&gt;value 타입으로 로직을 구성하기&lt;/p&gt;
&lt;p&gt;value 타입은 mutating 키워드를 붙이지 않는이상 mutable state를 갖지 못한다.&lt;/p&gt;
&lt;p&gt;mutable하게 만드는 과정에서 mutating 키워드를 붙이게 되고, 이것은 pr 리뷰에서 발견이 가능하다!&lt;/p&gt;
&lt;pre id=&quot;code_1602677468194&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;struct PriceCalculator {
    let shippingCosts: ShippingCostDirectory
    let currency: Currency

    func calculateTotalPrice(for products: [Product],
                             shippingTo region: Region) -&amp;gt; Cost {
        let productCost: Cost = products.reduce(0) { cost, product in
            return cost + product.price
        }

        return productCost.convert(to: currency)
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;출처&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.swiftbysundell.com/articles/pure-functions-in-swift/&quot;&gt;www.swiftbysundell.com/articles/pure-functions-in-swift/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.swiftbysundell.com/articles/functional-networking-in-swift/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;www.swiftbysundell.com/articles/functional-networking-in-swift/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>swift</category>
      <author>sanich8355</author>
      <guid isPermaLink="true">https://sanichdaniel.tistory.com/37</guid>
      <comments>https://sanichdaniel.tistory.com/37#entry37comment</comments>
      <pubDate>Wed, 14 Oct 2020 21:16:50 +0900</pubDate>
    </item>
    <item>
      <title>Currying</title>
      <link>https://sanichdaniel.tistory.com/36</link>
      <description>&lt;h3&gt;&lt;b&gt;Currying&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;여러 인자를 받는 함수를 하나의 인자만 받는 함수들의 시퀀스로 변환하는 것입니다.&lt;/p&gt;
&lt;p&gt;변환된 함수는 인자 하나를 받고, 값 대신 함수를 리턴한다. 이 리턴되는 함수는 다음 인자를 입력으로 받는다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-filename=&quot;스크린샷 2020-10-14 오후 11.24.36.png&quot; data-origin-width=&quot;1286&quot; data-origin-height=&quot;494&quot; width=&quot;662&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/botD9P/btqKXKLBqIM/beXOmu50MWZYOJFoAvgGNk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/botD9P/btqKXKLBqIM/beXOmu50MWZYOJFoAvgGNk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/botD9P/btqKXKLBqIM/beXOmu50MWZYOJFoAvgGNk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbotD9P%2FbtqKXKLBqIM%2FbeXOmu50MWZYOJFoAvgGNk%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-10-14 오후 11.24.36.png&quot; data-origin-width=&quot;1286&quot; data-origin-height=&quot;494&quot; width=&quot;662&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;예시 1&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1602685836391&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;func add2(_ x: Int, _ y: Int) -&amp;gt; Int {
    return x + y
}
add2(1, 2) 

func add2Currying(_ x: Int) -&amp;gt; ((Int) -&amp;gt; Int) {
    return { y in
        return x + y
    }
}
add2Currying(1)(2) &lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;예시 2&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1602686185959&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;func curry&amp;lt;A, B, C&amp;gt;(_ fn: @escaping (A, B) -&amp;gt; C) -&amp;gt; (A) -&amp;gt; (B) -&amp;gt; C {
    return { (a: A) in
        return { (b: B) in
            return fn(a, b)
        }
    }
}

enum LogLevel: String {
    case debug
    case error
}

func logMessage(level: LogLevel, message: String) {
    print(&quot;[\(level)] \(message)&quot;)
}

let logCurried = curry(logMessage)
let debug = logCurried(.debug)

debug(&quot;Log debug 1st&quot;)
debug(&quot;Log debug 2nd&quot;)
debug(&quot;Log debug 3rd&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;사실 우린 알게 모르게 Currying을 쓰고 있었는데, 모든 인스턴스 메서드는 currying 된 타입 메서드다&lt;/p&gt;
&lt;pre id=&quot;code_1602687009628&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;NSColor.blueColor().shadowWithLevel(1/3)
// 아래처럼 변환 가능
NSColor.shadowWithLevel(NSColor.blueColor())(1/3)&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1602687136875&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Adder  {
    func addOne(a: Int) -&amp;gt; Int {
        return a + 1
    }
}
let adder = Adder()

let addOne = Adder.addOne
let instanceMethod = addOne(adder)
print(instanceMethod(4))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;커링의 장점&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;1. 함수의 재사용을 쉽게 만들어 줌 (인자 중 변하지 않는 값은 고정시키고 변하는 값만 지정해서 함수를 실행할 수 있게 해줌)&lt;/p&gt;
&lt;p&gt;&lt;span&gt;2. 여러 파라미터를 한번에 받지않고 부분적으로 받은 후 함수의 실행을 늦출 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;3. 인스턴스를 모르는 상황에서 인스턴스 메서드를 참조 가능하다&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;출처&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://jusung.github.io/Currying/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;jusung.github.io/Currying/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://medium.com/@lazysoul/currying-%EC%BB%A4%EB%A7%81-b7af0b2aaef1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;medium.com/@lazysoul/currying-%EC%BB%A4%EB%A7%81-b7af0b2aaef1&lt;/a&gt;&lt;/p&gt;</description>
      <author>sanich8355</author>
      <guid isPermaLink="true">https://sanichdaniel.tistory.com/36</guid>
      <comments>https://sanichdaniel.tistory.com/36#entry36comment</comments>
      <pubDate>Wed, 14 Oct 2020 19:35:56 +0900</pubDate>
    </item>
    <item>
      <title>일급 시민 함수 - swift</title>
      <link>https://sanichdaniel.tistory.com/35</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;swift에서 함수는 일급 시민이다라는 말은 여러번 들어보았지만, 정작 일급 시민 개념에 대해 완전히 모르는것 같아 공부해보았다.&lt;/blockquote&gt;
&lt;h2&gt;일급 시민 (First-class Citizen)&lt;/h2&gt;
&lt;p&gt;&lt;span&gt;다른 객체들에 일반적으로 적용 가능한 연산을 모두 지원하는 객체를 가리킨다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;span&gt;1. 함수의 인자로 전달&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;span&gt;2. 함수에 의해 리턴&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;span&gt;3. 변수에 할당 가능&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;span&gt;4. 비교 연산이 가능&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;일급 함수 (First-class Function)&lt;/h2&gt;
&lt;p&gt;함수를 일급 시민으로 취급하는것&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;High Order Function&lt;/h2&gt;
&lt;p&gt;함수를 인자로 받거나, 함수를 리턴하는 함수&lt;/p&gt;
&lt;p&gt;함수가 일급 시민인 언어에서, high order function이 가능하다는것이 보장된다.&lt;/p&gt;
&lt;p&gt;-&amp;gt; 함수를 인자로 받거나 리턴할수 있기에&lt;/p&gt;
&lt;p&gt;high order function이 가능하다고 함수가 일급시민인것은 아니다&lt;/p&gt;
&lt;p&gt;-&amp;gt; 함수의 인자로 함수가 오는것은 특이케이스로 취급된다&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;아래 예시들에서 어떻게 일급 함수를 사용할지 알아보자&lt;/p&gt;
&lt;h3&gt;1. 함수의 인자로 전달&lt;/h3&gt;
&lt;pre id=&quot;code_1602666611619&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let subviews = [button, label, imageView]

subviews.forEach { subview in
    view.addSubview(subview)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;addSubview&lt;/span&gt; 함수를 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;(UIView) -&amp;gt; Void&lt;/span&gt; 타입의 클로져로 생각해보자.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;forEach 함수는 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;(Element) -&amp;gt; Void&lt;/span&gt; 타입의 클로져를 인자로 받는다.&lt;/p&gt;
&lt;p&gt;따라서 아래처럼 바로 &lt;span style=&quot;background-color: #dddddd;&quot;&gt;view.addSubview&lt;/span&gt; 를 인자로 넘길수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1602666817319&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;subviews.forEach(view.addSubview)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;조심해야할점은 위 예시처럼 인스턴스 메소드를 클로져처럼 사용하면 인스턴스가 클로져가 살아있는한 메모리상에 같이 남아있게 된다.&lt;/p&gt;
&lt;p&gt;위에선 non-escaping 클로져여서 문제가 안되었지만 escaping 클로져에서는 주의&lt;/p&gt;
&lt;h3&gt;2. 생성자를 인자로 전달&lt;/h3&gt;
&lt;p&gt;생성자도 일급 시민 함수로 취급할 수 있다&lt;/p&gt;
&lt;p&gt;아래 예시에서 생성자를 인자로 전달해보았다&lt;/p&gt;
&lt;pre id=&quot;code_1602667426089&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;images.map(UIImageView.init)
      .forEach(stackView.addArrangedSubview)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위와 같이 일급 시민 함수를 잘 사용하면 &lt;b&gt;선언적&lt;/b&gt;인 코드르 얻을 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;3. 인스턴스 메서드 참조하기&lt;/h3&gt;
&lt;p&gt;한 클래스의 static 메서드를 호출하려고 클래스 타입까지만 적었는데도, 인스턴스 메서들이 자동완성으로 뜬다&lt;/p&gt;
&lt;p&gt;이것은 버그가 아니라, 인스턴스 메서드 하나마다 대응되는 static 메서드가 생기기 때문이다.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;(사실 인스턴스 메서드란, 타입 메서드중 인스턴스를 인자로 받고, 인스턴스에 적용될 함수를 리턴하는 &lt;a href=&quot;https://sanichdaniel.tistory.com/36&quot;&gt;Currying&lt;/a&gt; 함수다)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;출처: &lt;a href=&quot;https://oleb.net/blog/2014/07/swift-instance-methods-curried-functions/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;oleb.net/blog/2014/07/swift-instance-methods-curried-functions/&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;이 static 메서드는 인자로 인스턴스를 받는다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1602668415862&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let closure = UIView.removeFromSuperview(view)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이 기능은 objective-c를 사용하는 target - action을 대체하는데 사용될수있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;해당 타입의 인스턴스 메서드를 리턴하는 typealias 선언.&lt;/p&gt;
&lt;pre id=&quot;code_1602668942859&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;typealias Action&amp;lt;Type, Input&amp;gt; = (Type) -&amp;gt; (Input) -&amp;gt; Void&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span&gt;&lt;/span&gt;ColorPicker는 target action을 추가할수 있는 함수가 있다. observations 변수에서 액션들을 클로져로 들고 있다.&lt;/p&gt;
&lt;p&gt;유저가 색깔을 선택하면 pickedColor 함수가 호출되고, 이 함수 내부에서 observations 어레이들을 실행시킨다&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1602669016391&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class ColorPicker: UIView {
    private(set) var selectedColor = UIColor.black
    private var observations = [(ColorPicker) -&amp;gt; Void]()

    func addTarget&amp;lt;T: AnyObject&amp;gt;(_ target: T,
                                 action: @escaping Action&amp;lt;T, ColorPicker&amp;gt;) {
        observations.append { [weak target] view in
            guard let target = target else {
                return
            }

            action(target)(view)
        }
    }
    
    func userPickedColor(color: UIColor) {
    	 selectedColor = color
         observations.forEach { $0(self) }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;* 위 코드는 아래와 같이 리팩토링 가능&lt;/p&gt;
&lt;pre id=&quot;code_1602669229262&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;observations.append { [weak target] view in
    target.map(action)?(view)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이제 뷰컨에서 ColorPicker에 대한 addTarget을 달아주자&lt;/p&gt;
&lt;pre id=&quot;code_1602669261785&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class CanvasViewController: UIViewController {
    private var drawingColor = UIColor.black

    func presentColorPicker() {
        let picker = ColorPicker()
        picker.addTarget(self, action: CanvasViewController.colorPicked)
        view.addSubview(picker)
    }

    private func colorPicked(using picker: ColorPicker) {
        drawingColor = picker.selectedColor
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이제 유저가 피커에서 색깔을 선택할때마다, 뷰컨의 인스턴스 함수 colorPicked 함수가 호출이된다!&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;출처&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.swiftbysundell.com/articles/first-class-functions-in-swift/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;www.swiftbysundell.com/articles/first-class-functions-in-swift/&lt;/a&gt;&lt;/p&gt;</description>
      <category>swift</category>
      <author>sanich8355</author>
      <guid isPermaLink="true">https://sanichdaniel.tistory.com/35</guid>
      <comments>https://sanichdaniel.tistory.com/35#entry35comment</comments>
      <pubDate>Wed, 14 Oct 2020 19:17:20 +0900</pubDate>
    </item>
  </channel>
</rss>