<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>mila's journal</title>
    <link>https://mila00a.tistory.com/</link>
    <description>기술과 예술을 좋아하는 사람의 블로그</description>
    <language>ko</language>
    <pubDate>Sat, 11 Jul 2026 13:35:58 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>Mila00a</managingEditor>
    <image>
      <title>mila's journal</title>
      <url>https://tistory1.daumcdn.net/tistory/5040243/attach/c6da2a4ac49a4529b45be82773960a27</url>
      <link>https://mila00a.tistory.com</link>
    </image>
    <item>
      <title>개인프로젝트 - 5 (SwiftLint)</title>
      <link>https://mila00a.tistory.com/67</link>
      <description>&lt;h1&gt;SwiftLint 적용하기&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트에 SwiftLint를 적용합니다. 팀 프로젝트에서는 사용해 보았지만 실제로 제가 적용해 본 적은 없어서 한 번 해보려고 합니다.&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;a id=&quot;user-content-목표-달성&quot; style=&quot;color: #000000;&quot; href=&quot;https://github.com/Minkyeong-Ko/HearMyVoice/wiki/%235-SwiftLint-%EC%A0%81%EC%9A%A9-%EA%B3%BC%EC%A0%95#%EB%AA%A9%ED%91%9C-%EB%8B%AC%EC%84%B1&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;목표 달성&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공식 깃헙을 참고해 보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/realm/SwiftLint&quot;&gt;https://github.com/realm/SwiftLint&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1681741164954&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - realm/SwiftLint: A tool to enforce Swift style and conventions.&quot; data-og-description=&quot;A tool to enforce Swift style and conventions. Contribute to realm/SwiftLint development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/realm/SwiftLint&quot; data-og-url=&quot;https://github.com/realm/SwiftLint&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/hpsYI/hySkOSoge0/Uo7V5bLfiEk1lG85dCuKC0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/realm/SwiftLint&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/realm/SwiftLint&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/hpsYI/hySkOSoge0/Uo7V5bLfiEk1lG85dCuKC0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&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;GitHub - realm/SwiftLint: A tool to enforce Swift style and conventions.&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;A tool to enforce Swift style and conventions. Contribute to realm/SwiftLint development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;a id=&quot;user-content-swiftlint-란&quot; style=&quot;color: #000000;&quot; href=&quot;https://github.com/Minkyeong-Ko/HearMyVoice/wiki/%235-SwiftLint-%EC%A0%81%EC%9A%A9-%EA%B3%BC%EC%A0%95#swiftlint-%EB%9E%80&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;SwiftLint 란&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Swift 스타일과 컨벤션을 강화하기 위한 도구입니다. &amp;nbsp;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://github.com/github/swift-style-guide&quot;&gt;GitHub Swift Style Guide&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;의 규칙들을 느슨하게 따릅니다. Swift 커뮤니티에서 주로 받아들여지는 규칙들을 따르도록 하고 있습니다. 가장 인기있는 스타일 가이드 중 하나는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://github.com/raywenderlich/swift-style-guide&quot;&gt;Ray Wenderlich's Swift Style Guide&lt;/a&gt;가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한마디로 왜 쓰냐? 묻는다면 저는 &lt;b&gt;&amp;lsquo;개인프로젝트라고 내 맘대로 내 멋대로 코드 지저분하게 쓰게 될까봐&amp;rsquo;&lt;/b&gt; 쓰게 되었습니다.&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;&lt;a id=&quot;user-content-설치하기&quot; style=&quot;color: #000000;&quot; href=&quot;https://github.com/Minkyeong-Ko/HearMyVoice/wiki/%235-SwiftLint-%EC%A0%81%EC%9A%A9-%EA%B3%BC%EC%A0%95#%EC%84%A4%EC%B9%98%ED%95%98%EA%B8%B0&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;설치하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SPM으로 하고 싶었는데 공식문서에 나와 있지 않았고,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;homebrew&lt;/code&gt;로 다운받는 법이 먼저 나와있어서 정석대로 해보려고 합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1681741220126&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;brew install swiftlint&lt;/code&gt;&lt;/pre&gt;
&lt;div&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;a id=&quot;user-content-run-script-추가하기&quot; style=&quot;color: #000000;&quot; href=&quot;https://github.com/Minkyeong-Ko/HearMyVoice/wiki/%235-SwiftLint-%EC%A0%81%EC%9A%A9-%EA%B3%BC%EC%A0%95#run-script-%EC%B6%94%EA%B0%80%ED%95%98%EA%B8%B0&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;Run Script 추가하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앱 타겟에서 &lt;i&gt;Build Phases &amp;rarr; New Run Script Phase&lt;/i&gt; 수행&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;726&quot; data-origin-height=&quot;496&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dHuFZ9/btsaTZ37twW/xo7wmQRbUmA48DmjIPJgOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dHuFZ9/btsaTZ37twW/xo7wmQRbUmA48DmjIPJgOk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dHuFZ9/btsaTZ37twW/xo7wmQRbUmA48DmjIPJgOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdHuFZ9%2FbtsaTZ37twW%2Fxo7wmQRbUmA48DmjIPJgOk%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;363&quot; height=&quot;496&quot; data-origin-width=&quot;726&quot; data-origin-height=&quot;496&quot;/&gt;&lt;/span&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1681741252536&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export PATH=&quot;$PATH:/opt/homebrew/bin&quot;
if which swiftlint &amp;gt;/dev/null; then
    swiftlint
else
    echo &quot;warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint&quot;
fi&lt;/code&gt;&lt;/pre&gt;
&lt;div&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;&amp;nbsp;&lt;/span&gt;&lt;code&gt;homebrew&lt;/code&gt;로 설치한 경우에 M1 맥북이라면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;export PATH=&quot;$PATH:/opt/homebrew/bin&quot;&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;코드를 추가하지 않으면 아래와 같은 경고가 뜨기 때문에 꼭 해당 코드를 넣어주어야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;warning: SwiftLint not installed, download from&amp;nbsp;&lt;a href=&quot;https://github.com/realm/SwiftLint&quot;&gt;https://github.com/realm/SwiftLint&lt;/a&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;642&quot; data-origin-height=&quot;96&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lOn6s/btsaSTXmO3b/HJnkp9T70kGwjFNLGKAbmk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lOn6s/btsaSTXmO3b/HJnkp9T70kGwjFNLGKAbmk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lOn6s/btsaSTXmO3b/HJnkp9T70kGwjFNLGKAbmk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlOn6s%2FbtsaSTXmO3b%2FHJnkp9T70kGwjFNLGKAbmk%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;321&quot; height=&quot;96&quot; data-origin-width=&quot;642&quot; data-origin-height=&quot;96&quot;/&gt;&lt;/span&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;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;homebrew&lt;/code&gt;로 설치하면 특정 경로 - &amp;nbsp;&lt;code&gt;/opt/homebrew/bin&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;- 에 저장이 되기 때문에 Xcode에 알려주는 것입니다.&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;code&gt;SwiftLint&lt;/code&gt;는 컴파일러의 파싱 단계를 완료한 클린한 코드에 대해 유효하게 동작되도록 디자인되었다고 합니다. 따라서 컴파일 전에 실행하는 것 (Compile Sources 전에 위치시키는 것) 은 부정확한 결과를 도출해 낼 수도 있다고 합니다.&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;&lt;a id=&quot;user-content-린트-rules-적용하기&quot; style=&quot;color: #000000;&quot; href=&quot;https://github.com/Minkyeong-Ko/HearMyVoice/wiki/%235-SwiftLint-%EC%A0%81%EC%9A%A9-%EA%B3%BC%EC%A0%95#%EB%A6%B0%ED%8A%B8-rules-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;린트&lt;span&gt;&amp;nbsp;&lt;/span&gt;Rules 적용하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선&amp;nbsp;&lt;code&gt;.swiftlint.yml&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;파일을 추가해서 린트 규칙을 정의해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://green1229.tistory.com/249&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://green1229.tistory.com/249&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;figure id=&quot;og_1681741432585&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;SwiftLint&quot; data-og-description=&quot;안녕하세요. 그린입니다  이번 포스팅에서는 SwiftLint에 대해 뿌셔보겠습니다! 코드 컨벤션을 체크해주는 툴이 필요한 이유 우선 다들 동료 개발자와 협업을 하면서 코드 컨벤션을 맞춰가는 과&quot; data-og-host=&quot;green1229.tistory.com&quot; data-og-source-url=&quot;https://green1229.tistory.com/249&quot; data-og-url=&quot;https://green1229.tistory.com/249&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/Zozx9/hySkRn215t/bvwvckPOuubNCzWecw2meK/img.png?width=402&amp;amp;height=272&amp;amp;face=0_0_402_272,https://scrap.kakaocdn.net/dn/bnOFMx/hySiXpUqMY/UCQDtTDY8o4Lgp9ftgOei1/img.png?width=402&amp;amp;height=272&amp;amp;face=0_0_402_272,https://scrap.kakaocdn.net/dn/AI7Wl/hySi5VLWGn/sOz5verOzR9gQdkocdGqB1/img.png?width=1290&amp;amp;height=618&amp;amp;face=0_0_1290_618&quot;&gt;&lt;a href=&quot;https://green1229.tistory.com/249&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://green1229.tistory.com/249&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/Zozx9/hySkRn215t/bvwvckPOuubNCzWecw2meK/img.png?width=402&amp;amp;height=272&amp;amp;face=0_0_402_272,https://scrap.kakaocdn.net/dn/bnOFMx/hySiXpUqMY/UCQDtTDY8o4Lgp9ftgOei1/img.png?width=402&amp;amp;height=272&amp;amp;face=0_0_402_272,https://scrap.kakaocdn.net/dn/AI7Wl/hySi5VLWGn/sOz5verOzR9gQdkocdGqB1/img.png?width=1290&amp;amp;height=618&amp;amp;face=0_0_1290_618');&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;SwiftLint&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요. 그린입니다  이번 포스팅에서는 SwiftLint에 대해 뿌셔보겠습니다! 코드 컨벤션을 체크해주는 툴이 필요한 이유 우선 다들 동료 개발자와 협업을 하면서 코드 컨벤션을 맞춰가는 과&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;green1229.tistory.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 style=&quot;color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;위의 친절한 블로그 글을 참고해서 나름대로 설정했습니다.&lt;/p&gt;
&lt;p style=&quot;color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;저는 남은 할 일들을 &lt;code&gt;TODO&lt;/code&gt;로 정리해놨기 때문에 계속해서 노란 경고를 보고 자극이 될 수 있도록.. &lt;code&gt;TODO&lt;/code&gt; 워닝을 켜 놨습니다.ㅎㅎ&lt;/p&gt;
&lt;p style=&quot;color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;a id=&quot;user-content-오류-해결하기&quot; style=&quot;color: #000000;&quot; href=&quot;https://github.com/Minkyeong-Ko/HearMyVoice/wiki/%235-SwiftLint-%EC%A0%81%EC%9A%A9-%EA%B3%BC%EC%A0%95#%EC%98%A4%EB%A5%98-%ED%95%B4%EA%B2%B0%ED%95%98%EA%B8%B0&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;오류 해결하기&lt;/h3&gt;
&lt;p style=&quot;color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Xcode 14 버전 이후부터 일어나는 경고인 것 같은데, 아래와 같은 경고 문구가 뜰 겁니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Run script build phase 'Run Script' will be run during every build because it does not specify any outputs. To address this warning, either add output dependencies to the script phase, or configure it to run in every build by unchecking &quot;Based on dependency analysis&quot; in the script phase.&lt;/blockquote&gt;
&lt;p style=&quot;color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;code&gt;Run Script&lt;/code&gt;가 모든 빌드마다 수행된다. 이유는 &lt;code&gt;output&lt;/code&gt;을 특정하지 않고 있기 때문에. &lt;code&gt;script phase&lt;/code&gt;에 &lt;code&gt;output dependency&lt;/code&gt;들을 추가하거나 &lt;code&gt;script phase&lt;/code&gt;에서 &quot;Based on dependency analysis&quot; 체크를 해제함으로써 모든 빌드마다 수행되도록 할 수 있다.&lt;/i&gt;&lt;/p&gt;
&lt;p style=&quot;color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;hellip; 고 합니다.&lt;/p&gt;
&lt;p style=&quot;color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;관련해서는 아래의 깃헙 이슈 글들이 꽤나 활발했습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/realm/SwiftLint/issues/4015&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/realm/SwiftLint/issues/4015&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1681741476304&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;Xcode 14 introduces new run script build phase warning for SwiftLint &amp;middot; Issue #4015 &amp;middot; realm/SwiftLint&quot; data-og-description=&quot;New Issue Checklist Updated SwiftLint to the latest version I searched for existing GitHub issues Describe the bug Possibly somewhat of a duple of #2783, but Xcode 14 appears to emit a new warning ...&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/realm/SwiftLint/issues/4015&quot; data-og-url=&quot;https://github.com/realm/SwiftLint/issues/4015&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/heYsu/hySkOrjKLs/0bK5kybEXf3P4XqN2taxyK/img.png?width=1200&amp;amp;height=600&amp;amp;face=988_144_1059_222&quot;&gt;&lt;a href=&quot;https://github.com/realm/SwiftLint/issues/4015&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/realm/SwiftLint/issues/4015&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/heYsu/hySkOrjKLs/0bK5kybEXf3P4XqN2taxyK/img.png?width=1200&amp;amp;height=600&amp;amp;face=988_144_1059_222');&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;Xcode 14 introduces new run script build phase warning for SwiftLint &amp;middot; Issue #4015 &amp;middot; realm/SwiftLint&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;New Issue Checklist Updated SwiftLint to the latest version I searched for existing GitHub issues Describe the bug Possibly somewhat of a duple of #2783, but Xcode 14 appears to emit a new warning ...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.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;span&gt;&amp;nbsp;&lt;/span&gt;Based on dependency analysis&lt;span&gt;&amp;nbsp;&lt;/span&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;1112&quot; data-origin-height=&quot;148&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sFnCb/btsaRw9ENYT/0aZ3sPwlDWMvm8zSFxPAG1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sFnCb/btsaRw9ENYT/0aZ3sPwlDWMvm8zSFxPAG1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sFnCb/btsaRw9ENYT/0aZ3sPwlDWMvm8zSFxPAG1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsFnCb%2FbtsaRw9ENYT%2F0aZ3sPwlDWMvm8zSFxPAG1%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;556&quot; height=&quot;148&quot; data-origin-width=&quot;1112&quot; data-origin-height=&quot;148&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;그런데 그런 경우에는 위에서 번역한 내용대로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&lt;code&gt;Run Script&lt;/code&gt;가 모든 빌드마다 수행되기 때문에 계속해서 린트가 중복 실행되어 퍼포먼스 문제가 발생할 수도 있습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;쭉 글을 읽던 중 한 능력자 분의 코멘트를 발견했고, 친절히 예제 레포지터리까지 만들어 위의 경고도 없애고 성능 문제도 해결하는 방법을 설명해 주시는 것이었습니다..&lt;/p&gt;
&lt;p style=&quot;color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/steven851007/SwiftLint_build_phase_example&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/steven851007/SwiftLint_build_phase_example&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1681741503440&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - steven851007/SwiftLint_build_phase_example&quot; data-og-description=&quot;Contribute to steven851007/SwiftLint_build_phase_example development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/steven851007/SwiftLint_build_phase_example&quot; data-og-url=&quot;https://github.com/steven851007/SwiftLint_build_phase_example&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/LUzHu/hySi2EK5y0/VnvK3ajdGzxbwi67L2D0p1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/steven851007/SwiftLint_build_phase_example&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/steven851007/SwiftLint_build_phase_example&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/LUzHu/hySi2EK5y0/VnvK3ajdGzxbwi67L2D0p1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&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;GitHub - steven851007/SwiftLint_build_phase_example&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Contribute to steven851007/SwiftLint_build_phase_example development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.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;간단하게는 input-output 파일 사용함으로써 변경된 파일만 린트 적용해서 빌드 시간을 단축할 수 있다는 것이 글의 요지였습니다.&lt;/p&gt;
&lt;p style=&quot;color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;그래서 열심히 따라서 프로젝트 셋업을 했고 중간에 아래와 같은 오류가 나왔지만 또 그 아래의 링크로 해결했습니다.&lt;/p&gt;
&lt;p style=&quot;color: #1f2328; text-align: start;&quot; 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;1280&quot; data-origin-height=&quot;108&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lbl4E/btsaR0bDSIe/6hnhLo1ekCmYRdMj0GqeD1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lbl4E/btsaR0bDSIe/6hnhLo1ekCmYRdMj0GqeD1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lbl4E/btsaR0bDSIe/6hnhLo1ekCmYRdMj0GqeD1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Flbl4E%2FbtsaR0bDSIe%2F6hnhLo1ekCmYRdMj0GqeD1%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;782&quot; height=&quot;108&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;108&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;&lt;a href=&quot;https://es1015.tistory.com/447&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://es1015.tistory.com/447&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1681741520438&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Xcode] Build error Permission denied 해결 방법&quot; data-og-description=&quot;Xcode Build Error Permission denied 해결 방법 Xcode Build 중 Permission denied 에러 발생 Unity Project를 iOS용으로 export 한 후 Xcode에서 Build 시 오류가 발생하였습니다. 발생 에러 /Users/Library/Developer/Xcode/DerivedData/U&quot; data-og-host=&quot;es1015.tistory.com&quot; data-og-source-url=&quot;https://es1015.tistory.com/447&quot; data-og-url=&quot;https://es1015.tistory.com/447&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/kBXaq/hySi3XVIRC/YWkYYW3spfXSKYRhXPaxf0/img.png?width=650&amp;amp;height=115&amp;amp;face=0_0_650_115,https://scrap.kakaocdn.net/dn/ZXTtQ/hySkXu2Inp/mAWF1OI7MdVg1UalKb36VK/img.png?width=650&amp;amp;height=115&amp;amp;face=0_0_650_115,https://scrap.kakaocdn.net/dn/bhCNDA/hySi9jyFEI/KjZ5xndneSWPrrUaSOZWK1/img.jpg?width=500&amp;amp;height=500&amp;amp;face=0_0_500_500&quot;&gt;&lt;a href=&quot;https://es1015.tistory.com/447&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://es1015.tistory.com/447&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/kBXaq/hySi3XVIRC/YWkYYW3spfXSKYRhXPaxf0/img.png?width=650&amp;amp;height=115&amp;amp;face=0_0_650_115,https://scrap.kakaocdn.net/dn/ZXTtQ/hySkXu2Inp/mAWF1OI7MdVg1UalKb36VK/img.png?width=650&amp;amp;height=115&amp;amp;face=0_0_650_115,https://scrap.kakaocdn.net/dn/bhCNDA/hySi9jyFEI/KjZ5xndneSWPrrUaSOZWK1/img.jpg?width=500&amp;amp;height=500&amp;amp;face=0_0_500_500');&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;[Xcode] Build error Permission denied 해결 방법&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Xcode Build Error Permission denied 해결 방법 Xcode Build 중 Permission denied 에러 발생 Unity Project를 iOS용으로 export 한 후 Xcode에서 Build 시 오류가 발생하였습니다. 발생 에러 /Users/Library/Developer/Xcode/DerivedData/U&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;es1015.tistory.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;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Xcode &lt;code&gt;Scheme&lt;/code&gt;의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;pre-build&lt;/code&gt;를 사용해 특정 파일을 실행하고, 그 파일을 실행하면서 변경사항이 있는 파일만 린트를 적용할 수 있게 해 주고 &lt;code&gt;SwiftLint&lt;/code&gt;의 인풋/아웃풋 파일을 생성해 주면서 워닝을 없애주는구나 까지는 이해를 했는데..&lt;/p&gt;
&lt;p style=&quot;color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;자세한 내용은 아직 깊게 이해를 못해서 또 &lt;code&gt;TODO&lt;/code&gt;를 추가해야 겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;a id=&quot;user-content-남아있는-질문들&quot; style=&quot;color: #000000;&quot; href=&quot;https://github.com/Minkyeong-Ko/HearMyVoice/wiki/%235-SwiftLint-%EC%A0%81%EC%9A%A9-%EA%B3%BC%EC%A0%95#%EB%82%A8%EC%95%84%EC%9E%88%EB%8A%94-%EC%A7%88%EB%AC%B8%EB%93%A4&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;남아있는 질문들&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #1f2328; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;SwiftLint_build_phase_example&lt;/code&gt; 완벽히 이해하기!!&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;대답한 질문들&lt;/h3&gt;
&lt;p style=&quot;color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;없습니다.. 정말 조만간 날 잡아서 해결할 것입니다.&lt;/p&gt;
&lt;p style=&quot;color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #1f2328; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>iOS/프로젝트</category>
      <category>SwiftLint</category>
      <category>개인프로젝트</category>
      <author>Mila00a</author>
      <guid isPermaLink="true">https://mila00a.tistory.com/67</guid>
      <comments>https://mila00a.tistory.com/67#entry67comment</comments>
      <pubDate>Mon, 17 Apr 2023 23:32:08 +0900</pubDate>
    </item>
    <item>
      <title>Lv3 프로그래머스 퍼즐 조각 채우기 풀이 과정 (Swift)</title>
      <link>https://mila00a.tistory.com/66</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;개요&lt;/h2&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 data-ke-size=&quot;size16&quot;&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;h2 data-ke-size=&quot;size26&quot;&gt;문제 분석&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 이 문제는, 프로그래머스 고득점 Kit 모음의 DFS/BFS 카테고리에 속해 있고 Level 3이라 제겐 굉장히 고난이도인 문제였습니다.&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;문제: 퍼즐 조각 채우기&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-04-13 오후 11.35.10.png&quot; data-origin-width=&quot;1117&quot; data-origin-height=&quot;578&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ALYHF/btr91z0N6Sz/RXntvcVOFHLGhA1PruIG20/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ALYHF/btr91z0N6Sz/RXntvcVOFHLGhA1PruIG20/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ALYHF/btr91z0N6Sz/RXntvcVOFHLGhA1PruIG20/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FALYHF%2Fbtr91z0N6Sz%2FRXntvcVOFHLGhA1PruIG20%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;1117&quot; height=&quot;578&quot; data-filename=&quot;스크린샷 2023-04-13 오후 11.35.10.png&quot; data-origin-width=&quot;1117&quot; data-origin-height=&quot;578&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;요약&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왼쪽의 &lt;code&gt;game_board&lt;/code&gt;의 빈 칸에 오른쪽 &lt;code&gt;table&lt;/code&gt;에 있는 퍼즐 조각을 최대한 많이 넣어서, 총 몇 칸을 채울 수 있는지를 리턴하는 문제.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;조건&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;조각은 한 번에 하나씩 채워 넣습니다.&lt;/li&gt;
