<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>JoonSwift</title>
    <link>https://joonswift.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Mon, 6 Jul 2026 08:19:46 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>JoonSwift</managingEditor>
    <item>
      <title>[Core Data] Delete Rule을 이해하고 적절하게 사용해보자!</title>
      <link>https://joonswift.tistory.com/47</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅에서는 제가 Core Data를 사용하여 Relationship을 만들 때, 항상 그냥 지나쳤던 Delete Rule에 대해서 이해하고, 이를 적절히 사용하는 방법에 대해 정리하려고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;NSDeleteRule&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 Delete Rule! 애플 공식 문서를 먼저 확인해보면 NSDeleteRule이라는 &lt;b&gt;Enumeration&lt;/b&gt;으로 정의되어 있는 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1674663531863&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;enum NSDeleteRule : UInt, @unchecked Sendable&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정의되어 있는 case들을 살펴보면&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;noActionDeleteRule&lt;/li&gt;
&lt;li&gt;nullifyDeleteRule&lt;/li&gt;
&lt;li&gt;cascadeDeleteRule&lt;/li&gt;
&lt;li&gt;denyDeleteRule&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모두 Core Data의 model editor에서 Relationship을 생성하고, 오른쪽의 Inspector에 Delete Rule을 눌러보면 확인할 수 있는 케이스들입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;296&quot; data-origin-height=&quot;84&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b2PBBk/btrW9lULeEe/8uaK0SKxDCYjtaYKlDThRK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b2PBBk/btrW9lULeEe/8uaK0SKxDCYjtaYKlDThRK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b2PBBk/btrW9lULeEe/8uaK0SKxDCYjtaYKlDThRK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb2PBBk%2FbtrW9lULeEe%2F8uaK0SKxDCYjtaYKlDThRK%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;296&quot; height=&quot;84&quot; data-origin-width=&quot;296&quot; data-origin-height=&quot;84&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나하나 살펴보겠습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Delete Rules&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;No Action&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫번째로 No Action 입니다. 이름처럼 아무 행동도 하지 않는 옵션입니다. 예를들어, A라는 객체와 B라는 객체 사이에 Relationship을 생성했다고 생각해보겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1248&quot; data-origin-height=&quot;352&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/el4NRC/btrXaDN13Uo/kia2fzPiN945f9EMGk5QXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/el4NRC/btrXaDN13Uo/kia2fzPiN945f9EMGk5QXK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/el4NRC/btrXaDN13Uo/kia2fzPiN945f9EMGk5QXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fel4NRC%2FbtrXaDN13Uo%2Fkia2fzPiN945f9EMGk5QXK%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;428&quot; height=&quot;121&quot; data-origin-width=&quot;1248&quot; data-origin-height=&quot;352&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;No Action으로 설정한 상태에서 여기서 A 라는 객체가 삭제된다면&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1248&quot; data-origin-height=&quot;352&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/A5mcf/btrXa2muiM5/TCFG91WCJk7J4Mrq10xmHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/A5mcf/btrXa2muiM5/TCFG91WCJk7J4Mrq10xmHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/A5mcf/btrXa2muiM5/TCFG91WCJk7J4Mrq10xmHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FA5mcf%2FbtrXa2muiM5%2FTCFG91WCJk7J4Mrq10xmHk%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;439&quot; height=&quot;124&quot; data-origin-width=&quot;1248&quot; data-origin-height=&quot;352&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런식으로 B는 존재하지 않는 A 객체를 가리키고 있을 것입니다. 그래서 애플 공식 문서에도, 만약 No Action인 Relationship에서 객체를 삭제한다면, &lt;b&gt;이를 참조하는 객체들을 꼭 삭제&lt;/b&gt; 해주거나, &lt;b&gt;반대 Relationship 객체들을 모두 Nullify로 설정&lt;/b&gt;하라고 적혀있습니다!&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Nullify&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 Nullify 입니다. Nullify가 default 이고, 제가 Delete rule을 모를 때 기본으로 놓고 사용했었던 옵션입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1248&quot; data-origin-height=&quot;352&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/laqr9/btrXa0oKmnD/v439uacgLvnVpjdNLhifk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/laqr9/btrXa0oKmnD/v439uacgLvnVpjdNLhifk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/laqr9/btrXa0oKmnD/v439uacgLvnVpjdNLhifk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Flaqr9%2FbtrXa0oKmnD%2Fv439uacgLvnVpjdNLhifk1%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;485&quot; height=&quot;137&quot; data-origin-width=&quot;1248&quot; data-origin-height=&quot;352&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아까의 이 Relationship에서 A라는 객체가 삭제되면, A라는 객체를 참조하고 있던 객체들은 이제 모두 참조하고 있던 A가 사라지게 되는것입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;448&quot; data-origin-height=&quot;352&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bNrJrs/btrXbsFld4K/TTDeCrQYiBk8gMQmqGxyz1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bNrJrs/btrXbsFld4K/TTDeCrQYiBk8gMQmqGxyz1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bNrJrs/btrXbsFld4K/TTDeCrQYiBk8gMQmqGxyz1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbNrJrs%2FbtrXbsFld4K%2FTTDeCrQYiBk8gMQmqGxyz1%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;171&quot; height=&quot;134&quot; data-origin-width=&quot;448&quot; data-origin-height=&quot;352&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림으로 나타낸다면.. A는 사라지고 B만 덩그러니 남은 그림이 될 수 있을 것 같습니다.&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Cascade&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 Cascade입니다. 이 옵션은 Relationship의 타겟이 &lt;b&gt;To One&lt;/b&gt; 일 때 정말 유용하게 사용될 수 있습니다. 예를들어, one-to-many Relationship이 있다고 가정해보겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1312&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6oaDC/btrXa3eCTdP/z9K8aFkZNFAOy1l9WsxkXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6oaDC/btrXa3eCTdP/z9K8aFkZNFAOy1l9WsxkXk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6oaDC/btrXa3eCTdP/z9K8aFkZNFAOy1l9WsxkXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6oaDC%2FbtrXa3eCTdP%2Fz9K8aFkZNFAOy1l9WsxkXk%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;309&quot; height=&quot;241&quot; data-origin-width=&quot;1312&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래 one-to-many의 그림은 위와 같지 않겠지만, 이해하기 쉽게 이렇게 그려보았습니다. 만약 여기서 one에 해당하는 A객체를 삭제하면, Delete rule이 Cascade일 때,&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1312&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/chlFSY/btrW77CtqyG/JN6IZNEy8iZg9leFxItaY1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/chlFSY/btrW77CtqyG/JN6IZNEy8iZg9leFxItaY1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/chlFSY/btrW77CtqyG/JN6IZNEy8iZg9leFxItaY1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FchlFSY%2FbtrW77CtqyG%2FJN6IZNEy8iZg9leFxItaY1%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;268&quot; height=&quot;209&quot; data-origin-width=&quot;1312&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 A 객체를 참조하고 있던 B 객체들을 모두 제거할 수 있습니다. 만약 Nullify 옵션을 사용했다면, A가 제거되었을 때, 제거 된 A를 가리키고 있는 B가 남아있게 됩니다. 그러므로 이렇게 one-to-many와 같은 Relationship에서 유용하게 사용할 수 있는 옵션입니다!&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Deny&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 Deny 입니다. Deny는 실수를 방지하기 위한 Rule입니다. 만약에 지우려고 하는 Relationship의 객체를 다른 객체가 Relationship으로 참조하고 있다면, 이를 지울 수 없게 하는 Rule입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2048&quot; data-origin-height=&quot;352&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bTR18s/btrXaETHDeE/PH0awZj4ERdNBwoqvL1d91/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bTR18s/btrXaETHDeE/PH0awZj4ERdNBwoqvL1d91/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bTR18s/btrXaETHDeE/PH0awZj4ERdNBwoqvL1d91/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbTR18s%2FbtrXaETHDeE%2FPH0awZj4ERdNBwoqvL1d91%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;529&quot; height=&quot;91&quot; data-origin-width=&quot;2048&quot; data-origin-height=&quot;352&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 A와 B라는 객체의 Relationship, B와 C의 Relationship이 있다면, A와 B에서 B를 삭제하려고 하면, B와 C사이의 Relationship에서 C라는 객체가 아직 B를 참조하고 있기 때문에, 지우는것이 불가능해져, 실수로 삭제하는 것을 방지해줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;정리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅을 통해서 Delete rule 4가지에 대해서 살펴보았습니다. 디폴트인 Nullify가 어떤 의미인지도 살펴보았고, Cascade와 같이 유용한 Delete rule에 대해서도 이해하고, 다음부터 사용하면서, Core Data 숙련도를 조금 높이는 계기가 되는 포스팅이었습니다. ㅎㅎ&lt;/p&gt;</description>
      <category>CoreData</category>
      <author>JoonSwift</author>
      <guid isPermaLink="true">https://joonswift.tistory.com/47</guid>
      <comments>https://joonswift.tistory.com/47#entry47comment</comments>
      <pubDate>Thu, 26 Jan 2023 02:10:13 +0900</pubDate>
    </item>
    <item>
      <title>[AutoLayout] LayoutGuide 활용하기</title>
      <link>https://joonswift.tistory.com/46</link>
      <description>&lt;pre id=&quot;code_1672291409792&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@MainActor class UILayoutGuide : NSObject&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공식문서에 따르면 LayoutGuide는 AutoLayout과 상호 작용할 수 있는 직사각형 영역입니다. 이전에 'dummy view', 'placeholder view'와 같이 원하는 Layout을 위해 만들었던 View들 대신, 더 안전하고, 효율적인 직사각형 영역을 만들어주는 방식입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주로 사용해본 UIKit의 Layout Guide 들은 간단하게 살펴보고, 직접 UILayoutGuide를 만드는 것을 중점적으로 글을 작성하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;제공해주는 Layout Guides&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Safe Area layout guide&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 번째로 가장 많이 사용하고 있는 Safe Area layout guide입니다. navigation bar, tab bar, tool bar를 덮지 않는 영역이고, notch 또한 덮지 않는 영역을 제공해 주며, 아주 유용하게 사용되고 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Layout Margin guide&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이름에서 알 수 있듯 약간의 margin이 들어간 View를 배치할 수 있게 도와주는 Layout Guide입니다.&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Readable Content guide&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 Layout Guide는 글이 많은 앱에서 아주 유용하게 사용됩니다. 사람이 머리를 돌리지 않고 읽을 수 있는 글의 길이 까지만 보여줄 수 있게 View를 배치할 수 있게 도와주는 Layout Guide입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;직접 Layout Guide를 만들어보자&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 View 사이에 공간을 주는 Layout Guide를 직접 만들어 보겠습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 UILayoutGuide를 선언하고, 해당 Layout Guide에 가운데 공간을 줄 수 있게 constraint를 만들어줍니다.&lt;/p&gt;
&lt;pre id=&quot;code_1672293009501&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let space = UILayoutGuide()
view.addLayoutGuide(space)

space.widthAnchor.constraint(equalToConstant: 16).isActive = true
space.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 좌, 우에 있을 View를 만들어 constraint를 만들어 줍니다.&lt;/p&gt;
&lt;pre id=&quot;code_1672293096260&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;leftView.translatesAutoresizingMaskIntoConstraints = false
leftView.backgroundColor = .systemRed

rightView.translatesAutoresizingMaskIntoConstraints = false
rightView.backgroundColor = .systemBlue