&lt;li&gt;조각을 회전시킬 수 있습니다.&lt;/li&gt;
&lt;li&gt;조각을 뒤집을 수는 없습니다.&lt;/li&gt;
&lt;li&gt;게임 보드에 새로 채워 넣은 퍼즐 조각과 인접한 칸이 비어있으면 안 됩니다&lt;/li&gt;
&lt;/ul&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;h3 data-ke-size=&quot;size23&quot;&gt;풀이 예상해 보기&lt;/h3&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 data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;제일 먼저 0과 1로만 되어 있는 table 배열에서 퍼즐 조각들을 식별하자&lt;/li&gt;
&lt;li&gt;그리고 퍼즐 조각들을 실제로 덩어리로 분리하자&lt;/li&gt;
&lt;li&gt;퍼즐 조각들을 회전해 가면서 퍼즐 조각들을 &lt;code&gt;game_board&lt;/code&gt;에 맞춰 보자&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1번에서는 dfs/bfs 를 사용할 수 있을 것 같고, 2번에서는 비교할 수 있을 작은 배열로 만들 수 있을 것 같았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3번에서는 배열을 회전하는 법, 전체 &lt;code&gt;game_board&lt;/code&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;h3 data-ke-size=&quot;size23&quot;&gt;1) &lt;code&gt;table&lt;/code&gt; 배열에서 퍼즐 조각들을 식별하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제일 먼저 &lt;code&gt;table&lt;/code&gt; 배열에서 퍼즐 조각들을 식별합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 근본 없는 야매 개발자로서 저는.. 제가 푼 방법이 확실히 dfs인지 확신이 없긴 하지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;stack을 사용해서 퍼즐을 식별할 때 까지 파고들었으니 dfs라고 생각..합니다..!&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;code&gt;table&lt;/code&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;/li&gt;
&lt;li&gt;반면 칸이 차 있는 경우 (퍼즐 조각의 일부인 경우) 에는 상/하/좌/우로 연결된 퍼즐 조각의 일부가 있는지 확인 후 있다면 해당 칸을 탐색할 수 있도록 &lt;code&gt;stack&lt;/code&gt;에 넣습니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;stack&lt;/code&gt;에서 꺼내진 요소들(퍼즐 조각에 해당하는 index들)은 &lt;code&gt;piece&lt;/code&gt;라는 배열에 넣음으로써 퍼즐 조각을 식별합니다.&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;즉 정리하자면,&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;stack&lt;/code&gt;에 들어가는 요소들 &amp;rarr; 퍼즐 조각의 일부이며 &lt;b&gt;탐색할 대상&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;piece&lt;/code&gt;에 들어가는 요소들 &amp;rarr; 이미 탐색이 완료되어 퍼즐 조각의 일부로 식별된 &lt;b&gt;인덱스&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;while&lt;/code&gt; 문이 종료되고 나면 (&lt;code&gt;stack&lt;/code&gt;이 비었다면) &amp;rarr; 퍼즐 조각 &lt;b&gt;하나&lt;/b&gt;가 식별됨&lt;/li&gt;
&lt;li&gt;&lt;code&gt;for&lt;/code&gt; 문이 종료되고 나면 &amp;rarr; &lt;b&gt;모든&lt;/b&gt; 퍼즐 조각들이 식별됨&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;이런 과정이라고 볼 수 있습니다.&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;풀이 코드&lt;/h4&gt;
&lt;pre class=&quot;swift&quot; data-ke-language=&quot;swift&quot;&gt;&lt;code&gt;func solution(_ game_board:[[Int]], _ table:[[Int]]) -&amp;gt; Int {

    // 전체 테이블의 크기
    var n = table.count
    
    // table에서 퍼즐 조각을 탐색한다
    var pieces = [[(Int, Int)]]() // 퍼즐 조각들을 담아놓을 곳
    var visited = Array(repeating: Array(repeating: false, count: n), count: n) // 방문 여부를 체크할 곳
    
    // table을 돌면서
    for i in 0..&amp;lt;table.count {
        for j in 0..&amp;lt;table.count {
            // 퍼즐이 없거나 이미 방문했다면 패스~
            if table[i][j] == 0 || visited[i][j] { continue }
            
            var stack = [(i, j)]    // 새로 탐색할 퍼즐이 들어가는 곳
            var piece = [(Int, Int)]()  // 퍼즐 조각들이 쌓이는 곳
            while !stack.isEmpty {
                var (a, b) = stack.removeFirst()
                visited[a][b] = true
                piece.append((a, b))
                
                // 상하좌우 확인 후 스택에 넣기
                let search = [(a-1, b), (a+1, b), (a, b-1), (a, b+1)]
                for (x, y) in search {
                    if x &amp;lt; 0 || y &amp;lt; 0 || x &amp;gt;= n || y &amp;gt;= n { continue }
                    if visited[x][y] || table[x][y] == 0 { continue }
                    stack.append((x, y))
                }
            }
            
            // 여기는 전체 퍼즐들이 모이는 곳
            pieces.append(piece)
        }
    }
    
    // ...


    return count
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2) &amp;lsquo;모든 퍼즐에 대해&amp;rsquo; 퍼즐 조각들을 작은 배열(덩어리)로 만들기&lt;/h3&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 data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;  앞선 퍼즐을 식별한 그 후의 과정&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;&lt;b&gt;반복문 1)&lt;/b&gt; 모든 퍼즐에 대해&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;반복문 2)&lt;/b&gt; 모든 모양(회전)에 대해&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;반복문 3)&lt;/b&gt; 모든 &lt;code&gt;game_board&lt;/code&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;따라서 지금은 반복문 1) 모든 퍼즐에 대해 반복문을 수행하면서, 해당 퍼즐들을 작은 배열로 만드는 과정에 있습니다.&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;그리고 그 과정은 아래와 같습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;퍼즐의 인덱스들의 최소, 최댓값을 활용하여 너비와 높이를 알아냅니다.&lt;/li&gt;
&lt;li&gt;그리고 퍼즐의 틀이 될 배열을 생성합니다.&lt;/li&gt;
&lt;li&gt;마지막으로 실제 퍼즐 정보를 반영합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;풀이 코드&lt;/h4&gt;
&lt;pre class=&quot;swift&quot; data-ke-language=&quot;swift&quot;&gt;&lt;code&gt;func solution(_ game_board:[[Int]], _ table:[[Int]]) -&amp;gt; Int {

    // ...
    
    var game_board_copy = game_board
    var count = 0

    // 반복문 1)
    // 퍼즐 조각들(을 나타내는 인덱스들)을 돌면서
    for piece in pieces {
        // 퍼즐의 크기 식별
        let sorted1 = piece.sorted{$0.1 &amp;lt; $1.1}
        let sorted2 = piece.sorted{$0.0 &amp;lt; $1.0}
        let width = sorted1.last!.1 - sorted1.first!.1 + 1
        let height = sorted2.last!.0 - sorted2.first!.0 + 1
        
        // 퍼즐 조각들을 실제 퍼즐(배열)으로 만들기 위한 배열(틀) 생성
        var pieceArray = Array(repeating: Array(repeating: 0, count: width), count: height)

        // 실제로 반영
        for (i, j) in piece {
            pieceArray[i-sorted2[0].0][j-sorted1[0].1] = 1
        }
            
        // ...
        
    }
    // 반복문 1)


    return count
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3) &amp;lsquo;모든 퍼즐에 대해&amp;rsquo; 배열을 90도 회전시키기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제의 조건을 보면 퍼즐을 회전시킬 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 퍼즐이 &lt;code&gt;game_board&lt;/code&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;4가지 회전의 경우가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;0도(360도), 90도, 180도, 270도 입니다.&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;2차원 배열을 90도를 회전하게 되면 규칙이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;row&lt;/code&gt;는 &lt;code&gt;column&lt;/code&gt; 값으로 그대로 교체되고, &lt;code&gt;column&lt;/code&gt; 값은 &lt;code&gt;row&lt;/code&gt; 인덱스의 반대값(최솟값이면 최댓값..)이 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 이 규칙을 활용해 &lt;code&gt;turn&lt;/code&gt; 함수를 구현하고, 이를 반복해서 사용했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;그리고 이제는 반복문 2) 모든 모양(회전)에 대해 탐색을 시작합니다.&lt;/blockquote&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;풀이 코드&lt;/h4&gt;
&lt;pre class=&quot;swift&quot; data-ke-language=&quot;swift&quot;&gt;&lt;code&gt;func solution(_ game_board:[[Int]], _ table:[[Int]]) -&amp;gt; Int {

    // ...
    
    // 퍼즐을 90도로 돌리는 함수
    func turn(_ w: Int, _ h: Int, _ originalArray: [[Int]]) -&amp;gt; [[Int]] {
        var tempArray = Array(repeating: Array(repeating: 0, count: h), count: w)
        for i in 0..&amp;lt;h {
            for j in 0..&amp;lt;w {
                if originalArray[i][j] == 1 {
                    tempArray[j][h-i-1] = 1
                }
            }
        }

        return tempArray
    }
    
    // ...
    
    // 반복문 1)
    // 퍼즐 조각들(을 나타내는 인덱스들)을 돌면서
    for piece in pieces {
        // ...
            
        // 90도, 180도, 270도로 회전시키기
        var turned90 = turn(width, height, pieceArray)
        var turned180 = turn(height, width, turned90)
        var turned270 = turn(width, height, turned180)
        
        var allAngles = [pieceArray, turned90, turned180, turned270]
        var stopLoop = false

        // 반복문 2)
        // 모든 모양(퍼즐)을 가지고 game_board 에 맞추어 본다
        for angle in allAngles {
            // ...
        }
        // 반복문 2)
        
    }
    // 반복문 1)


    return count
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4) &amp;lsquo;모든 &lt;code&gt;game_board&lt;/code&gt;의 빈 자리에 대해&amp;rsquo; 비교할 배열 만들기&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;이제는 반복문 3) 모든 &lt;code&gt;game_board&lt;/code&gt;의 빈 자리에 대해 퍼즐을 탐색할 차례입니다.&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;우선 퍼즐 조각들을 실제 &lt;code&gt;game_board&lt;/code&gt;와 비교할 수 있도록 &lt;code&gt;game_board&lt;/code&gt;를 부분 배열인 &lt;code&gt;subArray&lt;/code&gt;로 만들어 보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;/li&gt;
&lt;li&gt;퍼즐 조각의 최상단은 현재 &lt;code&gt;game_board&lt;/code&gt;의 &lt;code&gt;row&lt;/code&gt;, &lt;code&gt;column&lt;/code&gt; 인덱스가 되도록 합니다
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;i == row, j == column이 되어야 하기 때문에 &lt;code&gt;subArray[i-row+1][j-column+1] = 1&lt;/code&gt;&lt;/li&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;만약 퍼즐 말고 인접한 부분이 &lt;code&gt;game_board&lt;/code&gt; 배열을 벗어나면 채워진 것으로 처리합니다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;풀이 코드&lt;/h4&gt;
&lt;pre class=&quot;swift&quot; data-ke-language=&quot;swift&quot;&gt;&lt;code&gt;func solution(_ game_board:[[Int]], _ table:[[Int]]) -&amp;gt; Int {

    // ...

    // 반복문 1)
    // 퍼즐 조각들(을 나타내는 인덱스들)을 돌면서
    for piece in pieces {
        // ...
        
        // 반복문 2)
        // 모든 모양(퍼즐)을 가지고 game_board 에 맞추어 본다
        for angle in allAngles {
            // 퍼즐의 크기
            let h = angle.count, w = angle[0].count

            // 반복문 3) (3-1, 3-2)
            // 모든 game_board의 빈 자리에 대해 비교한다
            for row in 0..&amp;lt;n {
                for column in 0..&amp;lt;n {
                    // 비교할 수 있게 배열(틀)을 하나 만든다
                    var subArray = Array(repeating: Array(repeating: 0, count: w+2), count: h+2)
                    
                    // 안의 내용을 채운다
                    // (내부 반복문 - 1)
                    for i in row-1...row+h {
                        for j in column-1...column+w {
                            if (i &amp;gt;= 0 &amp;amp;&amp;amp; j &amp;gt;= 0 &amp;amp;&amp;amp; i &amp;lt; n &amp;amp;&amp;amp; j &amp;lt; n) {
                                // 퍼즐이 들어갈 수 없는 자리라면
                                if game_board_copy[i][j] == 1 {
                                    // 1로 설정
                                    subArray[i-row+1][j-column+1] = 1
                                }
                            } else {
                                // 만약에 배열을 벗어나도 1로 설정
                                subArray[i-row+1][j-column+1] = 1
                            }
                        }
                    }
                    // (내부 반복문 - 1)
                    
                    // ...
                    
                }
            }
            // 반복문 3) (3-1, 3-2)
            
        }
        // 반복문 2)
        
    }
    // 반복문 1)


    return count
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5) &amp;lsquo;모든 &lt;code&gt;game_board&lt;/code&gt;의 빈 자리에 대해&amp;rsquo; 실제 비교할 퍼즐 배열 (인접한 부분 포함) 만들기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 보았듯 중요한 것은 단순히 퍼즐 부분만 비교하는 것이 아니라, 인접한 부분이 비어 있지 않다는 것도 확인해야 한다는 것입니다. (조건 만족)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 처음엔 단순히 퍼즐만 비교해서 빈 칸에 맞춰지는지만 비교했다가, 조건의 존재를 깨닫고 굉장히 절망했던 기억이 납니다. &lt;s&gt;문제 조건을 잘 봐야 한다는 교훈..&lt;/s&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;아무튼 그래서 조건을 만족하기 위해 - 1) 인접한 칸들까지 표시하기 위해 배열 확장, 2) 인접한 칸들 식별 및 처리, 3) 실제 비교 - 이렇게 새로운 계획을 세웠습니다.&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;blockquote data-ke-style=&quot;style3&quot;&gt;  퍼즐과 인접한 칸들을 식별하는 법&lt;/blockquote&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-filename=&quot;IMG_2941.jpg&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;3024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d09U2q/btsafQ7AFGN/KJgSwequOHgzK5wQzq0iF0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d09U2q/btsafQ7AFGN/KJgSwequOHgzK5wQzq0iF0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d09U2q/btsafQ7AFGN/KJgSwequOHgzK5wQzq0iF0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd09U2q%2FbtsafQ7AFGN%2FKJgSwequOHgzK5wQzq0iF0%2Fimg.jpg&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;400&quot; data-filename=&quot;IMG_2941.jpg&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;3024&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안쪽의 빈 Z..? 모양은 퍼즐을 의미합니다. 그리고 반드시 비어있으면 안되는 인접한 칸들을 연필로 칠해 보았습니다. 이렇게 그림을 그리고 색을 칠하고 나니, 엇 이거 퍼즐 상하좌우로 움직이면 되는구나..? 하고 깨달았습니다.&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;b&gt;퍼즐을 상하좌우로 움직여 가면서 인접한 부분을 식별&lt;/b&gt;하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 처음은 퍼즐이 빈 상태 (모두 0) &amp;rarr; 상하좌우로 움직이며 채워진 모든 부분을 -1로 바꾸고 &amp;rarr; 마지막으로 실제 퍼즐 부분만 1로 변경하는 방식으로 하였습니다.&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;code&gt;game_board&lt;/code&gt;에 끼워넣는 데 성공하면 채워진 칸을 더해주어야 하기에, &lt;code&gt;blockCount&lt;/code&gt;를 미리 계산해 주었습니다.&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;풀이 코드&lt;/h4&gt;
&lt;pre class=&quot;swift&quot; data-ke-language=&quot;swift&quot;&gt;&lt;code&gt;func solution(_ game_board:[[Int]], _ table:[[Int]]) -&amp;gt; Int {

    // ...

    // 반복문 1)
    // 퍼즐 조각들(을 나타내는 인덱스들)을 돌면서
    for piece in pieces {
        // ...

        // 반복문 2)
        // 모든 모양(퍼즐)을 가지고 game_board 에 맞추어 본다
        for angle in allAngles {
            // ...

            // 반복문 3) (3-1, 3-2)
            // 모든 game_board의 빈 자리에 대해 비교한다
            for row in 0..&amp;lt;n {
                for column in 0..&amp;lt;n {
                    // ...
                    
                    // 인접한 부분 만들기 위해 빈 배열에
                    var largerArray = Array(repeating: Array(repeating: 0, count: w+2), count: h+2)
                                        
                                        // (내부 반복문 - 2)
                    // 인접, 안쪽 모두 1로 채워넣고
                    for i in 0..&amp;lt;h {
                        for j in 0..&amp;lt;w {
                            if angle[i][j] == 1 {
                                // 상, 하, 좌, 우
                                largerArray[i][j+1] = -1
                                largerArray[i+2][j+1] = -1
                                largerArray[i+1][j] = -1
                                largerArray[i+1][j+2] = -1
                            }
                        }
                    }
                    // (내부 반복문 - 2)
                                        
                    // (내부 반복문 - 3)
                    // 실제 퍼즐 부분만 1로 다시 처리하기
                    var blockCount = 0
                    for i in 0..&amp;lt;h {
                        for j in 0..&amp;lt;w {
                            if angle[i][j] == 1 {
                                largerArray[i+1][j+1] = 1
                                blockCount += 1
                            }
                        }
                    }
                    // (내부 반복문 - 3)

                    // ...
                    
                }
            }
            // 반복문 3) (3-1, 3-2)

        }
        // 반복문 2)
        
    }
    // 반복문 1)


    return count
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6) &amp;lsquo;모든 &lt;code&gt;game_board&lt;/code&gt;의 빈 자리에 대해&amp;rsquo; 실제 퍼즐 비교하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 마지막 과정입니다.. &lt;code&gt;subArray&lt;/code&gt;와 &lt;code&gt;largerArray&lt;/code&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;code&gt;subArray&lt;/code&gt;의 빈 자리에 들어갈 수 있어야 합니다.&lt;/li&gt;
&lt;li&gt;퍼즐의 인접한 부분은 비어 있지 않아야 합니다.&lt;/li&gt;
&lt;li&gt;위 조건들을 만족하지 않으면 퍼즐이 들어갈 수 없습니다.&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;만약 모든 퍼즐 조각들이 통과했으면 &lt;code&gt;count&lt;/code&gt;와 &lt;code&gt;game_board_copy&lt;/code&gt;를 업데이트 하고, 반복문을 종료합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;count&lt;/code&gt;는 지금까지 채워진 칸의 수, &lt;code&gt;game_board_copy&lt;/code&gt;는 지금까지 채워진 퍼즐들을 포함한 &lt;code&gt;game_board&lt;/code&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;여러 겹으로 중첩된 반복문들을 탈출하기 위해 Bool 값을 계속 활용하였는데, 별로 좋지 않은 방식인 것 같아 추후에는 꼭 보완하고 싶네요..ㅠ&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;h4 data-ke-size=&quot;size20&quot;&gt;풀이 코드&lt;/h4&gt;
&lt;pre class=&quot;swift&quot; data-ke-language=&quot;swift&quot;&gt;&lt;code&gt;func solution(_ game_board:[[Int]], _ table:[[Int]]) -&amp;gt; Int {

    // ...

    // 반복문 1)
    // 퍼즐 조각들(을 나타내는 인덱스들)을 돌면서
    for piece in pieces {
        // ...

        // 반복문 2)
        // 모든 모양(퍼즐)을 가지고 game_board 에 맞추어 본다
        for angle in allAngles {
            // ...

            // 반복문 3) (3-1, 3-2)
            // 모든 game_board의 빈 자리에 대해 비교한다
            for row in 0..&amp;lt;n {
                for column in 0..&amp;lt;n {
                    // ...

                    // subArray와 largerArray의 비교
                    var blockCanFit = true
                    var boardVisited = game_board_copy
                    
                    // (내부 반복문 - 4)
                    for i in 0..&amp;lt;h+2 {
                        for j in 0..&amp;lt;w+2 {
                            if largerArray[i][j] == 1 {
                                if subArray[i][j] == 1 {
                                    // 퍼즐이 들어가야 하는데 이미 차 있다
                                    blockCanFit = false
                                    break
                                } else {
                                    // 퍼즐이 들어갈 수 있다
                                    boardVisited[i+row-1][j+column-1] = 1
                                }
                            } else if largerArray[i][j] == -1 {
                                if subArray[i][j] == 0 {
                                    // 주변 공간은 이미 채워져 있어야 하는데 비어 있다
                                    blockCanFit = false
                                    break
                                }
                            }
                        }
                        
                        if !blockCanFit {
                            break
                        }
                    }
                    // (내부 반복문 - 4)

                    // 퍼즐이 통과했으면 count와 game_board_copy를 업데이트 하고, 반복문 종료
                    if blockCanFit {
                        count += blockCount
                        game_board_copy = boardVisited
                        stopLoop = true
                        break
                    }
                    
                }
                
                if stopLoop {
                    break
                }
                
            }
            // 반복문 3) (3-1, 3-2)
            
            if stopLoop {
                break
            }

        }
        // 반복문 2)
        
    }
    // 반복문 1)

    return count
}&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마무리하며&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주석 없이도 무려 160줄이 넘는 코드를 작성했습니다. 코딩테스트 트라우마가 있던 제가 이 문제를 포기하지 않고 끝까지 풀어냈다는 것만도 뿌듯하긴 합니다만..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 주석으로 일부러 써 보기도 했지만 진짜진짜 반복문이 많았네요. 3번 중첩에 내부 반복문이 4개고 심지어 안 센 외부 반복문까지.. 필히 개선해 보면 좋을 것 같지만 지금은 너무 지쳐서 지금 당장은 말고..!&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;&amp;nbsp;&lt;/p&gt;</description>
      <category>iOS/Swift</category>
      <category>Swift</category>
      <category>퍼즐 조각 채우기</category>
      <category>프로그래머스</category>
      <author>Mila00a</author>
      <guid isPermaLink="true">https://mila00a.tistory.com/66</guid>
      <comments>https://mila00a.tistory.com/66#entry66comment</comments>
      <pubDate>Fri, 14 Apr 2023 11:21:20 +0900</pubDate>
    </item>
    <item>
      <title>개인 프로젝트 기록 - 4 (MessageUI)</title>
      <link>https://mila00a.tistory.com/65</link>
      <description>&lt;h1&gt;메시지 전송 테스트&lt;/h1&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;a id=&quot;user-content-목표-달성&quot; style=&quot;color: #000000;&quot; href=&quot;https://github.com/Minkyeong-Ko/HearMyVoice/wiki/%234-MessageUI-%EA%B5%AC%ED%98%84-%EA%B3%BC%EC%A0%95#%EB%AA%A9%ED%91%9C-%EB%8B%AC%EC%84%B1&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;목표 달성&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;a id=&quot;user-content-messageui&quot; style=&quot;color: #000000;&quot; href=&quot;https://github.com/Minkyeong-Ko/HearMyVoice/wiki/%234-MessageUI-%EA%B5%AC%ED%98%84-%EA%B3%BC%EC%A0%95#messageui&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;MessageUI&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 문서를 살펴 보니 메시지 관련 두 프레임워크가 존재했습니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;Messages&lt;/code&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;MessageUI&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;였습니다. 살펴본 결과 앱에서 메시지를 전송하는 화면을 띄워야 하기 때문에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;MessageUI&lt;/code&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;&lt;a href=&quot;https://medium.com/@DevVenusK/swift-를-이용해-sms-를-보내보자-34555582f84c&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://medium.com/@DevVenusK/swift-를-이용해-sms-를-보내보자-34555582f84c&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1681280206312&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Swift 를 이용해 SMS 를 보내보자&quot; data-og-description=&quot;영화를 예매하거나, 공연을 예매할 때 우리는 예매내역을 문자로 전송을 할 수 있어요.&quot; data-og-host=&quot;medium.com&quot; data-og-source-url=&quot;https://medium.com/@DevVenusK/swift-를-이용해-sms-를-보내보자-34555582f84c&quot; data-og-url=&quot;https://medium.com/@DevVenusK/swift-%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%B4-sms-%EB%A5%BC-%EB%B3%B4%EB%82%B4%EB%B3%B4%EC%9E%90-34555582f84c&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bdnCPi/hySgnnbaYR/iikzg2dUyYU2VnKCWThXXK/img.png?width=788&amp;amp;height=1202&amp;amp;face=0_0_788_1202&quot;&gt;&lt;a href=&quot;https://medium.com/@DevVenusK/swift-를-이용해-sms-를-보내보자-34555582f84c&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://medium.com/@DevVenusK/swift-를-이용해-sms-를-보내보자-34555582f84c&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bdnCPi/hySgnnbaYR/iikzg2dUyYU2VnKCWThXXK/img.png?width=788&amp;amp;height=1202&amp;amp;face=0_0_788_1202');&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;Swift 를 이용해 SMS 를 보내보자&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;영화를 예매하거나, 공연을 예매할 때 우리는 예매내역을 문자로 전송을 할 수 있어요.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;medium.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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;a id=&quot;user-content-swiftui에서-viewcontroller-사용하기&quot; style=&quot;color: #000000;&quot; href=&quot;https://github.com/Minkyeong-Ko/HearMyVoice/wiki/%234-MessageUI-%EA%B5%AC%ED%98%84-%EA%B3%BC%EC%A0%95#swiftui%EC%97%90%EC%84%9C-viewcontroller-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;SwiftUI에서 ViewController 사용하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원하는 목표를 이루기 위해 사용자가 SMS/MMS 메시지를 구성하고 전송할 수 있도록 도와주는 뷰 컨트롤러인&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;MFMessageComposeViewController&lt;/code&gt;&lt;span&gt;&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://sarunw.com/posts/uiviewcontroller-in-swiftui/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://sarunw.com/posts/uiviewcontroller-in-swiftui/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1681280226076&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;How to use UIViewController in SwiftUI | Sarunw&quot; data-og-description=&quot;Learn how to use UIViewController as a SwiftUI view.&quot; data-og-host=&quot;sarunw.com&quot; data-og-source-url=&quot;https://sarunw.com/posts/uiviewcontroller-in-swiftui/&quot; data-og-url=&quot;https://sarunw.com/posts/uiviewcontroller-in-swiftui/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cVPmNR/hySgqjSStL/5t7hjzK6ED23dlCnKCgve1/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/bpxSj5/hySgkcUYGD/jVlRwlOkVU0Sjk8K2TMRW1/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675&quot;&gt;&lt;a href=&quot;https://sarunw.com/posts/uiviewcontroller-in-swiftui/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://sarunw.com/posts/uiviewcontroller-in-swiftui/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cVPmNR/hySgqjSStL/5t7hjzK6ED23dlCnKCgve1/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/bpxSj5/hySgkcUYGD/jVlRwlOkVU0Sjk8K2TMRW1/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675');&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;How to use UIViewController in SwiftUI | Sarunw&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Learn how to use UIViewController as a SwiftUI view.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;sarunw.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;div&gt;