view.addSubview(leftView)
view.addSubview(rightView)

NSLayoutConstraint.activate([
  leftView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
  leftView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
  leftView.trailingAnchor.constraint(equalTo: space.leadingAnchor),
  leftView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
  
  rightView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
  rightView.leadingAnchor.constraint(equalTo: space.trailingAnchor),
  rightView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
  rightView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
])&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 중요한 부분은&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;`leftView&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;trailingAnchor&lt;span&gt;.&lt;/span&gt;constraint&lt;span&gt;(&lt;/span&gt;equalTo&lt;span&gt;: space.&lt;/span&gt;leadingAnchor&lt;span&gt;)`&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;`rightView&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;leadingAnchor&lt;span&gt;.&lt;/span&gt;constraint&lt;span&gt;(&lt;/span&gt;equalTo&lt;span&gt;: space.&lt;/span&gt;trailingAnchor&lt;span&gt;)`&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 두 부분입니다. leftView의 trailing은 space의 leading, rightView의 leading은 space의 trailing에 걸어준 것을 확인할 수 있습니다. 실행하면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1179&quot; data-origin-height=&quot;2556&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ctdj1x/btrUSyONafc/q7hjLGHHVUmTvEWNMkeTbk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ctdj1x/btrUSyONafc/q7hjLGHHVUmTvEWNMkeTbk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ctdj1x/btrUSyONafc/q7hjLGHHVUmTvEWNMkeTbk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fctdj1x%2FbtrUSyONafc%2Fq7hjLGHHVUmTvEWNMkeTbk%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;167&quot; height=&quot;362&quot; data-origin-width=&quot;1179&quot; data-origin-height=&quot;2556&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 화면을 볼 수 있습니다!  &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;dummy view, placeholder view 대신에 UILayoutGuide를 사용해야하는 제일 큰 이유는 UILayoutGuide를 사용하면 View를 view hierarchy에 추가하지 않고도, 그 역할을 수행할 수 있기 때문인 것 같습니다. 이로 인해 dummy view를 그리는 비용도 감소하고, 실수도 줄일 수 있을 것 같습니다.&lt;/p&gt;</description>
      <category>iOS</category>
      <author>JoonSwift</author>
      <guid isPermaLink="true">https://joonswift.tistory.com/46</guid>
      <comments>https://joonswift.tistory.com/46#entry46comment</comments>
      <pubDate>Thu, 29 Dec 2022 14:58:47 +0900</pubDate>
    </item>
    <item>
      <title>Design Pattern, RxSwift ) RxFlow 맛보기 - 1</title>
      <link>https://joonswift.tistory.com/45</link>
      <description>&lt;h1&gt;RxFlow?&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RxFlow는 Reactive Flow Coordinator pattern을 기반으로 한 iOS 앱의 navigation framework입니다.&lt;/p&gt;