&lt;pre id=&quot;code_1681280248036&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;struct MessageUIView: UIViewControllerRepresentable {
    typealias UIViewControllerType = MFMessageComposeViewController
    
    /// 뷰 컨트롤러의 인스턴스를 반환한다
    func makeUIViewController(context: Context) -&amp;gt; MFMessageComposeViewController {
        let vc = MFMessageComposeViewController()
        
        vc.recipients = [&quot;123456789&quot;]   // 메시지를 받을 사람
        vc.body = &quot;음성 메시지를 보내고 싶어요&quot; // 메시지 내용
        
        return vc
    }
    
    /// SwiftUI 뷰의 정보로 뷰 컨트롤러의 상태를 업데이트한다
    func updateUIViewController(_ uiViewController: MFMessageComposeViewController, context: Context) {
    }
}&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;SwiftUI에서 뷰 컨트롤러를 사용하기 위해서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;UIViewControllerRepresentable&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;이라는,&lt;span&gt;&amp;nbsp;&lt;/span&gt;UIKit의 view controller를&lt;span&gt;&amp;nbsp;&lt;/span&gt;SwiftUI&lt;span&gt;&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&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;ViewController&lt;/code&gt;를 사용할 건지 타입 명시합니다.&lt;/li&gt;
&lt;li&gt;필수 함수들을 구현합니다.
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;code&gt;makeUIViewController&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;함수는 뷰 컨트롤러의 인스턴스를 반환합니다. 이 함수 내에서 필요한 설정을 할 수 있는데, 저는 메시지 수령 정보와 텍스트 내용을 넣어 주었습니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;updateUIViewController&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;SwiftUI&lt;span&gt;&amp;nbsp;&lt;/span&gt;뷰의 정보로 뷰 컨트롤러의 상태를 업데이트합니다. 저는 딱히 필요하지 않은 것 같아 스킵하였습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;a id=&quot;user-content-swiftui에서-delegate-사용하기&quot; style=&quot;color: #000000;&quot; href=&quot;https://github.com/Minkyeong-Ko/HearMyVoice/wiki/%234-MessageUI-%EA%B5%AC%ED%98%84-%EA%B3%BC%EC%A0%95#swiftui%EC%97%90%EC%84%9C-delegate-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;SwiftUI에서 delegate 사용하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메시지 화면은 잘 떴는데, 취소 버튼을 눌러도 아무 반응이 없더라구요! 그래서 취소 / 전송 성공 / 오류 등등의 처리를 하기 위한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;MFMessageComposeViewControllerDelegate&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;를 사용해야 했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아 그리고&lt;span&gt;&amp;nbsp;&lt;/span&gt;SwiftUI에서 모달을 닫기 위해서&lt;span&gt;&amp;nbsp;&lt;/span&gt;UIKit에서 사용되는&lt;span&gt;&amp;nbsp;&lt;/span&gt;dismiss&lt;span&gt;&amp;nbsp;&lt;/span&gt;대신 전달받은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;isPresented&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;값을 바꾸는 방식을 사용하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1681280283657&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;struct MessageUIView: UIViewControllerRepresentable {
    @Binding var isPresented: Bool
    
    // ...

    typealias Coordinator = MessageCoordinator
    
    func makeUIViewController(context: Context) -&amp;gt; MFMessageComposeViewController {
        // ...
        
        vc.messageComposeDelegate = context.coordinator
        
        return vc
    }
    
    // ...

    /// makeCoordinator(): 뷰 컨트롤러의 변화를 SwiftUI에 알리기 위해 사용하는 커스텀 인스턴스
    func makeCoordinator() -&amp;gt; Coordinator {
        return MessageCoordinator(self)
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;@Binding&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;값으로 모달이 보여질지 여부를 나타내는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;isPresented&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;변수를 받습니다&lt;/li&gt;
&lt;li&gt;&lt;code&gt;makeUIViewController&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;에서 뷰 컨트롤러를 설정할 때,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;messageComposeDelegate&lt;/code&gt;을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;context&lt;/code&gt;의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;coordinator&lt;/code&gt;로 설정합니다.&lt;/li&gt;
&lt;li&gt;뷰 컨트롤러의 변화를&lt;span&gt;&amp;nbsp;&lt;/span&gt;SwiftUI에 알리기 위해 사용하는 커스텀 인스턴스인&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;makeCoordinator()&lt;/code&gt;는 우리가 불러줄 필요 없이 자동으로 호출이 되며 따라서 위에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;context.coordiantor&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;로 접근할 수 있게 됩니다.&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;이제 실제&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;Coordinator&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;를 구현합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1681280313793&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/// 메시지 전송 처리를 하기 위한 Coordinator
class MessageCoordinator: NSObject, MFMessageComposeViewControllerDelegate {
    
    var parent: MessageUIView

    init(_ parent: MessageUIView) {
        self.parent = parent
    }
    
    // TODO: 메시지 전송 처리
    func messageComposeViewController(_ controller: MFMessageComposeViewController, didFinishWith result: MessageComposeResult) {
        switch result {
            case .cancelled:
                print(&quot;cancelled&quot;)
                parent.isPresented = false
            case .sent:
                print(&quot;sent message:&quot;, controller.body ?? &quot;&quot;)
                parent.isPresented = false
            case .failed:
                print(&quot;failed&quot;)
                parent.isPresented = false
            @unknown default:
                print(&quot;unkown Error&quot;)
                parent.isPresented = false
            }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;parent&lt;/code&gt;로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;MessageUIView&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;를 받습니다. 이는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;parent&lt;/code&gt;의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;isPresent&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;값에 접근하기 위함입니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;messageComposeViewController&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;result&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;값에 따라 알맞은 처리를 해줍니다. 우선은 어떤 경우든 다 모달을 닫도록 구현했습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;a id=&quot;user-content-실제-메시지-화면-띄워보기&quot; style=&quot;color: #000000;&quot; href=&quot;https://github.com/Minkyeong-Ko/HearMyVoice/wiki/%234-MessageUI-%EA%B5%AC%ED%98%84-%EA%B3%BC%EC%A0%95#%EC%8B%A4%EC%A0%9C-%EB%A9%94%EC%8B%9C%EC%A7%80-%ED%99%94%EB%A9%B4-%EB%9D%84%EC%9B%8C%EB%B3%B4%EA%B8%B0&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;실제 메시지 화면 띄워보기&lt;/h3&gt;
&lt;pre id=&quot;code_1681280328763&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import SwiftUI
import MessageUI

struct TestMessageView: View {
    @State var isPresented = false
    
    var body: some View {
        Button(&quot;메시지를 보내고 싶다&quot;) {
            /// canSendText: 지금 디바이스가 메시지를 보낼 수 있는 상태인지 Bool 값 리턴
            guard MFMessageComposeViewController.canSendText() else {
                    print(&quot;메시지를 보낼 수 없습니다.&quot;)
                    return
            }
            isPresented = true
        }
        .sheet(isPresented: $isPresented) {
            MessageUIView(isPresented: $isPresented)
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;isPresented&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;값을 선언하고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;MessageUIView&lt;/code&gt;에 Binding으로 넘겨줍니다. 그리고 그 값에 따라 모달이 닫힘 / 열림이 결정됩니다.&lt;/li&gt;
&lt;li&gt;메시지를 보내기 전에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;MFMessageComposeViewController.canSendText&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;를 통해 메시지를 보낼 수 있는 상태인지 확인해야 합니다.
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;만약 메시지를 보낼 수 없는 경우엔&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;MFMessageComposeViewControllerTextMessageAvailabilityDidChange&lt;/code&gt; notification의 옵저버를 등록해서 메시지를 보낼 수 있는 상태로 변할 때 알 수 있다고 합니다. 그런데 Notification은 아직 익숙치 않아 나중에 해 봐야겠습니다..&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;버튼을 누르면 메시지 수령 번호와 텍스트가 적힌 아까 설정한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;MFMessageComposeViewController&lt;/code&gt;, 즉&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;MessageUIView&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;가 화면에 띄워집니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;a id=&quot;user-content-결과-화면&quot; style=&quot;color: #000000;&quot; href=&quot;https://github.com/Minkyeong-Ko/HearMyVoice/wiki/%234-MessageUI-%EA%B5%AC%ED%98%84-%EA%B3%BC%EC%A0%95#%EA%B2%B0%EA%B3%BC-%ED%99%94%EB%A9%B4&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;결과 화면&lt;/h3&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;2532&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkFGBt/btr9N0Qiojt/bicCB5qg3Y2ZoNN4lWakv0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkFGBt/btr9N0Qiojt/bicCB5qg3Y2ZoNN4lWakv0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkFGBt/btr9N0Qiojt/bicCB5qg3Y2ZoNN4lWakv0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkFGBt%2Fbtr9N0Qiojt%2FbicCB5qg3Y2ZoNN4lWakv0%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;250&quot; height=&quot;2532&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;2532&quot;/&gt;&lt;/span&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;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;MessageUI&lt;/code&gt;는 시뮬레이터로는 확인이 되지 않습니다. 꼭 실제 기기로 확인하세요.&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;br /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;a id=&quot;user-content-남아있는-질문들&quot; style=&quot;color: #000000;&quot; href=&quot;https://github.com/Minkyeong-Ko/HearMyVoice/wiki/%234-MessageUI-%EA%B5%AC%ED%98%84-%EA%B3%BC%EC%A0%95#%EB%82%A8%EC%95%84%EC%9E%88%EB%8A%94-%EC%A7%88%EB%AC%B8%EB%93%A4&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;남아있는 질문들&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사용하지 않은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;updateUIViewController&lt;/code&gt;의 역할이 정확히 무엇인지?&lt;/li&gt;
&lt;li&gt;메시지 전송 결과를 제대로 처리하는 법?&lt;/li&gt;
&lt;li&gt;Notification을 통해 메시지 전송 가능 상태를 아는 법?&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;a id=&quot;user-content-대답한-질문들&quot; style=&quot;color: #000000;&quot; href=&quot;https://github.com/Minkyeong-Ko/HearMyVoice/wiki/%234-MessageUI-%EA%B5%AC%ED%98%84-%EA%B3%BC%EC%A0%95#%EB%8C%80%EB%8B%B5%ED%95%9C-%EC%A7%88%EB%AC%B8%EB%93%A4&quot; aria-hidden=&quot;true&quot;&gt;&lt;/a&gt;대답한 질문들&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;없습니다.. 반성해야겠습니다. 한번 날을 잡아서 대답 못한 질문들을 대답해야겠네요.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&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;</description>
      <category>iOS/프로젝트</category>
      <category>ios</category>
      <category>MessageUI</category>
      <category>개인프로젝트</category>
      <author>Mila00a</author>
      <guid isPermaLink="true">https://mila00a.tistory.com/65</guid>
      <comments>https://mila00a.tistory.com/65#entry65comment</comments>
      <pubDate>Wed, 12 Apr 2023 15:24:35 +0900</pubDate>
    </item>
    <item>
      <title>클로저에서의 weak self &amp;mdash; 순환참조 (2)</title>
      <link>https://mila00a.tistory.com/64</link>
      <description>&lt;div style=&quot;color: #000000; text-align: start;&quot;&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://medium.com/@wannapple/arc%EB%A5%BC-%EA%B3%81%EB%93%A4%EC%9D%B8-%EC%88%9C%ED%99%98%EC%B0%B8%EC%A1%B0-1-cad827f21cbf&quot;&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/a&gt;&lt;/div&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://mila00a.tistory.com/63&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://mila00a.tistory.com/63&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1681278617346&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;ARC를 곁들인 순환참조 (1)&quot; data-og-description=&quot;혹은 순환참조를 곁들인 ARC&amp;hellip; ARC (Automatic Reference Counting) Swift에서 앱의 메모리를 관리하는 방법 간단하게는 자동으로 메모리를 관리해주는 녀석이라고 할 수 있다. 여기서 &amp;lsquo;메모리&amp;rsquo; 란? 우선 &quot; data-og-host=&quot;mila00a.tistory.com&quot; data-og-source-url=&quot;https://mila00a.tistory.com/63&quot; data-og-url=&quot;https://mila00a.tistory.com/63&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/R8DY4/hySe1F1N9i/TXoqzYJIHTFpOQ08Pxk6w0/img.png?width=800&amp;amp;height=437&amp;amp;face=0_0_800_437,https://scrap.kakaocdn.net/dn/dGKlPJ/hySgmhtJQF/nrvxlBVm20qe2ZP0Ihkfe0/img.png?width=800&amp;amp;height=437&amp;amp;face=0_0_800_437,https://scrap.kakaocdn.net/dn/mzTy8/hySeU7YMCe/sDLcdh77N4wY1DXfSSVG30/img.png?width=1400&amp;amp;height=1082&amp;amp;face=0_0_1400_1082&quot;&gt;&lt;a href=&quot;https://mila00a.tistory.com/63&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://mila00a.tistory.com/63&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/R8DY4/hySe1F1N9i/TXoqzYJIHTFpOQ08Pxk6w0/img.png?width=800&amp;amp;height=437&amp;amp;face=0_0_800_437,https://scrap.kakaocdn.net/dn/dGKlPJ/hySgmhtJQF/nrvxlBVm20qe2ZP0Ihkfe0/img.png?width=800&amp;amp;height=437&amp;amp;face=0_0_800_437,https://scrap.kakaocdn.net/dn/mzTy8/hySeU7YMCe/sDLcdh77N4wY1DXfSSVG30/img.png?width=1400&amp;amp;height=1082&amp;amp;face=0_0_1400_1082');&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;ARC를 곁들인 순환참조 (1)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;혹은 순환참조를 곁들인 ARC&amp;hellip; ARC (Automatic Reference Counting) Swift에서 앱의 메모리를 관리하는 방법 간단하게는 자동으로 메모리를 관리해주는 녀석이라고 할 수 있다. 여기서 &amp;lsquo;메모리&amp;rsquo; 란? 우선&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;mila00a.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;6b45&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;오래 걸렸다. 위 1편에 이어 드디어 순환참조에 대한 두번째이자 마무리 글이다.&lt;/p&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;f9f6&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;원래 궁금했던 내용인&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;왜 클로저 안에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;b&gt;[weak self]&lt;/b&gt;&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;를 사용해야 하는가&lt;/b&gt;를 정리해 보았다.&lt;/p&gt;
&lt;p id=&quot;55fc&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;내용을 적기 전에 공부하면서 참고했던, 클로저에서의 약한 참조에 대해 가장 잘 정리한 블로그 글을 먼저 공유!&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://noah0316.github.io/Swift/2022-04-08-%5Bweak-self%5D-%EB%AC%B4%EC%A1%B0%EA%B1%B4-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94%EA%B2%8C-%EB%A7%9E%EB%8A%94%EA%B1%B8%EA%B9%8C/&quot;&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/a&gt;
&lt;div&gt;&lt;a href=&quot;https://noah0316.github.io/Swift/2022-04-08-%5Bweak-self%5D-무조건-사용하는게-맞는걸까/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://noah0316.github.io/Swift/2022-04-08-%5Bweak-self%5D-무조건-사용하는게-맞는걸까/&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;figure id=&quot;og_1681278639363&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;[weak self] 무조건 사용하는게 맞는걸까?  &quot; data-og-description=&quot;클로져에서 self를 캡쳐할 때 를 사용하는 경우는 순환 참조를 방지하기 위해 약한 참조로 클로져 내부에서 해당 클래스의 인스턴스를 사용할때 입니다. 클로져에서 약한 참조를 이용해 특정 인&quot; data-og-host=&quot;noah0316.github.io&quot; data-og-source-url=&quot;https://noah0316.github.io/Swift/2022-04-08-%5Bweak-self%5D-무조건-사용하는게-맞는걸까/&quot; data-og-url=&quot;https://noah0316.github.io/Swift/2022-04-08-%5Bweak-self%5D-%EB%AC%B4%EC%A1%B0%EA%B1%B4-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94%EA%B2%8C-%EB%A7%9E%EB%8A%94%EA%B1%B8%EA%B9%8C/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/mrxSj/hySe9jQ0bH/vSHimmxv16bbxxzUWAGCUK/img.png?width=650&amp;amp;height=221&amp;amp;face=0_0_650_221,https://scrap.kakaocdn.net/dn/O4me6/hySeXcxsoe/xilJLW8ejSruTL9VD1mcTk/img.png?width=650&amp;amp;height=221&amp;amp;face=0_0_650_221,https://scrap.kakaocdn.net/dn/vVs4j/hySggIkapu/GrEtfWsHZ9FVXMxBFLLMak/img.png?width=300&amp;amp;height=257&amp;amp;face=120_76_184_146&quot;&gt;&lt;a href=&quot;https://noah0316.github.io/Swift/2022-04-08-%5Bweak-self%5D-무조건-사용하는게-맞는걸까/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://noah0316.github.io/Swift/2022-04-08-%5Bweak-self%5D-무조건-사용하는게-맞는걸까/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/mrxSj/hySe9jQ0bH/vSHimmxv16bbxxzUWAGCUK/img.png?width=650&amp;amp;height=221&amp;amp;face=0_0_650_221,https://scrap.kakaocdn.net/dn/O4me6/hySeXcxsoe/xilJLW8ejSruTL9VD1mcTk/img.png?width=650&amp;amp;height=221&amp;amp;face=0_0_650_221,https://scrap.kakaocdn.net/dn/vVs4j/hySggIkapu/GrEtfWsHZ9FVXMxBFLLMak/img.png?width=300&amp;amp;height=257&amp;amp;face=120_76_184_146');&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;[weak self] 무조건 사용하는게 맞는걸까?  &lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;클로져에서 self를 캡쳐할 때 를 사용하는 경우는 순환 참조를 방지하기 위해 약한 참조로 클로져 내부에서 해당 클래스의 인스턴스를 사용할때 입니다. 클로져에서 약한 참조를 이용해 특정 인&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;noah0316.github.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;5d7d&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;많은 블로그 글 들이 있었지만, 가장 정리가 잘 되어 있었고 무엇보다 나를 이해시켰다.. 대단한 분..&lt;/p&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;3634&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;그래서 꼼꼼한 정보를 원한다면 위의 글을 참고하는 게 더 도움이 될 것 같고, 나는 이해한 것을 잊지 않기 위해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;최대한 개념적으로 풀어서 써보려고 한다.&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;div style=&quot;color: #000000; text-align: start;&quot;&gt;
&lt;h2 id=&quot;6c70&quot; style=&quot;color: #292929;&quot; data-ke-size=&quot;size26&quot;&gt;weak self를 쓰는 대략적인 이유&lt;/h2&gt;
&lt;p id=&quot;5c59&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;클로저 안에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;self&lt;/code&gt;를 사용하면 그 인스턴스를 참조하기 때문에 Reference Count 즉 RC가 증가한다. 그래서 RC를 증가시키지 않는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;weak&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;키워드를 사용하여&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;self&lt;/code&gt;를 쓰면 순환참조를 방지할 수 있기에 보통&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;~클로저 안에서 &lt;code&gt;weak self&lt;/code&gt;를 쓰면 좋다~&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;고 말하는 것이다.&lt;/p&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;56d3&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  함수와 클로저의 차이?&lt;/b&gt;&lt;/p&gt;
&lt;p id=&quot;4971&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;거의 같다고 보면 된다. 다만, 함수는 클로저 안에 속해 있고 이름이 있다는 점이 특징이다.&lt;/p&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;5203&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; &amp;zwj;♀️ self가 무슨 인스턴스를 참조한다는 건지 헷갈린다면&lt;/b&gt;&lt;/p&gt;
&lt;p id=&quot;ca41&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;이건 아래의 예제를 가져왔다.&lt;/p&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://benoitpasquier.com/weak-self-story-memory-management-closure-swift/&quot;&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/a&gt;
&lt;div&gt;&lt;a href=&quot;https://benoitpasquier.com/weak-self-story-memory-management-closure-swift/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://benoitpasquier.com/weak-self-story-memory-management-closure-swift/&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;figure id=&quot;og_1681278677874&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;Weak self, a story about memory management and closure in Swift&quot; data-og-description=&quot;Memory management is a big topic in Swift and iOS development. If there are plenty of tutorials explaining when to use weak self with closure, here is a short story when memory leaks can still happen with it.&quot; data-og-host=&quot;benoitpasquier.com&quot; data-og-source-url=&quot;https://benoitpasquier.com/weak-self-story-memory-management-closure-swift/&quot; data-og-url=&quot;https://benoitpasquier.com/weak-self-story-memory-management-closure-swift/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/GCC71/hySe68pRhq/yKik6hp5QJ2mf9nkZMxfU0/img.png?width=838&amp;amp;height=496&amp;amp;face=0_0_838_496,https://scrap.kakaocdn.net/dn/cWSr64/hySgrQC3KR/Xpv9jJQOQtfJ9K2kfQKjZK/img.png?width=838&amp;amp;height=496&amp;amp;face=0_0_838_496,https://scrap.kakaocdn.net/dn/bl5Hqa/hySe25Xv5Q/yEcewhttNKyYv52mq7sYP0/img.jpg?width=500&amp;amp;height=500&amp;amp;face=120_137_309_343&quot;&gt;&lt;a href=&quot;https://benoitpasquier.com/weak-self-story-memory-management-closure-swift/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://benoitpasquier.com/weak-self-story-memory-management-closure-swift/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/GCC71/hySe68pRhq/yKik6hp5QJ2mf9nkZMxfU0/img.png?width=838&amp;amp;height=496&amp;amp;face=0_0_838_496,https://scrap.kakaocdn.net/dn/cWSr64/hySgrQC3KR/Xpv9jJQOQtfJ9K2kfQKjZK/img.png?width=838&amp;amp;height=496&amp;amp;face=0_0_838_496,https://scrap.kakaocdn.net/dn/bl5Hqa/hySe25Xv5Q/yEcewhttNKyYv52mq7sYP0/img.jpg?width=500&amp;amp;height=500&amp;amp;face=120_137_309_343');&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;Weak self, a story about memory management and closure in Swift&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Memory management is a big topic in Swift and iOS development. If there are plenty of tutorials explaining when to use weak self with closure, here is a short story when memory leaks can still happen with it.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;benoitpasquier.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;pre class=&quot;swift&quot; style=&quot;background-color: #f9f9f9; color: #292929;&quot;&gt;&lt;code&gt;class MyClass {
    func doSomething(_ completion: (() -&amp;gt; Void)?) {
            // do something
            completion?()
     }

     var didSomething: Bool = false
      
     func doEverything() {
      
         self.doSomething { 
              self.didSomething = true // 여기서 self 인스턴스(MyClass 인스턴스)에 대한 강한 참조 발생
              print(&quot;did something&quot;)
          }
     }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;dd01&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;클래스의 인스턴스 그 자체를 참조하게 되는 것! 좀 더 이해하기 쉬운 예는 &lt;code&gt;ViewController&lt;/code&gt;가 될 것 같다. 뷰컨도 클래스를 정의하고 그 인스턴스를 생성해서 사용하니까 뷰컨 안의 클로저에서 self 를 사용한다면 해당 뷰 컨트롤러의 인스턴스가 될 것이다.&lt;/p&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;c96e&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;여기까지는 ARC와 Swift 참조방식에 대해 알고 있는 사람이라면 음 그렇구나 하게 되지만 이제는&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;그러면 늘 &lt;code&gt;weak self&lt;/code&gt;를 쓰지 왜 쓰는 경우가 있고 안쓰는 경우가 있는 거지?&lt;/blockquote&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;1988&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;하는 의문이 자연스럽게 들게 된다.&lt;/p&gt;
&lt;p id=&quot;c728&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;다음 단계로 가기 위해서는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;escaping&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;클로저에 대한 이해가 필요하다.&lt;/p&gt;
&lt;/div&gt;
&lt;div style=&quot;color: #000000; text-align: start;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div style=&quot;color: #000000; text-align: start;&quot;&gt;
&lt;h2 id=&quot;ab76&quot; style=&quot;color: #292929;&quot; data-ke-size=&quot;size26&quot;&gt;@escaping 클로저&lt;/h2&gt;
&lt;p id=&quot;cd14&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;클로저를 크게&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;escaping&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;클로저와&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;non-escaping&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;클로저로 나눌 수 있을 것 같다.&lt;/p&gt;
&lt;p id=&quot;6558&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;escaping&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;클로저란&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;함수의 리턴 이후에 실행되는 함수&lt;/b&gt;를 의미한다.&lt;/p&gt;
&lt;p id=&quot;0ea8&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;자유로운 만큼 외부 변수에 저장 후 함수 scope 밖에서도 실행이 가능하다.&lt;/p&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;5f53&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;반면,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;non-escaping&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;클로저는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;함수 내부에서만 사용이 가능&lt;/b&gt;하다는 한계가 있다.&lt;/p&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;4ab3&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;escaping&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;클로저는 위와 같은 특성 덕에 비동기적 작업 특히 네트워크 작업에 많이 쓰이는데 아직 사용해 본 경험이 너무 부족해 예시 코드를 작성하는 건 좀 위험할 것 같아서, 말로만 하고 넘어가려 한다.&lt;/p&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;2a35&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; &amp;zwj;♀️ 내가 간단하게 이해한 정도만 언급하자면&amp;hellip;&lt;/b&gt;&lt;/p&gt;
&lt;p id=&quot;c165&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;네트워크에서 다운로드가 오래걸리는 데이터를 요청하는 경우를 생각해 볼 수 있다. 그 데이터를 다 받고 나서 실행해야 하는 작업이 있을 것이다. 그 작업을 데이터 요청 함수의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;escaping&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;클로저로 받는 것이다.&lt;/p&gt;
&lt;p id=&quot;80f0&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;그렇게 하면 데이터를 요청하는 함수 자체는 끝이 나도, &lt;code&gt;escaping&lt;/code&gt; 클로저로 전달됐던 그 다음 해야 하는 작업은 요청한 데이터를 다운로드 받는 작업이 완료된 이후에 할 수 있다.&lt;/p&gt;
&lt;p id=&quot;7156&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;자 그래서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;결론적으로&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;escaping&lt;/code&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;non-escaping&lt;/code&gt;을 알아야 하는 이유는&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;weak self&lt;/code&gt;를 언제 써야 하고 언제 쓰지 말아야 할 지 알기 위해서&lt;/b&gt;다.&lt;/p&gt;
&lt;/div&gt;
&lt;div style=&quot;color: #000000; text-align: start;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div style=&quot;color: #000000; text-align: start;&quot;&gt;
&lt;p id=&quot;81f2&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;code&gt;non-escaping&lt;/code&gt;&lt;/b&gt;&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;클로저&lt;/b&gt;는 함수 종료 후 해당 클로저가 사용되지 않는다는 것이 명확하기 때문에 (함수의 scope 밖에서 사용할 수 없음) 순환참조를 일으킬 염려가 없고 &lt;code&gt;weak self&lt;/code&gt;를 사용하지 않아도 된다!&lt;/p&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;9ffe&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; &amp;zwj;♀️ 근데 나는 이 설명을 보고 self가 클로저보다 먼저 할당해제되면 어떡하지..? 하는 생각이 들었었다.&lt;/b&gt;&lt;/p&gt;
&lt;p id=&quot;ab05&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;보통은 클로저가 인스턴스 메소드에서 사용될 것이고, 이런 걱정이 없을 테지만, 만약 클로저가 타입 메소드에서 사용된다면? 하는 질문이 생겨났다.&lt;/p&gt;
&lt;p id=&quot;1a7c&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;그래서 찾아 봤는데 타입 메소드에서의 &lt;code&gt;self&lt;/code&gt;는 (당연하게도..) 인스턴스가 아니라 타입을 가리킨다고 한다.&lt;/p&gt;
&lt;p id=&quot;5577&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;또 참조가 발생하는 경우가 애초에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;인스턴스를 할당할 때&lt;/b&gt;니까 RC는 증가하지 않겠구나.. 하는 깨달음을 얻었다. 배운 건 기억하자.. 나 자신..&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;아무튼 결론은&amp;nbsp;&lt;code&gt;non-escaping&lt;/code&gt;&amp;nbsp;클로저는 &lt;code&gt;weak self&lt;/code&gt;를 쓸 필요가 없다!&lt;/blockquote&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;d741&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;그럼&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;code&gt;escaping&lt;/code&gt;&lt;/b&gt;&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;클로저에서는?&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 id=&quot;85e9&quot; style=&quot;list-style-type: disc; color: #292929;&quot; data-selectable-paragraph=&quot;&quot;&gt;클로저가 객체의 &lt;code&gt;property&lt;/code&gt;에 저장되거나 다른 클로저로 전달될 경우에 순환 참조의 위험이 있다.&lt;/li&gt;
&lt;li id=&quot;ff6e&quot; style=&quot;list-style-type: disc; color: #292929;&quot; data-selectable-paragraph=&quot;&quot;&gt;클로저 안의 객체가 어떤 클로저에 대한 강한 참조를 유지하는 경우에 순환 참조의 위험이 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p id=&quot;b826&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;와..닿진 않지만 어쨌든&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;강한 참조가 남아있을 가능성&lt;/b&gt;이 존재한다는 것이 포인트인 것 같다.&lt;/p&gt;
&lt;/div&gt;
&lt;div style=&quot;color: #000000; text-align: start;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div style=&quot;color: #000000; text-align: start;&quot;&gt;
&lt;h3 id=&quot;ab98&quot; style=&quot;color: #292929;&quot; data-ke-size=&quot;size23&quot;&gt;weak self를 쓸 필요없는 escaping 클로저&lt;/h3&gt;
&lt;p id=&quot;ea88&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;GCD 호출 (예: &lt;code&gt;DispatchQueue&lt;/code&gt;) 은 클로저를 인자로 받지만&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;나중에 실행하기 위해 &lt;code&gt;property&lt;/code&gt;에 저장하지 않는 한&lt;/b&gt;순환 참조의 위험성이 없다고 한다.&lt;/p&gt;
&lt;p id=&quot;7cbc&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Animation&lt;/code&gt; 작업도 마찬가지로 &lt;code&gt;weak self&lt;/code&gt;를 사용할 필요가 없다고 한다.&lt;/p&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;bc14&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  Animation이 순환참조가 일어나지 않는 이유&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://gyuios.tistory.com/219&quot;&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/a&gt;
&lt;div&gt;&lt;a href=&quot;https://gyuios.tistory.com/219&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://gyuios.tistory.com/219&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;figure id=&quot;og_1681278760214&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;iOS) UIView.animate(...) 왜 메모리릭이 발생하지 않나요?&quot; data-og-description=&quot;Is it necessary to use [unowned self] in closures of UIView.animateWithDuration(...)? 이 글은 위의 stackoverflow 질문을 읽고 정리해본 글입니다. 작성자님의 질문을 아래와 같았다. 아래의 코드는 메모리 릭을 피할 수&quot; data-og-host=&quot;gyuios.tistory.com&quot; data-og-source-url=&quot;https://gyuios.tistory.com/219&quot; data-og-url=&quot;https://gyuios.tistory.com/219&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/xVKqY/hySgizoEHw/y21QnVQr7RklhtPL7W1610/img.png?width=800&amp;amp;height=512&amp;amp;face=343_167_496_334,https://scrap.kakaocdn.net/dn/bgpRg4/hySeVlxmsi/Ery5gF95oLwsGcuZOw7twk/img.png?width=800&amp;amp;height=512&amp;amp;face=343_167_496_334,https://scrap.kakaocdn.net/dn/NciVq/hySgqjR3aW/nKVkeMjXS4K4bYJTZFpvZ1/img.png?width=1280&amp;amp;height=820&amp;amp;face=542_282_780_542&quot;&gt;&lt;a href=&quot;https://gyuios.tistory.com/219&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://gyuios.tistory.com/219&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/xVKqY/hySgizoEHw/y21QnVQr7RklhtPL7W1610/img.png?width=800&amp;amp;height=512&amp;amp;face=343_167_496_334,https://scrap.kakaocdn.net/dn/bgpRg4/hySeVlxmsi/Ery5gF95oLwsGcuZOw7twk/img.png?width=800&amp;amp;height=512&amp;amp;face=343_167_496_334,https://scrap.kakaocdn.net/dn/NciVq/hySgqjR3aW/nKVkeMjXS4K4bYJTZFpvZ1/img.png?width=1280&amp;amp;height=820&amp;amp;face=542_282_780_542');&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;iOS) UIView.animate(...) 왜 메모리릭이 발생하지 않나요?&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Is it necessary to use [unowned self] in closures of UIView.animateWithDuration(...)? 이 글은 위의 stackoverflow 질문을 읽고 정리해본 글입니다. 작성자님의 질문을 아래와 같았다. 아래의 코드는 메모리 릭을 피할 수&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;gyuios.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p id=&quot;0447&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;이 글을 참고하면, &lt;code&gt;Animation&lt;/code&gt;은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;타입 메소드&lt;/b&gt;이기 때문에 &lt;code&gt;weak self&lt;/code&gt;를 사용할 필요가 없다고 한다. (아까 내가 했던 고민이 생각나서 나름 뿌듯..?)&lt;/p&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;d5f7&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; &amp;zwj;♀️ GCD에 관하여 자세한 글을 보고 싶다면&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://medium.com/rocknnull/ios-gcd-what-the-weak-is-going-on-d5a10fc682a&quot;&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/a&gt;
&lt;div&gt;&lt;a href=&quot;https://medium.com/rocknnull/ios-gcd-what-the-weak-is-going-on-d5a10fc682a&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://medium.com/rocknnull/ios-gcd-what-the-weak-is-going-on-d5a10fc682a&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;figure id=&quot;og_1681278774739&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;iOS &amp;mdash; GCD what the __weak is going on?&quot; data-og-description=&quot;We all know that a reference to self in a block should always be done using __weak and not direct to self. Even Xcode warns you that this&amp;hellip;&quot; data-og-host=&quot;medium.com&quot; data-og-source-url=&quot;https://medium.com/rocknnull/ios-gcd-what-the-weak-is-going-on-d5a10fc682a&quot; data-og-url=&quot;https://medium.com/rocknnull/ios-gcd-what-the-weak-is-going-on-d5a10fc682a&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cYhyE0/hySe0tznIm/1Au2BeXga5uyCYB9Zs6pO0/img.jpg?width=600&amp;amp;height=450&amp;amp;face=0_0_600_450&quot;&gt;&lt;a href=&quot;https://medium.com/rocknnull/ios-gcd-what-the-weak-is-going-on-d5a10fc682a&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://medium.com/rocknnull/ios-gcd-what-the-weak-is-going-on-d5a10fc682a&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cYhyE0/hySe0tznIm/1Au2BeXga5uyCYB9Zs6pO0/img.jpg?width=600&amp;amp;height=450&amp;amp;face=0_0_600_450');&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;iOS &amp;mdash; GCD what the __weak is going on?&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;We all know that a reference to self in a block should always be done using __weak and not direct to self. Even Xcode warns you that this&amp;hellip;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;medium.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p id=&quot;8bf0&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;영어고, 내용이 많고, 오브젝티브 C로 되어 있고, 기타 등등의 이유로 나중에 다시 공부해야 하겠지만.. 중요한 포인트는 맨 위에 언급한 블로그에서도 나와 있지만&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&lt;code&gt;weak self&lt;/code&gt;를 쓰느냐 마느냐에 따라 다른 동작 결과가 나타날 수 있다&lt;/b&gt;는 것.&lt;/p&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;92b4&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;dispatch queue&lt;/code&gt;로 5초 후에 &lt;code&gt;self&lt;/code&gt;(인스턴스)의 프로퍼티를 출력한다고 해 보자.&lt;/p&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;7045&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;weak self&lt;/code&gt;를 썼을 때, 인스턴스를 해제시켜 버리면 그 프로퍼티 값은 &lt;code&gt;nil&lt;/code&gt;이 된다.&lt;/p&gt;
&lt;p id=&quot;d8d9&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;weak self&lt;/code&gt;를 쓰지 않았을 때, 인스턴스를 해제시켜 버려도 기존 프로퍼티 값이 잘 출력이 된다.&lt;/p&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;0015&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;그리고 두 경우 모두 순환참조는 일어나지 않는다. (따로 &lt;code&gt;property&lt;/code&gt;에 할당하지 않았기 때문에)&lt;/p&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;f141&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;어쨌든 위의 GCD를 언급했을 때 알 수 있었듯,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;변수에 클로저를 저장하는 경우는 반드시 &lt;code&gt;weak self&lt;/code&gt;를 사용해야 한다&lt;/b&gt;. 해당 변수를 사용하기 전에 인스턴스가 해제되어 버리면 여전히 RC가 남아있기 때문에 서로 참조를 하고 있고, 서로 할당 해제를 기다리는 상태가 되기 때문에 순환참조가 생겨 버린다.&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;color: #000000; text-align: start;&quot;&gt;
&lt;h3 id=&quot;4447&quot; style=&quot;color: #292929;&quot; data-ke-size=&quot;size23&quot;&gt;guard let 을 쓸 것이냐, 옵셔널 체이닝(?)을 쓸 것이냐&lt;/h3&gt;
&lt;p id=&quot;13a8&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;간단하게&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;guard let&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;은 클로저가 종료될 때 까지 강한참조로 &lt;code&gt;self&lt;/code&gt; 가 살아있다. (==클로저가 끝날 때 까지 &lt;code&gt;self&lt;/code&gt;의 해제를 지연시킨다)&lt;/p&gt;
&lt;p id=&quot;3674&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;옵셔널 체이닝&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;self?.&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;을 사용하면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;nil&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;인 경우를 바로 처리해 동작을 즉시 멈출 수도 있기 때문에 불필요한 작업을 줄일 수 있다.&lt;/p&gt;
&lt;p id=&quot;d245&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;이건 클로저 종료 전&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;self&lt;/code&gt;가 할당해제 되는 상황인지 (정확하게는 할당해제 되어야 하는 상황인지가 아닐까?) 아닌지를 고려해서 판단해야 할 것 같다.&lt;/p&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;8dcb&quot; style=&quot;color: #292929;&quot; data-ke-size=&quot;size26&quot;&gt;unowned를 쓰지 않는 이유&lt;/h2&gt;
&lt;p id=&quot;1026&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;마지막으로 &lt;code&gt;unowned self&lt;/code&gt; 를 쓰지 않는 이유를 간단하게 언급하고 끝내려고 한다.&lt;/p&gt;
&lt;p id=&quot;e230&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;이전 글에서 Swift의 참조 방식을 공부하며 다음과 같은 내용을 정리했다.&lt;/p&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;2271&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;weak&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 id=&quot;f741&quot; style=&quot;list-style-type: disc; color: #292929;&quot; data-selectable-paragraph=&quot;&quot;&gt;더 수명이 짧은 인스턴스에 대하여 약한 참조를 사용한다&lt;/li&gt;
&lt;li id=&quot;ca15&quot; style=&quot;list-style-type: disc; color: #292929;&quot; data-selectable-paragraph=&quot;&quot;&gt;참조하는 인스턴스가 해제되면 자동으로 &lt;code&gt;weak&lt;/code&gt; 참조를 &lt;code&gt;nil&lt;/code&gt;로 설정한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p id=&quot;5949&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;unowned&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 id=&quot;bf45&quot; style=&quot;list-style-type: disc; color: #292929;&quot; data-selectable-paragraph=&quot;&quot;&gt;더 수명이 긴 인스턴스에 대하여 미소유 참조를 사용한다&lt;/li&gt;
&lt;li id=&quot;770f&quot; style=&quot;list-style-type: disc; color: #292929;&quot; data-selectable-paragraph=&quot;&quot;&gt;참조하는 인스턴스가 해제되어도 nil로 만들어 주지 않는다 (항상 값이 있다고 예상 &amp;rarr; 잘못된 주소로 접근해서 Crash가 일어날 수도 있다)&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;7f58&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;(일단 우선 이건 순전히 나의 생각이다!) 우리가 우려하는 상황은 (&lt;code&gt;weak self&lt;/code&gt;를 쓰는 이유는) 강한 참조가 남아있는 상황에서 &lt;code&gt;self&lt;/code&gt;가 할당해제 되는 경우다. 그래서 이 경우 &lt;code&gt;self&lt;/code&gt;가 더 수명이 짧을 것을 예상하고 사용하는 것이기 때문에 &lt;code&gt;unowned&lt;/code&gt;가 아닌 &lt;code&gt;weak&lt;/code&gt; 를 쓰는 게 이치에 맞다고 생각했다.&lt;/p&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;1cd9&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;그리고 일반적인 (다른 블로그글에서도 언급하는) 이유는 위 정리 내용에서도 언급됐듯이 Crash의 우려 때문이다. 옵셔널 값을 가지는 &lt;code&gt;weak&lt;/code&gt;와 달리 안전하게 &lt;code&gt;self&lt;/code&gt;를 다룰 수 없다.&lt;/p&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;0237&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;따라서 &lt;code&gt;unowend self&lt;/code&gt; 대신 &lt;code&gt;weak self&lt;/code&gt;를 사용하기!&lt;/p&gt;
&lt;p id=&quot;1fbc&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;완벽하진 않지만 그래도 순환참조에 대한 공부를 끝냈다!!&lt;/p&gt;
&lt;/div&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;</description>
      <category>iOS/Swift</category>
      <category>ios</category>
      <category>순환참조</category>
      <category>클로저</category>
      <author>Mila00a</author>
      <guid isPermaLink="true">https://mila00a.tistory.com/64</guid>
      <comments>https://mila00a.tistory.com/64#entry64comment</comments>
      <pubDate>Wed, 12 Apr 2023 15:01:50 +0900</pubDate>
    </item>
    <item>
      <title>ARC를 곁들인 순환참조 (1)</title>
      <link>https://mila00a.tistory.com/63</link>
      <description>&lt;div style=&quot;color: #000000; text-align: start;&quot;&gt;
&lt;div&gt;
&lt;h1 id=&quot;d991&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; font-size: 16px; letter-spacing: 0px;&quot;&gt;혹은 순환참조를 곁들인 ARC&amp;hellip;&lt;/span&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;h1 id=&quot;28c2&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot;&gt;ARC (Automatic Reference Counting)&lt;/h1&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Swift에서 앱의 메모리를 관리하는 방법&lt;/blockquote&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;fd5a&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;간단하게는 자동으로 메모리를 관리해주는 녀석이라고 할 수 있다.&lt;/p&gt;
&lt;h1 style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot;&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 id=&quot;7f69&quot; style=&quot;color: #292929;&quot; data-ke-size=&quot;size26&quot;&gt;여기서 &amp;lsquo;메모리&amp;rsquo; 란?&lt;/h2&gt;
&lt;p id=&quot;471c&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;우선 여기서 메모리는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Heap&lt;/b&gt;을 의미한다.&lt;/p&gt;
&lt;p id=&quot;2610&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;Swift에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;인스턴스나&lt;span&gt;&amp;nbsp;&lt;/span&gt;클로저&lt;span&gt;&amp;nbsp;&lt;/span&gt;같은 참조(Referene) 타입들은 자동으로 힙에 할당이 된다.&lt;/p&gt;
&lt;p id=&quot;247c&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;그런데 Heap은 반드시 사용 후에 메모리 해제를 해 줘야 하는데.. 우리는 한 기억이 없다&lt;/p&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;bb8e&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&amp;rarr; 진짜 그런가? 진짜 메모리 해제를 꼭 해 줘야 하나? 안해주면 어떻게 되나? &lt;/i&gt;&lt;/p&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&amp;rarr; 메모리 누수 (필요없는 메모리 사용량 증가, 앱이 죽을 수 있음)&lt;/i&gt;&lt;/p&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;75be&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;어쨌든 우리가 하지 않아도 되는 이유는 ARC가 대신 해 주고 있기 때문!&lt;/p&gt;
&lt;p id=&quot;685e&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;필요 없는 메모리를 자동 해제해서 관리해 주는 게 ARC가 하는 일이다.&lt;/p&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;2ac9&quot; style=&quot;color: #292929;&quot; data-ke-size=&quot;size26&quot;&gt;Heap의 메모리 관리&lt;/h2&gt;
&lt;p id=&quot;b22c&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;Heap의 메모리를 관리하는 방법에는 두 가지가 있다.&lt;/p&gt;
&lt;p id=&quot;73b5&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;첫번째는 GC(Garbage Collection), 두 번째는 RC(Reference Counting).&lt;/p&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;83d1&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;GC는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;run-time&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;에 참조를 추적하고 RC는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;compile-time&lt;/code&gt;에 참조를 추적한다는 것이 가장 큰 차이점이다.&lt;/p&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;af77&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;ARC 에서 쓰이는 RC는 말 그대로 Reference Counting, 즉 참조의 수를 계산해서 0이 되면 메모리를 해제시키는 방법이다. 그런데 만약 어떠한 이유로 Reference가 0이 되지 않는 경우에는 영구적으로 메모리 해제가 되지 못할 수 있다는 단점이 있다.&lt;/p&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;89c3&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;이 경우는 여러 인스턴스가 서로 강한 참조를 하는, 사이클이 생성된 경우를 의미하고 이것을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;강한 순환 참조&lt;/b&gt;라고 한다. 오늘 알아볼 것이 이것!&lt;/p&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;0bf6&quot; style=&quot;color: #292929;&quot; data-ke-size=&quot;size26&quot;&gt;강한 참조&lt;/h2&gt;
&lt;p id=&quot;2396&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;서로 참조를 하는 것은 어느정도 이해가 가겠는데, 강한 참조는 무엇일까?&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;그래서 먼저 Swift의 참조 방식을 알아보자아&lt;/blockquote&gt;
&lt;p style=&quot;color: #292929;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;d4d8&quot; style=&quot;color: #292929;&quot; data-ke-size=&quot;size23&quot;&gt;Swift의 참조 방식&lt;/h3&gt;
&lt;/div&gt;
&lt;div style=&quot;color: #000000; text-align: start;&quot;&gt;
&lt;p id=&quot;86b2&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;strong&lt;/b&gt;&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 강한 참조&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 id=&quot;34c5&quot; style=&quot;list-style-type: disc; color: #292929;&quot; data-selectable-paragraph=&quot;&quot;&gt;참조하는 인스턴스의 Reference Count를 증가시킨다&lt;/li&gt;
&lt;/ul&gt;
&lt;p id=&quot;1289&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 인스턴스의 소유권을 가짐&lt;/p&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li id=&quot;2ff4&quot; style=&quot;list-style-type: disc; color: #292929;&quot; data-selectable-paragraph=&quot;&quot;&gt;인스턴스 참조의 default(기본) 방식이다&lt;/li&gt;
&lt;li id=&quot;a6ed&quot; style=&quot;list-style-type: disc; color: #292929;&quot; data-selectable-paragraph=&quot;&quot;&gt;강한 참조가 생기는 경우: 상수 또는 변수에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;클래스 인스턴스를 할당할 때&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;4c46&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;공식 문서에 나오는 아래 예시를 보자.&lt;/p&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;766&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cGvHI0/btr9Men55pQ/WrjVFRaPBkUYQFVdjO9wO1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cGvHI0/btr9Men55pQ/WrjVFRaPBkUYQFVdjO9wO1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cGvHI0/btr9Men55pQ/WrjVFRaPBkUYQFVdjO9wO1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcGvHI0%2Fbtr9Men55pQ%2FWrjVFRaPBkUYQFVdjO9wO1%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;700&quot; height=&quot;384&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;766&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;da5f&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;여기서 클래스 인스턴스를 할당하면 기본 방식인 강한 참조가 발생한다.&lt;/p&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;572&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/77aN6/btr9BGMNado/HOzhaZkkIp0TkYZBPfbBX1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/77aN6/btr9BGMNado/HOzhaZkkIp0TkYZBPfbBX1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/77aN6/btr9BGMNado/HOzhaZkkIp0TkYZBPfbBX1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F77aN6%2Fbtr9BGMNado%2FHOzhaZkkIp0TkYZBPfbBX1%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;700&quot; height=&quot;286&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;572&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;2e70&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;강한 참조는 RC를 증가시키기 때문에 각 인스턴스의 RC는 1이 된다.&lt;/p&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;480&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvHNCa/btr9DIDmqjo/4rpKL8l8mEqJlsUTG62wf0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvHNCa/btr9DIDmqjo/4rpKL8l8mEqJlsUTG62wf0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvHNCa/btr9DIDmqjo/4rpKL8l8mEqJlsUTG62wf0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvHNCa%2Fbtr9DIDmqjo%2F4rpKL8l8mEqJlsUTG62wf0%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;700&quot; height=&quot;240&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;480&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;e862&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;이 때, 아파트와 거주자에 서로를 (인스턴스를) 할당해 주면 또 다시 강한 참조가 발생하게 된다. 그리고 RC는 2로 늘어나게 된다.&lt;/p&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;827&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nCyq3/btr9DHqTI0H/060MRxIJdGmzDJ9WTgvXik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nCyq3/btr9DHqTI0H/060MRxIJdGmzDJ9WTgvXik/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nCyq3/btr9DHqTI0H/060MRxIJdGmzDJ9WTgvXik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnCyq3%2Fbtr9DHqTI0H%2F060MRxIJdGmzDJ9WTgvXik%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;700&quot; height=&quot;414&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;827&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;1128&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;이 때, john과 unit4A를 &lt;code&gt;nil&lt;/code&gt;로 만들어 주면서 강한참조가 하나씩 사라지지만, 여전히 인스턴스들이 서로를 참조하고 있기 때문에 RC=1로 유지되어 메모리에서 해제되지 않는 상태가 된다.&lt;/p&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;7ba3&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;이 때 인스턴스를 &lt;code&gt;nil&lt;/code&gt;로 만들어 주고 싶어도 이미 john과 unit4A와의 연결이 끊어졌기 때문에 방법이 없다.&lt;/p&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;711&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cLAFfF/btr9MoEiKmr/sOunwMNODzqQLBnhxuWIbK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cLAFfF/btr9MoEiKmr/sOunwMNODzqQLBnhxuWIbK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cLAFfF/btr9MoEiKmr/sOunwMNODzqQLBnhxuWIbK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcLAFfF%2Fbtr9MoEiKmr%2FsOunwMNODzqQLBnhxuWIbK%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;700&quot; height=&quot;356&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;711&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;9d66&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;이것이 바로 강한 참조 사이클!&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;color: #000000; text-align: start;&quot;&gt;
&lt;p id=&quot;a008&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;weak&lt;/b&gt;&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 약한 참조&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 id=&quot;3fa5&quot; style=&quot;list-style-type: disc; color: #292929;&quot; data-selectable-paragraph=&quot;&quot;&gt;참조하는 인스턴스의 Reference Count를 증가시키지 않는다&lt;/li&gt;
&lt;li id=&quot;5d57&quot; style=&quot;list-style-type: disc; color: #292929;&quot; data-selectable-paragraph=&quot;&quot;&gt;더 수명이 짧은 인스턴스에 대하여 약한 참조를 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p id=&quot;94e3&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;예) 아파트는 있고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;거주자&lt;/b&gt;는 사라짐, 나는 있고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;자동차&lt;/b&gt;는 바뀜&lt;/p&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li id=&quot;5c12&quot; style=&quot;list-style-type: disc; color: #292929;&quot; data-selectable-paragraph=&quot;&quot;&gt;참조하는 인스턴스가 해제되면 자동으로 &lt;code&gt;weak&lt;/code&gt; 참조를 &lt;code&gt;nil&lt;/code&gt;로 설정한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p id=&quot;9d89&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;예) Audi R8이 폐차되면 나의 car는 &lt;code&gt;nil&lt;/code&gt;이 된다.&lt;/p&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;ec3d&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;결과적으로 런타임에 값이 &lt;code&gt;nil&lt;/code&gt;로 변경될 수 있으니 그래서 규칙들이 있다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li id=&quot;cb34&quot; style=&quot;list-style-type: decimal; color: #292929;&quot; data-selectable-paragraph=&quot;&quot;&gt;항상 &lt;code&gt;Optional&lt;/code&gt;로 선언되어야 한다&lt;/li&gt;
&lt;li id=&quot;57d4&quot; style=&quot;list-style-type: decimal; color: #292929;&quot; data-selectable-paragraph=&quot;&quot;&gt;항상 &lt;code&gt;var&lt;/code&gt;로 선언되어야 한다&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;6d18&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;아까 사용했던 예시를 살짝 바꿔 보자. 이제는 거주자가 &lt;code&gt;weak var&lt;/code&gt;로 선언되었다.&lt;/p&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;784&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/z2myH/btr9GhS2BIj/QEq8EhuyXIo9g4fM6DvXx1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/z2myH/btr9GhS2BIj/QEq8EhuyXIo9g4fM6DvXx1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/z2myH/btr9GhS2BIj/QEq8EhuyXIo9g4fM6DvXx1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fz2myH%2Fbtr9GhS2BIj%2FQEq8EhuyXIo9g4fM6DvXx1%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;700&quot; height=&quot;392&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;784&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;6a26&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;아까와 같이 강한 참조가 발생하고, 이번에는 거주자가 &lt;code&gt;weak&lt;/code&gt; 로 선언되었기에 약한 참조가 발생한다. 그래서 Person 인스턴스의 RC는 1, Apartment 인스턴스의 RC는 2가 된다.&lt;/p&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;1082&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ezxjRZ/btr9NCaWZQQ/smIFUjQa72geeXCb9Ea3m1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ezxjRZ/btr9NCaWZQQ/smIFUjQa72geeXCb9Ea3m1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ezxjRZ/btr9NCaWZQQ/smIFUjQa72geeXCb9Ea3m1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FezxjRZ%2Fbtr9NCaWZQQ%2FsmIFUjQa72geeXCb9Ea3m1%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;700&quot; height=&quot;542&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;1082&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;050f&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;이 때 john을 &lt;code&gt;nil&lt;/code&gt;로 만들면서 RC가 0이 되어 Person 인스턴스는 메모리에서 사라집니다.&lt;/p&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;8bb1&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;여기서 중요한 점은 &lt;code&gt;weak&lt;/code&gt; 참조하던 인스턴스가 해제되면서 자동으로 &lt;code&gt;nil&lt;/code&gt;로 설정되었다는 것!&lt;/p&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;725&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cmYD0f/btr9ObjNG23/TnuACViozyi5MFGitW1930/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cmYD0f/btr9ObjNG23/TnuACViozyi5MFGitW1930/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cmYD0f/btr9ObjNG23/TnuACViozyi5MFGitW1930/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcmYD0f%2Fbtr9ObjNG23%2FTnuACViozyi5MFGitW1930%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;700&quot; height=&quot;363&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;725&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;78ef&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;그리고 마지막으로 unit4A를 &lt;code&gt;nil&lt;/code&gt;로 만들면서 Apartment 인스턴스도 성공적으로 메모리를 떠나게 됩니다..!!&lt;/p&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;710&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EATSd/btr9NDVaRna/vdKpvN8Xy29C34mXEXFfV1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EATSd/btr9NDVaRna/vdKpvN8Xy29C34mXEXFfV1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EATSd/btr9NDVaRna/vdKpvN8Xy29C34mXEXFfV1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEATSd%2Fbtr9NDVaRna%2FvdKpvN8Xy29C34mXEXFfV1%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;700&quot; height=&quot;355&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;710&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div style=&quot;color: #000000; text-align: start;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div style=&quot;color: #000000; text-align: start;&quot;&gt;
&lt;p id=&quot;95d7&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;unowned&lt;/b&gt;&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 미소유 참조&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 id=&quot;7370&quot; style=&quot;list-style-type: disc; color: #292929;&quot; data-selectable-paragraph=&quot;&quot;&gt;참조하는 인스턴스의 Reference Count를 증가시키지 않는다&lt;/li&gt;
&lt;li id=&quot;842b&quot; style=&quot;list-style-type: disc; color: #292929;&quot; data-selectable-paragraph=&quot;&quot;&gt;&lt;code&gt;weak&lt;/code&gt;와 반대로 수명이 동일하거나 더 긴 인스턴스에 대하여 &lt;code&gt;unowned&lt;/code&gt;를 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p id=&quot;42ed&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;예) 고객과 신용카드 객체가 있을 때, 고객은 신용카드가 없을 수 있지만 신용카드는 고객이 없을 수 없다. 이 때 신용카드 객체에서 고객을 선언할 때 &lt;code&gt;unowned&lt;/code&gt;를 사용하면 좋다.&lt;/p&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li id=&quot;e77d&quot; style=&quot;list-style-type: disc; color: #292929;&quot; data-selectable-paragraph=&quot;&quot;&gt;또 &lt;code&gt;weak&lt;/code&gt;와 차이점은 &lt;code&gt;nil&lt;/code&gt;로 만들어 주지 않는다 (항상 값이 있다고 예상)&lt;/li&gt;
&lt;/ul&gt;
&lt;p id=&quot;0010&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;단점) 그래서 여전히 포인터가 해제된 메모리 영역을 가리키고, 접근하려 하면 당연히 에러 뜬다 &amp;rarr; Crash 발생의 우려가 있다는 문제&lt;/p&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;d569&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;따라서 &lt;code&gt;unowned&lt;/code&gt;의 특징은 아래와 같다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li id=&quot;f092&quot; style=&quot;list-style-type: decimal; color: #292929;&quot; data-selectable-paragraph=&quot;&quot;&gt;항상 값이 있다고 예상하기 때문에 &lt;code&gt;Optional&lt;/code&gt;일 필요 없음 (옵셔널도 가능은 함)&lt;/li&gt;
&lt;li id=&quot;bb13&quot; style=&quot;list-style-type: decimal; color: #292929;&quot; data-selectable-paragraph=&quot;&quot;&gt;&lt;code&gt;let&lt;/code&gt; 으로 선언한다&lt;/li&gt;
&lt;/ol&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;e136&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;이번에는 위에서 언급한 Customer와 CreditCard의 예시가 사용됐다.&lt;/p&gt;
&lt;p id=&quot;5006&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;신용카드보다 당연히? 수명이 긴 소유주를 &lt;code&gt;unowned let&lt;/code&gt;으로 선언했다.&lt;/p&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;1034&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIm2Jk/btr9CIKoU4O/DTYzhKYJtKKuIEIkIoDfKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIm2Jk/btr9CIKoU4O/DTYzhKYJtKKuIEIkIoDfKk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIm2Jk/btr9CIKoU4O/DTYzhKYJtKKuIEIkIoDfKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIm2Jk%2Fbtr9CIKoU4O%2FDTYzhKYJtKKuIEIkIoDfKk%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;700&quot; height=&quot;518&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;1034&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;9e55&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;이번에는 john의 인스턴스를 생성하고, 그 안의 card의 인스턴스를 만들어 주었다.&lt;/p&gt;
&lt;p id=&quot;f6de&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;unowned&lt;/code&gt;는 RC를 증가시키지 않기에 RC는 1로 동일.&lt;/p&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;713&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/banyEV/btr9DIDmqrM/6rH4HdKiUerRYkQXVoOdg0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/banyEV/btr9DIDmqrM/6rH4HdKiUerRYkQXVoOdg0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/banyEV/btr9DIDmqrM/6rH4HdKiUerRYkQXVoOdg0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbanyEV%2Fbtr9DIDmqrM%2F6rH4HdKiUerRYkQXVoOdg0%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;700&quot; height=&quot;357&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;713&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;9d5e&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;이 때, john을 &lt;code&gt;nil&lt;/code&gt;로 설정하게 된다면 Customer 인스턴스는 사라지고, 따라서 CreditCard 의 RC도 0이 되어 메모리에서 해제되게 된다. 이 때 &lt;code&gt;weak&lt;/code&gt;와 다르게 &lt;code&gt;customer&lt;/code&gt;의 인스턴스가 자동으로 nil이 되지 않는다.&lt;/p&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;694&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/caEslx/btr9A4f5yPR/0j5QmuCx6ZgtyegtsMTpwK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/caEslx/btr9A4f5yPR/0j5QmuCx6ZgtyegtsMTpwK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/caEslx/btr9A4f5yPR/0j5QmuCx6ZgtyegtsMTpwK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcaEslx%2Fbtr9A4f5yPR%2F0j5QmuCx6ZgtyegtsMTpwK%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;700&quot; height=&quot;348&quot; data-origin-width=&quot;1400&quot; data-origin-height=&quot;694&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;6635&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;여기까지 순환참조에 대해 알아봤다..&lt;/p&gt;
&lt;p id=&quot;45b7&quot; style=&quot;color: #292929;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;원래는 클로저에서의 &lt;code&gt;weak self&lt;/code&gt;를 왜 써야하는 지 탐구하는 목적이었는데.. 다음 편에서 이어서 해야 할 것 같다 !&lt;/p&gt;
&lt;/div&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;&lt;a href=&quot;https://mila00a.tistory.com/64&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://mila00a.tistory.com/64&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1681279344292&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;클로저에서의 weak self &amp;mdash; 순환참조 (2)&quot; data-og-description=&quot;https://mila00a.tistory.com/63 ARC를 곁들인 순환참조 (1) 혹은 순환참조를 곁들인 ARC&amp;hellip; ARC (Automatic Reference Counting) Swift에서 앱의 메모리를 관리하는 방법 간단하게는 자동으로 메모리를 관리해주는 녀석&quot; data-og-host=&quot;mila00a.tistory.com&quot; data-og-source-url=&quot;https://mila00a.tistory.com/64&quot; data-og-url=&quot;https://mila00a.tistory.com/64&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/vbdVj/hySeZ2tvMB/4cR8zrPrbM4jOqWlGb21q1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/cBlsza/hySgtVdm4r/Son7AhtAfHriQOD1HQ1sJK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800&quot;&gt;&lt;a href=&quot;https://mila00a.tistory.com/64&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://mila00a.tistory.com/64&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/vbdVj/hySeZ2tvMB/4cR8zrPrbM4jOqWlGb21q1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/cBlsza/hySgtVdm4r/Son7AhtAfHriQOD1HQ1sJK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800');&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;클로저에서의 weak self &amp;mdash; 순환참조 (2)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;https://mila00a.tistory.com/63 ARC를 곁들인 순환참조 (1) 혹은 순환참조를 곁들인 ARC&amp;hellip; ARC (Automatic Reference Counting) Swift에서 앱의 메모리를 관리하는 방법 간단하게는 자동으로 메모리를 관리해주는 녀석&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;mila00a.tistory.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;&amp;nbsp;&lt;/p&gt;</description>
      <category>iOS/Swift</category>
      <category>ARC</category>
      <category>ios</category>
      <category>순환참조</category>
      <author>Mila00a</author>
      <guid isPermaLink="true">https://mila00a.tistory.com/63</guid>
      <comments>https://mila00a.tistory.com/63#entry63comment</comments>
      <pubDate>Wed, 12 Apr 2023 14:47:25 +0900</pubDate>
    </item>
    <item>
      <title>RxSwift 곰튀김 강의 정리 (기초)</title>
      <link>https://mila00a.tistory.com/62</link>
      <description>&lt;div style=&quot;color: #000000; text-align: start;&quot;&gt;
&lt;p id=&quot;d1a2&quot; style=&quot;color: #292929;&quot; data-ke-size=&quot;size16&quot;&gt;곰튀김님의 RxSwift 강의를 정리했습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;p style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 id=&quot;1897&quot; style=&quot;color: #292929; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;유튜브 링크&lt;/h4&gt;
&lt;div&gt;
&lt;div&gt;&lt;a href=&quot;https://youtu.be/iHKBNYMWd5I&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://youtu.be/iHKBNYMWd5I&lt;/a&gt;&lt;/div&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=iHKBNYMWd5I&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/bNF2q8/hySeZHG0kB/JSJ6GKqwrAmHHxw8WtTjk1/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720&quot; data-video-width=&quot;860&quot; data-video-height=&quot;484&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-video-title=&quot;시즌2 모임 종합편 입니다.&quot; data-original-url=&quot;&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/iHKBNYMWd5I&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;h4 id=&quot;0062&quot; style=&quot;color: #292929; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;깃허브 링크&lt;/h4&gt;
&lt;div style=&quot;color: #000000; text-align: start;&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/Minkyeong-Ko/RxSwift_In_4_Hours&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/Minkyeong-Ko/RxSwift_In_4_Hours&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1681218164222&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - Minkyeong-Ko/RxSwift_In_4_Hours: RxSwift, 4시간 안에 빠르게 익혀 실무에 사용하기&quot; data-og-description=&quot;RxSwift, 4시간 안에 빠르게 익혀 실무에 사용하기. Contribute to Minkyeong-Ko/RxSwift_In_4_Hours development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/Minkyeong-Ko/RxSwift_In_4_Hours&quot; data-og-url=&quot;https://github.com/Minkyeong-Ko/RxSwift_In_4_Hours&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dMWHG8/hySe1yIl3q/3jYQaTVWqHx8a9QxmgyZ0k/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/Minkyeong-Ko/RxSwift_In_4_Hours&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/Minkyeong-Ko/RxSwift_In_4_Hours&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dMWHG8/hySe1yIl3q/3jYQaTVWqHx8a9QxmgyZ0k/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&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;GitHub - Minkyeong-Ko/RxSwift_In_4_Hours: RxSwift, 4시간 안에 빠르게 익혀 실무에 사용하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;RxSwift, 4시간 안에 빠르게 익혀 실무에 사용하기. Contribute to Minkyeong-Ko/RxSwift_In_4_Hours development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.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;/div&gt;
&lt;h2 id=&quot;b556&quot; style=&quot;color: #292929; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;공부하게 된 이유&lt;/h2&gt;
&lt;p id=&quot;3145&quot; style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;팀 프로젝트에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;RxSwift를 사용하게 되었다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;MVC에서 C가 비대해지고 비즈니스 로직을 분리하기 위해서&lt;span&gt;&amp;nbsp;&lt;/span&gt;MVVM&lt;span&gt;&amp;nbsp;&lt;/span&gt;사용,&lt;span&gt;&amp;nbsp;&lt;/span&gt;MVVM에서 데이터 바인딩을 쉽게 하기 위해서&lt;span&gt;&amp;nbsp;&lt;/span&gt;RxSwift사용이라는 팀원의 말에 설득되었다.&lt;/p&gt;
&lt;p id=&quot;9296&quot; style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;팀 안에서 스터디도 하고 빠르게 실제로 프로젝트에 적용도 했지만, 애자일하게 진행되는 스프린트다 보니 겉핥기식 공부만 하게 되었다. 2주 가량의 개발이 끝나고&lt;span&gt;&amp;nbsp;&lt;/span&gt;RxSwift를 미처 적용하지 못한 코드들을 리팩토링을 하려 하니 전혀 손 댈 수 없이 막막해서 곰튀김님의 4시간짜리 강의를 듣기로 결심했다.&lt;/p&gt;
&lt;p style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;d4ae&quot; style=&quot;color: #292929; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;1교시 &amp;mdash; RxSwift를 사용한 비동기 프로그래밍&lt;/h2&gt;
&lt;p id=&quot;5247&quot; style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;모든 강의가 실습과 함께 이루어지기 때문에 모든 예시를 적기엔 힘들어서 최대한 이해한 개념을 적으려고 노력했다.&lt;/p&gt;
&lt;p style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;d330&quot; style=&quot;color: #292929; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;기존 코드에서 느끼는 불편한 점들&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li id=&quot;cd98&quot; style=&quot;list-style-type: disc; color: #292929;&quot; data-selectable-paragraph=&quot;&quot;&gt;동기로 작동하는 코드를 비동기로 바꿔주고 싶다. &amp;rarr; 어떤 일들이 동시에 일어났으면 좋겠다&lt;/li&gt;
&lt;li id=&quot;a159&quot; style=&quot;list-style-type: disc; color: #292929;&quot; data-selectable-paragraph=&quot;&quot;&gt;UI는 메인에서 그려져야 한다. &amp;rarr; 코드마다 사용하는 스레드가 달라서 불편하다&lt;/li&gt;
&lt;li id=&quot;a76b&quot; style=&quot;list-style-type: disc; color: #292929;&quot; data-selectable-paragraph=&quot;&quot;&gt;비동기적으로 이뤄지는 부분만 함수로 따로 빼고 싶다. &amp;rarr; 그런데 함수 안에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;DispatchQueue&lt;/code&gt;를 사용하면 값을 리턴하지 못해서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;completion&lt;/code&gt;을 사용해야 한다&lt;/li&gt;
&lt;li id=&quot;5d02&quot; style=&quot;list-style-type: disc; color: #292929;&quot; data-selectable-paragraph=&quot;&quot;&gt;비동기로 생성되는 데이터도&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;completion&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;대신 리턴 값을 받고 싶다. &amp;rarr; 일반적으로 여러 번 호출을 하면 depth가 깊어질 수 있어서 불편하다&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1272&quot; data-origin-height=&quot;559&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lz1Yn/btr9wIqxDzZ/Voe5WOxRXFxRkxFIXfaknk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lz1Yn/btr9wIqxDzZ/Voe5WOxRXFxRkxFIXfaknk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lz1Yn/btr9wIqxDzZ/Voe5WOxRXFxRkxFIXfaknk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Flz1Yn%2Fbtr9wIqxDzZ%2FVoe5WOxRXFxRkxFIXfaknk%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;700&quot; height=&quot;308&quot; data-origin-width=&quot;1272&quot; data-origin-height=&quot;559&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li id=&quot;d74f&quot; style=&quot;list-style-type: disc; color: #292929;&quot; data-selectable-paragraph=&quot;&quot;&gt;기타:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;@escaping&lt;/code&gt;은 본체 함수가 끝나고 나서 나중에 실행되는 함수라는 의미 &amp;rarr; 비동기적으로 코드가 처리되니 본 함수가 끝난 후에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;completion&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;이 실행된다&lt;/li&gt;
&lt;/ul&gt;
&lt;p id=&quot;b2a5&quot; style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;결과적으로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;비동기로 생성되는 데이터를 어떻게 리턴 값으로 만들지?&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;하는 고민이 생기게 된다.&lt;/p&gt;
&lt;p style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;6975&quot; style=&quot;color: #292929; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;비동기로 생성되는 데이터를 리턴 값으로 만들기&lt;/h3&gt;
&lt;p id=&quot;aa23&quot; style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;비동기적으로(나중에) 오는 &lt;code&gt;json(String)&lt;/code&gt; 값을 받아서 그게 오면 UI 를 업데이트 해 보자.&lt;/p&gt;
&lt;pre class=&quot;swift&quot; style=&quot;background-color: #f9f9f9; color: #292929; text-align: start;&quot; data-ke-language=&quot;swift&quot;&gt;&lt;code&gt;let json: 나중에생기는데이터&amp;lt;String&amp;gt; = downloadJSON(...)

json.나중에오면 {
  // UI 바꾸기(텍스트 변경) 등의 작업
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;8d1d&quot; style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;여기서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;나중에생기는데이터&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;는 아래와 같은 모습을 하고 있을 것이다.&lt;/p&gt;
&lt;p style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;swift&quot; style=&quot;background-color: #f9f9f9; color: #292929; text-align: start;&quot; data-ke-language=&quot;swift&quot;&gt;&lt;code&gt;class 나중에생기는데이터&amp;lt;T&amp;gt; {
    //// 여기서 나중에 생기는 데이터를 넣어 줄 거다
    private let task: (@escaping (T) -&amp;gt; Void) -&amp;gt; Void

    init(task: @escaping (@escaping (T) -&amp;gt; Void) -&amp;gt; Void) {
        self.task = task
    }

    //// 여기서는 나중에 생긴 데이터를 가지고 어떤 작업(f)을 해 줄 거다
    func 나중에오면(_ f: @escaping (T) -&amp;gt; Void) {
        task(f)
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;fed4&quot; style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;여기서 클로저가 너무 많아서 이해하는 데 정말 오래 걸렸다..&lt;/p&gt;
&lt;p id=&quot;510a&quot; style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;그래서 코드를 써 보면서 이해를 했다. 우선 결론은 아래 처럼 쓰면 된다.&lt;/p&gt;
&lt;p style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;swift&quot; style=&quot;background-color: #f9f9f9; color: #292929; text-align: start;&quot; data-ke-language=&quot;swift&quot;&gt;&lt;code&gt;let 나중에생길데이터1 = 나중에생기는데이터&amp;lt;String&amp;gt; { f in
    DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 3) {
        // 여기서 f는 나중에 데이터가 오면 할 작업
        f(&quot;나중에 생긴 데이터 1&quot;)
    }
}
        
let 나중에생길데이터2: 나중에생기는데이터&amp;lt;String&amp;gt; = 나중에생기는데이터 { f in
    DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 2) {
        // 여기서 f는 나중에 데이터가 오면 할 작업
        f(&quot;나중에 생긴 데이터 2&quot;)
    }
}
        
나중에생길데이터1.나중에오면 { str in
    print(str)
}
나중에생길데이터2.나중에오면 { str in
    print(str)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;d297&quot; style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;포인트는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;데이터가 나중에 생기더라도 그 리턴 값을 가지고 원하는 동작을 해 줄 수 있다&lt;/b&gt;는 것! 출력 결과는 아래와 같다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;807&quot; data-origin-height=&quot;437&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cNjGlq/btr9BYle8VH/TDo7v2KXiC3nrYEAFDEMxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cNjGlq/btr9BYle8VH/TDo7v2KXiC3nrYEAFDEMxK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cNjGlq/btr9BYle8VH/TDo7v2KXiC3nrYEAFDEMxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcNjGlq%2Fbtr9BYle8VH%2FTDo7v2KXiC3nrYEAFDEMxK%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;700&quot; height=&quot;380&quot; data-origin-width=&quot;807&quot; data-origin-height=&quot;437&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;e948&quot; style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;나중에생길데이터2&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;가 2초 뒤,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;나중에생길데이터1&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;이 3초 뒤에 전달이 되니까 순서가 저렇게 출력된다.&lt;/p&gt;
&lt;p id=&quot;a383&quot; style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;이제는 영상의 예제 코드 안의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;downloadJSON&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;이라는 함수를 예를 들어서 살펴 보자.&lt;/p&gt;
&lt;p id=&quot;6495&quot; style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;기존 구조는 아래와 같다.&lt;/p&gt;
&lt;p style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;swift&quot; style=&quot;background-color: #f9f9f9; color: #292929; text-align: start;&quot; data-ke-language=&quot;swift&quot;&gt;&lt;code&gt;func downloadJSON(_ url: String, _ completion: ((String) -&amp;gt; Void)?) {
    DispatchQueue.global().async {
        let url = URL(string: url)!
        let data = try! Data(contentsOf: url)
        let json = String(data: data, encoding: .utf8)
                
        DispatchQueue.main.async {
            completion?(json)
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;e8bc&quot; style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;아까 정의한 나중에생기는데이터 를 사용하면 아래처럼 바꿀 수 있을 것이다. 이 때&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;completion&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;대신&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;나중에생기는데이터&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;라는 것 자체를 리턴할 수 있다.&lt;/p&gt;
&lt;p style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;swift&quot; style=&quot;background-color: #f9f9f9; color: #292929; text-align: start;&quot; data-ke-language=&quot;swift&quot;&gt;&lt;code&gt;func downloadJSON(_ url: String) -&amp;gt; 나중에생기는데이터&amp;lt;String?&amp;gt; {
    return 나중에생기는데이터() { f in
        DispatchQueue.global().async {
            let url = URL(string: url)!
            let data = try! Data(contentsOf: url)
            let json = String(data: data, encoding: .utf8)
                
            // f는 메인 스레드에서 실행되어야 하는 작업 (UI를 바꿀 것임)
            DispatchQueue.main.async {
                // json 데이터가 오면 f에 넣어준다
                f(json)
            }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;4fc5&quot; style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;RxSwift&lt;span&gt;&amp;nbsp;&lt;/span&gt;문법을 써서 바꿔 보면 아래와 같다.&lt;/p&gt;
&lt;p style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;swift&quot; style=&quot;background-color: #f9f9f9; color: #292929; text-align: start;&quot; data-ke-language=&quot;swift&quot;&gt;&lt;code&gt;func downloadJSON(_ url: String) -&amp;gt; Observable&amp;lt;String?&amp;gt; {
    return Observable.create() { f in
        DispatchQueue.global().async {
            let url = URL(string: url)!
            let data = try! Data(contentsOf: url)
            let json = String(data: data, encoding: .utf8)
                
            DispatchQueue.main.async {
                f.onNext(json)
            }
        }
        return Disposables.create()
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;6cad&quot; style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;그래서 이제 과정을 좀 정리해 보면 아래와 같다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li id=&quot;d90e&quot; style=&quot;list-style-type: decimal; color: #292929;&quot; data-selectable-paragraph=&quot;&quot;&gt;비동기로 생기는 데이터를 &lt;code&gt;Observable&lt;/code&gt;로 감싸서 리턴한다.&lt;/li&gt;
&lt;li id=&quot;b4e7&quot; style=&quot;list-style-type: decimal; color: #292929;&quot; data-selectable-paragraph=&quot;&quot;&gt;&lt;code&gt;Observable&lt;/code&gt;로 오는 데이터를 받아서 처리한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p style=&quot;color: #292929; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;3b40&quot; style=&quot;color: #292929; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;비동기로 생기는 데이터를 &lt;code&gt;Observable&lt;/code&gt;로 감싸서 리턴하기&lt;/h2&gt;
&lt;p id=&quot;9183&quot; style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;RxSwift의 옵저버블에는 생명 주기가 있다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li id=&quot;a3c5&quot; style=&quot;list-style-type: decimal; color: #292929;&quot; data-selectable-paragraph=&quot;&quot;&gt;Create (생성)&lt;/li&gt;
&lt;li id=&quot;1153&quot; style=&quot;list-style-type: decimal; color: #292929;&quot; data-selectable-paragraph=&quot;&quot;&gt;Subscribed (구독됨) &amp;rArr; 여기 부터 동작하기 시작한다&lt;/li&gt;
&lt;li id=&quot;ff31&quot; style=&quot;list-style-type: decimal; color: #292929;&quot; data-selectable-paragraph=&quot;&quot;&gt;Next (데이터 전달)&lt;/li&gt;
&lt;li id=&quot;8fe4&quot; style=&quot;list-style-type: decimal; color: #292929;&quot; data-selectable-paragraph=&quot;&quot;&gt;Complete (완료) or Error (에러) &amp;rArr; 종료&lt;/li&gt;
&lt;li id=&quot;7eab&quot; style=&quot;list-style-type: decimal; color: #292929;&quot; data-selectable-paragraph=&quot;&quot;&gt;Disposed (메모리 해제)&lt;/li&gt;
&lt;/ol&gt;
&lt;p style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;a950&quot; style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;앞서 보았던 코드를 제대로 바꿔 보면 아래와 같은 모양을 하고 있을 것이다.&lt;/p&gt;
&lt;p style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;swift&quot; style=&quot;background-color: #f9f9f9; color: #292929; text-align: start;&quot; data-ke-language=&quot;swift&quot;&gt;&lt;code&gt;return Observable.create() { emitter in
    let url = URL(string: url)!
    let task = URLSession.shared.dataTask(with: url) { data, _, error in
        guard error == nil else {
            // 에러 방출
            emitter.onError(error!)
            return
        }
                
        if let data = data, let json = String(data: data, encoding: .utf8) {
            // 데이터 전달
            emitter.onNext(json)
        }
				
        // 옵저버블 할 일 완료
        emitter.onCompleted()
    }
            
    task.resume()
            
    return Disposables.create() {
        task.cancel()
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h1 style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot;&gt;&amp;nbsp;&lt;/h1&gt;
&lt;h2 id=&quot;6bfd&quot; style=&quot;color: #292929; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;Observable 로 오는 데이터를 받아서 처리하기&lt;/h2&gt;
&lt;pre class=&quot;swift&quot; style=&quot;background-color: #f9f9f9; color: #292929; text-align: start;&quot; data-ke-language=&quot;swift&quot;&gt;&lt;code&gt;let observable = downloadJSON(MEMBER_LIST_URL)

// subscribe 부터 동작
let disposable = observable.subscribe { event in
    switch event {
    case .next(let json):
        // json 가지고 작업
    case .error(let error):
        // 에러 처리
    case .completed:
        // 끝났을 때 할 일
    }
}
        
// 메모리에서 해제
disposable.dispose()&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;9c33&quot; style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;앞서&lt;span&gt;&amp;nbsp;&lt;/span&gt;나중에오면&lt;span&gt;&amp;nbsp;&lt;/span&gt;에서 했던 것과 큰 차이가 없다!&lt;/p&gt;
&lt;p style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;db4b&quot; style=&quot;color: #292929; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;ReaxtiveX 오퍼레이터&lt;/h2&gt;
&lt;p id=&quot;eb2c&quot; style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;옵저버블 데이터랑&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;subscriber&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;사이에서 뭔가 작업을 해 주는 녀석들을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;operator&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;라고 한다.&lt;/p&gt;
&lt;p style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;swift&quot; style=&quot;background-color: #f9f9f9; color: #292929; text-align: start;&quot; data-ke-language=&quot;swift&quot;&gt;&lt;code&gt;옵저버블
    .observeOn(MainSchedular.instance) // 메인 스레드 사용하는 operator
    .subscribe {
  	...
    }

// observeOn 말고도
.map{...}
.filter{...}
// 등등이 있다.&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;&lt;a href=&quot;https://reactivex.io/documentation/operators.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://reactivex.io/documentation/operators.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1681218372530&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;ReactiveX - Operators&quot; data-og-description=&quot;Introduction Each language-specific implementation of ReactiveX implements a set of operators. Although there is much overlap between implementations, there are also some operators that are only implemented in certain implementations. Also, each implementa&quot; data-og-host=&quot;reactivex.io&quot; data-og-source-url=&quot;https://reactivex.io/documentation/operators.html&quot; data-og-url=&quot;https://reactivex.io/documentation/operators.html&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://reactivex.io/documentation/operators.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://reactivex.io/documentation/operators.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;ReactiveX - Operators&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Introduction Each language-specific implementation of ReactiveX implements a set of operators. Although there is much overlap between implementations, there are also some operators that are only implemented in certain implementations. Also, each implementa&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;reactivex.io&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;div style=&quot;color: #000000; text-align: start;&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;p id=&quot;d4fd&quot; style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;여기 사이트를 가면 Marvel 그림과 함께 오퍼레이터들의 동작이 잘 설명되어 있다.&lt;/p&gt;
&lt;p id=&quot;4837&quot; style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;just&lt;/code&gt;는 데이터를 가지고 옵저버블을 생성할 수 있도록 해 주는 녀석인데 아래 그림처럼나와 있다.&lt;/p&gt;
&lt;p style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1249&quot; data-origin-height=&quot;822&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/de7Ug6/btr9yxvuKqk/5KISoH3pV7pnFxBbOguUt0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/de7Ug6/btr9yxvuKqk/5KISoH3pV7pnFxBbOguUt0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/de7Ug6/btr9yxvuKqk/5KISoH3pV7pnFxBbOguUt0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fde7Ug6%2Fbtr9yxvuKqk%2F5KISoH3pV7pnFxBbOguUt0%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;700&quot; height=&quot;461&quot; data-origin-width=&quot;1249&quot; data-origin-height=&quot;822&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;621f&quot; style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;그리고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;Map&lt;/code&gt;은 방출된 옵저버블 데이터에 함수를 적용할 수 있게 하는 녀석이다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1293&quot; data-origin-height=&quot;882&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bEVtJU/btr9AZEJ1HD/DkeHSbKwHI3l42efX8dUFk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bEVtJU/btr9AZEJ1HD/DkeHSbKwHI3l42efX8dUFk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bEVtJU/btr9AZEJ1HD/DkeHSbKwHI3l42efX8dUFk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbEVtJU%2Fbtr9AZEJ1HD%2FDkeHSbKwHI3l42efX8dUFk%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;700&quot; height=&quot;478&quot; data-origin-width=&quot;1293&quot; data-origin-height=&quot;882&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;c218&quot; style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;아래는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;observeOn&lt;/code&gt;과&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;subscribeOn&lt;/code&gt;의 차이를 알려주는 그림인데,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;observeOn&lt;/code&gt;은 즉각 스레드 적용이 되는 데 반해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;subscribeOn&lt;/code&gt;은 그렇지 않다는 것을 알 수 있다. 왜냐하면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;subscribeOn&lt;/code&gt;은 처음 스레드로만 적용이 되기 때문! 그림과 함께 너무나도 깔끔하게 이해할 있다.&lt;/p&gt;
&lt;p style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;818&quot; data-origin-height=&quot;1077&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/L0W46/btr9sjxyMso/uEED1eU9hMhtdKadd6qxw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/L0W46/btr9sjxyMso/uEED1eU9hMhtdKadd6qxw0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/L0W46/btr9sjxyMso/uEED1eU9hMhtdKadd6qxw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FL0W46%2Fbtr9sjxyMso%2FuEED1eU9hMhtdKadd6qxw0%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;700&quot; height=&quot;922&quot; data-origin-width=&quot;818&quot; data-origin-height=&quot;1077&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;211a&quot; style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;여기까지 1교시로 분류되는 것 같다. 정말 유익했다.. 곰튀김님 최고.&lt;/p&gt;
&lt;p style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #292929; text-align: start;&quot; data-selectable-paragraph=&quot;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>iOS</category>
      <category>ios</category>
      <category>RxSwift</category>
      <author>Mila00a</author>
      <guid isPermaLink="true">https://mila00a.tistory.com/62</guid>
      <comments>https://mila00a.tistory.com/62#entry62comment</comments>
      <pubDate>Tue, 11 Apr 2023 22:12:38 +0900</pubDate>
    </item>
    <item>
      <title>✍️ 협업을 통해 알게 된 Git 그리고 Github</title>
      <link>https://mila00a.tistory.com/61</link>
      <description>&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;개요&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘 제가 작성할 내용에는 제가 프로젝트를 하며 경험하고 배웠던 내용이 담겨있습니다. 저는 올해 iOS 개발을 시작한 후 지금까지 그간 4번의 팀 프로젝트를 경험했는데, 정말 협업에 대해 1도 몰랐던 사람에서 현재는 그래도 어찌됐든 1인분의 역할 정도는 하게 된 것 같다는.. 생각을 하고는 있습니다 &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;과거에도 깃이 정말 중요하다는 말을 들었지만, 저는 실제 협업을 경험하기 전까지는 그걸 깨닫지 못했었습니다. 이제는 여러 번의 협업 흐름을 경험했고, 점점 몸에 익기 시작하는 지금 시점에 Git과 Github가 얼마나 중요하게 쓰이는 지 얼른 정리를 해 두어야겠다 싶어서 글을 작성하게 되었습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;(제가 경험한) 협업의 흐름&lt;/h3&gt;
&lt;p data-ke-size=&quot;size14&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;팀 안에 협업 경력자가 있다면, 보통은 개발 시작 전 아래의 과정들을 주도하시게 됩니다. 경력자가 없더라도 충분히 가능하지만요!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(깃 레포지터리 생성 및 세팅각종 컨벤션 및 규칙 정하기, 프로젝트 설정, 디렉터리 구조,&amp;nbsp;&amp;hellip; 기타 등등)&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;b&gt;본격적으로 개발이 시작되면,&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;개발자들이 각자 맡은 태스크를 깃헙에&lt;span&gt;&amp;nbsp;&lt;/span&gt;Issue&lt;span&gt;&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&gt;&amp;nbsp;&lt;/span&gt;branch&lt;span&gt;&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;저는 계속 Feature 단위로 작업을 했었기 때문에, 하나의 task &amp;mdash; 즉 Feature 단위로 브랜치를 생성하였습니다.&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;code&gt;danila/notesView&lt;/code&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;feature/#32_notesView&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/code&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&gt;&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;작업이 끝이 나면,&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;각자 자신의 브랜치에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;열심히 개발을 한 뒤 끝이 나면&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;코드를 Push합니다.&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;Push 후 Github에서 작업 내용이 상세히 담긴&lt;span&gt;&amp;nbsp;&lt;/span&gt;Pull Request를 날립니다.&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;동료 개발자들 또는 디자이너/PM 들로 부터&lt;span&gt;&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;변경사항이나 실수가 있다면 즉각 수정하고 Push합니다.&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;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Approve를 받으면 머지&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;이 때, 올리고자 하는 브랜치와&lt;span&gt;&amp;nbsp;&lt;/span&gt;Conflict가 있으면 해결 뒤에 머지를 합니다.&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;p data-ke-size=&quot;size16&quot;&gt;하지만 매우 간략하게 정리한 만큼, 더 깊게 알아야 하는 내용들이 더 숨어있습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;브랜치 전략&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통의 경우엔 &lt;code&gt;main &amp;rarr; develop&lt;/code&gt;으로, 출시와 유지보수가 계획된 프로젝트라면 &lt;code&gt;main &amp;rarr; develop &amp;rarr; release&lt;/code&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;b&gt;main&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;출시된 버전만 존재하는 브랜치입니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Hotfix&lt;/code&gt; (급하게 수정해야 하는 버그 등등이 적용됨) 용 브랜치로도 쓰입니다.&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;&lt;b&gt;develop&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;지금까지 개발 내역이 담겨 있습니다.&lt;/li&gt;
&lt;li&gt;버그를 수정하는 데 쓰이기도 합니다.&lt;/li&gt;
&lt;li&gt;현재 진행중인 스프린트에 포함되지 않는 작업을 할 때, &lt;code&gt;develop&lt;/code&gt; 브랜치로부터 새로운 브랜치를 따서 작업을 합니다.&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;&lt;b&gt;release&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;스프린트 작업 (출시를 위한) 브랜치입니다.&lt;/li&gt;
&lt;li&gt;현재 진행중인 스프린트에 포함되는 작업을 할 때, &lt;code&gt;release&lt;/code&gt; 브랜치로부터 새로운 브랜치를 생성하여 작업합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;브랜치 원칙&lt;/h3&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;&lt;b&gt;스프린트 시작 상태&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;&lt;b&gt;&lt;code&gt;develop&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;rarr;&lt;span&gt;&amp;nbsp;&lt;/span&gt;release&lt;/code&gt;&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;release&lt;/code&gt; (스프린트 용) 브랜치를 하나 더 두는 이유는 &lt;code&gt;release&lt;/code&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;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;스프린트가 진행되면&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;&lt;b&gt;&lt;code&gt;release&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;rarr;&lt;span&gt;&amp;nbsp;&lt;/span&gt;releaseLocal (자유)&lt;/code&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;code&gt;releaseLocal&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;rarr;&lt;span&gt;&amp;nbsp;&lt;/span&gt;dani/feature1&amp;nbsp;,&amp;nbsp;&amp;hellip;&lt;/code&gt;&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;releaseLocal&lt;/code&gt; 브랜치는 굳이 딸 필요는 없지만, 저는 초기의 &lt;code&gt;release&lt;/code&gt; 브랜치 상태를 간직하기 위해 사용했었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;&lt;b&gt;&lt;code&gt;develop&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;rarr;&lt;span&gt;&amp;nbsp;&lt;/span&gt;develop&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/code&gt;으로는 버그 수정 외에는 웬만하면 머지하지 않습니다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;&lt;code&gt;release (에서 딴 브랜치)&amp;rarr;&lt;span&gt;&amp;nbsp;&lt;/span&gt;release&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/code&gt;로 머지합니다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미 초기 &lt;code&gt;release&lt;/code&gt; 상태가 보장되어 있고, 뒤늦게 한꺼번에 merge를 하면 무수한 컨플릭이 날 수 있기 때문에 머지 준비가 되는 즉시 &lt;code&gt;release&lt;/code&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;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;스프린트에 들어가지 않는 작업&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;&lt;b&gt;&lt;code&gt;develop&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/code&gt;에서 따서 계속 작업하다가 스프린트 머지될 때마다 코드를 최신 상태로 유지하고, 스프린트에 해당될 때 해당 &lt;code&gt;release&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/code&gt;로 PR을 날려야 합니다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 스프린트에 들어가지 않는 브랜치는 오래 놔두지 않는 게 좋습니다. 코드가 업데이트 될 때 마다 계속 pull을 해서 conflict를 해결하는 게 쉽지 않기 때문입니다. 이 문제를 해결하기 위해 스프린트에 들어갈 정도로 태스크를 쪼개는 것을 추천합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Origin과 Upstream (fork)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 주로 팀원 모두가 원본 레포지터리를 Clone 해서 작업을 했었습니다. 그런데 팀원 수가 많았던 한 프로젝트에서는 원본 레포지터리를 모두가 Fork 해서 작업을 했었습니다.&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;이유는, Fork를 하면 우선 원본 브랜치에는 필요한 브랜치만 남길 수 있어서 깔끔합니다. 그리고 잘못 push를 하더라도 바로 머지되는 게 아니라 PR를 반드시 거쳐야 하기 때문에 원격 레포지터리의 코드가 보호받을 수 있습니다.&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;code&gt;Origin&lt;/code&gt;은 Fork해서 새로 생긴 복사된 나의 레포지터리를 의미하고, &lt;code&gt;Upstream&lt;/code&gt;은 원본 레포지터리를 의미합니다. 때에 따라 적절한 곳에서 pull을 받고 push를 하기 위해서는 &lt;code&gt;Origin&lt;/code&gt;과 &lt;code&gt;Upstream&lt;/code&gt;을 잘 알고 사용하는 것이 중요합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;세 가지 종류의 Merge&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Merge에는 세 가지 종류가 있습니다.&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;Pull Request에서 머지를 할 때&lt;/p&gt;
  &lt;p data-ke-size=&quot;size16&quot;&gt;1) Create a merge commit, 2) Squash and merge, 3) Rebase and merge&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;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;커밋 기록이 남고 기존 브랜치가 트리에 그대로 남는 방식&lt;/li&gt;
&lt;li&gt;한 브랜치의 커밋 기록을 합쳐서 기존 브랜치에 병합하는 방식&lt;/li&gt;
&lt;li&gt;브랜치의 커밋 기록이 각각 기존 브랜치에 순서대로 모두 옮겨오는 방식&lt;/li&gt;
&lt;/ol&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;&amp;nbsp;&lt;/span&gt;Squash&lt;span&gt;&amp;nbsp;&lt;/span&gt;머지나&lt;span&gt;&amp;nbsp;&lt;/span&gt;Rebase&lt;span&gt;&amp;nbsp;&lt;/span&gt;머지가 Tree가 깔끔하게 남기 때문에 선호하는 편입니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Github의 다양한 기능&lt;/h3&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;wiki&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이름에 걸맞게 여러 가지 정보들을 적어놓을 수 있는 공간입니다. 보통은 팀원들 모두가 참고할 수 있게 다양한 컨벤션을 적어놓습니다. 그리고 가끔은 데일리 스크럼이나 스프린트 진행상황을 Wiki에 기록해 놓는 경우도 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;&lt;b&gt;projects&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 칸반을 관리할 수 있는 공간입니다. 원하는 대로 여러 자동화 설정을 할 수 있습니다. 보통은 이슈가 올라오면 자동으로 &lt;code&gt;Todo&lt;/code&gt;, PR이 올라오면 &lt;code&gt;In Progress&lt;/code&gt;, Approve 후 머지되면 &lt;code&gt;Done&lt;/code&gt;으로 이동하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;&lt;b&gt;Actions&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PR이 올라온 코드에 대해 빌드 테스트를 하도록 하는 기능입니다. 따로 확인하지 않아도 빌드 오류가 있는지 알 수 있어서 편리합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;&lt;b&gt;Discussion&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 내용을 자유롭게 적고 이야기 나눌 수 있는 공간입니다. 토론을 하는데 활발히 사용되지는 않지만, 보통은 새롭게 알게된 정보나 공유하고 싶은 정보를 적기도 합니다. 개인적으로 좋아하는 공간입니다:)&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;마무리하며&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘 단순히 깃을 정리한 게 아니라&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;협업을 위한&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;깃과 깃허브를 정리했다는게 저 개인적으로는 의미가 있는 것 같습니다. 계속해서 팀 프로젝트를 하며 정말 열심히 배우고 있긴 하지만, 아직도 주변 능력자 분들을 보면 &lt;code&gt;UITest&lt;/code&gt;, &lt;code&gt;RxSwift&lt;/code&gt;,&amp;nbsp;.. 등등 제가 알지 못하는 툴에 대해 관심을 가지고 계십니다. 언제쯤 그들을 따라잡을 수 있을지.. 걱정도 많이 듭니다. 그런데 보다 보면 단계가 있는 것 같다는 생각이 들었습니다. 단계가 있다는 건 따라갈 길이 있다는 것이니 다행이라고 생각이 드네요! 이제 어떻게 빠르게 그 단계를 따라 갈 수 있을지 고민하고 노력해야겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;665&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/beBctk/btr9A3G8lVs/I88yNohwKss9wgprAaN9Ok/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/beBctk/btr9A3G8lVs/I88yNohwKss9wgprAaN9Ok/img.jpg&quot; data-alt=&quot;귀여운 옥토캣&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/beBctk/btr9A3G8lVs/I88yNohwKss9wgprAaN9Ok/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbeBctk%2Fbtr9A3G8lVs%2FI88yNohwKss9wgprAaN9Ok%2Fimg.jpg&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;800&quot; height=&quot;665&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;665&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;귀여운 옥토캣&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Else</category>
      <category>github</category>
      <category>협업</category>
      <author>Mila00a</author>
      <guid isPermaLink="true">https://mila00a.tistory.com/61</guid>
      <comments>https://mila00a.tistory.com/61#entry61comment</comments>
      <pubDate>Tue, 11 Apr 2023 21:59:59 +0900</pubDate>
    </item>
    <item>
      <title>Xcode의 Scheme이란</title>
      <link>https://mila00a.tistory.com/60</link>
      <description>&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Xcode의 scheme 에 대하여&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트의 이름을 변경하는 과정에서 &lt;code&gt;Scheme&lt;/code&gt;에 대한 궁금증이 생겨서, 최신 애플 공식 문서를 보고 &lt;code&gt;target&lt;/code&gt;과 &lt;code&gt;scheme&lt;/code&gt;에 대한 가닥.. 정도만 잡는 것을 목표로 한번 알아보았다.&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;Target&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 처음에 알아보고 싶었던 건 &lt;code&gt;Scheme&lt;/code&gt;이었었는데, &lt;code&gt;Target&lt;/code&gt;을 먼저 알아야 온전히 이해할 수 있겠다는 생각이 들었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기 애플에서 제공하는 &lt;code&gt;target&lt;/code&gt;에 대한 설명을 보면,&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;A&lt;span&gt;&amp;nbsp;&lt;/span&gt;target&lt;span&gt;&amp;nbsp;&lt;/span&gt;specifies a product to build, such as an iOS, watchOS, or macOS app. When you create a project from a template, targets are added automatically. If you choose Unit and UI tests when creating a project, the project includes targets for the main app and the test apps. A watchOS app, that is dependent on an iOS app, has targets for the iOS app, WatchKit extension, and WatchKit app. macOS apps can have multiple targets too. Choose a target in the project editor to view and modify the target&amp;rsquo;s settings. Click the Add button (+) in the project editor to add a new Application, Framework &amp;amp; Library, Test, or Application Extension target to your project.&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;이렇게 나와 있는데 요약하자면,&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;target&lt;/code&gt;은 iOS/watchOS/macOS 앱과 같은, 빌드될 프로덕트를 정의한다&lt;/li&gt;
&lt;li&gt;타겟은 템플릿 프로젝트를 생성할 때 자동으로 추가된다&lt;/li&gt;
&lt;li&gt;프로젝트 생성 시 &lt;code&gt;UnitUI&lt;/code&gt;과 &lt;code&gt;UITest&lt;/code&gt;를 체크했다면 메인 앱과 함께 테스트 앱들의 &lt;code&gt;target&lt;/code&gt;들도 프로젝트에 추가된다&lt;/li&gt;
&lt;li&gt;iOS 앱에 의존적인 watchOS 앱은 iOS 앱, &lt;code&gt;watchKit extension&lt;/code&gt;, &lt;code&gt;WatchKit&lt;/code&gt; 앱을 위한 타겟들을 가진다&lt;/li&gt;
&lt;li&gt;macOS 앱도 마찬가지로 여러 타겟들을 가질 수 있다&lt;/li&gt;
&lt;li&gt;프로젝트 에디터에서 타겟을 선택하고 타겟의 설정을 변경할 수 있다&lt;/li&gt;
&lt;li&gt;프로젝트 에디터에서 + 버튼을 누르면 새로운 어플리케이션, 프레임워크와 라이브러리, 테스트 또는 어플리케이션 익스텐션 타겟을 프로젝트에 새로 추가할 수 있다&lt;/li&gt;
&lt;/ul&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;아래 사진처럼 Xcode 프로젝트 에디터 내의 메뉴들을 통해 타겟 설정을 변경할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;845&quot; data-origin-height=&quot;601&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blOpKz/btr9z9HQOPg/kdXLusSoI51w8c8dnoFO00/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blOpKz/btr9z9HQOPg/kdXLusSoI51w8c8dnoFO00/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blOpKz/btr9z9HQOPg/kdXLusSoI51w8c8dnoFO00/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblOpKz%2Fbtr9z9HQOPg%2FkdXLusSoI51w8c8dnoFO00%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;845&quot; height=&quot;601&quot; data-origin-width=&quot;845&quot; data-origin-height=&quot;601&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&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;b&gt;  결론적으로 나는 &lt;code&gt;target&lt;/code&gt;을 일반적으로 우리가 생각하는 하나의 앱, 프로덕트 단위라고 이해했다.&lt;/b&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Scheme&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마찬가지로 애플 help 사이트를 보면&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;A&lt;span&gt;&amp;nbsp;&lt;/span&gt;scheme&lt;span&gt;&amp;nbsp;&lt;/span&gt;is a collection of settings that specify the targets to build for a project, the build configuration to use, and the executable environment to use when the product is launched. When you open an existing project (or create a new one), Xcode automatically creates a scheme for each target. The default scheme is named after your project.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;code&gt;scheme은&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;설정의 집합&lt;/b&gt;이다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&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;/li&gt;
&lt;li&gt;사용할 빌드 &lt;code&gt;configuration&lt;/code&gt;을 정의하는 설정&lt;/li&gt;
&lt;li&gt;프로덕트가 실행될 때 사용할 실행 가능한 환경을 정의하는 설정&lt;/li&gt;
&lt;/ul&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;그리고&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로젝트를 새로 만들거나 오픈할 때, Xcode는 자동으로 각 타겟에 대한 &lt;code&gt;scheme&lt;/code&gt;을 생성한다&lt;/li&gt;
&lt;li&gt;디폴트 &lt;code&gt;scheme&lt;/code&gt;은 프로젝트의 이름을 따른다&lt;/li&gt;
&lt;/ul&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;그래서 실제 Xcode 프로젝트의 Edit Schemes 메뉴를 들어가 보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1561&quot; data-origin-height=&quot;995&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ebkMhv/btr9A4zdAM2/lqDUOrgmnW7NqovksMajC1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ebkMhv/btr9A4zdAM2/lqDUOrgmnW7NqovksMajC1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ebkMhv/btr9A4zdAM2/lqDUOrgmnW7NqovksMajC1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FebkMhv%2Fbtr9A4zdAM2%2FlqDUOrgmnW7NqovksMajC1%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;1561&quot; height=&quot;995&quot; data-origin-width=&quot;1561&quot; data-origin-height=&quot;995&quot;/&gt;&lt;/span&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;들어가 보니 App 언어나 지역 같은 테스트를 할 때 필요한 정보들을 설정할 수 있는 화면이 보인다!&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;b&gt;  앱을 빌드해서 실행할 때 필요한, 미리 정의해 놓은 설정들의 집합을 &lt;code&gt;Scheme&lt;/code&gt;이라 하고 그 설정들을 여러 개 만들어서 테스트할 수 있는 것 같았다.&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;실제로 Duplicate Scheme을 클릭해 보면 아래와 같이 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1172&quot; data-origin-height=&quot;843&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ehCfVe/btr9AZkorSv/00K9pv2XirhAhNUk97CxRK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ehCfVe/btr9AZkorSv/00K9pv2XirhAhNUk97CxRK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ehCfVe/btr9AZkorSv/00K9pv2XirhAhNUk97CxRK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FehCfVe%2Fbtr9AZkorSv%2F00K9pv2XirhAhNUk97CxRK%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;1172&quot; height=&quot;843&quot; data-origin-width=&quot;1172&quot; data-origin-height=&quot;843&quot;/&gt;&lt;/span&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;b&gt; 프로젝트를 빌드하고 테스트 할 때, 여러 환경에서 다양한 설정으로 &lt;code&gt;scheme&lt;/code&gt;을 만들어서 실행할 수 있을 것 같다..!!&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;Simulator를 고르기 전에 늘 선택되어 있었던 &lt;code&gt;Scheme&lt;/code&gt;을 아무 생각 없이 지나쳤던 과거가 생각나는데, 이렇게 이해하고 나니 &lt;code&gt;Scheme&lt;/code&gt;을 선택하고 Simulator를 선택하는 과정이 정말 자연스럽게 느껴지는 것 같다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뭔가.. 간단하기도 어렵기도 한 내용이었는데, 완벽히 이해하지는 못했을 수도 있지만 그래도 알아봤다는 데에 의의를..ㅎㅎ&lt;/p&gt;
&lt;/div&gt;
&lt;/div&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;</description>
      <category>iOS/Xcode</category>
      <category>scheme</category>
      <category>xcode</category>
      <author>Mila00a</author>
      <guid isPermaLink="true">https://mila00a.tistory.com/60</guid>
      <comments>https://mila00a.tistory.com/60#entry60comment</comments>
      <pubDate>Tue, 11 Apr 2023 21:37:45 +0900</pubDate>
    </item>
    <item>
      <title>2022 adiOS ASAP 컨퍼런스 후기</title>
      <link>https://mila00a.tistory.com/59</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000; font-size: 1.44em; letter-spacing: -1px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;나의 두번째 iOS 컨퍼런스&lt;/span&gt;&lt;/h3&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;포항에서 열린 Async Swift에 이어서 두번째로 참가한 iOS 컨퍼런스. 내용을 정리한 건 아니고 세션 별로 간단한 느낀 점을 기록하고자 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;1600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cgauk6/btr9AZxXR2p/D1r3cTtPGzuE64K53kxZQ0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cgauk6/btr9AZxXR2p/D1r3cTtPGzuE64K53kxZQ0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cgauk6/btr9AZxXR2p/D1r3cTtPGzuE64K53kxZQ0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcgauk6%2Fbtr9AZxXR2p%2FD1r3cTtPGzuE64K53kxZQ0%2Fimg.jpg&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;1600&quot; height=&quot;1600&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;1600&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;WWDC Winner 되는 법 &amp;mdash; 변진하&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 WWDC 위너로서 공감이 가는 부분도 있고 나랑 좀 달랐구나 느껴서 새로웠던 부분도 있었다. 근데 중요한 한 가지..&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://www.wwdcscholars.com/&quot; data-href=&quot;https://www.wwdcscholars.com/&quot;&gt;Welcome to WWDCScholars&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&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;hellip; 하드코어하지만 뭔가 울림이 있는.. 말씀이셨다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;iOS 개발 이렇게 시작하는 거 아니에요? &amp;mdash; 이현호&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아카데미에서 매일 뵙는 리이오의 말씀 익숙하면서도 유익했다. 꿀팁이 가득한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://dev200ok.blogspot.com/&quot; data-href=&quot;https://dev200ok.blogspot.com&quot;&gt;리이오의 블로그&lt;/a&gt;를 자주 찾아가야겠다. 그리고 다시 한 번 느낀 점은, 쉬운 앱을 여러개 만들어야 실력이 는다는 것.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;아&amp;hellip; 이력서 이렇게 쓰는 거 아닌데&amp;hellip; &amp;mdash; 여정승&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이력서에 노션 링크만 넣는 건 절대 비추! 라고 한다. 가볍게 지원한 느낌이 들고, 인담자 입장에서 기분이 나쁘다.&lt;/li&gt;
&lt;li&gt;그리고 당연한 말이지만 우대조건이 있다면 최대한 담도록 하는 게 좋다. 생각보다 우대조건을 만족하는 지원자가 많지 않다고 한다.&lt;/li&gt;
&lt;li&gt;이력서에 프로젝트 내용을 쓸 때, 무슨 기술을 했고 뭘 했는지 그냥 나열하면 보는 사람 입장에서 &amp;ldquo;당연히 그 기술 쓰고 그렇게 만드는 거 아냐?&amp;rdquo; 하는 생각을 하게 된다.&lt;/li&gt;
&lt;li&gt;그것 보다는 질문을 유발하는 느낌으로, &amp;ldquo;어떤 방법을 사용해서 의존도와 결합도를 높였다&amp;rdquo; 고 쓰게 되면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;lsquo;왜 그게 의존도와 결합도를 높인 거지?&amp;rsquo;&lt;span&gt;&amp;nbsp;&lt;/span&gt;라는 질문을 유도할 수 있게 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;i&gt;&amp;rarr; 당연한 말 보다는 궁금해 할 만한 키워드만 전달하자.&lt;/i&gt;&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;추가로 오픈소스 경험이 있으면 좋다고 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;i&gt;&amp;rarr;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://github.com/WWDCScholars/iOS-app&quot; data-href=&quot;https://github.com/WWDCScholars/iOS-app&quot;&gt;WWDC Scholars&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;오픈소스던데 한번 볼까..?   아무튼 오픈소스를 잘 찾아봐야겠다.&lt;/i&gt;&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;그리고 생각났던 질문이 있었는데, 네트워킹 시간이 여의치 않아 하지 못한 질문들이 있다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;이력서의 퀄리티가 낮을 때, 이력서 작성 스킬이 부족한건지 아니면 나의 개발 실력이 부족한 건지 알 수 있는 방법?&lt;/li&gt;
&lt;li&gt;개발 능력이 뛰어난데 이력서가 별로거나, 이력서는 좋은데 개발 실력이 부족했던 경험이 있는지?&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정성들여 링크드인 1촌 신청 메시지를 작성해서 요청한 상태인데.. 받아주셨으면 좋겠다  (받아주셨다! Yes!)&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;공채 준비 경험자의 취업 준비 왼손으로 비비고 오른손으로 비비기 &amp;mdash; 김예빈&lt;/h4&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;학력사항은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;어떤 교육을 받아 봤는가&lt;/b&gt;를 보기 위해서 존재한다고 하셨다. 지금까지 학력 부분을 안쓰기가 좀 그래서 그냥 쓰다가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;lsquo;쓰면 뭐가 좋지..?&amp;rsquo;&lt;span&gt;&amp;nbsp;&lt;/span&gt;하는 생각들이 있었는데 내가 받았던, 강조하고 싶은 교육들을 적으면 좋을 것 같았다.&lt;/li&gt;
&lt;li&gt;그리고 대기업과 스타트업의 차이에 대해 말씀하셨는데, 대기업은 주로 뽑고 나서 부서가 정해진다고 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;b&gt;&amp;rarr; 이 말인 즉, 모든 것을 제너럴하게 다 잘하는 어떤 부서를 가도 잘할 수 있는 인재를 원하는 것 같았다.&lt;/b&gt;&lt;/i&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;/li&gt;
&lt;li&gt;그리고 이 부분은 여정승님과 같은 내용이었는데, 절대 재활용 가능한 이력서 보다는 회사에 지원하기 위해 노력과 애정을 담은 티가 나는 이력서를 써야 한다고 하셨다.&lt;/li&gt;
&lt;li&gt;코테는 오픈북인 경우가 많기 때문에 미리 코드를 짜서 갔기도 했다고 한다.&lt;/li&gt;
&lt;li&gt;기술 면접은 꼬리면접을 대비하는 것이 중요한데, 그래서 면접 스터디가 도움이 많이 될 거라고 하셨다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;b&gt;&amp;rarr; 스택에 대해 설명해주실 수 있나요? ➡ iOS에서 스택은 언제 어떻게 사용되나요?&lt;/b&gt;&lt;/i&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CS 책 목차나 키워드를 봤을 때 다 알 수 있을 정도로 준비하면 좋다고 하셨다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;i&gt;&amp;rarr; 여기서 두려움이 엄습하기 시작했다. 주전공자가 아닌 입장에서 빼 먹은 과목도 많고 기초가 부족한데ㅜㅜ 그래도 비비는 늘 아카데미에 계시니.. 다음에 CS 공부 관련해서 팁을 또 얻으러 가야겠다.&lt;/i&gt;&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;모든 과정, 코테나 과제를 포함한 과정들을 상세히 적어놓고 계속 대비할 것을 추천하셨다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기까지 정리한 내용 이상으로 굉장히 많은 내용을 열심히, 컴팩트하게 담아 주셨고 많이 동기부여를 느꼈다. 그리고 뜬금없지만 세션 들으면서 코테 걱정을 하다가, 고등학교 때 수학을 정복할 수 있었던 오답노트 생각이 나서 다음날 바로 구매했다. 코딩테스트를 수학 정복하듯이.. 해 봐야겠다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;네트워킹 시간&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네트워킹까지 포함된 티켓을 구매했고, 솔직히 두려움이 있었다. 근데 일단 행사가 그리 크지 않기도 했고 첫 네트워킹 경험으로 좋았던 것 같다! 곧 9월 말쯤에 Async Swift 행사가 열리니 그 때를 준비하는 느낌으로..! 앞으로의 iOS 컨퍼런스들은 좀 더 적극적으로 네트워킹을 도전해 봐야겠다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&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;</description>
      <category>Else</category>
      <category>ios</category>
      <category>컨퍼런스</category>
      <author>Mila00a</author>
      <guid isPermaLink="true">https://mila00a.tistory.com/59</guid>
      <comments>https://mila00a.tistory.com/59#entry59comment</comments>
      <pubDate>Tue, 11 Apr 2023 21:29:50 +0900</pubDate>
    </item>
    <item>
      <title>코드 리뷰를 잘하기 위한 Github 모범답안 모으기</title>
      <link>https://mila00a.tistory.com/58</link>
      <description>&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; font-size: 1.44em;&quot;&gt;이 글을 쓰게 된 계기&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div&gt;
  &lt;p data-ke-size=&quot;size16&quot;&gt;아카데미에서 여러 프로젝트를 하면서 많이 성장했다고 생각한다. 깃, 깃헙, Xcode, Swift,... 기타 등등 여러 부분에서 익숙해졌다고 생각했는데 짧은 기간 안에 습득할 수 없었던 역량이 하나 있었다.&lt;span&gt;&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;/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;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;코드리뷰의 유형 정리&lt;/h3&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 data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://blog.banksalad.com/tech/banksalad-code-review-culture/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://blog.banksalad.com/tech/banksalad-code-review-culture/&lt;/a&gt;&lt;/p&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;figure id=&quot;og_1681039838185&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;코드 리뷰 in 뱅크샐러드 개발 문화 | 뱅크샐러드&quot; data-og-description=&quot;안녕하세요, 뱅크샐러드 BanksaladX iOS Engineer&amp;hellip;&quot; data-og-host=&quot;blog.banksalad.com&quot; data-og-source-url=&quot;https://blog.banksalad.com/tech/banksalad-code-review-culture/&quot; data-og-url=&quot;https://blog.banksalad.com/tech/banksalad-code-review-culture/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bXuT6H/hySdsW5la3/W8RKquoKs6e7BRStYhgPkK/img.png?width=1800&amp;amp;height=1200&amp;amp;face=0_0_1800_1200,https://scrap.kakaocdn.net/dn/2wESm/hySdl4Jsog/Is4reex7wOxoRsUJXO4cD1/img.png?width=650&amp;amp;height=475&amp;amp;face=0_0_650_475,https://scrap.kakaocdn.net/dn/dbuCX5/hySdkELklf/EptTbXDgCFnPJNDnCNdKc0/img.png?width=650&amp;amp;height=373&amp;amp;face=0_0_650_373&quot;&gt;&lt;a href=&quot;https://blog.banksalad.com/tech/banksalad-code-review-culture/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://blog.banksalad.com/tech/banksalad-code-review-culture/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bXuT6H/hySdsW5la3/W8RKquoKs6e7BRStYhgPkK/img.png?width=1800&amp;amp;height=1200&amp;amp;face=0_0_1800_1200,https://scrap.kakaocdn.net/dn/2wESm/hySdl4Jsog/Is4reex7wOxoRsUJXO4cD1/img.png?width=650&amp;amp;height=475&amp;amp;face=0_0_650_475,https://scrap.kakaocdn.net/dn/dbuCX5/hySdkELklf/EptTbXDgCFnPJNDnCNdKc0/img.png?width=650&amp;amp;height=373&amp;amp;face=0_0_650_373');&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;코드 리뷰 in 뱅크샐러드 개발 문화 | 뱅크샐러드&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요, 뱅크샐러드 BanksaladX iOS Engineer&amp;hellip;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;blog.banksalad.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;ol style=&quot;list-style-type: decimal; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;작성자의 의도를 확인하는 질문&lt;/li&gt;
&lt;li&gt;버그가 발생할 수 있는 가능성 제시&lt;/li&gt;
&lt;li&gt;오타나 잘못된 네이밍 지적&lt;/li&gt;
&lt;li&gt;잘못 작성된 코드 정정 (어떤 함수나 클래스 등등을 잘못 이해하고 사용)&lt;/li&gt;
&lt;li&gt;다른 해결 방법에 대한 의견 제시&lt;/li&gt;
&lt;li&gt;라이브러리 등 서드파티 제안&lt;/li&gt;
&lt;li&gt;기술적인 지식, 노하우 공유&lt;/li&gt;
&lt;li&gt;일관된 아키텍처를 유지하고 있는지&lt;/li&gt;
&lt;/ol&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;등등의 코드리뷰 유형이 있을 것이다.&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&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;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;1448&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c1DVSI/btr8UVJvEfW/kJt4OkyE30OoJakuxDpU9k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c1DVSI/btr8UVJvEfW/kJt4OkyE30OoJakuxDpU9k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c1DVSI/btr8UVJvEfW/kJt4OkyE30OoJakuxDpU9k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc1DVSI%2Fbtr8UVJvEfW%2FkJt4OkyE30OoJakuxDpU9k%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;1600&quot; height=&quot;1448&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;1448&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;실제 Github 보면서 유형&amp;nbsp;탐색해보기&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;네이밍 변경&amp;nbsp;제안&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;commonInit()&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;보다는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;setupViews()&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;라는 보다 명확한 이름을 쓰는 게 어떨까요?&lt;/li&gt;
&lt;li&gt;UIKit에서는 뒤에 View를 붙여주는 것이 일반적인 명명이랍니다~!&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;더 좋은 코드&amp;nbsp;제안&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;private&lt;/code&gt; method를 별도의&lt;span&gt;&amp;nbsp;&lt;/span&gt;extension&lt;span&gt;&amp;nbsp;&lt;/span&gt;으로 빼는 것은 어떨까요?&lt;/li&gt;
&lt;li&gt;&lt;code&gt;students&lt;/code&gt; 배열을 외부에서 주입받도록 구현하는게 어떨까요? 어차피 나중에 의존성을 외부에서 주입받게 구현해야할 것 같고, 프리뷰를 볼 때도 여러 경우를 보기 위해서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;initializer&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;를 수정하는게 좋아보입니다!&lt;/li&gt;
&lt;li&gt;if문 대신&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;guard&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;문을쓴다면 인덴트도 사라지고, 빠르게 리턴할 수 있지 않을까합니다~!&lt;/li&gt;
&lt;li&gt;&lt;code&gt;private var isInitialzed: Bool = false&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;에서 &lt;code&gt;Bool&lt;/code&gt;은 생략이 가능합니다&lt;/li&gt;
&lt;li&gt;외부에서 해당 함수를 건들이지 않는 거 같아서 &lt;code&gt;private&lt;/code&gt;으로 설정해주는 건 어떨까요?&lt;/li&gt;
&lt;li&gt;내부에서 리턴해줄 값이 없다면 &lt;code&gt;private let searchBarView = SearchBarView()&lt;/code&gt; 이런식은 어떨까요&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;vim&quot;&gt;&lt;code&gt;// 기존 코드
private let searchBarView: SearchBarView = { 
    let view = SearchBarView() 
    return view 
}()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;잘못 작성된 코드&amp;nbsp;정정&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;override&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;메소드에서는 부모 class의 실행이 되도록&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;super&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;함수 실행이 중요해요!&lt;/li&gt;
&lt;li&gt;이 부분은 비동기적인 코드라서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;await&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;를 함께 작성해야 맞을 것 같습니다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;작성자의 의도 확인 (보통 답변도&amp;nbsp;상세하게)&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;private extension 이라서 메소드들 &lt;code&gt;private&lt;/code&gt; 으로 선언해주지 않아도 되는건가요??&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 넵! private extension 이면 안에있는 메소드들은 전부 &lt;code&gt;private&lt;/code&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;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 해당 Size 값들을 다른 Class들은 사용하지 않는데, 따로 파일을 만들어서 &lt;code&gt;internal&lt;/code&gt;하게 사용하는 거 자체가 아닌 거 같아서 VC class 내부에서 &lt;code&gt;private&lt;/code&gt;하게 사용하도록 구현했습니다.&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;중복된 코드&amp;nbsp;지적&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;window&lt;/code&gt; 를 만들 때 &lt;code&gt;scene&lt;/code&gt; 과 함께 만들었는데, &lt;code&gt;windowScene&lt;/code&gt; 에 다시 &lt;code&gt;scene&lt;/code&gt; 을 넣을 필요가 있을까요?&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;window = UIWindow(windowScene: scene) 
window?.rootViewController = UISplitViewController() window?.windowScene = scene&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;import SwiftUI&lt;/code&gt;에 포함이 되어 있기 때문에 &lt;code&gt;import Foundation&lt;/code&gt;은 삭제해도 될 것 같습니다!&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;오타나 사소한 부분&amp;nbsp;정정&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;안 쓰는 코드라면 삭제해도 좋을 것 같습니다! (주석 등등)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;버그가 우려되는&amp;nbsp;부분&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;!&lt;/code&gt;보다는 &lt;code&gt;optional&lt;/code&gt;을 해제하거나 하는 안전한 방법으로 하면 어떨까요&amp;nbsp;?&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;일관성 유지&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 부분도 다른 파일의 코드들과 일관성을 유지할 수 있도록&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code&gt;setUpDelegate&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;함수 안에서 작성해주시면 보기 더 좋을 것 같아요&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;컨벤션 지킴이&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;import&lt;/code&gt; 컨벤션 알파벳 순인데 확인 부탁드립니다!&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;결론 (but&amp;nbsp;ing&amp;hellip;)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생각보다 코드리뷰 내용이 많이 겹친다. 그리고 단순히 코드리뷰 유형만 익혀서는 안되고, Swift와 아키텍처 그리고 좋은 코드에 대한 이해가 필수적으로 필요하다 (❗️매우 중요❗️)&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;그리고 또 중요한 것은 내 PR 에 달린 코드 리뷰가 아니더라도 계속 살펴보면서 이해하려고 하는 노력이 필요할 것 같다. 그렇지 않으면 좋은 코드리뷰를 그냥 지나치는 셈이니까!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&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;</description>
      <category>iOS</category>
      <category>코드리뷰</category>
      <author>Mila00a</author>
      <guid isPermaLink="true">https://mila00a.tistory.com/58</guid>
      <comments>https://mila00a.tistory.com/58#entry58comment</comments>
      <pubDate>Sun, 9 Apr 2023 20:32:25 +0900</pubDate>
    </item>
  </channel>
</rss>