&lt;h1&gt;Why use RxFlow?&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Storyboard를 더 작은 단위로 잘라내어 UIViewController들의 reusability와 collaboration이 가능하도록 해줍니다.&lt;/li&gt;
&lt;li&gt;navigation context에 따라 UIViewController가 나타나는 방식을 다양하게 가져갈 수 있습니다.&lt;/li&gt;
&lt;li&gt;의존성 주입(Dependency Injection)을 편리하게 구현할 수 있습니다.&lt;/li&gt;
&lt;li&gt;UIViewController에서 모든 navigation과 관련된 코드를 없앨 수 있습니다.&lt;/li&gt;
&lt;li&gt;navigation 코드도 Reactive Programming이 가능하게 도와줍니다.&lt;/li&gt;
&lt;li&gt;주된 navigation case들을 addressing하면서 선언형 방식으로 navigation을 표현할 수 있습니다.&lt;/li&gt;
&lt;li&gt;앱을 논리적인 navigation 블록들로 쉽게 잘라낼 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Key concept&lt;/h1&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Flow : 각 Flow는 navigation action을 정의하는 부분입니다. ex ) UIViewController를 push 하거나 present하는 코드.&lt;/li&gt;
&lt;li&gt;Step : Step은 navigation의 상태를 정의하는 곳입니다. Flow와 Step을 조합해서 모든 navigation action을 표현할 수 있습니다.&lt;/li&gt;
&lt;li&gt;Stepper : Flow 내에 있는 Step을 생성(emit)할 수 있는 모든것입니다. (ViewModel이나 UIViewController)&lt;/li&gt;
&lt;li&gt;Presentable : presented될 수 있는 것을 추상화한 것입니다. (기본적으로 UIViewController와 Flow가 Presentable입니다.)&lt;/li&gt;
&lt;li&gt;FlowContributor : FlowCoordinator에게 Flow 내의 Step을 생성(emit)할 다음것이 무엇인지 알려줍니다.&lt;/li&gt;
&lt;li&gt;FlowCoordinator : 개발자가 Flow와 Step을 잘 조합해서 가능한 모든 navigation 경우의 수를 나타내었다면, FlowCoordinator은 이것들을 잘 종합하여 앱의 navigation을 핸들링 해줍니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Project&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;직접 만들어보면서 감을 잡아보도록 하겠습니다ㅎㅎ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 구조를 가진 앱을 만들어보도록 하겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;849&quot; data-origin-height=&quot;647&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dQd8xW/btrHFG6XUon/N0971cm521Vjkppew69L51/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dQd8xW/btrHFG6XUon/N0971cm521Vjkppew69L51/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dQd8xW/btrHFG6XUon/N0971cm521Vjkppew69L51/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdQd8xW%2FbtrHFG6XUon%2FN0971cm521Vjkppew69L51%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;668&quot; height=&quot;509&quot; data-origin-width=&quot;849&quot; data-origin-height=&quot;647&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Step 구현하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 현재 구현할 앱에서 가능한 navigation 상태들을 담아둘 Step을 만들어보겠습니다.&lt;/p&gt;
&lt;pre class=&quot;crystal&quot;&gt;&lt;code&gt;enum ExampleStep: Step {
  case launchIsRequired
  
  case mainIsRequired
  
  case homeIsRequired
  case mypageIsRequired
  
  case homeNext
  case mypageNext
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각각의 상태를 나타내보았습니다. 위에 그림에서도 보이듯, 6개의 화면을 6개의 case들로 나타내었습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Flow들 구현하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제일 처음 앱이 실행되면, Launch Screen을 보여줄지, Main Screen을 그대로 보여줄지 결정하는 Flow를 하나 생성합니다. 이름은 AppFlow라고 하겠습니다.&lt;/p&gt;
&lt;pre class=&quot;swift&quot;&gt;&lt;code&gt;final class AppFlow: Flow {
  private let window: UIWindow
  
  var root: Presentable {
    return self.window
  }
  
  init(window: UIWindow) {
    self.window = window
  }
  
  func navigate(to step: Step) -&amp;gt; FlowContributors {
    guard let step = step as? ExampleStep else { return .none }
    switch step {
    case .launchIsRequired:
      return navigateToLaunchScreen()
    case .mainIsRequired:
      return navigateToMainTabBar()
    default:
      return .none
    }
  }
  
  private func navigateToLaunchScreen() -&amp;gt; FlowContributors {
    let viewController = LaunchViewController()
    window.rootViewController = viewController
    return .one(flowContributor: .contribute(withNext: viewController))
  }
  
  private func navigateToMainTabBar() -&amp;gt; FlowContributors {
    // ...
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;AppFlow의 root는 UIWindow&lt;/b&gt;&lt;/span&gt;입니다. 앱이 실행되고, window의 rootViewController를 바꿔주며 보여줄것이기 때문에 root를 UIWindow로 정했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 AppFlow에서는 2가지의 Step에 따라 화면 전환이 일어납니다. launchIsRequired, mainIsRequired.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Launch Screen은 다른 Flow가 필요없이 LaunchViewController만 보여주고 끝날것이라. navigateToLaunchScreen 메서드를 위와같이 구현합니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;LaunchViewController&lt;/h2&gt;
&lt;pre class=&quot;swift&quot; data-ke-language=&quot;swift&quot;&gt;&lt;code&gt;final class LaunchViewController: UIViewController, Stepper {
  var steps = PublishRelay&amp;lt;Step&amp;gt;()
  
  //viewDidLoad ... 

  override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    DispatchQueue.main.asyncAfter(deadline: .now() + 3, execute: { [unowned self] in
      self.steps.accept(ExampleStep.mainIsRequired)
    })
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LaunchViewController는 Stepper입니다. 왜냐하면 아래의 viewDidAppear 메서드에서 특정 시간이 지난 후에, mainIsRequired 라는 Step을 emit할 것이기 때문에 Stepper입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저 코드가 실행되고 나면 다시 AppFlow의 navigate(to : ) 메서드에서 받아온 Step을 확인한 후 mainIsRequired라는 상태에 따라 코드를 실행하게 됩니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;AppFlow - navigateToMainTabBar()&lt;/h2&gt;
&lt;pre class=&quot;swift&quot;&gt;&lt;code&gt;private func navigateToMainTabBar() -&amp;gt; FlowContributors {
    let flow = MainFlow()
    let stepper = MainStepper()
    
    Flows.use(flow, when: .created, block: { [unowned self] root in
      self.window.rootViewController = root
    })
    
    return .one(flowContributor: .contribute(
      withNextPresentable: flow,
      withNextStepper: stepper
    ))
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MainFlow의 경우에는 이후에 또 다른 Navagation 로직이 존재하기때문에 MainFlow를 구현하고, MainStepper 또한 구현해놓은 모습입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Flows.use 메서드를 통해 넘겨준 flow(MainFlow)가 created되는 시점에 실행될 block (여기서는 window의 rootViewController를 해당 flow(MainFlow)의 root로 바꿔주는 코드를 작성해주었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 FlowContributor를 반환해주면서, 다음에 시작될 Flow와 그와 관련된 Stepper를 넘겨주는 코드를 확인할 수 있습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;MainFlow&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MainFlow에서는 주로 UITabBarController의 navigation 코드를 다룹니다.&lt;/p&gt;
&lt;pre class=&quot;swift&quot;&gt;&lt;code&gt;final class MainFlow: Flow {
  var root: Presentable {
    return self.tabBarController
  }
  
  private let tabBarController = UITabBarController()
  
  func navigate(to step: Step) -&amp;gt; FlowContributors {
    guard let step = step as? ExampleStep else { return .none }
    switch step {
    case .homeIsRequired:
      return navigateToHome()
    default:
      return .none
    }
  }
  
  private func navigateToHome() -&amp;gt; FlowContributors {
    let homeFlow = HomeFlow()
    let mypageFlow = MyPageFlow()
    
    let homeStepper = HomeStepper()
    let mypageStepper = MyPageStepper()
    
    Flows.use(
      homeFlow, mypageFlow,
      when: .created,
      block: { [unowned self] (root1: UINavigationController, root2: UINavigationController) in

        //Setup TabBar item and title...

        self.tabBarController.setViewControllers([root1, root2], animated: false)
      })
    return .multiple(flowContributors: [
      .contribute(
        withNextPresentable: homeFlow,
        withNextStepper: homeStepper
      ),
      .contribute(
        withNextPresentable: mypageFlow,
        withNextStepper: mypageStepper
      )
    ])
  }
}

class MainStepper: Stepper {
  var steps = PublishRelay&amp;lt;Step&amp;gt;()
  
  var initialStep: Step {
    return ExampleStep.homeIsRequired
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 제가 생각하는 중요한 부분은 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;MainStepper의 initialStep을 homeIsRequired로 준 점&lt;/b&gt;&lt;/span&gt;과, &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;HomeFlow, HomeStepper, MyPageFlow, MyPageStepper를 생성하여 FlowContributor를 multimple로 넘겨준 부분&lt;/b&gt;&lt;/span&gt;이 중요하게 봐야 할 부분이라고 생각합니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;HomeFlow, MyPageFlow&lt;/h2&gt;
&lt;pre class=&quot;swift&quot;&gt;&lt;code&gt;final class HomeFlow: Flow {
  var root: Presentable {
    return self.navigationController
  }
  
  private let navigationController = UINavigationController()
  
  func navigate(to step: Step) -&amp;gt; FlowContributors {
    guard let step = step as? ExampleStep else { return .none }
    
    switch step {
    case .homeIsRequired:
      return navigateToHome()
    case .homeNext:
      return navigateToNext()
    default:
      return .none
    }
  }
  
  private func navigateToHome() -&amp;gt; FlowContributors {
    let viewController = HomeViewController()
    viewController.title = &quot;Home&quot;
    navigationController.pushViewController(
      viewController, animated: false
    )
    return .one(flowContributor: .contribute(withNext: viewController))
  }
  
  private func navigateToNext() -&amp;gt; FlowContributors {
    // ...
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;swift&quot;&gt;&lt;code&gt;final class MyPageFlow: Flow {
  var root: Presentable {
    return self.navigationController
  }
  
  private let navigationController = UINavigationController()
  
  func navigate(to step: Step) -&amp;gt; FlowContributors {
    guard let step = step as? ExampleStep else { return .none }
    switch step {
    case .mypageIsRequired:
      return navigateToMyPage()
    case .mypageNext:
      return navigateToNext()
    default:
      return .none
    }
  }
  
  private func navigateToMyPage() -&amp;gt; FlowContributors {
    let viewController = MyPageViewController()
    viewController.title = &quot;My Page&quot;
    navigationController.pushViewController(
      viewController, animated: false
    )
    return .one(flowContributor: .contribute(withNext: viewController))
  }
  
  private func navigateToNext() -&amp;gt; FlowContributors {
    // ...
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HomeFlow, MyPageFlow 둘 다 root를 UINavigationController로 사용하고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 HomeStepper, MyPageStepper 에서&lt;/p&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;class HomeStepper: Stepper {
  var steps = PublishRelay&amp;lt;Step&amp;gt;()
  
  var initialStep: Step {
    return ExampleStep.homeIsRequired
  }
}

class MyPageStepper: Stepper {
  var steps = PublishRelay&amp;lt;Step&amp;gt;()
  
  var initialStep: Step {
    return ExampleStep.mypageIsRequired
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 initialStep을 통해 각각의 navigate(to:) 메서드에 있는 알맞는 Step에 대한 메서드를 호출하게 구현했습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;NextViewController&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Home과 MyPage에서 버튼을 누르면 각각 HomeNextViewController, MyPageNextViewController로 이동할 수 있도록 설계했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 과정에서 중요하게 봐야할 점은, HomeViewController, MyPageViewController에 있는 UIButton이 바로 Next로 navigate하는 Step을 제공한다는 것입니다. 즉, Step을 emit하는 HomeViewController, MyPageViewController 둘 다 Stepper가 되어야합니다.&lt;/p&gt;
&lt;pre class=&quot;swift&quot;&gt;&lt;code&gt;final class HomeViewController: UIViewController, Stepper {
  var steps = PublishRelay&amp;lt;Step&amp;gt;()
	// ...
	@objc func didTappedButton() {
	  self.steps.accept(ExampleStep.homeNext)
	}
}
final class MyPageViewController: UIViewController, Stepper {
  var steps = PublishRelay&amp;lt;Step&amp;gt;()
	// ... 
	@objc func didTappedButton() {
    self.steps.accept(ExampleStep.mypageNext)
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 HomeFlow와 MyPageFlow의 navigateToNext() 메서드에는 각각&lt;/p&gt;
&lt;pre class=&quot;swift&quot;&gt;&lt;code&gt;private func navigateToNext() -&amp;gt; FlowContributors {
  let viewController = HomeNextViewController()
  viewController.title = &quot;Home_Next&quot;
  navigationController.pushViewController(
    viewController, animated: true
  )
  return .none
}

private func navigateToNext() -&amp;gt; FlowContributors {
  let viewController = MyPageNextViewController()
  navigationController.present(
    viewController, animated: true
  )
  return .none
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ViewController를 생성하여 navigation action을 작성해주면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구조를 그림으로 그려보았습니다 ㅎㅎ&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;717&quot; data-origin-height=&quot;494&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b3IwrU/btrHFH5TxK4/FVcWDW1lilu8pgYnkuxnI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b3IwrU/btrHFH5TxK4/FVcWDW1lilu8pgYnkuxnI1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b3IwrU/btrHFH5TxK4/FVcWDW1lilu8pgYnkuxnI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb3IwrU%2FbtrHFH5TxK4%2FFVcWDW1lilu8pgYnkuxnI1%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;717&quot; height=&quot;494&quot; data-origin-width=&quot;717&quot; data-origin-height=&quot;494&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;360&quot; data-origin-height=&quot;640&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cVKjh5/btrHJZrkqUZ/3kVKs4oADEqq0cJGjPAJj1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cVKjh5/btrHJZrkqUZ/3kVKs4oADEqq0cJGjPAJj1/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cVKjh5/btrHJZrkqUZ/3kVKs4oADEqq0cJGjPAJj1/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/cVKjh5/btrHJZrkqUZ/3kVKs4oADEqq0cJGjPAJj1/img.gif&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; loading=&quot;lazy&quot; width=&quot;224&quot; height=&quot;398&quot; data-origin-width=&quot;360&quot; data-origin-height=&quot;640&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;정리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ViewController에 어떤 navigation action이 발생할 때, 거기서 ViewController를 생성하고, 어떻게 보여줄지 결정하는 로직을 작성했었는데, RxFlow, Coordinator pattern을 사용하니 ViewController에서 그러한 로직들을 분리할 수 있어서 보기 좋았던것 같습니다. ㅎㅎ&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 아직 RxFlow를 사용은 해봤는데 정확하게 내부에서 어떻게 동작하는지, 그리고 RxSwift에 대한 이해가 아직 부족해서 사용법을 알아내는데 오래 걸렸었습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Design Patterns</category>
      <author>JoonSwift</author>
      <guid isPermaLink="true">https://joonswift.tistory.com/45</guid>
      <comments>https://joonswift.tistory.com/45#entry45comment</comments>
      <pubDate>Tue, 19 Jul 2022 15:37:13 +0900</pubDate>
    </item>
    <item>
      <title>Setup Vulkan on VSCode and macOS</title>
      <link>https://joonswift.tistory.com/44</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Vulkan을 mac에서 사용해보고 싶어서 그리고 Xcode가 아닌 VSCode에서 사용하는 법을 포스팅해보려고 합니다. Vulkan tutorial에는 Xcode밖에 안나와서... 저는 VSCode로 하고싶어서 한번 시도해봤습니다 ㅎㅎㅎ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 GLFW, GLM 그리고 VulkanSDK를 다운 받은 상태라고 생각하여 진행하겠습니다. &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GLFW, GLM 설치법 (&lt;a href=&quot;https://vulkan-tutorial.com/Development_environment&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://vulkan-tutorial.com/Development_environment&lt;/a&gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VulkanSDK 설치 (&lt;a href=&quot;https://vulkan.lunarg.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://vulkan.lunarg.com/&lt;/a&gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Create workspace&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;278&quot; data-origin-height=&quot;144&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dHzeJP/btrFShOE2EV/tubV1iDoZQ5DKjqGnF2fI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dHzeJP/btrFShOE2EV/tubV1iDoZQ5DKjqGnF2fI1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dHzeJP/btrFShOE2EV/tubV1iDoZQ5DKjqGnF2fI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdHzeJP%2FbtrFShOE2EV%2FtubV1iDoZQ5DKjqGnF2fI1%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;278&quot; height=&quot;144&quot; data-origin-width=&quot;278&quot; data-origin-height=&quot;144&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 저는 VSCode에서 Vulkan_Blog라는 폴더를 생성했습니다. 그리고 main.cpp 파일도 하나 만들어주겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Set tasks.json args&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;656&quot; data-origin-height=&quot;311&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBFqAc/btrFT15p1pW/MtyH6cUN8lUi5ZNGyvvt60/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBFqAc/btrFT15p1pW/MtyH6cUN8lUi5ZNGyvvt60/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBFqAc/btrFT15p1pW/MtyH6cUN8lUi5ZNGyvvt60/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBFqAc%2FbtrFT15p1pW%2FMtyH6cUN8lUi5ZNGyvvt60%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;610&quot; height=&quot;289&quot; data-origin-width=&quot;656&quot; data-origin-height=&quot;311&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VSCode의 Terminal 메뉴에서 'Configure Default Build Task...' 를 선택해주면&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;610&quot; data-origin-height=&quot;260&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nOnHa/btrFTOLYN2k/DVsfJfDFWxWh1DtKGVIyEK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nOnHa/btrFTOLYN2k/DVsfJfDFWxWh1DtKGVIyEK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nOnHa/btrFTOLYN2k/DVsfJfDFWxWh1DtKGVIyEK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnOnHa%2FbtrFTOLYN2k%2FDVsfJfDFWxWh1DtKGVIyEK%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;610&quot; height=&quot;260&quot; data-origin-width=&quot;610&quot; data-origin-height=&quot;260&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 컴파일러들이 나오는데 저는 C/C++: clang++ 활성 파일 빌드를 선택해주겠습니다. 그럼 workspace 폴더의 .vscode가 생기고, tasks.json 파일이 들어있는것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;289&quot; data-origin-height=&quot;126&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LaJ4n/btrFT0rVbMj/JuhcbCTEFMpiAdnX3hIO00/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LaJ4n/btrFT0rVbMj/JuhcbCTEFMpiAdnX3hIO00/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LaJ4n/btrFT0rVbMj/JuhcbCTEFMpiAdnX3hIO00/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLaJ4n%2FbtrFT0rVbMj%2FJuhcbCTEFMpiAdnX3hIO00%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;289&quot; height=&quot;126&quot; data-origin-width=&quot;289&quot; data-origin-height=&quot;126&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 tasks.json 파일의 tasks 의 args에 다음을 추가해줍니다. 제일 처음은 c++17을 사용할 수 있게 설정합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1656310307030&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
	&quot;version&quot;: ...
    &quot;tasks&quot;: [
    	{
        	&quot;type&quot;: ...
            //...
            &quot;args&quot;: [
            	// ... 
                &quot;-std=c++17&quot;, // add!
                // ...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 homebrew로 다운받았던 GLFW, GLM의 경로를 설정해줍니다. 각각 include 와 lib 폴더의 경로를 args에 추가해주겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;homebrew에서 다운받은 것들의 경로는 arm64 구조에서 받았다면 /opt/homebrew에 아니라면 /usr/local에 있습니다!&lt;/p&gt;
&lt;pre id=&quot;code_1656310478452&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&quot;-I/opt/homebrew/include&quot;,
&quot;-L/opt/homebrew/lib&quot;,&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 다시 강조하지만 위의 경로는 &lt;b&gt;GLFW, GLM을 설치한 경로를 써주어야합니다!&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 VulkanSDK의 경로를 설정해줍니다. VulkanSDK역시 include, lib의 경로를 args에 추가합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1656310627324&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&quot;-I/Users/kimhojoon/VulkanSDK/1.3.216.0/macOS/include&quot;,
&quot;-L/Users/kimhojoon/VulkanSDK/1.3.216.0/macOS/lib&quot;,&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 라이브러리들을 링크해주는 작업이 필요합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;.dylib파일을 링크해줄 것인데, 이는 위의 GLFW, GLM을 다운받는 방법을 설명하는 웹사이트에서 Xcode설정을 할 때 하는&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;636&quot; data-origin-height=&quot;222&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yiVmX/btrFTN0DpMd/ZbvfDw4q5XUbO7kHKeJ9s0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yiVmX/btrFTN0DpMd/ZbvfDw4q5XUbO7kHKeJ9s0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yiVmX/btrFTN0DpMd/ZbvfDw4q5XUbO7kHKeJ9s0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyiVmX%2FbtrFTN0DpMd%2FZbvfDw4q5XUbO7kHKeJ9s0%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;533&quot; height=&quot;186&quot; data-origin-width=&quot;636&quot; data-origin-height=&quot;222&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 부분과 유사합니다. 방법은 간단합니다. 저 libglfw.3.x.dylib 파일, libvulkan.1.dylib, libvulkan.1.x.dylib 을 가져와주면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;역시 args에 추가해줍니다.&lt;/p&gt;
&lt;pre id=&quot;code_1656310865889&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&quot;/opt/homebrew/lib/libglfw.3.3.dylib&quot;,
&quot;/Users/kimhojoon/VulkanSDK/1.3.216.0/macOS/lib/libvulkan.1.dylib&quot;,
&quot;/Users/kimhojoon/VulkanSDK/1.3.216.0/macOS/lib/libvulkan.1.3.216.dylib&quot;,&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자! 이제 main.cpp에 (&lt;a href=&quot;https://vulkan-tutorial.com/Development_environment&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://vulkan-tutorial.com/Development_environment&lt;/a&gt;) 여기 사이트에 나와있는 예제 코드를 복사 붙여넣기 한다음에 build and run을 하면!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1915&quot; data-origin-height=&quot;975&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cZRqz0/btrFSXCrPD2/2w7oHenZiwQESD9lxEPzP0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cZRqz0/btrFSXCrPD2/2w7oHenZiwQESD9lxEPzP0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cZRqz0/btrFSXCrPD2/2w7oHenZiwQESD9lxEPzP0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcZRqz0%2FbtrFSXCrPD2%2F2w7oHenZiwQESD9lxEPzP0%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1915&quot; height=&quot;975&quot; data-origin-width=&quot;1915&quot; data-origin-height=&quot;975&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Vulkan window 라는 창이 뜨게됩니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;tasks.json 파일&lt;/p&gt;
&lt;pre id=&quot;code_1656311100509&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
	&quot;version&quot;: &quot;2.0.0&quot;,
	&quot;tasks&quot;: [
		{
			&quot;type&quot;: &quot;cppbuild&quot;,
			&quot;label&quot;: &quot;C/C++: clang++ 활성 파일 빌드&quot;,
			&quot;command&quot;: &quot;/usr/bin/clang++&quot;,
			&quot;args&quot;: [
				&quot;-std=c++17&quot;,
				&quot;-fdiagnostics-color=always&quot;,
				&quot;-g&quot;,
				&quot;${file}&quot;,
				&quot;-I/opt/homebrew/include&quot;,
				&quot;-L/opt/homebrew/lib&quot;,
				&quot;-I/Users/kimhojoon/VulkanSDK/1.3.216.0/macOS/include&quot;,
				&quot;-L/Users/kimhojoon/VulkanSDK/1.3.216.0/macOS/lib&quot;,
				&quot;/opt/homebrew/lib/libglfw.3.3.dylib&quot;,
				&quot;/Users/kimhojoon/VulkanSDK/1.3.216.0/macOS/lib/libvulkan.1.dylib&quot;,
				&quot;/Users/kimhojoon/VulkanSDK/1.3.216.0/macOS/lib/libvulkan.1.3.216.dylib&quot;,
				&quot;-o&quot;,
				&quot;${fileDirname}/${fileBasenameNoExtension}&quot;
			],
			&quot;options&quot;: {
				&quot;cwd&quot;: &quot;${fileDirname}&quot;
			},
			&quot;problemMatcher&quot;: [
				&quot;$gcc&quot;
			],
			&quot;group&quot;: {
				&quot;kind&quot;: &quot;build&quot;,
				&quot;isDefault&quot;: true
			},
			&quot;detail&quot;: &quot;컴파일러: /usr/bin/clang++&quot;
		}
	]
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Vulkan</category>
      <author>JoonSwift</author>
      <guid isPermaLink="true">https://joonswift.tistory.com/44</guid>
      <comments>https://joonswift.tistory.com/44#entry44comment</comments>
      <pubDate>Mon, 27 Jun 2022 15:27:24 +0900</pubDate>
    </item>
    <item>
      <title>Swift ) Two-Phase Initialization?</title>
      <link>https://joonswift.tistory.com/43</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅에서는 Swift의 Two-Phase Initialization에 대해서 알아보겠습니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1653628617523&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class SomeSubClass: SomeSuperClass {
  let someProperty: String
  
  init(someProperty: String) {
    super.init()
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제가 Two-Phase Initialization을 가장 많이 접할 수 있는 코드는 바로 위와 같이 코드를 작성할 때였습니다. 위의 코드를 작성하면 바로 문구가 하나 뜨는데 Property &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;'self.someProperty' not initialized at super.init call&lt;/b&gt;&lt;/span&gt; 이런 문구입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;과연 왜 self.someProperty가 super.init 호출 시점에 초기화되어있지 않다고 코드를 빌드조차 못하게 하는것일까?! 한번 알아보겠습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Two-Phase Initialization&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Swift의 Class initialization에는 two-phase 과정이 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Phase 1 : 어떤 class hierarchy의 아래에서 위까지 모든 저장 프로퍼티들을 초기화 하는 과정이 바로 Phase one입니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Phase 2 : 이제 각 클래스는 저장 프로퍼티들을 수정할 수 있는 상태가 되고, 메서드 호출 등 self를 통해 접근하는 프로퍼티, 메서드들을 사용할 수 있게 됩니다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 Two-Phase initialization 과정은 초기화되지 않은 프로퍼티들에 대한 접근을 막고, 다른 initializer로 부터 예상치 못하게 값이 변경되는 것을 방지하는 안전장치라고 할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 Class hierarchy에서 각각의 클래스를 유연하게 유지하면서, initialization 과정을 안전하게 만들어주기도 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;그래서 Swift 컴파일러는 Two-Phase Initialization을 위해 4개의 Safety check를 사용하고 있습니다.&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Safety check 1&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지정된 이니셜라이저는 해당 클래스에 존재하는 모든 프로퍼티들이 superclass의 이니셜라이저를 위임하기 전에 모두 초기화 해줘야 합니다. 이것이 바로 제일 처음에 보았던 오류입니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2204&quot; data-origin-height=&quot;794&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dRBtBM/btrDiqtmZ24/4bY5xN0FVpc7u2TSySusJ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dRBtBM/btrDiqtmZ24/4bY5xN0FVpc7u2TSySusJ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dRBtBM/btrDiqtmZ24/4bY5xN0FVpc7u2TSySusJ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdRBtBM%2FbtrDiqtmZ24%2F4bY5xN0FVpc7u2TSySusJ1%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;755&quot; height=&quot;272&quot; data-origin-width=&quot;2204&quot; data-origin-height=&quot;794&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;super.init을 호출하기 전에 현재 클래스에 존재하는 language, device에 대한 초기화를 먼저 진행해주어야 합니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1653629558693&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;init(name: String, age: Int, language: String, device: String){
  self.language = language
  self.device = device
  super.init(name: name, age: age)
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Safety check 2&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상속받은 프로퍼티에 대한 접근을 하기 이전에 superclass의 이니셜라이저를 delegate up! 해야합니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1653629687244&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Person {
  let name: String
  let age: Int
  
  init(name: String, age: Int) {
    self.name = name
    self.age = age
  }
}

class Developer: Person {
  let language: String
  let device: String
  
  init(name: String, age: Int, language: String, device: String){
    self.language = language
    self.device = device
    self.name // Error! 'self' used in property access 'name' before 'super.init' call
    super.init(name: name, age: age)
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 self.name 즉, 상속받은 Person 클래스의 프로퍼티인 name에 superclass의 초기화 이전에 접근하게 된다면, 컴파일러가 이를 발견하고 에러를 보여주게 됩니다.&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Safety check 3&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Convenience &lt;span style=&quot;background-color: #ffffff;&quot;&gt;initializer&lt;/span&gt;은 반드시 다른 이니셜라이저에게 delegate한 이후에! 프로퍼티에 접근해야 합니다. 즉,&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1653629911823&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  convenience init() {
    self.language // Error! 'self' used before 'self.init' call or assignment to 'self'
    self.init(name: &quot;Joonswift&quot;, age: 27, language: &quot;Swift&quot;, device: &quot;MacBook Pro 13 M1&quot;)
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;이렇게 self.init 즉, 다른 이니셜라이저에게 delegate 하기 전에 language 프로퍼티에 대한 접근을 시도할 시 Swift는 그럴수 없다고 말해줍니다.&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Safety check 4&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;First phase 즉 Phase one이 끝나기 전 까지는 어떤 메서드를 호출하지도, 인스턴스 프로퍼티들에 대한 값을 읽어오지도 못합니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1653630091523&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;init(name: String, age: Int, language: String, device: String){
    self.language = language
    self.device = device
    someMethod() // Error! 'self' used in method call 'someMethod' before 'super.init' call
    super.init(name: name, age: age)
    //Phase one end
    
    //Phase two start
    print(self.language)
    someMethod() // No error!
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 Phase One에 someMethod()를 호출하면 에러가 납니다. 반면에 Phase two에서 someMethod()를 호출하거나 language프로퍼티의 값에 접근하면 정상적으로 실행되는 것을 확인할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 4가지 Safety check을 바탕으로 한 Two-Phase Initialization의 실행 과정을 보겠습니다.&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Phase 1&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클래스의 designated or convenience 이니셜라이저를 호출합니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;해당 클래스에 대한 새로운 인스턴스가 생성되면서, 메모리에 할당하는데, 이 메모리는 초기화되지 않은 상태입니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;designated 이니셜라이저가 해당 클래스에 존재하는 모든 저장 프로퍼티가 초기화 되었고, 값이 있다는 것을 확인한 이후에 이 저장 프로퍼티들을 위한 메모리가 초기화됩니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;이 designated 이니셜라이저는 superclass에게 똑같은 작업을 하도록 넘겨주고 superclass 역시 똑같은 과정을 통해서 저장 프로퍼티들을 초기화 하여 메모리에 초기화 시킵니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;이것을 계속 반복해서 결국 class hierarchy의 상속 chain의 제일 최상위 class까지 도달하면 마지막 클래스가 모든 저장 프로퍼티들이 값이 있는지, 인스턴스의 메모리가 모두 초기화 되었는지를 확인하고 Phase 1을 끝냅니다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Phase 2&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이제 다시 위에서 아래로 내려가면서 각각의 designated 이니셜라이저는 인스턴스를 수정할 수 있는 옵션이 생깁니다. 이제 self에 접근하여 프로퍼티를 수정하고, 메서드를 호출하는 등의 권한을 얻게됩니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;마지막으로 Convenience 이니셜라이저 역시 인스턴스를 수정할 수 있고, self에 대한 접근이 가능하게 됩니다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;정리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;swift.org에 정말 그림이랑 잘 그려서 설명을 해 둔 부분인데, 미루고 미루다가 계속 코드를 작성하며 super.init 전에 프로퍼티들을 초기화 하지 않아 생기는 에러들을 그저 아무생각없이 초기화 시켜주고 이것이 Two-Phase initialization이라는 개념 때문에 그런지도 모르고 넘어왔었습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이번 기회에 &quot; 아 이게 Two-Phase Initialization 때문에 나오는 에러였구나~&quot; 라는 사실을 알고 속이 뻥 뚫리는 느낌입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결론 : 기초를 튼튼하게 다지자....&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.swift.org/swift-book/LanguageGuide/Initialization.html#:~:text=Two%2Dphase%20initialization%20prevents%20property,value%20by%20another%20initializer%20unexpectedly.&amp;amp;text=Swift's%20two%2Dphase%20initialization%20process,to%20initialization%20in%20Objective%2DC.&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://docs.swift.org/swift-book/LanguageGuide/Initialization.html#:~:text=Two%2Dphase%20initialization%20prevents%20property,value%20by%20another%20initializer%20unexpectedly.&amp;amp;text=Swift's%20two%2Dphase%20initialization%20process,to%20initialization%20in%20Objective%2DC.&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1653631424841&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Initialization &amp;mdash; The Swift Programming Language (Swift 5.6)&quot; data-og-description=&quot;Initialization Initialization is the process of preparing an instance of a class, structure, or enumeration for use. This process involves setting an initial value for each stored property on that instance and performing any other setup or initialization t&quot; data-og-host=&quot;docs.swift.org&quot; data-og-source-url=&quot;https://docs.swift.org/swift-book/LanguageGuide/Initialization.html#:~:text=Two%2Dphase%20initialization%20prevents%20property,value%20by%20another%20initializer%20unexpectedly.&amp;amp;text=Swift's%20two%2Dphase%20initialization%20process,to%20initialization%20in%20Objective%2DC.&quot; data-og-url=&quot;https://docs.swift.org/swift-book/LanguageGuide/Initialization.html#:~:text=Two%2Dphase%20initialization%20prevents%20property,value%20by%20another%20initializer%20unexpectedly.&amp;amp;text=Swift's%20two%2Dphase%20initialization%20process,to%20initialization%20in%20Objective%2DC.&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.swift.org/swift-book/LanguageGuide/Initialization.html#:~:text=Two%2Dphase%20initialization%20prevents%20property,value%20by%20another%20initializer%20unexpectedly.&amp;amp;text=Swift's%20two%2Dphase%20initialization%20process,to%20initialization%20in%20Objective%2DC.&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.swift.org/swift-book/LanguageGuide/Initialization.html#:~:text=Two%2Dphase%20initialization%20prevents%20property,value%20by%20another%20initializer%20unexpectedly.&amp;amp;text=Swift's%20two%2Dphase%20initialization%20process,to%20initialization%20in%20Objective%2DC.&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Initialization &amp;mdash; The Swift Programming Language (Swift 5.6)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Initialization Initialization is the process of preparing an instance of a class, structure, or enumeration for use. This process involves setting an initial value for each stored property on that instance and performing any other setup or initialization t&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.swift.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Swift</category>
      <category>SWIFT</category>
      <author>JoonSwift</author>
      <guid isPermaLink="true">https://joonswift.tistory.com/43</guid>
      <comments>https://joonswift.tistory.com/43#entry43comment</comments>
      <pubDate>Fri, 27 May 2022 15:05:26 +0900</pubDate>
    </item>
    <item>
      <title>CoreData ) Core Data stack에 대해서</title>
      <link>https://joonswift.tistory.com/42</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Core Data stack은 Core Data의 이점을 모두 가져가며 Core Data를 사용하기 위해 필수적으로 알아야 할 부분이라고 생각됩니다. 이번 포스팅에서는 Core Data stack을 이루고 있는 클래스들을 공식문서를 바탕으로 정리해보도록 하겠습니다!&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;우선 Core Data stack의 이해를 위해 정리해볼 클래스들을 나열해보자면,&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;NSManagedObjectModel&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;NSPersistentStoreCoordinator&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;NSPersistentStore&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;NSManagedObjectContext&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;NSPersistentContainer&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이정도가 있겠습니다. 하나하나 알아보도록 하겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;NSManagedObjectModel&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;NSManagedObjectModel, Core Data 앱 개발을 시작할 때, 보통 Data model 파일을 생성하면 .xcdatamodeld 파일을 생성하게 됩니다. 여기에 Entity들을 생성하고, attribute, relationship 등 여러 설정을 별도의 코드 작성 없이 할 수 있는데, 이 &lt;span style=&quot;color: #ef6f53;&quot;&gt;&lt;b&gt;.xcdatamodeld 파일을 programmatic하게 표현한 것이 바로 NSManagedObjectModel 클래스 입니다.&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;하나 혹은 여러개의 Entity를 가질 수 있고, Entity에는 프로퍼티들이 존재합니다. 이 프로퍼티들이 attributes, relationships 등을 나타내는 클래스들을 가지고 있습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;&lt;b&gt;NSManagedObjectModel을 데이터베이스의 Schema라고 생각&lt;/b&gt;&lt;/span&gt;하면 편합니다. 물론 Schema보다는 더 넓은 개념이라고 할 수 있습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Core Data stack의 나머지 부분들은 바로 이 Model을 가지고 Object들을 생성하거나, Property를 저장하고, 데이터를 저장소에 저장하는 과정을 거칩니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;NSPersistentCoordinator&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;NSPersistent Coordinator를 알아보기 이전에, NSPersistentStore 클래스를 먼저 알아보도록 하겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;NSPersistentStore&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;NSPersistentStore 클래스는 Core Data의 persistent store들을 모두 추상화해둔 클래스입니다. Core Data는 4개의 저장소를 제공하고 있는데, SQLite, Binary, XML(iOS에서는 사용 불가능), In-memory 이렇게 4가지를 가지고 있고, 이들은 각각 다음과 같은 상수로 제공됩니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;NSSQLiteStoreType : non-atomic store type으로, SQLiteDB를 사용하며, Xcode Core Data 템플릿에서 default로 사용되고 있는 방식입니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;NSXMLStoreType : atomic store type으로, XML 파일을 사용하는 타입입니다. iOS에서는 사용이 불가능하고, memory footprint가 어마어마합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;NSBinaryStoreType : atomic store type으로, Binary Data file을 사용합니다.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;NSInMemoryStoreType : atomic store type으로, 메모리를 사용하는 타입입니다. persistent라는 이름이 잘 어울리지 않게, 앱이 종료되거나, 기기를 꺼버리면 사라지는 형태이지만, 유닛 테스트, 캐싱에 유용하게 사용될 수 있는 타입입니다.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이제 다시 NSPersistentStoreCoordinator로 돌아오겠습니다. NSPersistentCoordinator의 역할은 Managed Object Model과 Persistent Store을 연결해주는 Bridge 역할을 하는 녀석입니다. 즉, 이 둘을 이어주어 뒤에 나올 NSManagedObjectContext를 도와주는 역할을 합니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;NSManagedObjectContext는 NSPersistentStoreCoordinator를 통해 Object graph를 persistent store에 저장할 수 있습니다. 쉽게 말해&lt;span style=&quot;color: #ef6f53;&quot;&gt;&lt;b&gt; NSPersistentStoreCoordinator는 Context와 Model, Persistent Store 사이에서 인터페이스 역할을 해주는 클래스입니다.&lt;/b&gt;&lt;/span&gt; 그렇기에 Coordinator는 Model을 이해하고, 어떻게 정보를 Persistent Store에게 보낼지, 어떤 Persistent Store에서 fetch해올지에 대해 알고있어야 합니다. 또한, 여러개의 Thread에서 Coordinator를 사용할 수는 없습니다. Coordinator는 operator들을 Serializatize하기 때문입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;NSManagedObjectContext&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NSManagedObjectContext는 Managed object들의 변화를 추적하고, 다루기 위한 object 공간입니다. Core Data를 다룰 때, 가장 많이 사용되는 클래스이기도 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NSManagedObjectContext는 메모리에서 Object의 변화를 관찰하고, 다양한 처리를 하는 기능을 담당하고 있습니다. 그렇기 때문에 우리가 Managed object에 어떤 변화를 주어도 context를 통해 save() 메서드를 호출하지 않으면, persistent store에는 아무련 영향을 주지 않는것입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 Context는 Object들의 Lifecycle을 관리합니다. 이 관리를 통해 Validation, inverse relationship handling과 같은 다양한 좋은 기능들을 할 수 있는 권한이 주어집니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 Context는 Thread-safe하지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;NSPersistentContainer&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NSPersistentConatiner는 Core Data stack을 캡슐화한 Container입니다. Core Data stack의 모든 요소들의 코드를 작성하는데에 들어가는 시간을 줄여주고, NSPersistentContainer를 선언하여, persistent store들을 load 해주면 끝나는 아주 편리한 클래스 입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1651820046636&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;private lazy var storeContainer: NSPersistentContainer = {
  let container = NSPersistentContainer(name: self.modelName)
  container.loadPersistentStores { _, error in
    if let error = error as NSError? {
    	//some error message!
    }
  }
  return container
}()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;이런식으로 사용될 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇게 제가 이해한바로 Core Data stack을 그림으로 나타내보면...&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Group 2.png&quot; data-origin-width=&quot;955&quot; data-origin-height=&quot;201&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/crBlqn/btrBqHp0bHX/ZqeYugJe3gBpas7IcZgTzk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/crBlqn/btrBqHp0bHX/ZqeYugJe3gBpas7IcZgTzk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/crBlqn/btrBqHp0bHX/ZqeYugJe3gBpas7IcZgTzk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcrBlqn%2FbtrBqHp0bHX%2FZqeYugJe3gBpas7IcZgTzk%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;955&quot; height=&quot;201&quot; data-filename=&quot;Group 2.png&quot; data-origin-width=&quot;955&quot; data-origin-height=&quot;201&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런식으로 구성되어 동작하는 것으로 이해했습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;정리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각각의 클래스에 대한 명확한 이해나 어떤 기능이 있는지에 대해 100% 이해하지는 못했지만, Core Data stack의 구성 클래스, 그들의 대략적인 역할, 흐름 등에 대해서 알아보는 포스팅을 작성하였습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;직접 만들어보며 정리하는 시간을 가져야겠습니다. ㅎㅎㅎ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고 문서&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.apple.com/documentation/coredata/core_data_stack&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://developer.apple.com/documentation/coredata/core_data_stack&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1651820811012&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Apple Developer Documentation&quot; data-og-description=&quot;&quot; data-og-host=&quot;developer.apple.com&quot; data-og-source-url=&quot;https://developer.apple.com/documentation/coredata/core_data_stack&quot; data-og-url=&quot;https://developer.apple.com/documentation/coredata/core_data_stack&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://developer.apple.com/documentation/coredata/core_data_stack&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.apple.com/documentation/coredata/core_data_stack&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Apple Developer Documentation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developer.apple.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제가 잘못이해하고있는 부분이나 틀린 부분이 있다면 댓글에 남겨주시면 정말 감사하겠습니다!  &lt;/p&gt;</description>
      <category>CoreData</category>
      <category>CoreData</category>
      <category>IOS</category>
      <category>SWIFT</category>
      <author>JoonSwift</author>
      <guid isPermaLink="true">https://joonswift.tistory.com/42</guid>
      <comments>https://joonswift.tistory.com/42#entry42comment</comments>
      <pubDate>Fri, 6 May 2022 16:08:17 +0900</pubDate>
    </item>
    <item>
      <title>CoreData ) NSSecureCoding (정말정말정말 간단하게 알아봄)</title>
      <link>https://joonswift.tistory.com/41</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;CoreData의 Transformable 타입을 알아보다가 NSSecureCoding이라는 녀석을 만나고 한번 살펴보다가 엄청난 Objective-C 개념들을 만나고 우선은 공식문서의 내용에 대해서만 정리하도록 마음먹었습니다.      &amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;NSSecureCoding?&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;A protocol that enables encoding and decoding in a manner that is robust against object substitution attacks.&lt;br /&gt;- Apple Developer Document -&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Object Substitution 공격에 맞서기 위한 강력한 Encoding, Decoding 방식을 가능하게하는 프로토콜입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;음.... 직접 코드로 작성하며 이 NSSecureCoding이라는 프로토콜을 채택해보았습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1651640060938&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class MyClass: NSSecureCoding {
  static var supportsSecureCoding: Bool
  
  var someClass: SomeClass
  
  // ... 

  func encode(with coder: NSCoder) {
  	// coder.encode(someClass, forKey: &quot;someClass&quot;)
  }

  required init?(coder: NSCoder) {
    // Decode here...
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NSSecureCoding 프로토콜을 채택하자 &lt;span style=&quot;color: #ef6f53;&quot;&gt;&lt;b&gt;supportsSecureCoding&lt;/b&gt;&lt;/span&gt;, &lt;span style=&quot;color: #ef6f53;&quot;&gt;&lt;b&gt;encode(with coder: )&lt;/b&gt;&lt;/span&gt;, &lt;span style=&quot;color: #ef6f53;&quot;&gt;&lt;b&gt;required init?(coder: )&lt;/b&gt;&lt;/span&gt; 이렇게 3가지를 필수적으로 구현해야하는 것들로 주어집니다. (encode(with coder: )와 required init?(coder: )는 &lt;b&gt;NSCoding&lt;/b&gt;의 메서드입니다.)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;supportsSecureCoding : 이 static 프로퍼티는 이름에서도 알 수 있듯, 이 클래스가 SecureCoding을 지원하느냐 에 대한 Boolean 값을 나타내는 프로퍼티입니다. 공식문서의 Discussion을 보면 Seucre Coding을 지원하는 Class를 작성할 때, 이 클래스 프로퍼티의 getter 반환 값이 &lt;span style=&quot;color: #409d00;&quot;&gt;&lt;b&gt;true&lt;/b&gt;&lt;/span&gt;임을 보장해야한다고 합니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;encode(with coder: ) : 파라미터로 받아온 coder를 활용하여 인스턴스 변수들을 Encoding 과정을 작성해야하는 메서드입니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;required init?(coder : ) : 인코딩한 object들(enclosed objects)을 decodeObjectOfClass: forKey: 메서드를 사용하여 반드시 디코딩 해주어야 합니다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 이 NSSecureCoding을 활용하면 아래와 같이 Object를 디코드 할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1651641362071&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class MyClass: NSObject, NSSecureCoding { 
 // ...
}

class SomeOtherClass {
  var myClass: MyClass?
  
  init(coder: NSCoder) {
    let object = coder.decodeObject(of: MyClass.self, forKey: &quot;myClass&quot;)
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대충 이런 형태로 구현될 수 있는듯합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NSSecureCoding이 아닌 NSCoding만 활용할 경우에는&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1651641894414&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if let obj = coder.decodeObject(forKey: &quot;myClass&quot;) as? MyClass {
      
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런식으로 as? MyClass를 활용하여 MyClass라는 타입을 타입캐스팅을 통해 가져옵니다. 이런 디코딩의 경우, 공식문서의 설명을 빌리자면, 클래스의 타입을 확인할 때, 이미 object가 생성된 상태이며, 만약 이것이 컬렉션 클래스의 일부라면, 잠재적으로 object graph에 삽입될 수도 있기에 안전하지 않은 방법이라고 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 Object가 생성되기 전에 클래스의 타입을 확정짓기 못하기 때문에 안전하지 않다는 결론으로 생각됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면에 위의 NSSecureCoding을 채택한다면, Object가 생성되기 전에, 클래스의 타입을 확정지을 수 있기 때문에 더 안전합니다.&amp;nbsp;&lt;/p&gt;
&lt;div&gt;이상으로 NSSecureCoding의 정의가 무엇인지, 왜 안전한지, 채택하면 필수적으로 구현해주어야 하는 메서드나 프로퍼티에 대해서 아~~~주 간단하게 알아보았습니다.&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;정리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내용이 조금 어려운것 같아 문서를 읽는 듯이 포스팅을 한것 같습니다. CoreData를 계속 공부하면서 더 알게되는 부분, Transformable 타입을 사용하면 NSSecureCoding에 대해서 새롭게 알게되는 부분이 나온다면 다시 정리하여 포스팅을 수정하는 시간을 가져야겠습니다 ㅎㅎ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고 자료&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.apple.com/documentation/foundation/nssecurecoding&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://developer.apple.com/documentation/foundation/nssecurecoding&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1651641282421&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Apple Developer Documentation&quot; data-og-description=&quot;&quot; data-og-host=&quot;developer.apple.com&quot; data-og-source-url=&quot;https://developer.apple.com/documentation/foundation/nssecurecoding&quot; data-og-url=&quot;https://developer.apple.com/documentation/foundation/nssecurecoding&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://developer.apple.com/documentation/foundation/nssecurecoding&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.apple.com/documentation/foundation/nssecurecoding&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Apple Developer Documentation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developer.apple.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래에 Conforming Types를 보면 정말 많은 타입들이 이 프로토콜을 준수하고있다는걸 확인할 수 있습니다 ㄷ ㄷ!!&lt;/p&gt;</description>
      <category>CoreData</category>
      <author>JoonSwift</author>
      <guid isPermaLink="true">https://joonswift.tistory.com/41</guid>
      <comments>https://joonswift.tistory.com/41#entry41comment</comments>
      <pubDate>Wed, 4 May 2022 14:36:51 +0900</pubDate>
    </item>
    <item>
      <title>Swift ) Designated Initializer, Convenience Initializer</title>
      <link>https://joonswift.tistory.com/40</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;Designated Initializer?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;designated initializer는 클래스의 기본적인 이니셜라이저입니다. 보통 클래스에서 이니셜라이저를 생성하면 작성하게 되는&lt;/p&gt;
&lt;pre id=&quot;code_1651474403585&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;init(parameters) {
  statements
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 형태를 가진 이니셜라이저를 designated initializer라고 합니다. 클래스는 상속이 가능하기에, 이 designated initializer는 정말 중요한 역할을 합니다. 바로 상위 클래스(super class)의 이니셜라이저를 delegate하는 역할을 수행할 때 사용하기 때문입니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1651474769520&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class User {
  let email: String
  let name: String
  let authority: String
  
  init(email: String, name: String, authority: String) {
    self.email = email
    self.name = name
    self.authority = authority
  }
}

class SpecialUser: User {
  init(greeting: String) {
    super.init(email: &quot;special@email.com&quot;, name: &quot;special&quot;, authority: &quot;user&quot;)
    print(greeting + &quot;I'm \(name)&quot;)
  }
}

let speicalUser = SpecialUser(greeting: &quot;Hi!&quot;) // Hi!I'm special&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SpecialUser 클래스는 User클래스의 subclass입니다. 그래서 이니셜라이저 코드에 super.init( ... ) 을 추가하여 해당 클래스의 superclass 즉, User 클래스의 이니셜라이저를 호출합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UIKit에서 대표적으로 정말 많이 보는 viewDidLoad(animated: )가 있습니다. 항상 viewDidLoad 메서드를 override할 때, super.viewDidLoad를 호출해왔는데, 이는 UIViewController 클래스에 선언되어있는, viewDidLoad 실행문을 실행시킨다는 의미와 같습니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Designated Pattern.png&quot; data-origin-width=&quot;276&quot; data-origin-height=&quot;356&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HQyhm/btrA5tk0V74/lcK6fgB5otxnHx3QeUol9k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HQyhm/btrA5tk0V74/lcK6fgB5otxnHx3QeUol9k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HQyhm/btrA5tk0V74/lcK6fgB5otxnHx3QeUol9k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHQyhm%2FbtrA5tk0V74%2FlcK6fgB5otxnHx3QeUol9k%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;184&quot; height=&quot;237&quot; data-filename=&quot;Designated Pattern.png&quot; data-origin-width=&quot;276&quot; data-origin-height=&quot;356&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Designated Initializer의 Initializer Delegation 형태는 위의 그림과 같습니다. 이는 Swift 공식문서의 'Initializer Delegation for Class Types' 파트에서 Initializer들 간의 관계에 대한 Rule을 정리해놓은 부분이 있는데,&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Rule 1&lt;br /&gt;A designated initializer must call a designated initializer from its immediate superclass.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 Rule에 해당하는 케이스라고 볼 수 있습니다. 어떤 클래스가 super class가 있다면, 그 super class의 designated initializer를 꼭 호출해주어야 한다는 룰입니다. (super class는 본인이 super class이므로 해당 룰에 적용되지 않습니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Convenience Initializer&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Convenience Initializer는 supporting initializer라고도 합니다. Convenience Initializer의 주된 역할은, 같은 클래스에 있는 Designated Initializer의 파라미터에 기본값(Default Value)를 주는 역할을 하거나 그 클래스의 인스턴스를 생성하여 특별한 용도로 사용하기도 합니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1651476008933&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;convenience init(parameters) {
  statement
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;init 앞에 convenience 를 붙여 사용합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아까 위의 예제에서 init 아래에 convenience init을 추가해보도록 하겠습니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1651476097435&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// In User class

  // init 
  
  convenience init(name: String) {
    var email: String = &quot;&quot;
    var authority: String = &quot;&quot;
    
    if name == &quot;admin&quot; {
      email = &quot;admin@email.com&quot;
      authority = &quot;Admin&quot;
    } else {
      fatalError(&quot;관리자가 아니면 name만으로 생성할 수 없습니다.&quot;)
    }
    
    self.init(email: email, name: name, authority: authority)
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;활용법은 다음과 같습니다. convenience initializer 내부에는 name이 admin인지 확인하여 email 과 authority에 값을 넣어 &lt;span style=&quot;color: #ef6f53;&quot;&gt;&lt;b&gt;self&lt;/b&gt;&lt;/span&gt;.init을 호출해주는 코드입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1651476189503&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let user = User(email: &quot;user@email.com&quot;, name: &quot;user&quot;, authority: &quot;user&quot;)
let admin = User(name: &quot;admin&quot;)
let notAdmin = User(name: &quot;notadmin&quot;) // Fatal Error!&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 admin 과 notAdmin은 convenience initializer를 통해 생성된 인스턴스입니다. notAdmin의 경우 fatalError 코드가 호출되는데 이는 convenience initializer에서 name이 &quot;admin&quot;이 아니라면 fatalError 코드를 실행하게 했기 때문입니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1651476383602&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;print(user.email) // user@email.com
print(admin.email) // admin@email.com&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Designated Pattern.png&quot; data-origin-width=&quot;470&quot; data-origin-height=&quot;356&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cKgEdJ/btrA5sGueVR/0z3qTNq9LAT7gWb8pwtrkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cKgEdJ/btrA5sGueVR/0z3qTNq9LAT7gWb8pwtrkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cKgEdJ/btrA5sGueVR/0z3qTNq9LAT7gWb8pwtrkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcKgEdJ%2FbtrA5sGueVR%2F0z3qTNq9LAT7gWb8pwtrkK%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;303&quot; data-filename=&quot;Designated Pattern.png&quot; data-origin-width=&quot;470&quot; data-origin-height=&quot;356&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Convenience Initializer는 옆으로(?) 가는 형태로 볼 수 있습니다. Swift.org에 나머지 Rule 2, 3에 대한 것도 확인해보겠습니다.&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Rule 2&lt;br /&gt;A convenience initializer must call another initializer from the&amp;nbsp;same&amp;nbsp;class.&lt;br /&gt;Rule 3&lt;br /&gt;A convenience initializer must ultimately call a designated initializer.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Convenience initializer는 반드시 &lt;b&gt;같은 클래스&lt;/b&gt;에 있는 다른 initializer를 호출해야 합니다. 이 다른 initializer는 Designated Initializer가 될 수도, Convenience Initializer가 될 수도 있습니다. 하지만 중요한건 &lt;span style=&quot;color: #ef6f53;&quot;&gt;&lt;b&gt;Same class!&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Rule 3는 Convenience initializer는 반드시 마지막에는 &lt;span style=&quot;color: #ef6f53;&quot;&gt;&lt;b&gt;Designated initializer를 호출&lt;/b&gt;&lt;/span&gt;해야 합니다. 즉, 옆으로 옆으로 Convenience initializer들을 타고 가다가도 마지막 화살표는 해당 클래스의 Designated Initializer를 향해야 한다는 의미입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;정리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에 영어로 Designated Initializer라는 표현이 처음 들어보는 표현이라 어색했었습니다. 항상 그냥 이니셜라이저라고 부르던 녀석이 Designated initializer라는 이름을 가지고 있었다니..&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Convenience initializer에 대해서도 알아가는 시간을 가졌습니다. 코드를 작성하면서 한번도 써보지 않아 어떤 역할을 하는 녀석인지 몰랐지만, 이번 포스팅을 통해 알게되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 Initializer Delegation이라는 표현과 Rule이 있다는 사실 또한 배워가는 좋은 포스팅이 되었습니다~&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고 문서&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.swift.org/swift-book/LanguageGuide/Initialization.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://docs.swift.org/swift-book/LanguageGuide/Initialization.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1651476911296&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Initialization &amp;mdash; The Swift Programming Language (Swift 5.6)&quot; data-og-description=&quot;Initialization Initialization is the process of preparing an instance of a class, structure, or enumeration for use. This process involves setting an initial value for each stored property on that instance and performing any other setup or initialization t&quot; data-og-host=&quot;docs.swift.org&quot; data-og-source-url=&quot;https://docs.swift.org/swift-book/LanguageGuide/Initialization.html&quot; data-og-url=&quot;https://docs.swift.org/swift-book/LanguageGuide/Initialization.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.swift.org/swift-book/LanguageGuide/Initialization.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.swift.org/swift-book/LanguageGuide/Initialization.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Initialization &amp;mdash; The Swift Programming Language (Swift 5.6)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Initialization Initialization is the process of preparing an instance of a class, structure, or enumeration for use. This process involves setting an initial value for each stored property on that instance and performing any other setup or initialization t&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.swift.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Swift</category>
      <author>JoonSwift</author>
      <guid isPermaLink="true">https://joonswift.tistory.com/40</guid>
      <comments>https://joonswift.tistory.com/40#entry40comment</comments>
      <pubDate>Mon, 2 May 2022 16:37:58 +0900</pubDate>
    </item>
    <item>
      <title>CoreData ) .xcdatamodeld?</title>
      <link>https://joonswift.tistory.com/39</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;.xcdatamodeld 파일&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CoreData를 활용하여 Data Model을 만들면 .xcdatamodeld 확장자를 가진 파일을 쉽게 찾아볼 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;26&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ewkwar/btrApmBLusl/5ul2LA41POp40r7upfras1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ewkwar/btrApmBLusl/5ul2LA41POp40r7upfras1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ewkwar/btrApmBLusl/5ul2LA41POp40r7upfras1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fewkwar%2FbtrApmBLusl%2F5ul2LA41POp40r7upfras1%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;300&quot; height=&quot;26&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;26&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅에서는 .xcdatamodeld 파일이 어떤 역할을 하는지에 대해 정리해보려고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;d 의 의미&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;.xcdatamodeld 에서 .xcdatamodel 이라면, datamodel 확장자 같은데, 뒤에 d가 하나 더 붙으면서 이 의미가 궁금해지게 만들고 있습니다. .xcdatamodel&lt;span style=&quot;color: #ef6f53;&quot;&gt;&lt;b&gt;d &amp;nbsp;&lt;/b&gt;&lt;/span&gt;에서 d의 의미는 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;document (Document Package) 라는 의미&lt;/b&gt;&lt;/span&gt;를 가지고 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(Document Package에 대한 설명은 아래의 참고문서에 남겨놓겠습니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 우리는 CoreData를 사용할 때, 이 Versioning을 지원하는 Managed Object Model을 사용하는데, 이 모델들이 파일 시스템에서 .xcdatamodeld 라는 document에 의해 보여집니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;What's in document?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;.xcdatamodeld document는 모델에 대한 version들을 그룹화 해놓은 파일 패키지 입니다. 이는 각각 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;.xcdatamodel 확장자를 가진 파일&lt;/b&gt;&lt;/span&gt;과, &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;모델에 대한 version 정보를 담은 Info.plist&lt;/b&gt;&lt;/span&gt;로 나타내어 집니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;297&quot; data-origin-height=&quot;78&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3udxo/btrAoIE5ARJ/0KYsdQZENKCCppXQOs6BLk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3udxo/btrAoIE5ARJ/0KYsdQZENKCCppXQOs6BLk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3udxo/btrAoIE5ARJ/0KYsdQZENKCCppXQOs6BLk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3udxo%2FbtrAoIE5ARJ%2F0KYsdQZENKCCppXQOs6BLk%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;297&quot; height=&quot;78&quot; data-origin-width=&quot;297&quot; data-origin-height=&quot;78&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 어떤 모델을 만들어 해당 모델에 대한 다른 version을 생성하면, 이렇게 .xcdatamodel 확장자를 가진 파일 2개가 .xcdatamodeld 패키지 안에 생성되는것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;정리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문서들을 읽으며 이해한바로는 &lt;b&gt;다양한 버전을 가질 수 있는 Managed Object Model의 관리가 복잡하고 여러울 수 있기 때문에, 이를 패키지화 하여 내부적으로 유연하게 관리해주는 역할&lt;/b&gt;을 하는 것이 .xcdatamodeld라고 이해했습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;.xcdatamodeld 패키지 안에는 여러 버전의 .xcdatamodel 파일들이 존재할 수 있고, 버전에 대한 정보 또한 가지고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고 문서&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.apple.com/library/archive/documentation/CoreFoundation/Conceptual/CFBundles/DocumentPackages/DocumentPackages.html#//apple_ref/doc/uid/10000123i-CH106&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://developer.apple.com/library/archive/documentation/CoreFoundation/Conceptual/CFBundles/DocumentPackages/DocumentPackages.html#//apple_ref/doc/uid/10000123i-CH106&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1650897559476&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Document Packages&quot; data-og-description=&quot;Document Packages If your document file formats are getting too complex to manage because of several disparate types of data, you might consider adopting a package format for your documents. Document packages give the illusion of a single document to users&quot; data-og-host=&quot;developer.apple.com&quot; data-og-source-url=&quot;https://developer.apple.com/library/archive/documentation/CoreFoundation/Conceptual/CFBundles/DocumentPackages/DocumentPackages.html#//apple_ref/doc/uid/10000123i-CH106&quot; data-og-url=&quot;https://developer.apple.com/library/archive/documentation/CoreFoundation/Conceptual/CFBundles/DocumentPackages/DocumentPackages.html#//apple_ref/doc/uid/10000123i-CH106&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://developer.apple.com/library/archive/documentation/CoreFoundation/Conceptual/CFBundles/DocumentPackages/DocumentPackages.html#//apple_ref/doc/uid/10000123i-CH106&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.apple.com/library/archive/documentation/CoreFoundation/Conceptual/CFBundles/DocumentPackages/DocumentPackages.html#//apple_ref/doc/uid/10000123i-CH106&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Document Packages&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Document Packages If your document file formats are getting too complex to manage because of several disparate types of data, you might consider adopting a package format for your documents. Document packages give the illusion of a single document to users&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developer.apple.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreDataVersioning/Articles/vmModelFormat.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreDataVersioning/Articles/vmModelFormat.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1650900720805&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Model File Format and Versions&quot; data-og-description=&quot;Model File Format and Versions A managed object model that supports versioning is represented in the filesystem by a .xcdatamodeld document. An .xcdatamodeld document is a file package (see Document Packages) that groups versions of the model, each represe&quot; data-og-host=&quot;developer.apple.com&quot; data-og-source-url=&quot;https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreDataVersioning/Articles/vmModelFormat.html&quot; data-og-url=&quot;https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreDataVersioning/Articles/vmModelFormat.html&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/deLJxF/hyN9WvmY9j/t3SSehgQz3aSYmMkD7E121/img.png?width=682&amp;amp;height=494&amp;amp;face=0_0_682_494,https://scrap.kakaocdn.net/dn/hVdBq/hyN9ZTcPjk/uzoMRo7XQDNblskhIF2PVK/img.png?width=650&amp;amp;height=509&amp;amp;face=0_0_650_509,https://scrap.kakaocdn.net/dn/fFxpO/hyObk9eD4s/k6sSs8M4qHekv2TTRfR4sk/img.png?width=682&amp;amp;height=494&amp;amp;face=0_0_682_494&quot;&gt;&lt;a href=&quot;https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreDataVersioning/Articles/vmModelFormat.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreDataVersioning/Articles/vmModelFormat.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/deLJxF/hyN9WvmY9j/t3SSehgQz3aSYmMkD7E121/img.png?width=682&amp;amp;height=494&amp;amp;face=0_0_682_494,https://scrap.kakaocdn.net/dn/hVdBq/hyN9ZTcPjk/uzoMRo7XQDNblskhIF2PVK/img.png?width=650&amp;amp;height=509&amp;amp;face=0_0_650_509,https://scrap.kakaocdn.net/dn/fFxpO/hyObk9eD4s/k6sSs8M4qHekv2TTRfR4sk/img.png?width=682&amp;amp;height=494&amp;amp;face=0_0_682_494');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Model File Format and Versions&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Model File Format and Versions A managed object model that supports versioning is represented in the filesystem by a .xcdatamodeld document. An .xcdatamodeld document is a file package (see Document Packages) that groups versions of the model, each represe&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developer.apple.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;</description>
      <category>CoreData</category>
      <author>JoonSwift</author>
      <guid isPermaLink="true">https://joonswift.tistory.com/39</guid>
      <comments>https://joonswift.tistory.com/39#entry39comment</comments>
      <pubDate>Tue, 26 Apr 2022 00:33:11 +0900</pubDate>
    </item>
    <item>
      <title>Swift ) Difference between components and split</title>
      <link>https://joonswift.tistory.com/38</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;저는 주로 백준 온라인 저지의 알고리즘 문제를 풀 때, split 메서드를 사용하여 인풋을 공백 단위로 받아오곤 했는데, components를 사용하는 방법도 있어 아래와 같이 두 가지 코드를 번갈아가며 사용했었습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1650346779026&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let input = readLine()?.split( ... )
let input = readLine()?.components( ... )&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅을 통해 두 메서드의 차이점을 한번 알아보도록 하겠습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;components return [String] split return [Substring]&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 눈에 띄게 확인할 수 있었던 차이점은 리턴타입입니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1650347583409&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;func components&amp;lt;T&amp;gt;(separatedBy separator: T) -&amp;gt; [String] where T : StringProtocol&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;components는 StringProtocol 의 타입인 T를 받아 [String]을 반환합니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1650347616659&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;func split(
	separator: Character,
	maxSplits: Int = Int.max, 
	omittingEmptySubsequences: Bool = true) -&amp;gt; [Substring]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면에 split은 [Substring]을 반환해주고 있는 모습을 확인할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;String and Substring&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Substring을 잘 이해하면, split을 사용할 때, components를 사용할 때의 이점을 잘 살릴 수 있겠다는 생각을 가지고 Substring에 대해서 알아보겠습니다.&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Substrings in Swift have most of the same methods as strings, which means you can work with substrings the same way you work with strings.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Swift.org 의 Substrings 부분을 보면 Substring에 대한 설명이 나옵니다. Swift의 Substrings은 string과 거의 동일한 메서드를 가지고 있고, 이는 string과 똑같이 활용할 수 있다는 의미라고 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;String과 동일하게 활용할 수 있는 Substring! 차이점도 아래에 나와있는 것을 확인할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;The difference between strings and substrings is that, as a performance optimization, a substring can reuse part of the memory that&amp;rsquo;s used to store the original string, or part of the memory that&amp;rsquo;s used to store another substring.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 제가 가장 흥미로웠던 구문은 &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;'a substring can reuse part of the memory that's used to store the original stirng'&lt;/b&gt;&lt;/span&gt; 입니다.&amp;nbsp; 원래의 string이 저장된 메모리를 재사용한다!&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 확인해보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1650348400053&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let base: String = &quot;This is base string&quot;

let componentString = base.components(separatedBy: &quot; &quot;)
let splitString = base.split(separator: &quot; &quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;base라는 String을 하나는 components로, 하나는 split으로 나누었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 base에 대한 정볼르 눈에 담아두겠습니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;772&quot; data-origin-height=&quot;188&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/buI8ni/btrzQoy2rm4/1fZF2xY7qnuUjYKxfQGc50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/buI8ni/btrzQoy2rm4/1fZF2xY7qnuUjYKxfQGc50/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/buI8ni/btrzQoy2rm4/1fZF2xY7qnuUjYKxfQGc50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbuI8ni%2FbtrzQoy2rm4%2F1fZF2xY7qnuUjYKxfQGc50%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;542&quot; height=&quot;132&quot; data-origin-width=&quot;772&quot; data-origin-height=&quot;188&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음은 componentString으로 가보겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;806&quot; data-origin-height=&quot;474&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cZfIhR/btrzMaWiyRd/K8PpZf8CPkkBwGH1FSjFGk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cZfIhR/btrzMaWiyRd/K8PpZf8CPkkBwGH1FSjFGk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cZfIhR/btrzMaWiyRd/K8PpZf8CPkkBwGH1FSjFGk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcZfIhR%2FbtrzMaWiyRd%2FK8PpZf8CPkkBwGH1FSjFGk%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;503&quot; height=&quot;296&quot; data-origin-width=&quot;806&quot; data-origin-height=&quot;474&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;components 메서드로 String을 나눈 결과는 base라는 String과 아무런 관련이 없습니다. 새로운 메모리 공간에 &quot;This&quot;, &quot;is&quot;, &quot;base&quot;, &quot;string&quot; 각각이 할당되고, 그것들의 배열을 만들어 낸 것을 확인할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 splitString! 이녀석을 한번 확인해보겠습니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;912&quot; data-origin-height=&quot;470&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cLZV83/btrzQYzOZpP/IDkHHP1uKGDsIykOfurtkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cLZV83/btrzQYzOZpP/IDkHHP1uKGDsIykOfurtkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cLZV83/btrzQYzOZpP/IDkHHP1uKGDsIykOfurtkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcLZV83%2FbtrzQYzOZpP%2FIDkHHP1uKGDsIykOfurtkK%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;538&quot; height=&quot;277&quot; data-origin-width=&quot;912&quot; data-origin-height=&quot;470&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어디서 많이 본 주소값이 있습니다. 바로 저 0x8000000100003eb0 이 주소! 아까 base의 StringObject가 담긴 주소값과 동일한 것을 확인할 수 있습니다. 이를 startIndex와 endIndex를 활용하여 Slice 즉, 잘라서 표시해주는 것을 알 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 부분에서 위에서 확인했던 Original String의 메모리 공간을 재사용 한다는것을 확인할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림으로 확인해보면 (그림을 잘 못그려서 미리 죄송합니다. ㅎㅎ)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;822&quot; data-origin-height=&quot;829&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/civvVX/btrzL9pykTA/VD7koZMdxScuUMlR0KKCj1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/civvVX/btrzL9pykTA/VD7koZMdxScuUMlR0KKCj1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/civvVX/btrzL9pykTA/VD7koZMdxScuUMlR0KKCj1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcivvVX%2FbtrzL9pykTA%2FVD7koZMdxScuUMlR0KKCj1%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;307&quot; height=&quot;310&quot; data-origin-width=&quot;822&quot; data-origin-height=&quot;829&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;751&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lrtOV/btrzPgadXe2/RH6Rl5JleKr3a2BC9Uv2bK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lrtOV/btrzPgadXe2/RH6Rl5JleKr3a2BC9Uv2bK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lrtOV/btrzPgadXe2/RH6Rl5JleKr3a2BC9Uv2bK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlrtOV%2FbtrzPgadXe2%2FRH6Rl5JleKr3a2BC9Uv2bK%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;395&quot; height=&quot;232&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;751&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 차이점이 있습니다. 위와 같은 특징 때문에 공식 문서에서 Substring은 String과 달리 해당 String을 활용하고 있을 때만 짧은 시간 그 String을 활용하여 어떤 작업을 할 때 사용할 수 있다고 합니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;However, unlike strings, you use substrings for only a short amount of time while performing actions on a string.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 이제 componentString과 splitString을 활용하여 새로운 String을 생성하면 어떤 결과가 나오는지 한번 확인해보겠습니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1650349644136&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let newString = String(splitString[0])
let componentsNewString = String(componentString[0])&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;newString은 splitString[0] 즉, &quot;This&quot; 라는 String을 새로운 String으로 가지게 됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;786&quot; data-origin-height=&quot;184&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/chQdjb/btrzL9iPjkr/R8t7B4JW5krT6yGcGGdOY0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/chQdjb/btrzL9iPjkr/R8t7B4JW5krT6yGcGGdOY0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/chQdjb/btrzL9iPjkr/R8t7B4JW5krT6yGcGGdOY0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FchQdjb%2FbtrzL9iPjkr%2FR8t7B4JW5krT6yGcGGdOY0%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;632&quot; height=&quot;148&quot; data-origin-width=&quot;786&quot; data-origin-height=&quot;184&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림으로 그려보면&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1189&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b0F00P/btrzRm8lJ0z/FV6nD7mKvIx8dcS2qwUzl0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b0F00P/btrzRm8lJ0z/FV6nD7mKvIx8dcS2qwUzl0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b0F00P/btrzRm8lJ0z/FV6nD7mKvIx8dcS2qwUzl0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb0F00P%2FbtrzRm8lJ0z%2FFV6nD7mKvIx8dcS2qwUzl0%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;490&quot; height=&quot;455&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;1189&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;newString이라는 새로운 String을 만들어 &quot;This&quot;를 참조하게 만드는 순간 Original String에서 벗어나 새로운 공간을 참조하게됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;정리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Substring은 기존의 String의 메모리 공간을 재사용 하여 문자열을 표현한다는 사실을 알게되었습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 실제 백준에서 사용하는 방법인 아래의 코드들&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1650350536145&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let componentInput = base.components(separatedBy: &quot; &quot;)
let splitInput = base.split(separator: &quot; &quot;).map({ String($0) })&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 둘 중 어떤 것이 더 성능에 좋은지? 에 대한 정답은 없는것 같다는 것이 저의 생각입니다. 결국 split도 Substring을 그대로 사용하지 않고 다시 map을 통해 String으로 변환하는 작업이 들어가므로 결국 똑같지 않을까? 라는 것이 저의 생각입니다. ㅎㅎㅎ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.swift.org/swift-book/LanguageGuide/StringsAndCharacters.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://docs.swift.org/swift-book/LanguageGuide/StringsAndCharacters.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1650350695941&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Strings and Characters &amp;mdash; The Swift Programming Language (Swift 5.6)&quot; data-og-description=&quot;Strings and Characters A string is a series of characters, such as &amp;quot;hello, world&amp;quot; or &amp;quot;albatross&amp;quot;. Swift strings are represented by the String type. The contents of a String can be accessed in various ways, including as a collection of Character values. Swi&quot; data-og-host=&quot;docs.swift.org&quot; data-og-source-url=&quot;https://docs.swift.org/swift-book/LanguageGuide/StringsAndCharacters.html&quot; data-og-url=&quot;https://docs.swift.org/swift-book/LanguageGuide/StringsAndCharacters.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.swift.org/swift-book/LanguageGuide/StringsAndCharacters.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.swift.org/swift-book/LanguageGuide/StringsAndCharacters.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Strings and Characters &amp;mdash; The Swift Programming Language (Swift 5.6)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Strings and Characters A string is a series of characters, such as &quot;hello, world&quot; or &quot;albatross&quot;. Swift strings are represented by the String type. The contents of a String can be accessed in various ways, including as a collection of Character values. Swi&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.swift.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(Substrings 파트)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 혼자 공부하면서 이해한 부분이니 혹시나 틀리거나 잘못 이해하고 있는 부분이 있다면 댓글로 알려주시면 감사하겠습니다!!&lt;/p&gt;</description>
      <category>Swift</category>
      <author>JoonSwift</author>
      <guid isPermaLink="true">https://joonswift.tistory.com/38</guid>
      <comments>https://joonswift.tistory.com/38#entry38comment</comments>
      <pubDate>Tue, 19 Apr 2022 15:46:14 +0900</pubDate>
    </item>
  </channel>
</rss>