<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>@Override</title>
    <link>https://mrgamza.tistory.com/</link>
    <description>Bohemian Software Engineer</description>
    <language>ko</language>
    <pubDate>Tue, 21 Jul 2026 16:21:32 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>out of coding</managingEditor>
    <image>
      <title>@Override</title>
      <url>https://tistory1.daumcdn.net/tistory/1645932/attach/2f92f547b0c542cdb9f1ba8b123e68ac</url>
      <link>https://mrgamza.tistory.com</link>
    </image>
    <item>
      <title>iOS closure를 async, await 으로 변경하는</title>
      <link>https://mrgamza.tistory.com/887</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;xcode 13.2 Beat에 iOS13 이상부터 Swift concurrency (async, await) 기능을 사용가능합니다.&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;p data-ke-size=&quot;size16&quot;&gt;그럼 바로 변경하는 방법으로 넘어가겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;withCheckedThrowingContinuation, withCheckedContinuation 를 이용하는 방법입니다.&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;다음과 같은 closure를 사용하는 곳이 있었다고 합시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1686066429811&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;func testFunction(number: Int, handler: (Int) -&amp;gt; Void) {
  let sum = number + 1
  handler(sum)
}

testFunction(number: 1) { value in
  print(value)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과는 2가 나옵니다.&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;withCheckedThrowingContinuation을 이용합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1686066812435&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;func testContinuation(number: Int) async throws -&amp;gt; Int {
  try await withCheckedThrowingContinuation { continuation in
    if number == 0 {
      continuation.resume(throwing: NSError(domain: &quot;Sorry&quot;, code: -1))
    } else {
      let sum = number + 1
      continuation.resume(returning: sum)
    }
    
    // 이렇게 보낼수도 있습니다. 한꺼번에 나오는 케이스들도 가능
    // continuation.resume(with: Result&amp;lt;Int, Error&amp;gt;)
  }
}

Task {
  let sum1 = try? await testContinuation(number: 0)
  print(sum1) // nil
  
  let sum2 = try? await testContinuation(number: 1)
  print(sum2) // Optional(2)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;closure를 만들지 않아도 되고&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;( 사실 한개만 해서 그렇지 비동기로 계속 호출하게 된다면 콜백 지옥에 빠져서 나오질 못합니다. )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 이 방법은 throws를 하는 경우에 대해서 만들어주는 방법입니다.&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;그럼 throws가 발생하지 않을 경우에는 어떻게 하면 될까요?&lt;/p&gt;
&lt;pre id=&quot;code_1686067072612&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;func testContinuation2(number: Int) async -&amp;gt; Int {
  await withCheckedContinuation { continuation in
    let sum = number + 1
    continuation.resume(returning: sum)
  }
}

Task {
  let sum1 = await testContinuation2(number: 0)
  print(sum1) // 1
  
  let sum2 = await testContinuation2(number: 1)
  print(sum2) // 2
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 continuation 에 같은 function을 가지고 있는데 특이한 부분은 Never 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;절대로 안 일어난다는거죠.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-06-07 00.56.38.png&quot; data-origin-width=&quot;816&quot; data-origin-height=&quot;364&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQi0GO/btsiRELltwu/a7TYE7vh4PRJhlBZCeW4wk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQi0GO/btsiRELltwu/a7TYE7vh4PRJhlBZCeW4wk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQi0GO/btsiRELltwu/a7TYE7vh4PRJhlBZCeW4wk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQi0GO%2FbtsiRELltwu%2Fa7TYE7vh4PRJhlBZCeW4wk%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;816&quot; height=&quot;364&quot; data-filename=&quot;스크린샷 2023-06-07 00.56.38.png&quot; data-origin-width=&quot;816&quot; data-origin-height=&quot;364&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나머지는 위의 withCheckedThrowingContinuation 하고 같지만 Error만 던지지 못합니다.&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Mobile/iOS</category>
      <category>async</category>
      <category>await</category>
      <category>closure</category>
      <category>ios</category>
      <category>withCheckedContinuation</category>
      <category>withCheckedThrrowingContinuation</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/887</guid>
      <comments>https://mrgamza.tistory.com/887#entry887comment</comments>
      <pubDate>Wed, 7 Jun 2023 01:00:06 +0900</pubDate>
    </item>
    <item>
      <title>JavaScript. 가장 짧은 TETRIS 소스</title>
      <link>https://mrgamza.tistory.com/886</link>
      <description>&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;pre class=&quot;matlab&quot;&gt;&lt;code&gt;&amp;lt;body onKeyDown=K=event.keyCode&amp;gt;&amp;lt;script&amp;gt;X=[Z=[B=A=12]];h=e=K=t=P=0;function Y() 
{C=[d=K-38];c=0;for(i=4;i--*K;K-13?c+=!Z[h+p+d]:c-=!Z[h+(C[i]=p*A-Math.round(p/ 
A)*145)])p=B[i];!t|c+4?c-4?0:h+=d:B=C;for(f=K=i=0;i&amp;lt;4;f+=Z[A+p])X[p=h+B[i++]]=1 
if(e=!e){if(f|B){for(l=228;i--;)Z[h+B[i]]=k=1;for(B=[[-7,-20,6,17,-9,3,6][t=++t 
%7]-4,0,1,t-6?-A:-1];l--;h=5)if(l%A)l-=l%A*!Z[l];else for(P+=k++,j=l+=A;--j&amp;gt;A;) 
Z[j]=Z[j-A]}h+=A}for(i=S=&quot;&quot;;i&amp;lt;240;X[i]=Z[i]|=++i%A&amp;lt;2|i&amp;gt;228)i%A?0:S+=&quot;&amp;lt;br&amp;gt;&quot;,S+=X 
[i]?&quot;■&quot;:&quot;□&quot;;document.body.innerHTML=S+P;Z[5]||setTimeout(Y,99-P)}Y()&amp;lt;/script&amp;gt; &lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이걸로 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;/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-filename=&quot;스크린샷 2023-05-05 16.59.59.png&quot; data-origin-width=&quot;372&quot; data-origin-height=&quot;804&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kyIRy/btsdZrdxBfW/ER3M7cuwVQ63vTqhXpRpaK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kyIRy/btsdZrdxBfW/ER3M7cuwVQ63vTqhXpRpaK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kyIRy/btsdZrdxBfW/ER3M7cuwVQ63vTqhXpRpaK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkyIRy%2FbtsdZrdxBfW%2FER3M7cuwVQ63vTqhXpRpaK%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;372&quot; height=&quot;804&quot; data-filename=&quot;스크린샷 2023-05-05 16.59.59.png&quot; data-origin-width=&quot;372&quot; data-origin-height=&quot;804&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;html 파일도 첨부할게요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제되려나?&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignCenter&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/beQ7ls/btsdZHHfoWm/k3yG9jGwXkUPFXQFkseMe0/tetris.html?attach=1&amp;amp;knm=tfile.html&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;tetris.html&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;0.00MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Language/JavaScript</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/886</guid>
      <comments>https://mrgamza.tistory.com/886#entry886comment</comments>
      <pubDate>Fri, 5 May 2023 17:01:28 +0900</pubDate>
    </item>
    <item>
      <title>slack channel에 chat 남기기. with python code</title>
      <link>https://mrgamza.tistory.com/885</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;최근 회사에서 많이 사용하는 slack으로 어떠한 동작을 하게 나면 slack에 chat을 남기도록 할 수 있도록 하고 있지요.&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;p data-ke-size=&quot;size16&quot;&gt;그럼 시작해볼게요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;slack의 channel에 chat을 남기는걸 해보겠습니다.&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;저는 SNKR 알리미 같은걸 이걸로 만들었었습니다.&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;자... 그럼 일단 slack에서 설정부터 해야합니다.&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;a href=&quot;https://api.slack.com/apps&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://api.slack.com/apps&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1682772251905&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;Slack API: Applications | Slack&quot; data-og-description=&quot;Your Apps Don't see an app you're looking for? Sign in to another workspace.&quot; data-og-host=&quot;api.slack.com&quot; data-og-source-url=&quot;https://api.slack.com/apps&quot; data-og-url=&quot;https://api.slack.com/apps&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://api.slack.com/apps&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://api.slack.com/apps&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;Slack API: Applications | Slack&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Your Apps Don't see an app you're looking for? Sign in to another workspace.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;api.slack.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 링크로 진입하게 되면 화면에서 다음과 같은 부분을 찾습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Create New App&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-04-29 21.44.46.png&quot; data-origin-width=&quot;1596&quot; data-origin-height=&quot;764&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cYf8BF/btsdbOOtByH/SWoMt76HpqmOg1xiDlYedk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cYf8BF/btsdbOOtByH/SWoMt76HpqmOg1xiDlYedk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cYf8BF/btsdbOOtByH/SWoMt76HpqmOg1xiDlYedk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcYf8BF%2FbtsdbOOtByH%2FSWoMt76HpqmOg1xiDlYedk%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;1596&quot; height=&quot;764&quot; data-filename=&quot;스크린샷 2023-04-29 21.44.46.png&quot; data-origin-width=&quot;1596&quot; data-origin-height=&quot;764&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음으로는 From scratch를 해줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(글 작성일 기준이라서 나중에 아래 설정이 더 맞을수도 있으니 이건 자신에게 맞도록!!)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-04-29 21.44.58.png&quot; data-origin-width=&quot;1178&quot; data-origin-height=&quot;872&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ctdwz8/btsdcINX78R/ksYOPVBshshcZLbv8YUxj1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ctdwz8/btsdcINX78R/ksYOPVBshshcZLbv8YUxj1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ctdwz8/btsdcINX78R/ksYOPVBshshcZLbv8YUxj1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fctdwz8%2FbtsdcINX78R%2FksYOPVBshshcZLbv8YUxj1%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;1178&quot; height=&quot;872&quot; data-filename=&quot;스크린샷 2023-04-29 21.44.58.png&quot; data-origin-width=&quot;1178&quot; data-origin-height=&quot;872&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이름이랑 워크 스페이스 설정해주세요&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-04-29 21.45.12.png&quot; data-origin-width=&quot;1114&quot; data-origin-height=&quot;1074&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6NgbQ/btsddS97OUZ/kSFTC7phOPXKf9Mh5U2Kck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6NgbQ/btsddS97OUZ/kSFTC7phOPXKf9Mh5U2Kck/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6NgbQ/btsddS97OUZ/kSFTC7phOPXKf9Mh5U2Kck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6NgbQ%2FbtsddS97OUZ%2FkSFTC7phOPXKf9Mh5U2Kck%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;1114&quot; height=&quot;1074&quot; data-filename=&quot;스크린샷 2023-04-29 21.45.12.png&quot; data-origin-width=&quot;1114&quot; data-origin-height=&quot;1074&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 후다다닥 하고 만들어집니다. ㅎㅎ&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-04-29 21.46.46.png&quot; data-origin-width=&quot;2192&quot; data-origin-height=&quot;1948&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/db73ke/btsdem4e6vc/0boavsXuxNhG64zixUWLc0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/db73ke/btsdem4e6vc/0boavsXuxNhG64zixUWLc0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/db73ke/btsdem4e6vc/0boavsXuxNhG64zixUWLc0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdb73ke%2Fbtsdem4e6vc%2F0boavsXuxNhG64zixUWLc0%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;2192&quot; height=&quot;1948&quot; data-filename=&quot;스크린샷 2023-04-29 21.46.46.png&quot; data-origin-width=&quot;2192&quot; data-origin-height=&quot;1948&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 그럼 OAuth &amp;amp; Permission을 설정해줄겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스크롤을 조금하면 아래에 &lt;b&gt;Scopes &amp;gt; Add an OAuth Scope&lt;/b&gt; 가 있어요&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-04-29 21.48.08.png&quot; data-origin-width=&quot;1406&quot; data-origin-height=&quot;576&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Wz1kX/btsddFXuB1F/qNPgBGgcEly08yiKk37O8k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Wz1kX/btsddFXuB1F/qNPgBGgcEly08yiKk37O8k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Wz1kX/btsddFXuB1F/qNPgBGgcEly08yiKk37O8k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWz1kX%2FbtsddFXuB1F%2FqNPgBGgcEly08yiKk37O8k%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;1406&quot; height=&quot;576&quot; data-filename=&quot;스크린샷 2023-04-29 21.48.08.png&quot; data-origin-width=&quot;1406&quot; data-origin-height=&quot;576&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;chat:write.public&lt;/b&gt; 을 선택&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-04-29 21.48.40.png&quot; data-origin-width=&quot;1154&quot; data-origin-height=&quot;578&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mLh6q/btsdc7zZd8Q/N36dXwjah4lPIV8W1T3EAk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mLh6q/btsdc7zZd8Q/N36dXwjah4lPIV8W1T3EAk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mLh6q/btsdc7zZd8Q/N36dXwjah4lPIV8W1T3EAk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmLh6q%2Fbtsdc7zZd8Q%2FN36dXwjah4lPIV8W1T3EAk%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;1154&quot; height=&quot;578&quot; data-filename=&quot;스크린샷 2023-04-29 21.48.40.png&quot; data-origin-width=&quot;1154&quot; data-origin-height=&quot;578&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘다 넣을건지 물어보는겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론해줍시다.&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;Install to Workspace&lt;/b&gt;를 눌러줍니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-04-29 21.49.17.png&quot; data-origin-width=&quot;1456&quot; data-origin-height=&quot;604&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbim8Z/btsdc6Vl7bT/t0FDiUAyiEHyZFBWt8LaL0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbim8Z/btsdc6Vl7bT/t0FDiUAyiEHyZFBWt8LaL0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbim8Z/btsdc6Vl7bT/t0FDiUAyiEHyZFBWt8LaL0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbbim8Z%2Fbtsdc6Vl7bT%2Ft0FDiUAyiEHyZFBWt8LaL0%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;1456&quot; height=&quot;604&quot; data-filename=&quot;스크린샷 2023-04-29 21.49.17.png&quot; data-origin-width=&quot;1456&quot; data-origin-height=&quot;604&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;와 이제 정말 거의 다 되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Allow!!!&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-04-29 21.50.04.png&quot; data-origin-width=&quot;1222&quot; data-origin-height=&quot;870&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cGEPIO/btsdcsxReVD/DvzllR5josdiKrsbCtV8dk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cGEPIO/btsdcsxReVD/DvzllR5josdiKrsbCtV8dk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cGEPIO/btsdcsxReVD/DvzllR5josdiKrsbCtV8dk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcGEPIO%2FbtsdcsxReVD%2FDvzllR5josdiKrsbCtV8dk%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;1222&quot; height=&quot;870&quot; data-filename=&quot;스크린샷 2023-04-29 21.50.04.png&quot; data-origin-width=&quot;1222&quot; data-origin-height=&quot;870&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 이렇게 나올겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(후훗. 혹시 제가 생성한거 쓰실려고 하시면 안될거에요. 사진만 찍고 앱을 아예 삭제했습니다.)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-04-29 21.50.30.png&quot; data-origin-width=&quot;1314&quot; data-origin-height=&quot;572&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/brFWBX/btsdhB0Q61H/GQesyWIHYErxIJll9zRkZ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/brFWBX/btsdhB0Q61H/GQesyWIHYErxIJll9zRkZ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/brFWBX/btsdhB0Q61H/GQesyWIHYErxIJll9zRkZ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbrFWBX%2FbtsdhB0Q61H%2FGQesyWIHYErxIJll9zRkZ0%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;1314&quot; height=&quot;572&quot; data-filename=&quot;스크린샷 2023-04-29 21.50.30.png&quot; data-origin-width=&quot;1314&quot; data-origin-height=&quot;572&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자 그럼 이제 외부에서 글을 쓸수 있도록 하는 설정을 끝났어요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래에 파이썬 코드에 들어갈 부분에 이용하기 위해서 여러분은 Copy해서 쓰시길!!&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;아... 참고로 requests는 설치해야합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본 python 설치부분과 lib 를 가져오는건 설명하지 않도록 할게요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;( 사실 IDE에서 거의 자동으로 해주긴 합니다. )&lt;/p&gt;
&lt;pre id=&quot;code_1682772831735&quot; class=&quot;python&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import requests


def send_message(channel, message):
    token = '여기에 위의 토큰을 넣어주세요'

    headers = {
        'Authorization': f'Bearer {token}'
    }

    data = {
        'channel': f'#{channel}',
        'text': message
    }

    url = 'https://slack.com/api/chat.postMessage'
    return requests.post(url, headers=headers, data=data)


if __name__ == '__main__':
    response = send_message('여기는 당신의 채널', 'Hello, slack!')
    print(response.status_code)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/mrgamza/slack-sender&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/mrgamza/slack-sender&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1682774625617&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 - mrgamza/slack-sender: simple slack chat send source&quot; data-og-description=&quot;simple slack chat send source. Contribute to mrgamza/slack-sender development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/mrgamza/slack-sender&quot; data-og-url=&quot;https://github.com/mrgamza/slack-sender&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/0BPfp/hySq0mxscl/fXRAvdn7Hp6IJ3O2kp7fS1/img.png?width=1200&amp;amp;height=600&amp;amp;face=1003_116_1070_189&quot;&gt;&lt;a href=&quot;https://github.com/mrgamza/slack-sender&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/mrgamza/slack-sender&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/0BPfp/hySq0mxscl/fXRAvdn7Hp6IJ3O2kp7fS1/img.png?width=1200&amp;amp;height=600&amp;amp;face=1003_116_1070_189');&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 - mrgamza/slack-sender: simple slack chat send source&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;simple slack chat send source. Contribute to mrgamza/slack-sender 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;</description>
      <category>Language/Python</category>
      <category>git</category>
      <category>Python</category>
      <category>slack</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/885</guid>
      <comments>https://mrgamza.tistory.com/885#entry885comment</comments>
      <pubDate>Sat, 29 Apr 2023 22:24:46 +0900</pubDate>
    </item>
    <item>
      <title>Apple Developer. 조치 필요: Distribution 인증서가 30일 후에 만료됨</title>
      <link>https://mrgamza.tistory.com/884</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;애플에서 Distribution 인증서가 30일 후에 만료된다고 이메일이 왔네요.&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;p data-ke-size=&quot;size16&quot;&gt;1. Apple Developer에서 기존 인증서중에 Distribution 을 골라줍니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-02-27 14.09.13.png&quot; data-origin-width=&quot;2096&quot; data-origin-height=&quot;636&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/veWpn/btr0VJKjuwp/UB6DwTGpsx7j8V8AGMdfK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/veWpn/btr0VJKjuwp/UB6DwTGpsx7j8V8AGMdfK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/veWpn/btr0VJKjuwp/UB6DwTGpsx7j8V8AGMdfK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FveWpn%2Fbtr0VJKjuwp%2FUB6DwTGpsx7j8V8AGMdfK1%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;2096&quot; height=&quot;636&quot; data-filename=&quot;스크린샷 2023-02-27 14.09.13.png&quot; data-origin-width=&quot;2096&quot; data-origin-height=&quot;636&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 선택하고 나서 보면 Revoke 가 보일거에요. 해줍니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-02-27 14.09.27.png&quot; data-origin-width=&quot;2432&quot; data-origin-height=&quot;716&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ccUMXw/btr0ObUXRlQ/JNLcLkAvTOCNJskbMXHH2K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ccUMXw/btr0ObUXRlQ/JNLcLkAvTOCNJskbMXHH2K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ccUMXw/btr0ObUXRlQ/JNLcLkAvTOCNJskbMXHH2K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FccUMXw%2Fbtr0ObUXRlQ%2FJNLcLkAvTOCNJskbMXHH2K%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;2432&quot; height=&quot;716&quot; data-filename=&quot;스크린샷 2023-02-27 14.09.27.png&quot; data-origin-width=&quot;2432&quot; data-origin-height=&quot;716&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;괜찮습니다. 마구 지워도 다시 만들면 되니까요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. Xcode를 열어서 상단의 메뉴에서 Settings를 선택&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-02-27 14.12.00.png&quot; data-origin-width=&quot;468&quot; data-origin-height=&quot;664&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cQsUxM/btr0RKpeY2e/nKx31iDeKYZYvEuCHakpbk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cQsUxM/btr0RKpeY2e/nKx31iDeKYZYvEuCHakpbk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cQsUxM/btr0RKpeY2e/nKx31iDeKYZYvEuCHakpbk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcQsUxM%2Fbtr0RKpeY2e%2FnKx31iDeKYZYvEuCHakpbk%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;468&quot; height=&quot;664&quot; data-filename=&quot;스크린샷 2023-02-27 14.12.00.png&quot; data-origin-width=&quot;468&quot; data-origin-height=&quot;664&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. Accounts / 아이디에서 / Team은 Admin으로 선택하고 Manage Certificates... 를 선택&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-filename=&quot;스크린샷 2023-02-27 14.12.17.png&quot; data-origin-width=&quot;1884&quot; data-origin-height=&quot;1328&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/17YXC/btr0IFJgE8C/9EAy7nkXbUfExhigJS84dk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/17YXC/btr0IFJgE8C/9EAy7nkXbUfExhigJS84dk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/17YXC/btr0IFJgE8C/9EAy7nkXbUfExhigJS84dk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F17YXC%2Fbtr0IFJgE8C%2F9EAy7nkXbUfExhigJS84dk%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;1884&quot; height=&quot;1328&quot; data-filename=&quot;스크린샷 2023-02-27 14.12.17.png&quot; data-origin-width=&quot;1884&quot; data-origin-height=&quot;1328&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. Apple Distribution을 다시 만들어 줍니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-02-27 14.12.29.png&quot; data-origin-width=&quot;608&quot; data-origin-height=&quot;556&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b2WJJi/btr0IuVjp5r/PATPPo1rPO2p0ntDqxdoDK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b2WJJi/btr0IuVjp5r/PATPPo1rPO2p0ntDqxdoDK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b2WJJi/btr0IuVjp5r/PATPPo1rPO2p0ntDqxdoDK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb2WJJi%2Fbtr0IuVjp5r%2FPATPPo1rPO2p0ntDqxdoDK%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;608&quot; height=&quot;556&quot; data-filename=&quot;스크린샷 2023-02-27 14.12.29.png&quot; data-origin-width=&quot;608&quot; data-origin-height=&quot;556&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;</description>
      <category>Mobile/iOS</category>
      <category>Apple</category>
      <category>ios</category>
      <category>인증서</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/884</guid>
      <comments>https://mrgamza.tistory.com/884#entry884comment</comments>
      <pubDate>Mon, 27 Feb 2023 14:14:46 +0900</pubDate>
    </item>
    <item>
      <title>Swift. Snake -&amp;gt; Camel, Camel -&amp;gt; Snake</title>
      <link>https://mrgamza.tistory.com/883</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;최근 Clojure 를 다루면서 function name 을 -&amp;gt; 이것을 넣어서 만들수 있었는데 조금 아쉽긴하네요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;snake-&amp;gt;camel 이런 이름으로 만드는건 좀 가독성이 좋은뎁 ㅎㅎ&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;pre id=&quot;code_1676717997465&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;struct Coding {
    func snakeToCamel(from input: String) -&amp;gt; String {
        if input.isEmpty { return &quot;&quot; }

        let split = input
            .split(separator: &quot;_&quot;)
            .enumerated()
            .map { $0.0 == 0 ? $0.1.lowercased() : $0.1.capitalized }

        return split.joined()
    }  
  
    func camelToSnake(from input: String) -&amp;gt; String {
        let pattern = &quot;([a-z0-9])([A-Z])&quot;
        guard let regex = try? NSRegularExpression(pattern: pattern, options: []) else {
            return &quot;&quot;
        }
        
        let range = NSRange(location: 0, length: input.utf16.count)
        let result = regex.stringByReplacingMatches(in: input,
                                                    options: [],
                                                    range: range,
                                                    withTemplate: &quot;$1_$2&quot;)
        return result.lowercased()
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;snake-&amp;gt;camel은 split 방식으로&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;camel-&amp;gt;snake는 regex로&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://github.com/mrgamza-playground/snakeCamelConverter&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/mrgamza-playground/snakeCamelConverter&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1676717949095&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 - mrgamza-playground/snakeCamelConverter: Snake -&amp;gt; Camel, Camel -&amp;gt; Snake&quot; data-og-description=&quot;Snake -&amp;gt; Camel, Camel -&amp;gt; Snake. Contribute to mrgamza-playground/snakeCamelConverter development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/mrgamza-playground/snakeCamelConverter&quot; data-og-url=&quot;https://github.com/mrgamza-playground/snakeCamelConverter&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bUefio/hyRF2c9OQW/rHNsh0ihtPrI9k9Hcc8A2k/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/mrgamza-playground/snakeCamelConverter&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/mrgamza-playground/snakeCamelConverter&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bUefio/hyRF2c9OQW/rHNsh0ihtPrI9k9Hcc8A2k/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 - mrgamza-playground/snakeCamelConverter: Snake -&amp;gt; Camel, Camel -&amp;gt; Snake&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Snake -&amp;gt; Camel, Camel -&amp;gt; Snake. Contribute to mrgamza-playground/snakeCamelConverter 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;</description>
      <category>Coding</category>
      <category>Camel</category>
      <category>SNAKE</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/883</guid>
      <comments>https://mrgamza.tistory.com/883#entry883comment</comments>
      <pubDate>Sat, 18 Feb 2023 20:00:38 +0900</pubDate>
    </item>
    <item>
      <title>iOS - Swift. SwiftUI. @Environment</title>
      <link>https://mrgamza.tistory.com/882</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;@Environment?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뷰에서 EnvironmentValues의 특정 요소를 읽어와 뷰 구성에 반영할 때에 사용하는 요소라고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것 또한 Injection 관련된 부분으로 보이는데, 좋은건 다 가지고 와주길 바랍니다.&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;자... 그럼 일단 우리가 프로젝트를 하나 만들때에 CoreData, SwiftUI를 포함해서 만든다고 합시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;XYZApp 파일을 보면 다음과 같은 부분이 있어요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;App file 이라고 하면 다들 아시겠죠? ㅎㅎㅎ&lt;/p&gt;
&lt;pre id=&quot;code_1675668461100&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var body: some Scene {
    WindowGroup {
        ContentView()
            .environment(\.managedObjectContext, persistenceController.container.viewContext)
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 우리가 처음에 불러오는 ContentView에 environment에 managedObjectContext에 persistenceController.container.viewContext를 넣어주고 있네요.&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;그럼 이번에는 ContentView로 가보겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1675752243001&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;struct ContentView: View {
    @Environment(\.managedObjectContext) private var viewContext
    @Environment(\.layoutDirection) var layoutDirection

    @FetchRequest(
        sortDescriptors: [NSSortDescriptor(keyPath: \Item.timestamp, ascending: true)],
        animation: .default)
    private var items: FetchedResults&amp;lt;Item&amp;gt;
    ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른거 다 생각하지 말고 위에 @Environment를 봅시다.&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;viewContext 변수에 저걸 그냥 넣어주는거에요.&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;이제부터는 그럼 ContentView에서는 viewContext를 통해서 그냥 NSManagedObjectContext에 접근이 가능합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-02-07 15.45.22.png&quot; data-origin-width=&quot;798&quot; data-origin-height=&quot;518&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpFmN8/btrYkMqr0nx/JkVW5Uv0XVnP0jvmi3ITo1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpFmN8/btrYkMqr0nx/JkVW5Uv0XVnP0jvmi3ITo1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpFmN8/btrYkMqr0nx/JkVW5Uv0XVnP0jvmi3ITo1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbpFmN8%2FbtrYkMqr0nx%2FJkVW5Uv0XVnP0jvmi3ITo1%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;798&quot; height=&quot;518&quot; data-filename=&quot;스크린샷 2023-02-07 15.45.22.png&quot; data-origin-width=&quot;798&quot; data-origin-height=&quot;518&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그냥 View에서 사용하는것들을 주입하여 주고 아주 쉽게 사용 할 수 있도록 하여주는거에요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;와... 뭐야... Injection 입니다. ㅎㅎ&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;/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;Custom이 가능합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Custom Environment 만들어 봅시다.&lt;/b&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; EnvironmentKey를 채택해서 타입을 만들어주고, 이것을 EnvironmentValues에 추가하여줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뭔소릴까요? 그래서 코드를 만들었습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1675752921617&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;private struct ExtraColorKey: EnvironmentKey {
    static let defaultValue = Color.secondary
}

extension EnvironmentValues {
    var extraColorKey: Color {
        get { self[ExtraColorKey.self] }
        set { self[ExtraColorKey.self] = newValue }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;넣어줄때는?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 넣어주기만 하면 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1675752998914&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ContentView()
    .environment(\.managedObjectContext, persistenceController.container.viewContext)
    .environment(\.extraColorKey, Color.cyan)&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;/p&gt;
&lt;pre id=&quot;code_1675752940031&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Environment(\.extraColorKey) var extraColor&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비교적 쉽게 사용이 가능합니다. ㅎ&lt;/p&gt;</description>
      <category>Mobile/iOS</category>
      <category>@Environment</category>
      <category>EnvironmentKey</category>
      <category>EnvironmentValues</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/882</guid>
      <comments>https://mrgamza.tistory.com/882#entry882comment</comments>
      <pubDate>Tue, 7 Feb 2023 15:58:09 +0900</pubDate>
    </item>
    <item>
      <title>iOS - Swift. Property Wrappers</title>
      <link>https://mrgamza.tistory.com/881</link>
      <description>&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;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;p data-ke-size=&quot;size16&quot;&gt;A란변수에 이걸 적용해 달라고 하는것과 같습니다.&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;pre id=&quot;code_1675664875331&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@propertyWrapper
struct TestPropertyWrapper {
    private var height = 0.0
    
    var wrappedValue: Double {
        get { height }
        set { height = (newValue - 100) * 0.7 }
    }
}

struct TestStruct {
    @TestPropertyWrapper
    var size: Double
}

func test() {
    var test = TestStruct()
    test.size = 178.9
    print(test.size.rounded())
}

test()
// 출력 : 55.0&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같이 해서 UserDefault에 응용 가능합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1675665121157&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@propertyWrapper
struct UserDefault&amp;lt;T&amp;gt; {
    enum Key: String {
        case age = &quot;age&quot;
    }
    
    private let key: String
    private let defaultValue: T

    init(key: Key, defaultValue: T) {
        self.key = key.rawValue
        self.defaultValue = defaultValue
    }

    var wrappedValue: T {
        get {
            UserDefaults.standard.object(forKey: key) as? T ?? defaultValue
        }
        set {
            UserDefaults.standard.set(newValue, forKey: key)
        }
    }
}

struct TestStruct {    
    @UserDefault(key: .age, defaultValue: 123)
    var age: Int
}

func test() {
    var test = TestStruct()
    test.age = 1
    print(test.age)
}

test()
// 출력 : 1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UserDefaults를 쉽게 접근할수 있도록 만들어줍니다. 좋네요.&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;wrappedValue에 대해서 알아봤으니 projectedValue에 대해서 알아볼게요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;혹시나 SwiftUI를 사용할 경우에 @State를 이용해서 선언했을 경우에 $를 붙여서 Binding으로 넘겨주는 형태를 사용해본적이 있나요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Binding과 State는 한번 다시 정리해볼게요.&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;wrappedValue는 그 값 자체를 의미하고요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;projectedValue는 내부에서 가지고 있는 다른 값을 의미합니다.&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;@State var name = &quot;DDD&quot;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 경우에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;name으로 접근하면 바로 String의 형태입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$name으로 접근하면? 바로 Binding 형태가 됩니다.&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;이것은 name으로 접근&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-02-06 15.51.47.png&quot; data-origin-width=&quot;436&quot; data-origin-height=&quot;516&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dAo25U/btrYiWr7tv6/k5NO0ugCOzbHJ5xzKLdTGk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dAo25U/btrYiWr7tv6/k5NO0ugCOzbHJ5xzKLdTGk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dAo25U/btrYiWr7tv6/k5NO0ugCOzbHJ5xzKLdTGk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdAo25U%2FbtrYiWr7tv6%2Fk5NO0ugCOzbHJ5xzKLdTGk%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;436&quot; height=&quot;516&quot; data-filename=&quot;스크린샷 2023-02-06 15.51.47.png&quot; data-origin-width=&quot;436&quot; data-origin-height=&quot;516&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것은 Binding으로 접근됨&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-02-06 15.51.55.png&quot; data-origin-width=&quot;538&quot; data-origin-height=&quot;202&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/brkuAh/btrX7YY8SXD/RaYfvcc9Xbyw0k99dXRbE0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/brkuAh/btrX7YY8SXD/RaYfvcc9Xbyw0k99dXRbE0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/brkuAh/btrX7YY8SXD/RaYfvcc9Xbyw0k99dXRbE0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbrkuAh%2FbtrX7YY8SXD%2FRaYfvcc9Xbyw0k99dXRbE0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;538&quot; height=&quot;202&quot; data-filename=&quot;스크린샷 2023-02-06 15.51.55.png&quot; data-origin-width=&quot;538&quot; data-origin-height=&quot;202&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내부에서 무언가를 했다는 느낌이 들죠?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 위에 만들었던 TestPropertyWrapper를 다음과 같이 수정해봤어요.&lt;/p&gt;
&lt;pre id=&quot;code_1675666658878&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@propertyWrapper
struct TestPropertyWrapper {
    private var height = 0.0
    
    var wrappedValue: Double {
        get { height }
        set { height = (newValue - 100) * 0.7 }
    }
    
    var projectedValue: String {
        String(&quot;Hi: \(height)&quot;)
    }
}

struct TestStruct {
    @TestPropertyWrapper
    var size: Double
}

func test() {
    var test = TestStruct()
    test.size = 177.9
    print(type(of: test.$size))
    print(test.$size)
}

test()
// String
// Hi: 54.53&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과가 왜 이렇게 나온지 이해가 되었나요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;type은 string이고 formatting 된 string이 전달되었기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;궁금한점은 질문주세요&lt;/p&gt;</description>
      <category>Mobile/iOS</category>
      <category>propertyWrapper</category>
      <category>SWIFT</category>
      <category>UserDefaults</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/881</guid>
      <comments>https://mrgamza.tistory.com/881#entry881comment</comments>
      <pubDate>Mon, 6 Feb 2023 16:00:33 +0900</pubDate>
    </item>
    <item>
      <title>MySQL - Docker로 띄우기</title>
      <link>https://mrgamza.tistory.com/880</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;자신의 컴퓨터에 그냥 MySQL을 띄우고 사용해도 되지만 도커를 이용해서 띄우는게 깔끔하고 나중에 사용하다가 버전업을 할때에도 용의합니다.&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;그럼 MySQL을 Docker를 이용해서 사용하는 방법을 알아볼게요.&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. Docker 설치&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 부분은 많은 Docker 설치 관련된 문서가 있으니 찾아보시면 좋을거 같아요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따로 설명하지는 않겠고 Mac을 이용하면 다음의 다운로드를 이용하면 되겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.docker.com/products/docker-desktop/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.docker.com/products/docker-desktop/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1670649406735&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;Docker Desktop - Docker&quot; data-og-description=&quot;Docker Desktop is available to download for free on Mac, Windows, or Linux operating systems. Get started with Docker today!&quot; data-og-host=&quot;www.docker.com&quot; data-og-source-url=&quot;https://www.docker.com/products/docker-desktop/&quot; data-og-url=&quot;https://www.docker.com/products/docker-desktop/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/tlM4t/hyQQvVm4GD/kk2VnRqGi4jwO4a5GDYzQ0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/UM6kd/hyQQo22fg8/dO77ldKkKB8vJtOx3FSMX0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/cY7ElE/hyQQC73nCy/hINOduuaJmMSKYdqLOia9k/img.png?width=2880&amp;amp;height=855&amp;amp;face=0_0_2880_855&quot;&gt;&lt;a href=&quot;https://www.docker.com/products/docker-desktop/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.docker.com/products/docker-desktop/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/tlM4t/hyQQvVm4GD/kk2VnRqGi4jwO4a5GDYzQ0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/UM6kd/hyQQo22fg8/dO77ldKkKB8vJtOx3FSMX0/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/cY7ElE/hyQQC73nCy/hINOduuaJmMSKYdqLOia9k/img.png?width=2880&amp;amp;height=855&amp;amp;face=0_0_2880_855');&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;Docker Desktop - Docker&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Docker Desktop is available to download for free on Mac, Windows, or Linux operating systems. Get started with Docker today!&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.docker.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;2. MySQL Docker 이미지 다운로드&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Docker를 다운로드 받고 제대로 실행되도록 한 상태에서 다음과 같이 하면 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1670649445754&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ docker pull mysql&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 하면 latest 버전이 다운로드 되는데요. 특정 버전을 다운받고 싶다면 다음과 같이 해주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아무리 로컬에서 한다고 하더라도 Prod 버전과 다르면 예기치 않은 문제가 발생할수도 있으니까요.&lt;/p&gt;
&lt;pre id=&quot;code_1670649523519&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ docker pull mysql:8.0.22&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;터미널에 문자들이 주욱 나오게 될 것이고 완료가 될겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. Docker 컨테이너 생성 및 실행&lt;/p&gt;
&lt;pre id=&quot;code_1670649623754&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ docker run --name mysql -e MYSQL_ROOT_PASSWORD=&amp;lt;password&amp;gt; -d -p 3306:3306 mysql&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. DB 접근 확인&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DBeaver 등을 이용해서 3306 포트로 localhost 접근하면 됩니다.&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;</description>
      <category>Database</category>
      <category>docker</category>
      <category>MySQL</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/880</guid>
      <comments>https://mrgamza.tistory.com/880#entry880comment</comments>
      <pubDate>Sat, 10 Dec 2022 14:21:39 +0900</pubDate>
    </item>
    <item>
      <title>SpringBoot - MySQL 연결하도록 설정하고 난 이후에 프로젝트 실행시 에러 발생한다면?</title>
      <link>https://mrgamza.tistory.com/879</link>
      <description>&lt;h1&gt;MySQL을 프로젝트에 연결하고 프로젝트 실행을 했는데 다음과 같은 에러가 발생하게 된다면?&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 다음과 같은 에러를 만났습니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;caused&amp;nbsp;by:&amp;nbsp;org.springframework.beans.factory.beancreationexception:&amp;nbsp;error&amp;nbsp;creating&amp;nbsp;bean&amp;nbsp;with&amp;nbsp;name&amp;nbsp;'datasource'&amp;nbsp;defined&amp;nbsp;in&amp;nbsp;class&amp;nbsp;path&amp;nbsp;resource&amp;nbsp;[org/springframework/boot/autoconfigure/jdbc/datasourceconfiguration$hikari.class]:&amp;nbsp;bean&amp;nbsp;instantiation&amp;nbsp;via&amp;nbsp;factory&amp;nbsp;method&amp;nbsp;failed;&amp;nbsp;nested&amp;nbsp;exception&amp;nbsp;is&amp;nbsp;org.springframework.beans.beaninstantiationexception:&amp;nbsp;failed&amp;nbsp;to&amp;nbsp;instantiate&amp;nbsp;[co&lt;a href=&quot;http://m.zaxxer.hikari.hikaridatasource]:&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;m.zaxxer.hikari.hikaridatasource]:&lt;/a&gt;&amp;nbsp;factory&amp;nbsp;method&amp;nbsp;'datasource'&amp;nbsp;threw&amp;nbsp;exception;&amp;nbsp;nested&amp;nbsp;exception&amp;nbsp;is&amp;nbsp;java.lang.illegalstateexception:&amp;nbsp;cannot&amp;nbsp;load&amp;nbsp;driver&amp;nbsp;class:&amp;nbsp;co&lt;a href=&quot;http://m.mysql.jdbc.driver&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;m.mysql.jdbc.driver&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원인은 dataSource 연결 문제. MySQL이나 MyBatis등 DB 관련 설정을 추가하고 나서 build gradle에 제대로 추가를 안해주어서 그렇습니다.&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;그래도 안된다면 다른 dependencies를 추가하여 주어야 합니다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;dependencies {
    .....
    implementation(&quot;mysql:mysql-connector-java&quot;)
    .....
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Backend/Spring</category>
      <category>datasource</category>
      <category>MySQL</category>
      <category>Spring Boot</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/879</guid>
      <comments>https://mrgamza.tistory.com/879#entry879comment</comments>
      <pubDate>Fri, 9 Dec 2022 22:43:15 +0900</pubDate>
    </item>
    <item>
      <title>MySQL 완전히 삭제하고 재설치 - Mac</title>
      <link>https://mrgamza.tistory.com/878</link>
      <description>&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;또한 brew를 이용해서 설치하고 삭제하는 방법이에요.&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;MySQL 프로세스 죽이기&lt;/p&gt;
&lt;pre id=&quot;code_1670592833817&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;brew services stop mysql&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관련 파일들 삭제하기&lt;/p&gt;
&lt;pre id=&quot;code_1670592880449&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;brew uninstall --force mysql&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음을 한줄씩 수행합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1670592918899&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo rm -rf /usr/local/mysql
sudo rm -rf /usr/local/bin/mysql
sudo rm -rf /usr/local/var/mysql
sudo rm -rf /usr/local/Cellar/mysql
sudo rm -rf /usr/local/mysql*
sudo rm -rf /tmp/mysql.sock.lock
sudo rm -rf /tmp/mysqlx.sock.lock
sudo rm -rf /tmp/mysql.sock
sudo rm -rf /tmp/mysqlx.sock
sudo rm ~/Library/LaunchAgents/homebrew.mxcl.mysql.plist
sudo rm -rf /Library/StartupItems/MySQLCOM
sudo rm -rf /Library/PreferencePanes/My*&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;삭제하고 난 다음에 컴퓨터를 재부팅!&lt;/p&gt;</description>
      <category>Database</category>
      <category>MySQL</category>
      <category>삭제</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/878</guid>
      <comments>https://mrgamza.tistory.com/878#entry878comment</comments>
      <pubDate>Fri, 9 Dec 2022 22:36:03 +0900</pubDate>
    </item>
    <item>
      <title>파일 끝에 개행을 추가해야 하는 이유</title>
      <link>https://mrgamza.tistory.com/877</link>
      <description>&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;h3 data-ke-size=&quot;size23&quot;&gt;결론부터 이야기 하면&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a title=&quot;POSIX &quot; href=&quot;https://ko.wikipedia.org/wiki/POSIX&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;POSIX&lt;/a&gt;&amp;nbsp;명세에 내용이 들어가 있습니다.&lt;/p&gt;
&lt;figure id=&quot;og_1670510800616&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;POSIX - 위키백과, 우리 모두의 백과사전&quot; data-og-description=&quot;위키백과, 우리 모두의 백과사전.&quot; data-og-host=&quot;ko.wikipedia.org&quot; data-og-source-url=&quot;https://ko.wikipedia.org/wiki/POSIX&quot; data-og-url=&quot;https://ko.wikipedia.org/wiki/POSIX&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/POSIX&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ko.wikipedia.org/wiki/POSIX&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;POSIX - 위키백과, 우리 모두의 백과사전&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;ko.wikipedia.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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;b&gt;Definitions - 3.392 Text File&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: A file that contains characters organized into one or more lines. The lines do not contain NUL characters and none can exceed {LINE_MAX} bytes in length, including the&lt;span&gt;&amp;nbsp;&lt;/span&gt;Although IEEE Std 1003.1-2001 does not distinguish between text files and binary files (See the ISO C Standard), many utilities only produce predictable or meaningful output when operating on text files. The standard utilities that have such restrictions always specify &amp;ldquo;text files&amp;rdquo;in their STDIN or INPUT FILES sections.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Definitions - 3.205 Line&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: A sequence of zero or more non-&lt;span&gt;&amp;nbsp;&lt;/span&gt;s plus a terminating.&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;/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;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;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;인텔리제이에서 저장시에 자동으로 개행문자 추가하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Settings &amp;gt; Editor &amp;gt; General &amp;gt; Ensure every saved file ends with a line break.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(문장의 조금 다를수는 있지만 비슷한 문장을 찾아서 체크를 하여줍니다.)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-12-08 23.51.50.png&quot; data-origin-width=&quot;2188&quot; data-origin-height=&quot;1680&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bm6HRh/btrTb1dMdHq/G4e5mhsbN0f2SCN0zsSXT1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bm6HRh/btrTb1dMdHq/G4e5mhsbN0f2SCN0zsSXT1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bm6HRh/btrTb1dMdHq/G4e5mhsbN0f2SCN0zsSXT1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbm6HRh%2FbtrTb1dMdHq%2FG4e5mhsbN0f2SCN0zsSXT1%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;2188&quot; height=&quot;1680&quot; data-filename=&quot;스크린샷 2022-12-08 23.51.50.png&quot; data-origin-width=&quot;2188&quot; data-origin-height=&quot;1680&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Language/Kotlin</category>
      <category>개행</category>
      <category>마지막 개행</category>
      <category>인텔리제이</category>
      <category>파일</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/877</guid>
      <comments>https://mrgamza.tistory.com/877#entry877comment</comments>
      <pubDate>Thu, 8 Dec 2022 23:54:01 +0900</pubDate>
    </item>
    <item>
      <title>[Postman] Pre-Request Script 사용하기</title>
      <link>https://mrgamza.tistory.com/876</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Postman을 자주 사용하게 되면서 사용하게 되는 기능입니다.&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;우리가 개발을 할때에 access_token 기반의 로그인 서비스들의 경우에는 token이 만료되는 시점 때문에 지속적으로 로그인 관련 API를 호출하여 주어야 하는데 굉장히 불편하죠.&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;Pre-Request Script를 사용하면 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-12-01 08.20.43.png&quot; data-origin-width=&quot;1158&quot; data-origin-height=&quot;478&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbWgvK/btrSwq7zNrf/LlK1L8Am0qLGuP3Pp1eKEk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbWgvK/btrSwq7zNrf/LlK1L8Am0qLGuP3Pp1eKEk/img.png&quot; data-alt=&quot;저기 보이죠?&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbWgvK/btrSwq7zNrf/LlK1L8Am0qLGuP3Pp1eKEk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbWgvK%2FbtrSwq7zNrf%2FLlK1L8Am0qLGuP3Pp1eKEk%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;1158&quot; height=&quot;478&quot; data-filename=&quot;스크린샷 2022-12-01 08.20.43.png&quot; data-origin-width=&quot;1158&quot; data-origin-height=&quot;478&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;저기 보이죠?&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같이 script 코드를 작성하면 되는데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Postman이 지원하는 펑션들이 존재하기도 하기 때문에 사용이 편합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1669850709458&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pm.sendRequest({
  url: 'https://your-url/auth',
  method: 'POST',
  header: {
    'Accept': 'application/json',
    'Content-Type': 'application/x-www-form-urlencoded'
  },
  body: {
    mode: 'urlencoded',
    urlencoded: [
    {
      key: &quot;id&quot;,
      value: &quot;exam@exam.com&quot;,
      disabled: false
    },
    {
      key: &quot;password&quot;,
      value: &quot;string&quot;,
      disabled: false
    }]
  }
}, function (err, res) {
  res_data = res.json()
  console.log(res_data)
  pm.request.headers.add({
    key: &quot;Authorization&quot;,
    value: &quot;Bearer &quot; + res_data.accessToken
  });
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 내용을 설명을 드리면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;sendRequest에서 url에 id와 password를 넣어서 access_token을 받아오는것이고요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후에 function (err, res) 를 통해서 받은 데이터를 json으로 변경하고 request의 header에 자동으로 넣어주는 방법입니다.&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;각 Key, URL 등은 각자의 환경에 따라서 변경하셔서 사용하시길 바래요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 즐코딩 되시길.&lt;/p&gt;
&lt;div id=&quot;gtx-trans&quot; style=&quot;position: absolute; left: 101px; top: 1419.23px;&quot;&gt;
&lt;div class=&quot;gtx-trans-icon&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;</description>
      <category>Tool</category>
      <category>Postman</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/876</guid>
      <comments>https://mrgamza.tistory.com/876#entry876comment</comments>
      <pubDate>Thu, 1 Dec 2022 08:27:34 +0900</pubDate>
    </item>
    <item>
      <title>Python - requirements.txt 패키지 관리</title>
      <link>https://mrgamza.tistory.com/875</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;python으로 프로젝트를 개발하면 pip로 여러가지 패키지를 설치하여서 사용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 내용들을 하나씩 README 등에 넣어서 하나씩 설치하게 해도 되지만 굉장히 불편하게 만듭니다.&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;그래서 pip로 설치한 파일들을 하나로 관리하는게 좋은데요&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그때 사용되는것이 requirements.txt 파일입니다.&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;requirements.txt 파일이 생성되어 있지 않다면 다음과 같이 생성이 가능합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1664690874893&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ pip freeze &amp;gt; requirements.txt&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pip list 명령을 통해서 리스트도 가져올 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1664690933298&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ pip list
Package                       Version
----------------------------- -----------
기타등등&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 들어가 있는 내용들은 다른 환경에서 다음과 같이 한번에 설치 가능합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1664690998941&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ pip install -r requirements.txt&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Language/Python</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/875</guid>
      <comments>https://mrgamza.tistory.com/875#entry875comment</comments>
      <pubDate>Sun, 2 Oct 2022 15:11:10 +0900</pubDate>
    </item>
    <item>
      <title>Nodejs + MySQL 8.0 ER_NOT_SUPPORTED_AUTH_MODE</title>
      <link>https://mrgamza.tistory.com/874</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Nodejs를 이용해서 MySQL을 연동하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같은 에러가 발생하였고 에러 내용은 다음과 같았죠.&lt;/p&gt;
&lt;pre id=&quot;code_1652612272838&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;code: 'ER_NOT_SUPPORTED_AUTH_MODE',
errno: 1251,
sqlMessage: 'Client does not support authentication protocol requested by server; consider upgrading MySQL client.&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;에러의 원인은 만들어준 프로그램에서 MySQL의 패스워드 플러그인인 caching_sha2_password를 사용하지 못하기 때문입니다.&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_1652612395247&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mysql&amp;gt;  ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '{You password}';&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;You password 부분은 지정할 패스워드입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러고나면 정상적으로 동작할거에요. 성공하세요.&lt;/p&gt;</description>
      <category>Database</category>
      <category>MySQL</category>
      <category>nodejs</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/874</guid>
      <comments>https://mrgamza.tistory.com/874#entry874comment</comments>
      <pubDate>Sun, 15 May 2022 20:00:28 +0900</pubDate>
    </item>
    <item>
      <title>Android11 이상부터? 무선 디버깅으로 Adb 연결하고 명령하기</title>
      <link>https://mrgamza.tistory.com/873</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;iOS에서도 무선으로 연결하는 기능이 존재했는데, Android11부터 이게 된다고 하네요.&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;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;아래의 내용들은 SDK 도구나 기타 등등을 최신으로 해뒀다는 가정으로 이야기 합니다.&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;p data-ke-size=&quot;size16&quot;&gt;Wireless debugging. 이걸 On 하여 주면, Allow 할것이냐고 나오게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당연스럽게 Allow 합니다.&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;그 상태에서 Switch 가 아니라 전체 열을 클릭하면 들어가는 부분이 있는데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그곳에서 Pair deviec with pairing code 를 눌러줍니다. 한국말로는 페어링 어떻고가 될거 같네요.&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;그걸 누르면 페어링 코드가 나오고 아래쪽에 ip가 보일겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자 그 상태에서 컴퓨터로 돌아와서.&lt;/p&gt;
&lt;pre id=&quot;code_1641630515456&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ adb pair [ip]:[port]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 해서 페이링을 하여 줍니다. ip:port는 페어링 코드가 나오는쪽에 있습니다. 그냥 저대로 타이핑 하지 마세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;adb pair 192.168.0.XYZ:abcde 정도로 나올겁니다.&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;자 그럼 페어링이 된거고 connect를 하여 주어야 합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1641630678856&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ adb connect [IP]:[PORT]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서는 무선 디버깅 화면에서 나오는 IP 주소 및 포트를 넣어줍니다.&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;pre id=&quot;code_1641630813254&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ adb devices&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 선없이 디버깅합니다.&lt;/p&gt;</description>
      <category>Mobile/Android</category>
      <category>ADB</category>
      <category>무선연결</category>
      <category>신난다</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/873</guid>
      <comments>https://mrgamza.tistory.com/873#entry873comment</comments>
      <pubDate>Sat, 8 Jan 2022 17:33:57 +0900</pubDate>
    </item>
    <item>
      <title>React native. Could not get BatchedBridge, make sure your bundle is packaged correctly</title>
      <link>https://mrgamza.tistory.com/870</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;어쩌다보니 이런걸 하게 되었는데 정말 RN은 머하다보면 잘 안되고 막히고...&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;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;이유는 metro의 cache가 이전에 쓰던 버전과 꼬여서 문제가 생기는 건데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같이 실행하여 줍니다.&lt;/p&gt;
&lt;pre id=&quot;code_1639048662740&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ react-native start --reset-cache&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정말 백엔드만 하고 싶네요.&lt;/p&gt;</description>
      <category>Mobile/React Native</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/870</guid>
      <comments>https://mrgamza.tistory.com/870#entry870comment</comments>
      <pubDate>Thu, 9 Dec 2021 20:18:00 +0900</pubDate>
    </item>
    <item>
      <title>direnv. 디렉토리 별로 개발환경 구축하기. feat Python, Node...</title>
      <link>https://mrgamza.tistory.com/869</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 서비스를 하는 회사에서도 실제적으로는 많은 프로젝트들을 동시에 진행하기도 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이럴때에 각 서비스들의 version 등과 같은 환경을 다 동일하게 맞추면 좋지만 버전 업데이트를 위해서는 많은 시간을 들여야 할수도 있습니다.&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;이러한 문제점을 없애기 위해서 direnv를 이용할 수 있습니다.&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;동작원리는 사용자가 지금 사용하고 있는 디렉토리의 .envrc 파일을 생성하고 읽어 들이면서 필요한 설정들을 불러오는 방식입니다.&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;p data-ke-size=&quot;size16&quot;&gt;물론 brew는 설치가 되어 있어야 합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1638763096773&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ brew install direnv&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설치 여부 확인은 다음과 같이 합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1638763142813&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ direnv --version&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;그리고 shell 설정 파일에 값을 추가하여 줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공식적으로는 BASH, ZSH, FISH, TCSH, Elvish를 지원한다고 합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1638763300709&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# BASH
~/.bashrc에 아래 내용 추가
$ eval &quot;$(direnv hook bash)&quot;

# ZSH
~/.zshrc에 아래 내용 추가
$ eval &quot;$(direnv hook zsh)&quot;

# FISH
~/.config/fish/config.fish에 아래 내용 추가
$ eval (direnv hook fish)

# TCSH
~/.cshrc에 아래 내용 추가
$ eval `direnv hook tcsh`

# Elvish
$ direnv hook elvish &amp;gt; ~/.elvish/lib/direnv.elv
~/.elvish/rc.elv에 아래 내용 추가
$ use direnv&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하고 난 다음에는 source를 이용하여서 적용하여 주도록 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 zsh을 이용하기 때문에 다른분들은 자신의 환경에 맞는걸로 찾아보도록 해요.&lt;/p&gt;
&lt;pre id=&quot;code_1638763542917&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ source ~/.zshrc&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 적용 방법 하나의 폴더를 만들고 내부에서 적용할수 있는 .envrc 파일을 만들어 줍니다.&lt;/p&gt;
&lt;pre id=&quot;code_1638763683632&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ cd myDir
$ vi .envrc&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일이 생성되면 allow 해달라고 나오는데요. 이때에&amp;nbsp;direnv allow를 하면 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1638763719574&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ direnv allow&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간략하게 direnv를 사용하는 방법에 대해서 알아봤습니다.&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;</description>
      <category>Tool</category>
      <category>direnv</category>
      <category>Node</category>
      <category>Python</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/869</guid>
      <comments>https://mrgamza.tistory.com/869#entry869comment</comments>
      <pubDate>Mon, 6 Dec 2021 14:16:36 +0900</pubDate>
    </item>
    <item>
      <title>You are using safe update mode</title>
      <link>https://mrgamza.tistory.com/868</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;WorkBench에서 대량으로 업데이트를 할 일이 생겼는데, 명령을 했더니 다음과 비슷한 에러가 발생합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1637657456085&quot; class=&quot;html xml&quot; style=&quot;display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; margin: 20px auto 0px; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Error Code: 1175. You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column To disable safe mode, toggle the option in Preferences -&amp;gt; SQL Editor and reconnect.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원인은 키값을 이용하여서 하나 정도의 범위의 값들을 update나 delete 하여야 하는데, 한꺼번에 많은것을 하기 때문입니다.&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;h3 data-ke-size=&quot;size23&quot;&gt;첫번째&lt;/h3&gt;
&lt;pre id=&quot;code_1637661098920&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;set sql_safe_updates=0;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 해서 잠시 환경변수로 풀어줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하고 나서는 다시 1로 변경합시다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;두번째&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Workbench 설정에서 safe mode를 해제하여줍니다.&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;</description>
      <category>Database</category>
      <category>MySQL</category>
      <category>Safe Update</category>
      <category>안전</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/868</guid>
      <comments>https://mrgamza.tistory.com/868#entry868comment</comments>
      <pubDate>Tue, 23 Nov 2021 18:59:29 +0900</pubDate>
    </item>
    <item>
      <title>git 터미널에서 한글 출력되는것 없애기</title>
      <link>https://mrgamza.tistory.com/867</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;git을 받고 나서 터미널에서 git 명령어를 쳤더니 한글로 나온다...&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;p data-ke-size=&quot;size16&quot;&gt;뭐 그럼 방법을 이야기 드리겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1636705147773&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ echo $LANG&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 타이핑하고 나면 어떤 글자가 나오는지 봐야합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;en_US로 나오면 난감하지만 저와 같은 분들은 아무것도 안나올겁니다.&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;그럼 zsh 기준으로 영어로 설정하는 방법을 알려드립니다.&lt;/p&gt;
&lt;pre id=&quot;code_1636705228583&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ vi ~/.zshrc&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내부에 이렇게 넣어줍니다.&lt;/p&gt;
&lt;pre id=&quot;code_1636705251477&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export LANG=en_US&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 저장하고 나와서. 다음을 해줍니다.&lt;/p&gt;
&lt;pre id=&quot;code_1636705279053&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ source ~/.zshrc&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 나서 git 관련 명령을 쳐보면 영어로 나옵니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 주의 다른것들도 다 영어로 나올거에요.&lt;/p&gt;</description>
      <category>OS</category>
      <category>git</category>
      <category>개발자는 영어</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/867</guid>
      <comments>https://mrgamza.tistory.com/867#entry867comment</comments>
      <pubDate>Fri, 12 Nov 2021 17:22:27 +0900</pubDate>
    </item>
    <item>
      <title>SSH Key 생성하여 여러개 사용하기</title>
      <link>https://mrgamza.tistory.com/866</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;github같은것을 이용하기 위해서 ssh key를 이용하여서 사용하는 경우가 있을겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래의 순서대로 사용하면 됩니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Local에 ssh key 생성하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일단 .ssh 폴더로 이동하도록 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개인 계정의 루트에서 ssh로 이동합시다.&lt;/p&gt;
&lt;pre id=&quot;code_1622951928798&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ cd ~/.ssh&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ls 명령을 통해서 기존에 사용하던 key가 있는지 확인 해봅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;잘 사용하던 key가 안될수가 있으니까요&lt;/p&gt;
&lt;pre id=&quot;code_1622951984811&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;id_rsa.pub
is_rsa&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 파일들이 보인다면 기존에 만들어둔것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;.pub는 공개 키, 없는것은 개인 키입니다.&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;ssh-keygen을 이용하여서 만들어야 합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1622952121544&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ ssh-keygen -t rsa -b 4096 -C &quot;your-email&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 명령을 하게 되면 다음과 같이 나오게 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1622952151569&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Generating public/private rsa key pair.
Enter file in which to save the key (/Users/You/.ssh/id_rsa): github_outofcoding_rsa
Enter passphrase (empty for no passphrase):
Enter same passphrase again:&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;패스워드는 넣어도 되고 안 넣어도 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른곳에 복사할 경우에 패스워드를 이용하는 방법을 사용한다고 합니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;공개키를 사용하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SSH-Agent에 개인키를 등록하여 줍니다.&lt;/p&gt;
&lt;pre id=&quot;code_1622952970116&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ eval $(ssh-agent -s)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;agent pid 12345&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;그리고 ssh-add 명령어를 이용하여 개인키를 ssh-agent에 등록하여 줍니다.&lt;/p&gt;
&lt;pre id=&quot;code_1622953033001&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ ssh-add ~/.ssh/github_outofcoding_rsa&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;github에 공개키 등록하기&lt;/h2&gt;
&lt;pre id=&quot;code_1622953105848&quot; class=&quot;swift&quot; style=&quot;display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; margin: 20px auto 0px; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ cat github_outofcoding_rsa.pub&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 하면 키가 나오게 됩니다. 이걸 복사합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 github에 가서 다음의 메뉴를 찾아가서 Key를 등록합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f9f9f9; color: #000000;&quot;&gt;Settings &amp;gt; SSH and GPG keys &amp;gt; New SSH key 버튼 클릭&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f9f9f9; color: #000000;&quot;&gt;Title에는 구분 가능하게 입력하고 Key에는 복사된 부분을 붙여넣기 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f9f9f9; color: #000000;&quot;&gt;Add SSH key 버튼 클릭&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기까지 하신다면 일반적으로 그냥 한개 등록된 rsa키가 한개라면 사용이 가능합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 이름까지 변경을 하여 주어서 이 부분을 config 파일에 등록 하여야 합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1622952482224&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ vi config&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 형태의 값을 넣어줍니다.&lt;/p&gt;
&lt;pre id=&quot;code_1622952677527&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# First
Host outofcoding.github.com
    HostName github.com
    User git
    Port 22
    IdentityFile ~/.ssh/github_outofcoding_rsa
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Host는 host의 name이므로 구분되게 지정하여 주면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;똑같은 형태로 계속 넣어주면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ssh를 하나씩 만들어서 파일을 지정하여 주면 됩니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;테스트&lt;/h2&gt;
&lt;pre id=&quot;code_1622952794365&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ ssh -T outofcoding.github.com&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Backend/Server</category>
      <category>github</category>
      <category>ssh</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/866</guid>
      <comments>https://mrgamza.tistory.com/866#entry866comment</comments>
      <pubDate>Sun, 6 Jun 2021 13:14:00 +0900</pubDate>
    </item>
    <item>
      <title>iOS. UICollectionView로 Header만들고 Stretch 동작하도록 만들기</title>
      <link>https://mrgamza.tistory.com/865</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;오랜만에 iOS 글을 적는거 같네요.&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;오늘 올려볼 글은 CollectionView를 이용해서 Header를 만들고 Stretch 동작하도록 할거에요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뮤직 어플등에서 상단에 View를 Stretch 하는 것이에요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지를 보여주는게 더 나을것 같아요. 사진은 이쁜 지수.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;2532&quot; data-filename=&quot;test.gif&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDpgSF/btq4X6CTeNZ/j3Kgq727yNn7ivyewwXVdK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDpgSF/btq4X6CTeNZ/j3Kgq727yNn7ivyewwXVdK/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDpgSF/btq4X6CTeNZ/j3Kgq727yNn7ivyewwXVdK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/bDpgSF/btq4X6CTeNZ/j3Kgq727yNn7ivyewwXVdK/img.gif&quot; data-origin-width=&quot;1170&quot; data-origin-height=&quot;2532&quot; data-filename=&quot;test.gif&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Storyboard는 최근 사용하지 않아서 코드로 만들어진 부분들을 넣었습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;기본 CollectionView 만들기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ViewController에 다음과 같이 만들어 봅시다.&lt;/p&gt;
&lt;pre id=&quot;code_1621161479521&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;final class ViewController: UIViewController {
    
    private let headerReusableId = &quot;HeaderReusableView&quot;
    private let cellReusableId = &quot;CollectionViewCell&quot;
    
    private lazy var collectionView: UICollectionView = { [unowned self] in
        let view = UICollectionView(frame: .zero, collectionViewLayout: self.collectionViewFlowLayout)
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }()
    private lazy var collectionViewFlowLayout: UICollectionViewFlowLayout = {
        let layout = StretchableUICollectionViewFlowLayout()
        layout.sectionInset = .init(top: 10, left: 0, bottom: 0, right: 0)
        layout.headerReferenceSize = CGSize(width: UIScreen.main.bounds.width, height: 300)
        return layout
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        
        setupCollectionView()
    }
}

private extension ViewController {
    func setupCollectionView() {
        view.addSubview(collectionView)
        NSLayoutConstraint.activate([
            collectionView.leftAnchor.constraint(equalTo: view.leftAnchor),
            collectionView.rightAnchor.constraint(equalTo: view.rightAnchor),
            collectionView.topAnchor.constraint(equalTo: view.topAnchor),
            collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
        ])
        
        collectionView.register(CollectionReusableView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: headerReusableId)
        
        collectionView.register(CollectionViewCell.self, forCellWithReuseIdentifier: cellReusableId)
        
        collectionView.delegate = self
        collectionView.dataSource = self
    }
}

extension ViewController: UICollectionViewDataSource, UICollectionViewDelegate {
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -&amp;gt; Int {
        return 300
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -&amp;gt; UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellReusableId, for: indexPath)
        return cell
    }
    
    func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -&amp;gt; UICollectionReusableView {
        switch kind {
        case UICollectionView.elementKindSectionHeader:
            let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: headerReusableId, for: indexPath)
            return headerView
        default:
            #if DEBUG
            assert(false, &quot;Don't use this kind.&quot;)
            #else
            return UICollectionReusableView()
            #endif
            
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;collectionView&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UICollectionView를 초기화하는 부분&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;collectionViewFlowLayout&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UICollectionViewFlowLayout을 초기화하는 부분&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이곳에서 StretchableUICollectionViewFlowLayout을 가지고 초기화를 하여 줍니다.&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;나머지 부분들중 delegate, datasource 같은 부분들은 설명하지 않을게요.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;StretchableUICollectionViewFlowLayout&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것을 만들지 않고 기본적인 UICollectionViewFlowLayout을 이용하면 우리가 아는 CollectionView처럼 스크롤되는 방향대로 그대로 스크롤 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1621161707917&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;final class StretchableUICollectionViewFlowLayout: UICollectionViewFlowLayout {
    override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -&amp;gt; Bool {
        return true
    }
    
    override func layoutAttributesForElements(in rect: CGRect) -&amp;gt; [UICollectionViewLayoutAttributes]? {
        let layoutAttributes = super.layoutAttributesForElements(in: rect)
        
        guard let offset = collectionView?.contentOffset, let stLayoutAttributes = layoutAttributes else {
            return layoutAttributes
        }
        
        if offset.y &amp;lt; 0 {
            for attributes in stLayoutAttributes where attributes.representedElementKind == UICollectionView.elementKindSectionHeader {
                let diffValue = abs(offset.y)
                var frame = attributes.frame
                frame.size.height = max(0, headerReferenceSize.height + diffValue)
                frame.origin.y = frame.minY - diffValue
                attributes.frame = frame
            }
        }
        return layoutAttributes
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 프로젝트의 핵심이라고 할 수 있을거 같습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;CollectionViewCell&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그냥 표현해주는 collection view cell입니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;CollectionReusableView&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;Image를 View의 높이에 따라서 늘어날수 있도록 AutoLayout을 정의하여 두고 사용하여 줍니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&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;git에 프로젝트 전체 올려 두었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/outofcode-example/iOS-UICollectionReusableViewExample&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/outofcode-example/iOS-UICollectionReusableViewExample&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1621162056641&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;outofcode-example/iOS-UICollectionReusableViewExample&quot; data-og-description=&quot;UICollectionReusableViewExample. Contribute to outofcode-example/iOS-UICollectionReusableViewExample development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/outofcode-example/iOS-UICollectionReusableViewExample&quot; data-og-url=&quot;https://github.com/outofcode-example/iOS-UICollectionReusableViewExample&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/FXxJH/hyKeZU3Ulh/6nZuS08GAANkwzWr8DKVR1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/outofcode-example/iOS-UICollectionReusableViewExample&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/outofcode-example/iOS-UICollectionReusableViewExample&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/FXxJH/hyKeZU3Ulh/6nZuS08GAANkwzWr8DKVR1/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;outofcode-example/iOS-UICollectionReusableViewExample&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;UICollectionReusableViewExample. Contribute to outofcode-example/iOS-UICollectionReusableViewExample 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;</description>
      <category>Mobile/iOS</category>
      <category>cell</category>
      <category>collectionview</category>
      <category>reusable</category>
      <category>STRETCH</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/865</guid>
      <comments>https://mrgamza.tistory.com/865#entry865comment</comments>
      <pubDate>Sun, 16 May 2021 19:47:55 +0900</pubDate>
    </item>
    <item>
      <title>AWS Lambda로 Hello, Lambda! 를 만들어 봅시다.</title>
      <link>https://mrgamza.tistory.com/864</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Lambda는 AWS에서 제공하는 FaaS 서비스입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Google Cloud Functions, Azure Functions 같은것들이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이중에 AWS가 가장 많이 사용되고 있습니다.&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;다음에 접속해서 Lambda를 &lt;b&gt;새로 생성&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ap-northeast-2.console.aws.amazon.com/lambda/home?region=ap-northeast-2#/functions&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ap-northeast-2.console.aws.amazon.com/lambda/home?region=ap-northeast-2#/functions&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1620537275797&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;https://ap-northeast-2.console.aws.amazon.com/lambda/home?region=ap-northeast-2#/functions&quot; data-og-description=&quot;&quot; data-og-host=&quot;ap-northeast-2.console.aws.amazon.com&quot; data-og-source-url=&quot;https://ap-northeast-2.console.aws.amazon.com/lambda/home?region=ap-northeast-2#/functions&quot; data-og-url=&quot;https://ap-northeast-2.console.aws.amazon.com/lambda/home?region=ap-northeast-2#/functions&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://ap-northeast-2.console.aws.amazon.com/lambda/home?region=ap-northeast-2#/functions&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://ap-northeast-2.console.aws.amazon.com/lambda/home?region=ap-northeast-2#/functions&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;https://ap-northeast-2.console.aws.amazon.com/lambda/home?region=ap-northeast-2#/functions&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;ap-northeast-2.console.aws.amazon.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;화면 캡처 2021-05-09 141523.png&quot; data-origin-width=&quot;1342&quot; data-origin-height=&quot;238&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dG998P/btq4vQ6I9yB/nl9BTSGOuZN0nKkryX6330/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dG998P/btq4vQ6I9yB/nl9BTSGOuZN0nKkryX6330/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dG998P/btq4vQ6I9yB/nl9BTSGOuZN0nKkryX6330/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdG998P%2Fbtq4vQ6I9yB%2Fnl9BTSGOuZN0nKkryX6330%2Fimg.png&quot; data-filename=&quot;화면 캡처 2021-05-09 141523.png&quot; data-origin-width=&quot;1342&quot; data-origin-height=&quot;238&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같이 세팅하여 주도록 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그냥 만들거라 Node.js를 이용하였는데 자신이 좋아하는 언어를 선택해서 생성하여 주면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개인적으로는 Go lang을 좋아합니다. :)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1744&quot; data-origin-height=&quot;1621&quot; data-filename=&quot;화면 캡처 2021-05-09 141750.png&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oDpQo/btq4o5Y7i2m/WvxqIz0jCwcl13Ya8C2FYK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oDpQo/btq4o5Y7i2m/WvxqIz0jCwcl13Ya8C2FYK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oDpQo/btq4o5Y7i2m/WvxqIz0jCwcl13Ya8C2FYK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoDpQo%2Fbtq4o5Y7i2m%2FWvxqIz0jCwcl13Ya8C2FYK%2Fimg.png&quot; data-origin-width=&quot;1744&quot; data-origin-height=&quot;1621&quot; data-filename=&quot;화면 캡처 2021-05-09 141750.png&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래쪽의 index.js파일을 &lt;b&gt;더블클릭&lt;/b&gt; 하세요&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;화면 캡처 2021-05-09 142054.png&quot; data-origin-width=&quot;1102&quot; data-origin-height=&quot;1027&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bK6FaH/btq4p8OxKhO/9WsS1XkviaXzcRKKxki281/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bK6FaH/btq4p8OxKhO/9WsS1XkviaXzcRKKxki281/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bK6FaH/btq4p8OxKhO/9WsS1XkviaXzcRKKxki281/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbK6FaH%2Fbtq4p8OxKhO%2F9WsS1XkviaXzcRKKxki281%2Fimg.png&quot; data-filename=&quot;화면 캡처 2021-05-09 142054.png&quot; data-origin-width=&quot;1102&quot; data-origin-height=&quot;1027&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 부분을 자신이 원하는 형태로 수정하여 줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Hello from Lambda! 부분이 응답이 되는 부분입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;화면 캡처 2021-05-09 142121.png&quot; data-origin-width=&quot;613&quot; data-origin-height=&quot;238&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJR1FG/btq4rzrl29p/CYopWifhmMnCdk8T27CCI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJR1FG/btq4rzrl29p/CYopWifhmMnCdk8T27CCI1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJR1FG/btq4rzrl29p/CYopWifhmMnCdk8T27CCI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJR1FG%2Fbtq4rzrl29p%2FCYopWifhmMnCdk8T27CCI1%2Fimg.png&quot; data-filename=&quot;화면 캡처 2021-05-09 142121.png&quot; data-origin-width=&quot;613&quot; data-origin-height=&quot;238&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;URL로 접근해야 하므로 트리거를 생성하여 줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같이 하고 추가하여 줍니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;화면 캡처 2021-05-09 142308.png&quot; data-origin-width=&quot;1237&quot; data-origin-height=&quot;1111&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ss4Pb/btq4rAcJMOl/9Ko0DY4lMNKxvkkGA4BPR0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ss4Pb/btq4rAcJMOl/9Ko0DY4lMNKxvkkGA4BPR0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ss4Pb/btq4rAcJMOl/9Ko0DY4lMNKxvkkGA4BPR0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSs4Pb%2Fbtq4rAcJMOl%2F9Ko0DY4lMNKxvkkGA4BPR0%2Fimg.png&quot; data-filename=&quot;화면 캡처 2021-05-09 142308.png&quot; data-origin-width=&quot;1237&quot; data-origin-height=&quot;1111&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 나오면 생성된것이고&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;화면 캡처 2021-05-09 142415.png&quot; data-origin-width=&quot;1093&quot; data-origin-height=&quot;379&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rLury/btq4o5Y7lD4/BdnraifFC3LLfveKt3cHEK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rLury/btq4o5Y7lD4/BdnraifFC3LLfveKt3cHEK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rLury/btq4o5Y7lD4/BdnraifFC3LLfveKt3cHEK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrLury%2Fbtq4o5Y7lD4%2FBdnraifFC3LLfveKt3cHEK%2Fimg.png&quot; data-filename=&quot;화면 캡처 2021-05-09 142415.png&quot; data-origin-width=&quot;1093&quot; data-origin-height=&quot;379&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래쪽의 구성 &amp;gt; 트리거 &amp;gt; 세부 정보를 알여주면 접속 가능한 URL이 보입니다.&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;서버 구성을 하지 않고도 아주 쉽게 서비스를 만들 수 있는 Lambda의 맛보기였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즐거운 시간되세요.&lt;/p&gt;</description>
      <category>Backend/AWS</category>
      <category>AWS</category>
      <category>Lambda</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/864</guid>
      <comments>https://mrgamza.tistory.com/864#entry864comment</comments>
      <pubDate>Sun, 9 May 2021 14:26:26 +0900</pubDate>
    </item>
    <item>
      <title>Ubuntu netplan으로 고정 IP 설정하기</title>
      <link>https://mrgamza.tistory.com/863</link>
      <description>&lt;p&gt;요즘은 우분투를 설치하는 시점에 고정 IP를 설정할 수 있도록 되어 있는데요.&lt;/p&gt;
&lt;p&gt;이렇게 사용하다가도 IP를 변경하고 싶을때도 있고 아니면 고정으로 안쓰다가 나중에 설정할수도 있습니다.&lt;/p&gt;
&lt;p&gt;포트포워딩 해줄려면 이렇게 해야겠죠.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;일단 해당 방법은 Ubuntu 18 LTS 이상을 사용한다고 생각하고 글을 적어보겠습니다.&lt;/p&gt;
&lt;p&gt;그리고 다들 LTS를 이용한다고 가정할게요.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;거의 한개의 인터페이스를 이용하여서 되어 있을거라고 생각하고&lt;/p&gt;
&lt;p&gt;이름은 enp0s31f6 형태로 되어 있을겁니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;vi를 이용하여 다음의 설정 파일을 수정하여 줍니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Ubuntu 20&lt;/p&gt;
&lt;pre id=&quot;code_1620532129628&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ sudo vi /etc/netplan/00-installer-config.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ubuntu 18&lt;/p&gt;
&lt;pre id=&quot;code_1620532146792&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ sudo vi /etc/netplan/50-cloud-init.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;내용은 다음과 같이 수정하시면 되요.&lt;/p&gt;
&lt;pre id=&quot;code_1620532241327&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;...
        enp0s31f6:
            addresses: [192.168.0.200/24]
            ...
...&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;...으로 표시된것까지 타이핑을 하라는것이 아니라 addresses 부분을 수정하라는 이야기 입니다.&lt;/p&gt;
&lt;p&gt;저는 192.168.0.200으로 하였습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;주의할 점은 yaml 파일이라서 줄맞춤을 꼭 해주어야 합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;:wq로 저장하고 vi를 종료합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이후에 설정 반영을 하여 주어야 하기 때문에 다음과 같이 해주고요.&lt;/p&gt;
&lt;pre id=&quot;code_1620532353410&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ sudo netplan apply&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;정상 설정 되었는지 확인&lt;/p&gt;
&lt;pre id=&quot;code_1620532440563&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ nslookup google.com&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;lookup을 통해서 google.com으로 통신을 하고 왔는지 확인이 가능합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이런 형태로 나올거에요&lt;/p&gt;
&lt;pre id=&quot;code_1620532934748&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ nslookup google.com
Server:         127.0.0.53
Address:        127.0.0.53#53

Non-authoritative answer:
Name:   google.com
Address: 172.217.25.78
Name:   google.com
Address: 2404:6800:4004:822::200e&lt;/code&gt;&lt;/pre&gt;</description>
      <category>OS</category>
      <category>netplan</category>
      <category>ubuntu</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/863</guid>
      <comments>https://mrgamza.tistory.com/863#entry863comment</comments>
      <pubDate>Sun, 9 May 2021 12:57:26 +0900</pubDate>
    </item>
    <item>
      <title>VSCode를 원격에서 브라우저로 접속해서 코딩하기</title>
      <link>https://mrgamza.tistory.com/862</link>
      <description>&lt;p&gt;오늘은 VSCode를 원격으로 돌리는 방법을 알아보려고 합니다.&lt;/p&gt;
&lt;p&gt;물론 VSCode가 그렇게 무겁지 않기 때문에 웬만하면 노트북에 설치가 다 되어 있을거라...&lt;/p&gt;
&lt;p&gt;이동하면서 코딩하기 어렵지는 않습니다.&lt;/p&gt;
&lt;p&gt;그래도 이런 방법도 있다는걸 공유하고 싶어서 글을 남깁니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;일단 docker를 이용해서 원격지에 image를 pull 하여 주면 됩니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://hub.docker.com/r/codercom/code-server&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;hub.docker.com/r/codercom/code-server&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1619621761876&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Docker Hub&quot; data-og-description=&quot;&quot; data-og-host=&quot;hub.docker.com&quot; data-og-source-url=&quot;https://hub.docker.com/r/codercom/code-server&quot; data-og-url=&quot;https://hub.docker.com/r/codercom/code-server&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://hub.docker.com/r/codercom/code-server&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://hub.docker.com/r/codercom/code-server&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;&gt;Docker Hub&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;hub.docker.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;이미지는 code-server를 이용할겁니다.&lt;/p&gt;
&lt;pre id=&quot;code_1619621810929&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ sudo docker pull codercom/code-server&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;image를 다 받아오게 되면 다음과 같이 docker container를 실행하면 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1619621915235&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ sudo docker run --name code-server -p 8080:8080 -v {YOUR_VOLUME_PATH}:/home/coder/project -e PASSWORD={YOUR_PASSWORD} codercom/code-server:latest&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;docker를 조금 아시는 분들은 -p의 port 부분과 -v 부분의 연결해줄 volume를 조정해서 하시면 됩니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;접속 테스트는 localhost:8080으로 하면 됩니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;만약 자신의 개인 컴퓨터를 해놓으신거면 공유기 설정에서 포트 포워딩해서 사용하시기 바랍니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Tool</category>
      <category>docker</category>
      <category>vscode</category>
      <category>원격</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/862</guid>
      <comments>https://mrgamza.tistory.com/862#entry862comment</comments>
      <pubDate>Thu, 29 Apr 2021 00:00:13 +0900</pubDate>
    </item>
    <item>
      <title>애플 미리알림과 마이크로소프트 To Do 동기화하여 사용하기</title>
      <link>https://mrgamza.tistory.com/861</link>
      <description>&lt;p&gt;저는 폰은 아이폰을 사용합니다.&lt;/p&gt;
&lt;p&gt;그래서 맥과 연결된 환경에서는 작업하던중에 컴퓨터로도 미리알림을 시간을 맞춰두면 간단한 메모들을 넣어놔서 편안하게 사용 할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;컴퓨터를 멀티로 사용하다 보니까 윈도우로도 이런것들을 같이 사용하고 싶을때가 있습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;윈도우에서는 To Do라는 앱이 있고요.&lt;/p&gt;
&lt;p&gt;Microsoft Store 에서 무료로 다운로드 받을수 있습니다.&lt;/p&gt;
&lt;p&gt;따로 링크는 넣지 않을게요.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;script src=&quot;https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot;&gt;&lt;/script&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;script&gt;
     (adsbygoogle = window.adsbygoogle || []).push({});
&lt;/script&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;두번째로는 아이폰에서 계정을 연동하여 주어야 합니다.&lt;/p&gt;
&lt;p&gt;아이폰 설정에서 계정을 찾아서 추가하여 줍니다.&lt;/p&gt;
&lt;p&gt;방법은 설정에서 가서 위에 검색에서 계정 을 넣어주면 &quot;계정 추가&quot; 도 보이실거에요.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Microsoft Exchange를 선택하여 주고 자신의 계정을 등록하여 주면 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;KakaoTalk_Photo_2021-04-24-11-53-42.png&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;2688&quot; width=&quot;500&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cz3vi5/btq3n9s45k2/D0xQiy9LKt3uBcIKRn5Qdk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cz3vi5/btq3n9s45k2/D0xQiy9LKt3uBcIKRn5Qdk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cz3vi5/btq3n9s45k2/D0xQiy9LKt3uBcIKRn5Qdk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcz3vi5%2Fbtq3n9s45k2%2FD0xQiy9LKt3uBcIKRn5Qdk%2Fimg.png&quot; data-filename=&quot;KakaoTalk_Photo_2021-04-24-11-53-42.png&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;2688&quot; width=&quot;500&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;저는 미리 알림만 동기화 할거라 나머지는 빼두었습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;KakaoTalk_Photo_2021-04-24-11-53-53.png&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;2688&quot; width=&quot;500&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqZqJc/btq3lSGvvAg/a7IFjjREYpdGiuXT97fql0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqZqJc/btq3lSGvvAg/a7IFjjREYpdGiuXT97fql0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqZqJc/btq3lSGvvAg/a7IFjjREYpdGiuXT97fql0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbqZqJc%2Fbtq3lSGvvAg%2Fa7IFjjREYpdGiuXT97fql0%2Fimg.png&quot; data-filename=&quot;KakaoTalk_Photo_2021-04-24-11-53-53.png&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;2688&quot; width=&quot;500&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;그리고 나서 미리 알림 앱에서 Exchange를 들어가서 항목을 만들어주면 됩니다.&lt;/p&gt;
&lt;p&gt;기존에 사용하던 항목들은 이쪽으로 옮겨야지 윈도우랑 동기화가 됩니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;KakaoTalk_Photo_2021-04-24-12-01-36.jpeg&quot; data-origin-width=&quot;1242&quot; data-origin-height=&quot;398&quot; width=&quot;500&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/z2lDH/btq3lSNhurR/6hd1FTSfDW0y1KAMXQqvak/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/z2lDH/btq3lSNhurR/6hd1FTSfDW0y1KAMXQqvak/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/z2lDH/btq3lSNhurR/6hd1FTSfDW0y1KAMXQqvak/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fz2lDH%2Fbtq3lSNhurR%2F6hd1FTSfDW0y1KAMXQqvak%2Fimg.jpg&quot; data-filename=&quot;KakaoTalk_Photo_2021-04-24-12-01-36.jpeg&quot; data-origin-width=&quot;1242&quot; data-origin-height=&quot;398&quot; width=&quot;500&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;동기화는 앱, 폰의 상태에 따라 동기화가 언제 될지 결정되므로 조금 늦게 될수도 있어요. 기다리는걸로&lt;/p&gt;</description>
      <category>Tool</category>
      <category>To do</category>
      <category>미리보기</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/861</guid>
      <comments>https://mrgamza.tistory.com/861#entry861comment</comments>
      <pubDate>Sat, 24 Apr 2021 12:04:01 +0900</pubDate>
    </item>
    <item>
      <title>swift. RealmSwift 이용하여 봅시다.</title>
      <link>https://mrgamza.tistory.com/859</link>
      <description>&lt;p&gt;프로젝트를 생성하고 pod을 가져와서 사용하는 방법까지는 설명하지 않도록 할게요.&lt;/p&gt;
&lt;p&gt;대신에 이 곳에 설명이 아주 잘되어 있으므로 참고해봅시다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.mongodb.com/realm-legacy/docs/swift/latest/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;docs.mongodb.com/realm-legacy/docs/swift/latest/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1617454472260&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Realm: Create reactive mobile apps in a fraction of the time&quot; data-og-description=&quot;Oops something went wrong You will not be receiving an email shortly with details&quot; data-og-host=&quot;docs.mongodb.com&quot; data-og-source-url=&quot;https://docs.mongodb.com/realm-legacy/docs/swift/latest/&quot; data-og-url=&quot;https://docs.mongodb.com/realm-legacy/docs/swift/latest/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.mongodb.com/realm-legacy/docs/swift/latest/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.mongodb.com/realm-legacy/docs/swift/latest/&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;&gt;Realm: Create reactive mobile apps in a fraction of the time&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;Oops something went wrong You will not be receiving an email shortly with details&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;docs.mongodb.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;그리고 사용 방법은 간단합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이 기능을 사용하여야 하는 파일의 상단에 import를 추가합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1617454599313&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import RealmSwift&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;보기 편하게 저는 write와 read를 만들거에요.&lt;/p&gt;
&lt;pre id=&quot;code_1617455158501&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;private func write() {
    guard let realm = try? Realm() else { return }

    let person = Person()
    person.name = &quot;outofcoding&quot;
    person.address = &quot;Korea&quot;

    try? realm.write {
        realm.add(person)
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이렇게 하면 넣고 싶은 데이터를 넣습니다. 이게 끝입니다. ㅎㅎ&lt;/p&gt;
&lt;p&gt;그럼 read도 넣어 볼게요.&lt;/p&gt;
&lt;pre id=&quot;code_1617455230904&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;private func read() {
    guard let realm = try? Realm() else { return }

    let models = realm.objects(Person.self)
    for model in models {
        print(model.name, model.address)
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이 예제는 간단하게 들어간 값들을 다 불러오는 것입니다.&lt;/p&gt;
&lt;p&gt;조건문을 붙여서 가져와서 사용하는 방법도 있는데 위에 적어드린 Realm 주소에 가서 document를 참조하시면 많은걸 얻으실수 있을거에요.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그럼 전체 내용은 어떨까요?&lt;/p&gt;
&lt;pre id=&quot;code_1617455386040&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import UIKit
import RealmSwift

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        write()
        read()
    }
    
    private func write() {
        guard let realm = try? Realm() else { return }
        
        let person = Person()
        person.name = &quot;outofcoding&quot;
        person.address = &quot;Korea&quot;
        
        try? realm.write {
            realm.add(person)
        }
    }
    
    private func read() {
        guard let realm = try? Realm() else { return }
        
        let models = realm.objects(Person.self)
        for model in models {
            print(model.name, model.address)
        }
    }
}

@objcMembers
class Person: Object {
    dynamic var name = &quot;&quot;
    dynamic var address = &quot;&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이것에서 취향적으로 다를게 있기는 합니다.&lt;/p&gt;
&lt;p&gt;Person class를 만드는 방법인데요. Realm은 변수 자체가 @objc dynamic 이어야 합니다.&lt;/p&gt;
&lt;p&gt;이것은 dynamic dispatch 관련된 부분으로 접근해서 값을 가져오게 만드는것이라 다른 글에서 참조 바라고요.&lt;/p&gt;
&lt;pre id=&quot;code_1617455485736&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Person: Object {
    @objc dynamic var name = &quot;&quot;
    @objc dynamic var address = &quot;&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;때에 따라서는 위와 같이 @objc를 바로 붙여서 사용하여도 됩니다.&lt;/p&gt;
&lt;p&gt;한번에 다 objcMember로 만들고 싶다면 class 자체를 @objcMembers로 넣어도 되고요.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;예제는 프로젝트로 올려두었습니다.&lt;/p&gt;
&lt;p&gt;github에서 받아서 하시면 되고요. pod install 하고 실행하시길 바랍니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/outofcode-example/iOS-RealmDemo&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;github.com/outofcode-example/iOS-RealmDemo&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1617455957197&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;object&quot; data-og-title=&quot;outofcode-example/iOS-RealmDemo&quot; data-og-description=&quot;Contribute to outofcode-example/iOS-RealmDemo development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/outofcode-example/iOS-RealmDemo&quot; data-og-url=&quot;https://github.com/outofcode-example/iOS-RealmDemo&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dF1RRS/hyJK2M8jHE/23T2auRjy9eFdGcIAnvWLK/img.jpg?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400&quot;&gt;&lt;a href=&quot;https://github.com/outofcode-example/iOS-RealmDemo&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/outofcode-example/iOS-RealmDemo&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dF1RRS/hyJK2M8jHE/23T2auRjy9eFdGcIAnvWLK/img.jpg?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;outofcode-example/iOS-RealmDemo&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;Contribute to outofcode-example/iOS-RealmDemo development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Mobile/iOS</category>
      <category>Demo</category>
      <category>Relam</category>
      <category>SWIFT</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/859</guid>
      <comments>https://mrgamza.tistory.com/859#entry859comment</comments>
      <pubDate>Sat, 3 Apr 2021 22:19:40 +0900</pubDate>
    </item>
    <item>
      <title>Python3. lotto 발생기</title>
      <link>https://mrgamza.tistory.com/858</link>
      <description>&lt;p&gt;python은 뭔가를 해도 그냥 다 만들어 놓은 언어같습니다.&lt;/p&gt;
&lt;p&gt;심심해서 만든 lotto 발생기&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1617374146109&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import random


def lotto(sort=True):
    result = []
    numbers = list(range(1, 46))

    for _ in range(6):
        number = random.choice(numbers)
        result.append(number)
        numbers.remove(number)

    if sort:
        result.sort()

    return result


print(lotto())
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Coding</category>
      <category>Lotto</category>
      <category>Python</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/858</guid>
      <comments>https://mrgamza.tistory.com/858#entry858comment</comments>
      <pubDate>Fri, 2 Apr 2021 23:36:44 +0900</pubDate>
    </item>
    <item>
      <title>Python. 간단한 크롤링 만들기 with BeautifulSoup</title>
      <link>https://mrgamza.tistory.com/857</link>
      <description>&lt;p&gt;어떤 서비스에서 API를 제공해주지 않으면 해볼만한게 크롤링입니다.&lt;/p&gt;
&lt;p&gt;파이썬과 BeautifulSoup을 이용합니다. 그리고 Web page를 호출하기 위해서 requests를 이용합니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;BeautifulSoup&lt;/h2&gt;
&lt;p&gt;우리가 크롤링을 하기 위해서는 Tag안에 Tag안에 Tag안에...&lt;/p&gt;
&lt;p&gt;이렇게 구조를 가지고 계속 파고 들어서 무언가의 유의미한 값을 찾아야 합니다.&lt;/p&gt;
&lt;p&gt;그러나 이러한 구조를 찾아주는 라이브러리가 없다면 굉장히 힘들게 파싱을 해야하겠죠.&lt;/p&gt;
&lt;p&gt;find를 쓰던지 등등... BeautifulSoup은 이런 HTML 문서를 아름답게 정리된 상태로 변환하여 주는 라이브러리입니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;만들어 봅시다.&lt;/h2&gt;
&lt;p&gt;python을 처음부터 구성하는 부분은 생략을 하도록 하겠습니다.&lt;/p&gt;
&lt;p&gt;requests를 가져와서 사용하기 위해서 다음과 같이 합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1615092803037&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ pip install requests&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;그리고 def같은 function 안에서 다음을 호출하여 주도록 합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1615092869747&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def get_html(url):
    resp = requests.get(url, headers=headers)
    if resp.status_code == 200:
        _html = resp

    return _html&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;그러면 사용하려고 하는쪽에서 html을 불러와서 그대로 text로 사용을 할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1615092989662&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def work():
    html = get_html('YOUR-URL')
    soup = BeautifulSoup(html.text, 'html.parser')
    ...
    &lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;find를 이용하여 찾기&lt;/h2&gt;
&lt;p&gt;찾는데 두가지 방법이 있습니다. select와 find...&lt;/p&gt;
&lt;p&gt;find를 먼저 알아보도록 할게요.&lt;/p&gt;
&lt;pre id=&quot;code_1615093369547&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;result = soup.find('p')
result = soup.find(class_='name')
result = soup.find(attrs = {'class': 'name')
result = soup.find('p', class_='name')&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;딱 보면 느낌이 거의 오실겁니다.&lt;/p&gt;
&lt;p&gt;1줄은 p tag를 찾는거고&lt;/p&gt;
&lt;p&gt;2줄은 class 이름으로 찾기&lt;/p&gt;
&lt;p&gt;3줄은 attrs중에 class 이름으로 찾기&lt;/p&gt;
&lt;p&gt;4줄은 p tag중에 class 이름으로 찾기&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;이렇게 찾아내고 사용 방법&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1615093476445&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# tag의 이름을 표시
result.name
# tag의 값
result.text
# tag의 속성과 속성값 eg. {'class': ['name]'}
result.attrs&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;find_all도 있는데 이건 array로 return 하여 주는 형태입니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;select를 이용하여 찾기&lt;/h2&gt;
&lt;pre id=&quot;code_1615093908624&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# tag로 찾기
soup.select_one('p')

# class 이름으로 찾기
soup.select_one('.name')

# tag.class이름으로 찾기
soup.select_one('p.name')

# id로 찾기
soup.select_one('#name') 

# tag#id로 찾기
특정 soup.select_one('p#name')

# tag.class#id로 찾기
soup.select_one('p.name#name')
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;뭔가 find와 select가 비슷하지 않나요?&lt;/p&gt;
&lt;p&gt;select를 이용하면 문장을 그냥 다 붙여서 쓸수 있고. 크롬 개발자 모드에서 copy selector로 그냥 복사해서 붙여 넣어도 되서 타이핑하는데 눈이 아플 필요가 없습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;즉! 다음과 같이 값을 찾아서 쓸수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1615094023981&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;result = soup.select('#area &amp;gt; lu &amp;gt; li')&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;select를 쓰는게 수행시간하고 메모리도 덜 사용한다고 하니 필요하면 사용해 보도록 합시다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Language/Python</category>
      <category>beautifulsoup</category>
      <category>Crawling</category>
      <category>Python</category>
      <category>크롤링</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/857</guid>
      <comments>https://mrgamza.tistory.com/857#entry857comment</comments>
      <pubDate>Sun, 7 Mar 2021 14:15:31 +0900</pubDate>
    </item>
    <item>
      <title>ParallaxScrollView</title>
      <link>https://mrgamza.tistory.com/856</link>
      <description>&lt;p&gt;요즘 ClubHouse를 보다가 카테고리 선택하는 화면이 Parallax하게 동작하는것을 보고 한번 만들어봤습니다.&lt;/p&gt;
&lt;p&gt;복잡하게 만들지는 않고 AutoLayout을 이용해서 간단하게 만들었습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이런 형태로 여러가지 View를 만드는것이 가능하므로 많은 분들 좋은 의견 있으면 참여 부탁드립니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;아래와 같이 동작합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;109017870-e9b84000-76fa-11eb-9d5e-5cf7927ac7e3.gif&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;1299&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Vy96y/btqZlPfSIGI/oxM71lbetMA84V2WhzoTr0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Vy96y/btqZlPfSIGI/oxM71lbetMA84V2WhzoTr0/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Vy96y/btqZlPfSIGI/oxM71lbetMA84V2WhzoTr0/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/Vy96y/btqZlPfSIGI/oxM71lbetMA84V2WhzoTr0/img.gif&quot; data-filename=&quot;109017870-e9b84000-76fa-11eb-9d5e-5cf7927ac7e3.gif&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;1299&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;소스는 여기에...&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/outofcoding/ParallaxScrollView&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;github.com/outofcoding/ParallaxScrollView&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1615092107341&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;object&quot; data-og-title=&quot;outofcoding/ParallaxScrollView&quot; data-og-description=&quot;Make scroll parallax. ( like Club House ). Contribute to outofcoding/ParallaxScrollView development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/outofcoding/ParallaxScrollView&quot; data-og-url=&quot;https://github.com/outofcoding/ParallaxScrollView&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/nO0Jn/hyJtzRI46n/QqkJKZDiTthdWrTNRPztK0/img.jpg?width=298&amp;amp;height=298&amp;amp;face=125_55_227_166&quot;&gt;&lt;a href=&quot;https://github.com/outofcoding/ParallaxScrollView&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/outofcoding/ParallaxScrollView&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/nO0Jn/hyJtzRI46n/QqkJKZDiTthdWrTNRPztK0/img.jpg?width=298&amp;amp;height=298&amp;amp;face=125_55_227_166');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;outofcoding/ParallaxScrollView&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;Make scroll parallax. ( like Club House ). Contribute to outofcoding/ParallaxScrollView development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>My</category>
      <category>clubhouse</category>
      <category>cocoaPod</category>
      <category>ParallaxScrollView</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/856</guid>
      <comments>https://mrgamza.tistory.com/856#entry856comment</comments>
      <pubDate>Sun, 7 Mar 2021 13:42:28 +0900</pubDate>
    </item>
    <item>
      <title>Windows10. 작업표시줄 시계 초 단위 표시하기</title>
      <link>https://mrgamza.tistory.com/855</link>
      <description>&lt;p&gt;기본적으로 작업표지줄에 시간은 시와 분까지만 표시가 되게 됩니다.&lt;/p&gt;
&lt;p&gt;Mac에는 초를 보여주는 옵션이 있는데 윈도우에는 옵션으로 제공은 하지 않아요.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;1. Win + R 눌러서 실행 창을 열어 줍니다.&lt;/p&gt;
&lt;p&gt;2. regedit를 타이핑하고 엔터를 눌러줍니다.&lt;/p&gt;
&lt;p&gt;3. 레지스트리 편집기가 노출이 되면 다음의 경로를 찾아갑니다.&lt;br /&gt;&lt;span style=&quot;color: #000000;&quot;&gt;HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;4. 이 경로에서 마우스 오른쪽을 누르고 DWORD(32비트) 값을 선택하여 줍니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;화면 캡처 2021-02-20 120827.png&quot; data-origin-width=&quot;1180&quot; data-origin-height=&quot;1026&quot; width=&quot;652&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c0pjRp/btqX0qNLkqx/8BQklk3xvqBOZJP5KMMC1K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c0pjRp/btqX0qNLkqx/8BQklk3xvqBOZJP5KMMC1K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c0pjRp/btqX0qNLkqx/8BQklk3xvqBOZJP5KMMC1K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc0pjRp%2FbtqX0qNLkqx%2F8BQklk3xvqBOZJP5KMMC1K%2Fimg.png&quot; data-filename=&quot;화면 캡처 2021-02-20 120827.png&quot; data-origin-width=&quot;1180&quot; data-origin-height=&quot;1026&quot; width=&quot;652&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;5. ' ShowSecondsInSystemClock ' 을 생성하여 줍니다.&lt;/p&gt;
&lt;p&gt;6. 항목을 더블클릭해서 값을 1로 변경하여 줍니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;화면 캡처 2021-02-20 121131.png&quot; data-origin-width=&quot;760&quot; data-origin-height=&quot;507&quot; width=&quot;549&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/m1pz6/btqXXkuvmI1/FXrA7HgPdCQBmKjrGFKuy1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/m1pz6/btqXXkuvmI1/FXrA7HgPdCQBmKjrGFKuy1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/m1pz6/btqXXkuvmI1/FXrA7HgPdCQBmKjrGFKuy1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fm1pz6%2FbtqXXkuvmI1%2FFXrA7HgPdCQBmKjrGFKuy1%2Fimg.png&quot; data-filename=&quot;화면 캡처 2021-02-20 121131.png&quot; data-origin-width=&quot;760&quot; data-origin-height=&quot;507&quot; width=&quot;549&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;화면 캡처 2021-02-20 121112.png&quot; data-origin-width=&quot;841&quot; data-origin-height=&quot;639&quot; width=&quot;471&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d5nZiC/btqXU28J1CL/KPrV1zJ4icxWCDGRa2ZcjK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d5nZiC/btqXU28J1CL/KPrV1zJ4icxWCDGRa2ZcjK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d5nZiC/btqXU28J1CL/KPrV1zJ4icxWCDGRa2ZcjK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd5nZiC%2FbtqXU28J1CL%2FKPrV1zJ4icxWCDGRa2ZcjK%2Fimg.png&quot; data-filename=&quot;화면 캡처 2021-02-20 121112.png&quot; data-origin-width=&quot;841&quot; data-origin-height=&quot;639&quot; width=&quot;471&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;7. 윈도우를 재부팅, 로그아웃하였더가 로그인 하던지 아니면 탐색기를 재실행하여 줍니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;* 탐색기 재실행 방법&lt;/p&gt;
&lt;p&gt;여러가지 방법이 있지만 Ctrl + Alt + Delete 를 누르면 작업관리자가 보입니다.&lt;/p&gt;
&lt;p&gt;누르시고 프로세스 항목중에 Windows 탐색기를 선택하고 다시 시작을 눌러주세요.&lt;/p&gt;
&lt;p&gt;이 방법을 잘 모르시겠으면 그냥 재부팅하는게 편합니다.&lt;/p&gt;
&lt;p&gt;윈도우 창을 열어서 작업중이던 부분들이 다 종료가 될수도 있기 때문입니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>OS</category>
      <category>Windows</category>
      <category>초단위 표시</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/855</guid>
      <comments>https://mrgamza.tistory.com/855#entry855comment</comments>
      <pubDate>Sat, 20 Feb 2021 12:14:56 +0900</pubDate>
    </item>
    <item>
      <title>Swift. Method Swizzle.</title>
      <link>https://mrgamza.tistory.com/854</link>
      <description>&lt;p&gt;Objective-C는 런타임에 정적으로 메소드를 호출하는 방식으로 되어 있습니다.&lt;/p&gt;
&lt;p&gt;우리가 호출하는 Method를 적어줘도 컴파일러가 런타임에 있는지 확인하고 호출하는거죠.&lt;/p&gt;
&lt;p&gt;이전에는 그래서 아주 생뚱 맞은 동작이 가능하게도 할 수 있었습니다.&lt;/p&gt;
&lt;p&gt;Int에 String을 넣어놓고 method가 없는데도 호출하게 하는...&lt;/p&gt;
&lt;p&gt;물론 지금도 이런 동작이 가능하지만 이렇게 개발하지는 않죠.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이런 방식을 사용하기 때문에 정적으로 호출하는 방식중에 중간에 메세지를 가로채서 내가 만든 메소드를 호출할 수 있도록 할 수 있습니다.&lt;/p&gt;
&lt;p&gt;이게 바로 메소드 스위즐링입니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;대부분 어떻게 많이 사용하냐면 UIViewController 등에서 로그등 동일한 동작을 하고 싶을때 사용하게 됩니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;사용방법만 알려드리고 주의 할점은 너무 남발하면 어플리케이션이 동작하는데 커다란 무리가 올수도 있고&lt;/p&gt;
&lt;p&gt;지금 버전에서는 되는데 추후 버전에서는 동작하지 않는 문제들도 있을수 있으니 주의를 해야 합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1609671017416&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@main
class AppDelegate: UIResponder, UIApplicationDelegate {

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -&amp;gt; Bool {
        setSwizzle()
        return true
    }

    func setSwizzle() {
        let originalSelector = #selector(UIViewController.viewWillAppear(_:))
        let swizzledSelector = #selector(swizzleViewWillAppear)

        let originalMethod = class_getInstanceMethod(UIViewController.self, originalSelector)
        let swizzledMethod = class_getInstanceMethod(AppDelegate.self, swizzledSelector)

        if let origin = originalMethod, let swizzle = swizzledMethod {
            method_exchangeImplementations(origin, swizzle)
        }
    }
    
    @objc func swizzleViewWillAppear() {
        print(&quot;swizzleViewWillAppear&quot;)
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;예를 든 부분은 UIViewController의 viewWillApper가 호출되면 swizzleViewWillAppear가 호출됩니다.&lt;/p&gt;
&lt;p&gt;다른분들은 extension 하여서 만든 클래스의 이름등을 이용해서 로그를 남기도록 개발하여 두었더군요.&lt;/p&gt;
&lt;p&gt;그 부분은 궁금하시면 댓글 남겨주세요.&lt;/p&gt;</description>
      <category>Mobile/iOS</category>
      <category>dynamic</category>
      <category>objc</category>
      <category>SWIFT</category>
      <category>swizzle</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/854</guid>
      <comments>https://mrgamza.tistory.com/854#entry854comment</comments>
      <pubDate>Sun, 3 Jan 2021 19:54:49 +0900</pubDate>
    </item>
    <item>
      <title>Swift. @dynamicMemberLookup</title>
      <link>https://mrgamza.tistory.com/853</link>
      <description>&lt;p&gt;swift의 dynamicMemberLookup에 대해서 알아볼까 합니다.&lt;/p&gt;
&lt;p&gt;4.2에서 만들어진 녀석인데요.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Dictionary 형태의 값을 가지고 subscript(dynamicMember:)를 가지고 값을 마치 property 처럼 사용이 가능하도록 한 겁니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;다음과 같은 형태로 만들수 있어요.&lt;/p&gt;
&lt;pre id=&quot;code_1609653840691&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@dynamicMemberLookup
struct PropertyDictionary {
    private let properties: [String: Any]
    
    init(_ dictionary: [String: Any]) {
        properties = dictionary
    }

    subscript(dynamicMember string: String) -&amp;gt; Any? {
        return properties[string]
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;자 이렇게 만들어 두면 사용하는 쪽에서는?&lt;/p&gt;
&lt;pre id=&quot;code_1609653905252&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let dictionary: [String: Any] = [
    &quot;abc&quot;: 1, &quot;a&quot;: &quot;abc&quot;
]

let property = PropertyDictionary(dictionary)
print(&quot;test:&quot;, property.a ?? &quot;aaa&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;그냥 이렇게 파싱해서 사용한것처럼 사용이 가능합니다.&lt;/p&gt;
&lt;p&gt;코드는 아래에도 올려두었어요&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/outofcode-example/iOS-PropertyDictionary&quot;&gt;github.com/outofcode-example/iOS-PropertyDictionary&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1609655502764&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;object&quot; data-og-title=&quot;outofcode-example/iOS-PropertyDictionary&quot; data-og-description=&quot;Using dictionary a like property. Contribute to outofcode-example/iOS-PropertyDictionary development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/outofcode-example/iOS-PropertyDictionary&quot; data-og-url=&quot;https://github.com/outofcode-example/iOS-PropertyDictionary&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bVmd9z/hyIOnKkvDR/Ngk99p8FXK5fFKaxQQPP4k/img.png?width=400&amp;amp;height=400&amp;amp;face=75_87_272_204&quot;&gt;&lt;a href=&quot;https://github.com/outofcode-example/iOS-PropertyDictionary&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/outofcode-example/iOS-PropertyDictionary&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bVmd9z/hyIOnKkvDR/Ngk99p8FXK5fFKaxQQPP4k/img.png?width=400&amp;amp;height=400&amp;amp;face=75_87_272_204');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;outofcode-example/iOS-PropertyDictionary&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;Using dictionary a like property. Contribute to outofcode-example/iOS-PropertyDictionary development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;그런데 Swift 5.1에서 추가가 되었습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1609655891295&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@dynamicMemberLookup
struct PersonWrapper&amp;lt;T&amp;gt; {
    private let primate: T
    
    init(_ primate: T) {
        self.primate = primate
    }
    
    subscript&amp;lt;U&amp;gt;(dynamicMember keyPath: WritableKeyPath&amp;lt;T, U&amp;gt;) -&amp;gt; U {
        return primate[keyPath: keyPath]
    }
}

struct Person {
    var name: String = &quot;DH&quot;
    var age: Int = 100
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이렇게 접근이 가능합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1609655920015&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let person = PersonWrapper(Person())
print(person.name)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;그렇네요 정말 Wrapping 하여서 사용하는 케이스 외에는 생각이 안나는데...&lt;/p&gt;
&lt;p&gt;아무튼 알아두고 나중에 요긴하게 사용하렵니다.&lt;/p&gt;</description>
      <category>Mobile/iOS</category>
      <category>dynamicMemberLookup</category>
      <category>SWIFT</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/853</guid>
      <comments>https://mrgamza.tistory.com/853#entry853comment</comments>
      <pubDate>Sun, 3 Jan 2021 15:39:17 +0900</pubDate>
    </item>
    <item>
      <title>RxSwift, RxCocoa. Publish</title>
      <link>https://mrgamza.tistory.com/852</link>
      <description>&lt;p&gt;RxSwift에서는 Cold, Hot가 있습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;구독자가 생기는 순간에 흐름을 방출하는 Cold와&lt;/p&gt;
&lt;p&gt;구독자가 생기지도 않았는데 흐름을 방출하는 Hot이 있습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Hot은 뜨겁게 달궈져서 만들어지기 때문에 시작부터 방출하는것이고&lt;/p&gt;
&lt;p&gt;Cold는 차갑게 얼어서 만들어지기 때문에 시작할때는 방출하지 않는것입니다.&lt;/p&gt;
&lt;p&gt;추후에 subscribe를 만나게 되면 따뜻해지는것이지요.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그래서 우리는 Subject를 이용해서 구독 시점에 발생되던것을 구독과 상관없이 Hot 하게 만들수 있습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;예를 들어서 Network 통신을 하고 나서 값을 가져오는 다음과 같은 예제가 있다고 합시다.&lt;/p&gt;
&lt;pre id=&quot;code_1609642770811&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;API.requestMe()
    .observe(on: MainScheduler.instance)
    .subscribe(onNext: { value in
        print(&quot;1:&quot;, value)
    })
    .disposed(by: disposeBag)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;자 그럼 이것은 흐름을 방출하지 않고 subscribe를 하는 대상이 생겼을때 방출하게 되겠죠.&lt;/p&gt;
&lt;p&gt;이것이 바로 Cold한겁니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그럼 PublishRelay를 한번 볼까요?&lt;/p&gt;
&lt;p&gt;초기에 값을 설정하지 못하지만 subscribe되고 난 다음에도 값을 받고 있죠.&lt;/p&gt;
&lt;p&gt;이전의 값은 방출하여도 가져오질 못합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1609642879807&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let publishRelay = PublishRelay&amp;lt;Int&amp;gt;()

publishRelay.accept(1)

publishRelay
    .observe(on: MainScheduler.instance)
    .subscribe(onNext: { value in
        print(&quot;1:&quot;, value)
    })
    .disposed(by: disposeBag)

publishRelay.accept(2)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이런 예제가 있다고 할 경우에 어떻게 될까요?&lt;/p&gt;
&lt;p&gt;답은 다음과 같아요.&lt;/p&gt;
&lt;pre id=&quot;code_1609643913657&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;1: 2&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;1: 1은 출력이 되지 않아요.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;왜냐면 subscribe가 1을 넣기 전에 만들어지기 때문이죠.&lt;/p&gt;
&lt;p&gt;그럼 이걸 BehaviorRelay로 만들면 어떻게 되는지 보겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1609643886380&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let relay = BehaviorRelay&amp;lt;Int&amp;gt;(value: 1)

relay
  .observe(on: MainScheduler.instance)
  .subscribe(onNext: { value in
    print(&quot;1:&quot;, value)
  })
  .disposed(by: disposeBag)

relay.accept(2)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이번에는 어떤까요?&lt;/p&gt;
&lt;pre id=&quot;code_1609643937911&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;1: 1
1: 2&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;초기값을 가지고 있는 값이 들어가게 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1609643984487&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let relay = BehaviorRelay&amp;lt;Int&amp;gt;(value: 1)

relay.accept(0)

relay
  .observe(on: MainScheduler.instance)
  .subscribe(onNext: { value in
    print(&quot;1:&quot;, value)
  })
  .disposed(by: disposeBag)

relay.accept(2)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;중간에 값을 변경하면 다음과 같아지게 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1609644011667&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;1: 0
1: 2&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;마지막 값을 가지고 있다가 subscribe되는 시점에 전달하게 되어 있습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;PublishRelay를 가지고 BehaviorRelay와 동일하게 만들어 보겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1609644420642&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let publishRelay = PublishRelay&amp;lt;Int&amp;gt;()
let behaviorRelay = publishRelay.replay(1)
behaviorRelay.connect().disposed(by: disposeBag)
pyblishRelay.accept(1)
publishRelay.accept(2)
publishRelay.accept(3)
publishRelay.accept(4)
        
behaviorRelay
  .subscribe(onNext: { value in
    print(&quot;1:&quot;, value)
  })
  .disposed(by: disposeBag)
        
publishRelay.accept(5)
publishRelay.accept(6)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;어떻게 결과가 나올까요?&lt;/p&gt;
&lt;pre id=&quot;code_1609644463477&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;1: 4
1: 5
1: 6&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;그렇습니다. replay가 1이어서 이전에 가지고 있던 값중 마지막 것을 유지하고 있습니다.&lt;/p&gt;
&lt;p&gt;그것과 이후에 발생하는 값들에 대해서도 모두 수신하고 있군요.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;현업에서는 아무래도 초기값을 가지고 화면의 처리를 하다보니까&lt;/p&gt;
&lt;p&gt;BehaviorRelay를 많이 쓰는거 같고 이런 부분들은 적절히 잘 사용하면 좋을거 같습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;추가로 ReplayRelay라는것도 제공을 하여 주는데요.&lt;/p&gt;
&lt;p&gt;위에 예제 부분에서 replay 부분을 조정해서 받을수 있게 해줍니다.&lt;/p&gt;
&lt;p&gt;위의 예제에서 replay 부분을 2로 넣은것과 동일한 결과 입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1609644846890&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let replayRelay = ReplayRelay&amp;lt;Int&amp;gt;.create(bufferSize: 2)
replayRelay.accept(1)
replayRelay.accept(2)
replayRelay.accept(3)
replayRelay.accept(4)

replayRelay
  .subscribe(onNext: { value in
    print(&quot;1:&quot;, value)
  })
  .disposed(by: disposeBag)

replayRelay.accept(5)
replayRelay.accept(6)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;결과는&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1609644866015&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;1: 3
1: 4
1: 5
1: 6&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;3, 4가 버퍼에 들어가서 있을것이고 subscribe 이후이기 때문에 5, 6은 그냥 한개씩 나오게 됩니다.&lt;/p&gt;</description>
      <category>Mobile/iOS</category>
      <category>Behavior</category>
      <category>cold</category>
      <category>hot</category>
      <category>publish</category>
      <category>Relay</category>
      <category>RxCocoa</category>
      <category>rxswift</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/852</guid>
      <comments>https://mrgamza.tistory.com/852#entry852comment</comments>
      <pubDate>Sun, 3 Jan 2021 12:35:13 +0900</pubDate>
    </item>
    <item>
      <title>Linux. samba 설치하고 패스워드 지정하기</title>
      <link>https://mrgamza.tistory.com/851</link>
      <description>&lt;p&gt;이게 유용한곳은 패스워드를 까먹었던지 아니면 새로 만들때 사용합니다.&lt;/p&gt;
&lt;p&gt;제가 기억력이 안 좋아서 계속 까먹네요. ㅠㅠ&lt;/p&gt;
&lt;pre id=&quot;code_1609602766550&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ sudo smbpasswd -a user&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;역시 user는 당신이 넣은 유저 이름이에요.&lt;/p&gt;</description>
      <category>Backend/Server</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/851</guid>
      <comments>https://mrgamza.tistory.com/851#entry851comment</comments>
      <pubDate>Sun, 3 Jan 2021 00:53:00 +0900</pubDate>
    </item>
    <item>
      <title>Happy new year!!</title>
      <link>https://mrgamza.tistory.com/850</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;68747470733a2f2f6d656469612e67697068792e636f6d2f6d656469612f64526b4d7954764375416459342f67697068792e676966.gif&quot; data-origin-width=&quot;280&quot; data-origin-height=&quot;280&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/calpZK/btqR9mKPPjW/KjnFUGlJuhn5IQAnxLr0j1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/calpZK/btqR9mKPPjW/KjnFUGlJuhn5IQAnxLr0j1/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/calpZK/btqR9mKPPjW/KjnFUGlJuhn5IQAnxLr0j1/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/calpZK/btqR9mKPPjW/KjnFUGlJuhn5IQAnxLr0j1/img.gif&quot; data-filename=&quot;68747470733a2f2f6d656469612e67697068792e636f6d2f6d656469612f64526b4d7954764375416459342f67697068792e676966.gif&quot; data-origin-width=&quot;280&quot; data-origin-height=&quot;280&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot;&gt;2021년 복 많이 받으세요&lt;/p&gt;</description>
      <category>Any</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/850</guid>
      <comments>https://mrgamza.tistory.com/850#entry850comment</comments>
      <pubDate>Fri, 1 Jan 2021 18:18:47 +0900</pubDate>
    </item>
    <item>
      <title>Algorithm. permutation 순회</title>
      <link>https://mrgamza.tistory.com/849</link>
      <description>&lt;p&gt;만약 배열로 무슨 값들이 들어온다고 할 경우에 이것들의 모든 순서의 조합을 만들어야 할 경우가 있습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;[&quot;a&quot;, &quot;b&quot;, &quot;c&quot;]라는 값이 들어왔을때에&lt;/p&gt;
&lt;p&gt;[[&quot;a&quot;, &quot;b&quot;, &quot;c&quot;], [&quot;a&quot;, &quot;c&quot;, &quot;b&quot;] ... ] 이렇게 값이 나올겁니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Swift를 이용해서 풀었습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1609137707101&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Permutation&amp;lt;T&amp;gt; {
    func get(_ nums: [T]) -&amp;gt; [[T]] {
        var result = [[T]]()
        var nums = nums
        recurse(0, &amp;amp;nums, &amp;amp;result)
        return result
    }
    
    private func recurse(_ position: Int, _ nums: inout [T], _ result: inout [[T]]) {
        if position == nums.count {
            result.append(nums)
            return
        }
        
        for index in position..&amp;lt;nums.count {
            nums.swapAt(position, index)
            recurse(position + 1, &amp;amp;nums, &amp;amp;result)
            nums.swapAt(position, index)
        }
    }
}

let permutation = Permutation&amp;lt;String&amp;gt;()
let output = permutation.get([&quot;a&quot;, &quot;b&quot;, &quot;c&quot;])
print(output)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Coding</category>
      <category>Permutation</category>
      <category>순회</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/849</guid>
      <comments>https://mrgamza.tistory.com/849#entry849comment</comments>
      <pubDate>Mon, 28 Dec 2020 17:03:04 +0900</pubDate>
    </item>
    <item>
      <title>Dynamic Programming</title>
      <link>https://mrgamza.tistory.com/848</link>
      <description>&lt;p&gt;한국말로는 동적 프로그램입니다.&lt;/p&gt;
&lt;p&gt;그런데 이게 말로만 동적이지 전혀 동적으로 뭘하는게 아니고 처음에 이름을 지은 분이 이게 멋있어서 지었다고 합니다. ㅎㅎ&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;문제의 최적해를 구할 경우에 불필요한 계산을 줄이고 효율적으로 최적해를 찾을수 있고&lt;/p&gt;
&lt;p&gt;전체 문제를 작은 문제로 단순화 하고 점화식으로 만들어서 재귀적인 구조를 활용해서 전체 문제를 해결하는 방식입니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;잘 와닿지는 않습니다. 그래서 알고리즘 문제를 하나 풀어볼까 합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;경로의 최고의 합을 구하는 문제인데요.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;문제는 0,0에서 시작해서 마지막까지 이동을 할 수 있는데 이동 조건은 오른쪽으로 가거나 아래로 갈수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1608385446310&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let route = [
    [3, 7, 9, 2, 7],
    [9, 8, 3, 5, 5],
    [1, 7, 9, 8, 5],
    [3, 8, 6, 4, 10],
    [6, 3, 9, 7, 8]
]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이걸 잘 보면 first column 은 위쪽에서밖에 오지 못하고 first row는 왼쪽에서밖에 오지 못합니다.&lt;/p&gt;
&lt;p&gt;그럼 다음과 같이 값을 채워놓고 시작을 하면 되겠죠.&lt;/p&gt;
&lt;pre id=&quot;code_1608385651332&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var sum = Array(repeating: Array(repeating: 0, count: route[0].count), count: route.count)

sum[0][0] = route[0][0]

var colSum = sum[0][0]
var rowSum = sum[0][0]

for index in 1..&amp;lt;route.count {
    colSum += route[index][0]
    sum[index][0] = colSum
}

for index in 1..&amp;lt;route.count {
    rowSum += route[0][index]
    sum[0][index] = rowSum
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;일단 값을 이것들 밖에 안오기 때문에 이렇게만 채우고 점화식을 적용하도록 합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1608385791809&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;for y in 1..&amp;lt;route.count {
    for x in 1..&amp;lt;route[0].count {
        if sum[y][x - 1] &amp;gt; sum[y - 1][x] {
            sum[y][x] = sum[y][x - 1] + route[y][x]
        } else {
            sum[y][x] = sum[y - 1][x] + route[y][x]
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;if문에서 위쪽의 값과 왼쪽의 값중에서 더 큰 값을 기준으로 sum에 넣어주게 되어있고요.&lt;/p&gt;
&lt;p&gt;그렇게 되면 마지막 4,4에서 max 값을 가질수 있게 되는겁니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;전체 코드는 이렇습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1608385890742&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let route = [
    [3, 7, 9, 2, 7],
    [9, 8, 3, 5, 5],
    [1, 7, 9, 8, 5],
    [3, 8, 6, 4, 10],
    [6, 3, 9, 7, 8]
]

var sum = Array(repeating: Array(repeating: 0, count: route[0].count), count: route.count)

sum[0][0] = route[0][0]

var colSum = sum[0][0]
var rowSum = sum[0][0]

for index in 1..&amp;lt;route.count {
    colSum += route[index][0]
    sum[index][0] = colSum
}

for index in 1..&amp;lt;route.count {
    rowSum += route[0][index]
    sum[0][index] = rowSum
}

for y in 1..&amp;lt;route.count {
    for x in 1..&amp;lt;route[0].count {
        if sum[y][x - 1] &amp;gt; sum[y - 1][x] {
            sum[y][x] = sum[y][x - 1] + route[y][x]
        } else {
            sum[y][x] = sum[y - 1][x] + route[y][x]
        }
    }
}

print(sum[4][4]) // 67&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;많은 문제들을 풀어봐야지 응용에 좋을거 같습니다.&lt;/p&gt;</description>
      <category>Coding</category>
      <category>dynamic</category>
      <category>Programming</category>
      <category>동적</category>
      <category>점화식</category>
      <category>프로그래밍</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/848</guid>
      <comments>https://mrgamza.tistory.com/848#entry848comment</comments>
      <pubDate>Sat, 19 Dec 2020 22:52:35 +0900</pubDate>
    </item>
    <item>
      <title>SwiftUI 처럼 Code로 View를 만들고 Preview를 바로 바로 보여주면서 개발하기</title>
      <link>https://mrgamza.tistory.com/847</link>
      <description>&lt;p&gt;안녕하세요 Out of code 입니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;UI를 개발하는것은 굉장히 복잡하며 미세하여 제대로 가이드 수치를 맞춰 두어도 확인하기 위해서는 빌드를 하면서 확인합니다.&lt;/p&gt;
&lt;p&gt;이전까지는 스토리 보드에서 개발을 할때 느린 프리뷰를 보고 개발을 하고 실제 동작을 해보고 하는 작업들이 너무 지치게 했습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;* 물론 Storyboard에 Preview 기능이 있기는 하지만 이 부분은 많은 버그와 느린 속도로 인하여 사용성이 좋지 않죠.&lt;/p&gt;
&lt;p&gt;* 저는 View를 만드는 방법도 이제는 스토리보드를 사용하지 않습니다. 너무 느리거든요!!&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;저는 코드에서 바로 만들기 때문에 SwiftUI처럼 코드에서 바로 프리뷰를 보고 싶었어요.&lt;/p&gt;
&lt;p&gt;그래서 SwiftUI처럼 Preview를 사용 할 수 있는 방법을 공유하려고 합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;지금 이 글을 보는 여러분들은 아마도 xcode 11 이라고 생각하고 있습니다.&lt;/p&gt;
&lt;p&gt;아니라면 지금 바로 업그레이드 하세요!!&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;저는 Deployment Target도 9.0입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;580&quot; data-origin-height=&quot;218&quot; data-filename=&quot;blob&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b9fO0t/btqQDEmX26X/DFju6GR9VfUhFBxW778cGK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b9fO0t/btqQDEmX26X/DFju6GR9VfUhFBxW778cGK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b9fO0t/btqQDEmX26X/DFju6GR9VfUhFBxW778cGK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb9fO0t%2FbtqQDEmX26X%2FDFju6GR9VfUhFBxW778cGK%2Fimg.png&quot; data-origin-width=&quot;580&quot; data-origin-height=&quot;218&quot; data-filename=&quot;blob&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;방법은 #if #endif문을 이용하여 하는 방법입니다.&lt;/p&gt;
&lt;p&gt;그것과 함께 우리가 SwiftUI의 Preview를 보여주기 위해서는 ~~Representable을 이용하여야 하는데요.&lt;/p&gt;
&lt;p&gt;실제로 동작을 시켜보면 Autolayout의 적용은 UIViewControllerRepresentable에서만 잘 나오더군요.&lt;/p&gt;
&lt;p&gt;버그인건지...&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;ViewController만 설명을 하지만 제가 만든 방식대로면 다른 작은 뷰들도 만들고 ViewController의 중앙에 배치하는 방식으로 한번 해봐도 좋지 않을까요?&lt;/p&gt;
&lt;p&gt;방법은 궁금하시면 댓글 남겨주시면 코드 남길게요.&lt;/p&gt;
&lt;pre id=&quot;code_1608379702005&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#if canImport(SwiftUI) &amp;amp;&amp;amp; DEBUG
import SwiftUI

@available(iOS 13.0, *)
extension UIViewController {
    private struct ViewControllerRepresentable: UIViewControllerRepresentable {
        private let viewController: UIViewController
        
        init(with viewController: UIViewController) {
            self.viewController = viewController
        }
        
        func makeUIViewController(context: Context) -&amp;gt; some UIViewController {
            return viewController
        }
        
        func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
            // Not Use
        }
    }
    
    func toPreview() -&amp;gt; some View {
        ViewControllerRepresentable(with: self)
    }
}

#endif
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;UIViewController를 extension 하였는데 #if안에 들어가서 canImport하게 될 경우에만 사용이 가능합니다.&lt;/p&gt;
&lt;p&gt;그러면 빌드 오류가 나지 않고 잘 되겠죠.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;자 그리고 Preview를 보여줄 ViewController에 다음과 같이 만들어 봅시다.&lt;/p&gt;
&lt;p&gt;extension 을 하여서 contentView를 내부에 만들어 주면 더 깔끔하지 않을까요?&lt;/p&gt;
&lt;pre id=&quot;code_1608381285146&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import UIKit

#if canImport(SwiftUI) &amp;amp;&amp;amp; DEBUG
import SwiftUI

@available(iOS 13.0, *)
struct ViewControllerPreview: PreviewProvider {
    static let deviceNames = [
        &quot;iPhone SE&quot;,
        &quot;iPhone 11 Pro Max&quot;,
        &quot;iPhone 7&quot;
    ]
    
    static var previews: some View {
        ForEach(deviceNames, id: \.self) { deviceName in
            ViewController().toPreview()
                .previewDevice(.init(rawValue: deviceName))
                .previewDisplayName(deviceName)
        }
    }
}
#endif

class ViewController: UIViewController {
    
    private lazy var contentView = ContentView()

    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.addSubview(contentView)
        NSLayoutConstraint.activate([
            contentView.leftAnchor.constraint(equalTo: view.leftAnchor),
            contentView.rightAnchor.constraint(equalTo: view.rightAnchor),
            contentView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
            contentView.heightAnchor.constraint(equalToConstant: 200)
        ])
    }
}

extension ViewController {
    final class ContentView: UIView {
        private lazy var button: UIButton = {
            let button = UIButton()
            button.translatesAutoresizingMaskIntoConstraints = false
            button.backgroundColor = .blue
            button.setTitle(&quot;Test&quot;, for: .normal)
            button.heightAnchor.constraint(equalToConstant: 100).isActive = true
            return button
        }()
        
        private lazy var imageView: UIImageView = {
            let imageView = UIImageView()
            imageView.translatesAutoresizingMaskIntoConstraints = false
            
            let image = UIImage(named: &quot;apple.png&quot;)
            guard let size = image?.size else { return imageView }
            
            let height: CGFloat = 60.0
            let width = (height / size.height) * size.width
            
            imageView.image = image
            
            NSLayoutConstraint.activate([
                imageView.heightAnchor.constraint(equalToConstant: height),
                imageView.widthAnchor.constraint(equalToConstant: width)
            ])
            
            return imageView
        }()
        
        override init(frame: CGRect) {
            super.init(frame: frame)
            
            backgroundColor = .lightGray
            translatesAutoresizingMaskIntoConstraints = false
            
            addSubview(button)
            NSLayoutConstraint.activate([
                button.leadingAnchor.constraint(equalTo: leadingAnchor),
                button.trailingAnchor.constraint(equalTo: trailingAnchor),
                button.bottomAnchor.constraint(equalTo: bottomAnchor),
                
            ])
            
            addSubview(imageView)
            NSLayoutConstraint.activate([
                imageView.centerXAnchor.constraint(equalTo: centerXAnchor),
                imageView.topAnchor.constraint(equalTo: topAnchor)
            ])
        }
        
        required init?(coder: NSCoder) {
            fatalError(&quot;init(coder:) has not been implemented&quot;)
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위쪽에 PreviewProvider를 상속받아서 사용하게 한 부분이 주요한 부분입니다.&lt;/p&gt;
&lt;p&gt;deviceNames를 넣어서 여러개의 device의 preview를 한번에 볼수 있도록 할 수도 있습니다.&lt;/p&gt;
&lt;p&gt;아래쪽은 View를 만들어주기 위해서 하는 부분이라 여러분이 해보고 싶은대로 해보시는것도 좋습니다.&lt;/p&gt;
&lt;p&gt;대신에 수정하고 오른쪽에 Resume만 눌러주면 고친 부분이 자동으로 반영됩니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;마치 SwiftUI를 고치는거처럼요.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;한가지 주의할것은 deviceNames를 너무 많이 넣으면 성능이 안 좋아져서 오히려 안 좋으니까 zeplin 기준으로 나온 디자인은 보고 나머지는 변경해가면서 돌려보는것도 좋을거 같습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;위의 예제에서 button title을 test -&amp;gt; 타이틀입니다. 로 변경하였습니다. 바로 변경이 되요.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;399&quot; data-origin-height=&quot;931&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lVocb/btqQCz7fhVF/gu2uIQuc76IbmLHBl19g9K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lVocb/btqQCz7fhVF/gu2uIQuc76IbmLHBl19g9K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lVocb/btqQCz7fhVF/gu2uIQuc76IbmLHBl19g9K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlVocb%2FbtqQCz7fhVF%2Fgu2uIQuc76IbmLHBl19g9K%2Fimg.png&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;399&quot; data-origin-height=&quot;931&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;시뮬레이터와도 비교를 해봅니다.&lt;/p&gt;
&lt;p&gt;시뮬레이터와도 차이가 없네요!! 당연하겠죠? ㅋㅋ&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;2198&quot; data-origin-height=&quot;1912&quot; data-filename=&quot;스크린샷 2020-12-19 오후 9.44.11.png&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bW2Yhk/btqQNpatbxW/PDfD9KxzLPgub9JJ2Akdb1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bW2Yhk/btqQNpatbxW/PDfD9KxzLPgub9JJ2Akdb1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bW2Yhk/btqQNpatbxW/PDfD9KxzLPgub9JJ2Akdb1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbW2Yhk%2FbtqQNpatbxW%2FPDfD9KxzLPgub9JJ2Akdb1%2Fimg.png&quot; data-origin-width=&quot;2198&quot; data-origin-height=&quot;1912&quot; data-filename=&quot;스크린샷 2020-12-19 오후 9.44.11.png&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;질문은 남겨주시고 이후에 SwiftUI처럼 뷰를 Stackable하게 쌓아서 만드는 방법도 구현했는데 이건 추후에 공개할게요.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;마지막으로 소스입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/outofcode-example/iOS-XCodePreview&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;github.com/outofcode-example/iOS-XCodePreview&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1608381980376&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;object&quot; data-og-title=&quot;outofcode-example/iOS-XCodePreview&quot; data-og-description=&quot;Contribute to outofcode-example/iOS-XCodePreview development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/outofcode-example/iOS-XCodePreview&quot; data-og-url=&quot;https://github.com/outofcode-example/iOS-XCodePreview&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/PO2Su/hyICWF40SR/crYZiH4PZFoj8l3EIVenxK/img.png?width=400&amp;amp;height=400&amp;amp;face=75_87_272_204&quot;&gt;&lt;a href=&quot;https://github.com/outofcode-example/iOS-XCodePreview&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/outofcode-example/iOS-XCodePreview&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/PO2Su/hyICWF40SR/crYZiH4PZFoj8l3EIVenxK/img.png?width=400&amp;amp;height=400&amp;amp;face=75_87_272_204');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;outofcode-example/iOS-XCodePreview&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;Contribute to outofcode-example/iOS-XCodePreview development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Mobile/iOS</category>
      <category>CodePreview</category>
      <category>Preview</category>
      <category>swiftUI</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/847</guid>
      <comments>https://mrgamza.tistory.com/847#entry847comment</comments>
      <pubDate>Sat, 19 Dec 2020 21:54:17 +0900</pubDate>
    </item>
    <item>
      <title>JavaScript? ECMAScript?</title>
      <link>https://mrgamza.tistory.com/846</link>
      <description>&lt;p&gt;우리가 흔히 개발을 할 때에 JavaScript를 이용해서 개발을 한다고 합니다.&lt;/p&gt;
&lt;p&gt;그런데 어느쪽에서 보면 ECMAScript라는 이야기도 나오고요.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;왜 이렇게 된거냐면?&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;다른 프로그래밍 언어와 마찬가지로, JavaScript라는 언어에는 표준 명세(standard specification)라는 것이 존재합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;여러 브라우저 개발사에서 통일된 JavaScript 기능을 구현할 수 있도록, 언어의 문법과 기능을 세부적으로 정의해놓은 설계도라고 생각하면 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;JavaScript의 표준 명세는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;ECMAScript&lt;/b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;라는 이름을 갖고 있는데, Netscape에 탑재되었던 JavaScript 구현체(implementation)를 ECMA(European Computer Manufacturer&amp;rsquo;s Association)라는 단체에서 표준화한 것입니다. 이 표준은 1997년에 처음 제정되어 계속 발전하고 있는 중입니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;ECMAScript?&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;ECMAScript는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Ecma 인터내셔널에 의해 제정된 ECMA-262 기술 규격에 의해 정의된 범용 스크립트 언어&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p&gt;ECMA-262는&lt;span&gt;&amp;nbsp;하나의 표준의 이름입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;그리고 ECMAScript는 ECMA-262에서 정의된 하나의 사양을 의미합니다.&lt;/p&gt;
&lt;p&gt;ECMAScript는 스크립트 언어가 준수해야 하는 규칙, 세부 사항 및 지침을 제공합니다.&lt;/p&gt;
&lt;p&gt;쉽게 말해서 ECMA-262을 표준으로 하여서 ECMAScript라는 규칙을 만들었다고 생각하면 됩니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;JavaScript?&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;JavaScript는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;ECMAScript 사양을 준수하는 범용 스크립팅 언어&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p&gt;그러므로 따지고 보면 ECMA와 동일하다고 볼수도 있지만 같지는 않다고 할 수 있어요.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;그런데 말입니다?&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;이렇게 정의된 JavaScript를 각 브라우저들마다 해석하는 능력이 다른 문제점들이 있습니다.&lt;/p&gt;
&lt;p&gt;어떤것들은 속도가 빠르고 어떤것들은 선을 조금 더 이쁘게 그리고 하는 능력들이죠.&lt;/p&gt;
&lt;p&gt;이런것들을 ECMAScript를 얼마나 잘 적용할수있게 해두었는지에 대해서 이야기 하는것이라고 생각하면 됩니다.&lt;/p&gt;
&lt;p&gt;ES6 (&amp;lsquo;ES2015&amp;rsquo;, &amp;lsquo;ECMAScript 2015&amp;rsquo;) 가 나오면서 문제가 더 생겼습니다.&lt;/p&gt;
&lt;p&gt;그래서 다음과 같은것을 사용하게 되었죠.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;바벨(Babel)&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;대부분의 개발자들은 ES6을 지원하는 환경에서 개발이 가능했습니다.&lt;/p&gt;
&lt;p&gt;그런데 마이크로소프트에서 자기들 마음대로 만든 Internet Explorer에서 ES6 사양을 준수하지 않고 있기도 하고요.&lt;/p&gt;
&lt;p&gt;저야 뭐 프론트 개발은 하지 않아서 이런 내용만 알고 있지만 다들 이것 때문에 많이 힘들어 하시죠.&lt;/p&gt;
&lt;p&gt;이런 문제를 바벨이 해력하여 줍니다.&lt;/p&gt;
&lt;p&gt;ES6 사양으로 개발된 JavaScript code를 ES5로 변경하여 줍니다.&lt;/p&gt;
&lt;p&gt;산출물도 JavaScript입니다. :D&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;아주 편하고 좋지만 이것을 사용 할 때 만능은 아니어서 염두에 두기는 하여야 합니다.&lt;/p&gt;
&lt;p&gt;사라져라 윈도우여...&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;마지막으로...&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;제 입장에서는 JavaScript라 불러도 그만이고 ECMAScript라고 불러도 그만인거 같습니다.&lt;/p&gt;
&lt;p&gt;저는 입에 붙은 JavaScript라고 부르는게 더 편하긴 합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그냥 이런 개념이 있다는 정도만 알면 되고 누가 이게 잘못되었다고 표현하는것은 아니라고 생각합니다.&lt;/p&gt;
&lt;p&gt;재밌는건 JavaScript가 먼저 탄생했고 ECMAScript가 이것을 정의하기 위해서 만들어졌는데&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;ECMAScript는 JavaScript를 기반으로 하고, JavaScript 역시 ECMAScript를 기반으로 한다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;입니다.&lt;/p&gt;
&lt;p&gt;뭔소리죠. ㅎㅎㅎ&lt;/p&gt;</description>
      <category>Language/JavaScript</category>
      <category>babel</category>
      <category>ECMAScript</category>
      <category>JavaScript</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/846</guid>
      <comments>https://mrgamza.tistory.com/846#entry846comment</comments>
      <pubDate>Sat, 19 Dec 2020 12:13:58 +0900</pubDate>
    </item>
    <item>
      <title>UIWindowSceneDelegate란 무엇인가? 어떨때 필요한가?</title>
      <link>https://mrgamza.tistory.com/845</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;iOS13에서 Scene이라는 개념과 SceneDelegate가 나오게 되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;iPad에서 사용하는 개념으로 앱을 하나를 띄우고 화면을 여러개 분할해서 사용이 가능해졌죠.&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;그렇죠 일반적으로 iPad Application을 잘 만들지는 않기 때문에 이 부분을 꺼버리거나 다르게 설정을 하고 개발합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저처럼요... ㅎㅎㅎ&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://mrgamza.tistory.com/835&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2020/09/27 - [Mobile/iOS] - iOS13 이상에서 스토리보드 없이 프로젝트 시작하기&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1608342332029&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;iOS13 이상에서 스토리보드 없이 프로젝트 시작하기&quot; data-og-description=&quot;애플에서 Scene을 적용하면서 이렇게 하게 되어 버렸네요. 저는 얼마전까지는 화면이 눈에 잘 보이는 스토리보드를 좋아하였지만 지금은 그냥 화면을 코드에 만들고 있습니다. 이것이 더 코드의 &quot; data-og-host=&quot;mrgamza.tistory.com&quot; data-og-source-url=&quot;https://mrgamza.tistory.com/835&quot; data-og-url=&quot;https://mrgamza.tistory.com/835&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dQyKbt/hyIB7CalyX/7ku4UWiA6Uz1Jj4WK5qlik/img.png?width=800&amp;amp;height=179&amp;amp;face=0_0_800_179,https://scrap.kakaocdn.net/dn/3Zp53/hyIC2lH0cM/yPcFnDGoYy33uctqhc8m21/img.png?width=800&amp;amp;height=179&amp;amp;face=0_0_800_179,https://scrap.kakaocdn.net/dn/cbuO7E/hyICdvCKis/V9zudZ6ZavwNX6uCKkAHfk/img.png?width=1766&amp;amp;height=396&amp;amp;face=0_0_1766_396&quot;&gt;&lt;a href=&quot;https://mrgamza.tistory.com/835&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://mrgamza.tistory.com/835&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dQyKbt/hyIB7CalyX/7ku4UWiA6Uz1Jj4WK5qlik/img.png?width=800&amp;amp;height=179&amp;amp;face=0_0_800_179,https://scrap.kakaocdn.net/dn/3Zp53/hyIC2lH0cM/yPcFnDGoYy33uctqhc8m21/img.png?width=800&amp;amp;height=179&amp;amp;face=0_0_800_179,https://scrap.kakaocdn.net/dn/cbuO7E/hyICdvCKis/V9zudZ6ZavwNX6uCKkAHfk/img.png?width=1766&amp;amp;height=396&amp;amp;face=0_0_1766_396');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;iOS13 이상에서 스토리보드 없이 프로젝트 시작하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;애플에서 Scene을 적용하면서 이렇게 하게 되어 버렸네요. 저는 얼마전까지는 화면이 눈에 잘 보이는 스토리보드를 좋아하였지만 지금은 그냥 화면을 코드에 만들고 있습니다. 이것이 더 코드의&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;mrgamza.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;그렇다면 설정해서 사용하는 방법을 적어보고 이것이 어떻게 동작하는지 알아보도록 하죠.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;일단 저는 xcode 12 버전을 사용하고 있습니다.&lt;/p&gt;
&lt;p&gt;스크린샷이 다를 수 있습니다. 참고해주세요.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;프로젝트 설정에서 Supports multiple windows를 선택하여 줍니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-12-19 오전 10.37.41.png&quot; data-origin-width=&quot;984&quot; data-origin-height=&quot;294&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vBCii/btqQKtRKDjg/loSqQjaSSZQgh0A0ERJtNk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vBCii/btqQKtRKDjg/loSqQjaSSZQgh0A0ERJtNk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vBCii/btqQKtRKDjg/loSqQjaSSZQgh0A0ERJtNk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvBCii%2FbtqQKtRKDjg%2FloSqQjaSSZQgh0A0ERJtNk%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-12-19 오전 10.37.41.png&quot; data-origin-width=&quot;984&quot; data-origin-height=&quot;294&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;바로 옆의 Configure를 눌러주세요.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-12-19 오전 10.38.08.png&quot; data-origin-width=&quot;1488&quot; data-origin-height=&quot;378&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ci75hJ/btqQKu39hD7/WwcfSJhcYtm4IV3bZ2OpKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ci75hJ/btqQKu39hD7/WwcfSJhcYtm4IV3bZ2OpKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ci75hJ/btqQKu39hD7/WwcfSJhcYtm4IV3bZ2OpKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fci75hJ%2FbtqQKu39hD7%2FWwcfSJhcYtm4IV3bZ2OpKK%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-12-19 오전 10.38.08.png&quot; data-origin-width=&quot;1488&quot; data-origin-height=&quot;378&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;저 부분들이 제대로 들어가 있는지 확인하여 주도록 합니다.&lt;/p&gt;
&lt;p&gt;저는 프로젝트에 SceneDelegate가 있고 StoryboardName은 Main으로 설정되어 있습니다.&lt;/p&gt;
&lt;p&gt;프로젝트 설정 기본일거에요. 혹시나 변경되면 변경해주세요.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;UIApplicationDelegate 기반&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;580&quot; data-origin-height=&quot;670&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dsBLgQ/btqQLkAdItg/IIQxm2zRKpZGdS9lIKKgiK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dsBLgQ/btqQLkAdItg/IIQxm2zRKpZGdS9lIKKgiK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dsBLgQ/btqQLkAdItg/IIQxm2zRKpZGdS9lIKKgiK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdsBLgQ%2FbtqQLkAdItg%2FIIQxm2zRKpZGdS9lIKKgiK%2Fimg.png&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;580&quot; data-origin-height=&quot;670&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;iOS 12이하 버전에서는 다음과 같은 상태를 가졌었습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Not Running&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 앱이 실행되지 않은 상태를 의미합니다. 간혹 홈이나 노치 스타일에서 앱을 백그라운드에 넣어두고는 실행중이 아니라고 하는 분들이 있는데 이건 그 상태가 아니라 아예 실행중이지 않은겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Inactive&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 앱이 실행되고 나서 아무 동작을 안하는 상태 didFinishLaunchingWithOptions 상태&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 앱을 실행하다가 앱스위처 같은 상태로 완전히 background에 진입하지 않은 상태 applicationWillResignActive 상태&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Active&lt;/b&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;- 혹은 background, inactive 였다가 foreground에 올라올때의 상태&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- inactive일 경우에는 바로 applicationDidRecomeActive를 가지게 되고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- background일 경우에는 applicationWillEnterForeground를 거치게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Background&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 앱이 background에 있으면서 실행되고 있을 경우&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 대부분은 suspended로 바로 이동하지만 네트워크 사용이나 기타 작업할것이 있을 경우에는 이 상태로 있게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 시스템이&amp;nbsp;임의로&amp;nbsp;Background 상태의 앱을 Suspended 상태로 만든다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- applicationDidEnterBackground 상태가 여기에 해당합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Suspended&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 앱이 background에 있지만 실행되는 코드가 없는 상태&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 메모리가 부족한 상황이 오면 iOS system은 foreground에 있는 앱의 여유 메모리 공간 확보를 위해 이 상태에 있는 앱들을 특별한 알림없이 정리할 수도 있음. Not Running 상태가 됨.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;UIWindowSceneDelegate기반&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;633&quot; height=&quot;NaN&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;580&quot; data-origin-height=&quot;618&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cOPZ0y/btqQLlMFxvI/E5oIH2UP4VQQxNz6jgPLUk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cOPZ0y/btqQLlMFxvI/E5oIH2UP4VQQxNz6jgPLUk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cOPZ0y/btqQLlMFxvI/E5oIH2UP4VQQxNz6jgPLUk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcOPZ0y%2FbtqQLlMFxvI%2FE5oIH2UP4VQQxNz6jgPLUk%2Fimg.png&quot; width=&quot;633&quot; height=&quot;NaN&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;580&quot; data-origin-height=&quot;618&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;13이상의 버전에서는 다음의 상태를 가집니다.&lt;/p&gt;
&lt;p&gt;13버전부터 이렇게 된 이유는 App Switcher에서 복사본을 만들수도 있고 전환도 가능하기 때문입니다.&lt;/p&gt;
&lt;p&gt;App Switcher는 홈버튼 더블클릭하거나 위로 쓸어 올려서 화면에 앱들이 보이는 상태를 이야기 합니다.&lt;/p&gt;
&lt;p&gt;그러면 이것들은 무슨 의미인가 싶기도 하지만 하나의 scene을 사용할 경우에는 동일한 동작을 합니다.&lt;/p&gt;
&lt;p&gt;하지만 여러개일 경우에는 자신 외의 Scene에서는 다른 상태가 될수 있습니다.&lt;/p&gt;
&lt;p&gt;한곳에는 Foreground일 수 있는데 다른것은 Background일수도 있고요...&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Unattached&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- scene이 연결되지 않은 상태&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Not Running이랑 다르기도 합니다. 여러개의 scene을 띄울거라면 다음 scene은 없는 상태니까요... 뭐람 ㅋㅋ&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Foreground Inactive&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- UIApplicationDelegate 기반의 Inactive와 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Foreground Active&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- UIApplicationDelegate 기반의 active와 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Background&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- UIAppliactionDelegate 기반의 background와 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Suspended&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- UIApplicationDelegate 기반의 suspended와 같습니다.&lt;span style=&quot;color: #666666;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기까지는 설명이었고 그렇다면 13이상에서는 scene을 이용하고 싶은데 방법이 없을까 싶은데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 공통된 부분의 실행되어야 하는 부분을 하나의 Helper class로 만들고 그것을 바로 호출해서 사용하는것이 어떨까 싶습니다.&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;두가지 AppDelegate와 SceneDelegate는 iOS의 버전 따라서 자동으로 어느쪽으로 호출해줄지를 결정하기 때문이죠.&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;더 나아가 이것을 각 Scene별로 구분을 하고 싶다면 만들어지는 시간에 대해서 관리해줄수 있도록 Helper class를 만들어주는것도 좋은 방법일거 같습니다.&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;앱이 실행되고 각 Scene별로 관리가 된다고 생각하면 됩니다.&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>Mobile/iOS</category>
      <category>UIApplicationDelegate</category>
      <category>UIWindowSceneDelegate</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/845</guid>
      <comments>https://mrgamza.tistory.com/845#entry845comment</comments>
      <pubDate>Sat, 19 Dec 2020 11:39:08 +0900</pubDate>
    </item>
    <item>
      <title>Noname</title>
      <link>https://mrgamza.tistory.com/844</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;1.gif&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;225&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/P50Ko/btqQE8AOOXv/86eBPwyoxa8aBtEOHH8zT1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/P50Ko/btqQE8AOOXv/86eBPwyoxa8aBtEOHH8zT1/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/P50Ko/btqQE8AOOXv/86eBPwyoxa8aBtEOHH8zT1/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/P50Ko/btqQE8AOOXv/86eBPwyoxa8aBtEOHH8zT1/img.gif&quot; data-filename=&quot;1.gif&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;225&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Any</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/844</guid>
      <comments>https://mrgamza.tistory.com/844#entry844comment</comments>
      <pubDate>Fri, 18 Dec 2020 21:32:54 +0900</pubDate>
    </item>
    <item>
      <title>Chrome 확장 프로그램을 다 보여주기 / 숨기기</title>
      <link>https://mrgamza.tistory.com/843</link>
      <description>&lt;p&gt;현재 20년 12월 2일 기준의 크롬 ( &lt;span&gt;버전 86.0.4240.198(공식 빌드) (64비트)) 저는 이 버전이에요.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;에서는 확장 프로그램을 숨기거나 보여줄수 있도록 되어 있습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그런데 저는 많은 프로그램을 사용하지 않기 때문에 이것을 그냥 다 보여주고 싶은 욕망이 있는데요.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이런걸 선택해서 하나씩 눌러서 선택해줘야 합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;화면 캡처 2020-12-02 122121.png&quot; data-origin-width=&quot;495&quot; data-origin-height=&quot;655&quot; width=&quot;287&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ba9Rb/btqOMo7ndMt/fQfcmim43s2R4R0LaFK8nk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ba9Rb/btqOMo7ndMt/fQfcmim43s2R4R0LaFK8nk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ba9Rb/btqOMo7ndMt/fQfcmim43s2R4R0LaFK8nk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBa9Rb%2FbtqOMo7ndMt%2FfQfcmim43s2R4R0LaFK8nk%2Fimg.png&quot; data-filename=&quot;화면 캡처 2020-12-02 122121.png&quot; data-origin-width=&quot;495&quot; data-origin-height=&quot;655&quot; width=&quot;287&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;저는 이게 좀 불편합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;다 보이게 하는 방법&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;chrome://flags/#extensions-toolbar-menu&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;위의것을 복사해서 주소창에 넣어주세요. (크롬에서 하세요 ㅋㅋ)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그리고 나면 다음과 비슷한 화면이 나올겁니다.&lt;/p&gt;
&lt;p&gt;버전마다 다르니 참고 바랍니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;화면 캡처 2020-12-02 122318.png&quot; data-origin-width=&quot;1165&quot; data-origin-height=&quot;258&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b1zJ9G/btqON8iy5je/hTSUf4V1uvlmuqeEX5WHm1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b1zJ9G/btqON8iy5je/hTSUf4V1uvlmuqeEX5WHm1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b1zJ9G/btqON8iy5je/hTSUf4V1uvlmuqeEX5WHm1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb1zJ9G%2FbtqON8iy5je%2FhTSUf4V1uvlmuqeEX5WHm1%2Fimg.png&quot; data-filename=&quot;화면 캡처 2020-12-02 122318.png&quot; data-origin-width=&quot;1165&quot; data-origin-height=&quot;258&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;디폴트로 아마도 지정이 되어 있을겁니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이 부분을 Disable로 변경하주고 재시작을 하여 줍니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그러면 모든 확장 프로그램이 숨겨지지 않고 보여집니다.&lt;/p&gt;</description>
      <category>Any</category>
      <category>Chrome</category>
      <category>확장프로그램</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/843</guid>
      <comments>https://mrgamza.tistory.com/843#entry843comment</comments>
      <pubDate>Wed, 2 Dec 2020 12:24:41 +0900</pubDate>
    </item>
    <item>
      <title>Go. encoding, decoding, marshaling, unmarshaling</title>
      <link>https://mrgamza.tistory.com/842</link>
      <description>&lt;p&gt;컴퓨터에서 기본적으로 바이트 단위로 데이터를 인식하게 됩니다.&lt;/p&gt;
&lt;p&gt;즉 우리가 인식하는 문자가 아니라 숫자 개념으로 모든것을 가지고 인식을 하게 됩니다.&lt;/p&gt;
&lt;p&gt;00010001 이렇다고 할까요?&lt;/p&gt;
&lt;p&gt;그래서 이것들을 사람들이 알아들을수 있는 개념으로 변경하는것이 &lt;span style=&quot;color: #333333;&quot;&gt;decoding, unmarshaling&lt;/span&gt; 이라고 합니다.&lt;/p&gt;
&lt;p&gt;반대로 사람들이 알아들을수 있는것을 바이트로 변환하는것을 &lt;span style=&quot;color: #333333;&quot;&gt;encoding, marshaling &lt;/span&gt;&amp;nbsp;이라고 합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;golang에서는 이것을 encoding/json 패키지에서 담당을 하게 되는데 이것에 대해서 알아보도록 할게요.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Marshal&lt;/h2&gt;
&lt;p&gt;구조체 같은 형태의 값을 byte 로 변환하는 작업을 합니다.&lt;/p&gt;
&lt;p&gt;json.Marshal에서 이것을 사용 가능합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1605796502514&quot; class=&quot;go&quot; data-ke-language=&quot;go&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;type User struct {
    Name string
    Age  int
}

user := User{&quot;DH&quot;, 100}
bytes, err := json.Marshal(user)

// [123, 111, 122, ...] 예라서 실제 숫자는 아닐거에요.
fmt.Println(bytes)

// {&quot;Name&quot;: &quot;DH&quot;, &quot;Age&quot;: 100}
fmt.Println(string(b))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;type은 다른 형태로 만들수가 있는데요.&lt;/p&gt;
&lt;p&gt;값을 적어주면 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1605796657335&quot; class=&quot;go&quot; data-ke-language=&quot;go&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;type User struct {
    Name    string `json:&quot;-&quot;` // 출력 안됨
    Age     int    `json:&quot;age, string&quot;` // age: 100으로 노출됨
    Address string `json:&quot;omitempty&quot;` // 값이 비면 출력하지 않음.
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이것 말고도 많은것들이 있지만 그런 부분들은 찾아보시기 바랍니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Encoder&lt;/h2&gt;
&lt;p&gt;만약에 짧은 데이터를 사용한다면 상관이 없지만 많은 데이터를 처리할 때는 스트림을 사용하는 것이 좋은 방법입니다.&lt;/p&gt;
&lt;p&gt;사용하게 되면 Marshaling 하는것과 동일하게 처리가 가능합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1605796779393&quot; class=&quot;go&quot; data-ke-language=&quot;go&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;type User struct {
    Name string
    Age  int
}

user := User{&quot;DH&quot;, 100}
err := json.NewEncoder(os.Stdout).Encode(user) // 표준입력을 넣어줍니다.
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Unmarshal&lt;/h2&gt;
&lt;p&gt;byte로 만들어진 부분을 struct로 만들어주는 역할을 합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1605797069925&quot; class=&quot;go&quot; data-ke-language=&quot;go&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var user User
err := json.Unmarshal(response.Body, &amp;amp;user)
// json으로 들어가 있던 byte 값들이 User에 채워지게 됩니다.
fmt.Printf(&quot;%+v\n&quot;, user)&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Decoder&lt;/h2&gt;
&lt;p&gt;이것도 마찬가지로 Unmarshal data를 stream으로 처리하는것입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1605797294787&quot; class=&quot;go&quot; data-ke-language=&quot;go&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;var user User
err := json.NewDecoder(response).Decode(user) // response는 network의 *http.Response입니다.
// json으로 들어가 있던 byte 값들이 User에 채워지게 됩니다.
fmt.Printf(&quot;%+v\n&quot;, user)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;response부분은 encoder와 마찬가지로 표준 입력을 넣어주면 됩니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;정리&lt;/h2&gt;
&lt;p&gt;Marshal, Encoder는 Value type을 byte로 변환&lt;/p&gt;
&lt;p&gt;UnMarshal, Decoder는 byte를 Valut type으로 변환하여 줍니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그러면 Marshal, UnMarshal / Encoder, Decoder의 차이는?&lt;/p&gt;
&lt;p&gt;표준 입력출력이 가능하고 자료량이 많은때는 Encoder, Decoder를 이용합니다.&lt;/p&gt;
&lt;p&gt;이것은 이점이 있는데 50%정도의 빠른 성능을 보여준다고 합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그리고 그것이 아닐때는 Marshal, Unmarshal합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Golang는 정말 쉬운거 같습니다.&lt;/p&gt;</description>
      <category>Language/Go</category>
      <category>Decoder</category>
      <category>Encoder</category>
      <category>go</category>
      <category>golang</category>
      <category>Marshal</category>
      <category>Stream</category>
      <category>Unmarshal</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/842</guid>
      <comments>https://mrgamza.tistory.com/842#entry842comment</comments>
      <pubDate>Thu, 19 Nov 2020 23:54:53 +0900</pubDate>
    </item>
    <item>
      <title>RIBs를 이용한 개발 - 4. NextPage</title>
      <link>https://mrgamza.tistory.com/841</link>
      <description>&lt;p&gt;이전 시간까지는 MainViewController를 화면에 표현하여 주고 Button Action을 받아올수 있도록 만들었습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://mrgamza.tistory.com/840&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2020/10/04 - [Mobile/iOS] - RIBs를 이용한 개발 - 3. Main RIBs&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1601739790253&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;RIBs를 이용한 개발 - 3. Main RIBs&quot; data-og-description=&quot;이전까지 하게 되면 빌드는 되지만 검은 화면이 나오는 프로젝트를 만들게 될겁니다. 그러면 이제 하나씩 만들어 보도록 할게요. 이전글 2020/10/03 - [Mobile/iOS] - RIBs를 이용한 개발 - 2. RIBs Setting. RI&quot; data-og-host=&quot;mrgamza.tistory.com&quot; data-og-source-url=&quot;https://mrgamza.tistory.com/840&quot; data-og-url=&quot;https://mrgamza.tistory.com/840&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/K2IEq/hyHHQoabJ1/q8ccl5BYOroKHJzj7VbYk0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bI50W0/hyHHAS9W3k/ludOXfE6neaAk8ZleU7ed1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800&quot;&gt;&lt;a href=&quot;https://mrgamza.tistory.com/840&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://mrgamza.tistory.com/840&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/K2IEq/hyHHQoabJ1/q8ccl5BYOroKHJzj7VbYk0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bI50W0/hyHHAS9W3k/ludOXfE6neaAk8ZleU7ed1/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;&gt;RIBs를 이용한 개발 - 3. Main RIBs&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;이전까지 하게 되면 빌드는 되지만 검은 화면이 나오는 프로젝트를 만들게 될겁니다. 그러면 이제 하나씩 만들어 보도록 할게요. 이전글 2020/10/03 - [Mobile/iOS] - RIBs를 이용한 개발 - 2. RIBs Setting. RI&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;mrgamza.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;이번에는 만들어진 이것을 이용하여서 Click을 하게 되면 ViewController를 present하고 Component를 전달하도록 하겠습니다.&lt;span style=&quot;font-size: 1.44em;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-size: 1.44em;&quot;&gt;MainRIB를 고칩니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;MainViewController&lt;/h4&gt;
&lt;p&gt;아래의 두가지 부분을 이렇게 고쳐줍시다.&lt;/p&gt;
&lt;pre id=&quot;code_1601741049960&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// MARK: - ViewControllable

protocol MainViewControllable: ViewControllable {
    func present(_ viewController: ViewControllable, animated: Bool)
    func dismiss(_ viewController: ViewControllable, animated: Bool)
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1601741069691&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;extension MainViewController: MainViewControllable {
    func present(_ viewController: ViewControllable, animated: Bool) {
        present(viewController.uiviewController, animated: animated)
    }
    
    func dismiss(_ viewController: ViewControllable, animated: Bool) {
        guard !viewController.uiviewController.isBeingDismissed else { return }
        viewController.uiviewController.dismiss(animated: animated)
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;MainInteractor&lt;/h4&gt;
&lt;p&gt;이곳은 이전글에서 만든 function 이름이 마음에 안들어서 수정한 부분도 있으니 이것도 수정합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1601741154116&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// MARK: - Listener

protocol MainListener: class {
    
}

// MARK: - Routing

protocol MainRouting: ViewableRouting {
    func attachNext()
    func detachNext()
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1601741193027&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// MARK: - Interactor

final class MainInteractor: PresentableInteractor&amp;lt;MainPresentable&amp;gt;,
                            MainInteractable {
    private let buttonTextRelay: BehaviorRelay&amp;lt;String&amp;gt;
    
    var router: MainRouting?
    var listener: MainListener?
  
    init(title: String,
         presenter: MainPresentable) {
        buttonTextRelay = .init(value: title)
        super.init(presenter: presenter)
        presenter.handler = self
    }
    
    override func didBecomeActive() {
        super.didBecomeActive()
        setup()
    }
    
    private func setup() {
        guard let action = presenter.action else { return }
        action.didClickButton
            .bind { [weak self] in
                self?.router?.attachNext()
            }
            .disposeOnDeactivate(interactor: self)
    }
}

extension MainInteractor: MainPresentableHandler {
    var buttonText: Observable&amp;lt;String&amp;gt; {
        return buttonTextRelay.asObservable()
    }
}

extension MainInteractor: MainListener {
    func detachNext() {
        router?.detachNext()
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;MainRouter&lt;/h4&gt;
&lt;p&gt;라우터도 수정을 하여 주어야 하는데요.&lt;/p&gt;
&lt;p&gt;NextBuilder를 가지고 사용하는 방법으로 만들어 줍니다.&lt;/p&gt;
&lt;pre id=&quot;code_1601948679727&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import RIBs

final class MainRouter: LaunchRouter&amp;lt;MainInteractable, MainViewControllable&amp;gt; {
    
    private let nextBuilder: NextBuilable
    private var nextRouter: NextRouting?
    
    init(nextBuilder: NextBuilable,
         interactor: MainInteractable,
         viewController: MainViewControllable) {
        self.nextBuilder = nextBuilder
        self.nextRouter = nil
        super.init(interactor: interactor, viewController: viewController)
        interactor.router = self
    }
}

extension MainRouter: MainRouting {
    func attachNext() {
        let time = &quot;Now is \(Date().description)&quot;
        let router = nextBuilder.build(with: interactor, title: time)
        nextRouter = router
        attachChild(router)
        viewController.present(router.viewControllable, animated: true)
    }
    
    func detachNext() {
        guard let router = nextRouter else { return }
        viewController.dismiss(router.viewControllable, animated: true)
        nextRouter = nil
        detachChild(router)
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;MainBuilder&lt;/h4&gt;
&lt;p&gt;이곳에서 Builder를 이용하여서 Router를 만들어 주도록 할게요&lt;/p&gt;
&lt;pre id=&quot;code_1601948748171&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import RIBs

// MARK: - Component

protocol MainDependency: Dependency {}

final class MainComponent: Component&amp;lt;MainDependency&amp;gt;, NextDependency {
    var title: String = &quot;&quot;
}

// MARK: - Builder

protocol MainBuilable: Buildable {
    func build() -&amp;gt; LaunchRouting
}

final class MainBuilder: Builder&amp;lt;MainDependency&amp;gt;, MainBuilable {

    func build() -&amp;gt; LaunchRouting {
        let component = MainComponent(dependency: dependency)
        let viewController = MainViewController()
        let interactor = MainInteractor(title: &quot;Hello, RIBs\nClick Button!&quot;,
                                        presenter: viewController)
        
        let nextBuilder = NextBuilder(dependency: component)
        
        return MainRouter(nextBuilder: nextBuilder,
                          interactor: interactor,
                          viewController: viewController)
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Group을 만들어 줍시다.&lt;/h3&gt;
&lt;p&gt;저는 NextRIB를 만들었는데 자신의 상황에 맞도록 만들어 주세요.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;508&quot; height=&quot;NaN&quot; data-filename=&quot;스크린샷 2020-10-04 오전 12.46.35.png&quot; data-origin-width=&quot;788&quot; data-origin-height=&quot;610&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zrlUF/btqJ4GDv8Co/TKzKglYKBUeW8arTgnoBN0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zrlUF/btqJ4GDv8Co/TKzKglYKBUeW8arTgnoBN0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zrlUF/btqJ4GDv8Co/TKzKglYKBUeW8arTgnoBN0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzrlUF%2FbtqJ4GDv8Co%2FTKzKglYKBUeW8arTgnoBN0%2Fimg.png&quot; width=&quot;508&quot; height=&quot;NaN&quot; data-filename=&quot;스크린샷 2020-10-04 오전 12.46.35.png&quot; data-origin-width=&quot;788&quot; data-origin-height=&quot;610&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;NextViewController&lt;/h4&gt;
&lt;p&gt;이전의 MainViewController와 거의 흡사합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1601741379498&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import RIBs
import SnapKit
import RxSwift
import RxCocoa

// MARK: - Presenter

protocol NextPresentableAction: class {
    var didClickButton: Observable&amp;lt;Void&amp;gt; { get }
}

protocol NextPresentableHandler: class {
    var timeText: Observable&amp;lt;String&amp;gt; { get }
}

protocol NextPresentable: Presentable {
    var action: NextPresentableAction? { get set }
    var handler: NextPresentableHandler? { get set }
}

// MARK: - ViewControllable

protocol NextViewControllable: ViewControllable {
    
}

// MARK: - ViewController

final class NextViewController: UIViewController, NextPresentable {
    
    // MARK: - UI Components
    
    private lazy var button: UIButton = {
        let button = UIButton(type: .system)
        button.setTitleColor(.blue, for: .normal)
        button.titleLabel?.numberOfLines = 1
        button.titleLabel?.textAlignment = .center
        button.setTitle(&quot;Close&quot;, for: .normal)
        return button
    }()
    
    private lazy var label: UILabel = {
        let label = UILabel()
        label.textColor = .black
        label.numberOfLines = 0
        return label
    }()
    
    // MARK: - Properties
    
    private let disposeBag = DisposeBag()
    
    // MARK: - Presentable
    
    var action: NextPresentableAction?
    var handler: NextPresentableHandler?
    
    init() {
        super.init(nibName: nil, bundle: nil)
        action = self
    }
    
    required init?(coder: NSCoder) {
        fatalError(&quot;init(coder:) has not been implemented&quot;)
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        setupView()
        bindPresentable()
    }
    
    private func setupView() {
        view.backgroundColor = .white
        view.addSubview(button)
        button.snp.makeConstraints { maker in
            maker.center.equalToSuperview()
        }
        
        view.addSubview(label)
        label.snp.makeConstraints { maker in
            maker.centerX.equalToSuperview()
            maker.bottom.equalTo(button.snp.top).offset(-30)
        }
    }
    
    private func bindPresentable() {
        guard let handler = handler else { return }
        handler.timeText
            .bind(to: label.rx.text)
            .disposed(by: disposeBag)
    }
}

extension NextViewController: NextPresentableAction {
    var didClickButton: Observable&amp;lt;Void&amp;gt; {
        return button.rx.tap.asObservable()
    }
}

extension NextViewController: NextViewControllable {
    
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;NextInteractor&lt;/h4&gt;
&lt;p&gt;Main과 다른점은 listener를 통해서 detachNext를 호출하는 것이 다릅니다.&lt;/p&gt;
&lt;pre id=&quot;code_1601741921142&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import RIBs
import RxSwift
import RxCocoa

// MARK: - Listener

protocol NextListener: class {
    func detachNext()
}

// MARK: - Routing

protocol NextRouting: ViewableRouting {
    
}

// MARK: - Interactable

protocol NextInteractable: Interactable {
    var router: NextRouting? { get set }
    var listener: NextListener? { get set }
}

// MARK: - Interactor

final class NextInteractor: PresentableInteractor&amp;lt;NextPresentable&amp;gt;,
                            NextInteractable {
    private let timeTextRelay: BehaviorRelay&amp;lt;String&amp;gt;
    
    var router: NextRouting?
    var listener: NextListener?
  
    init(component: NextComponent,
         presenter: NextPresentable) {
        timeTextRelay = .init(value: component.dependency.title)
        super.init(presenter: presenter)
        presenter.handler = self
    }
    
    override func didBecomeActive() {
        super.didBecomeActive()
        setup()
    }
    
    private func setup() {
        presenter.action?.didClickButton
            .bind { [weak self] in
                self?.listener?.detachNext()
            }
            .disposeOnDeactivate(interactor: self)
    }
}

extension NextInteractor: NextPresentableHandler {
    var timeText: Observable&amp;lt;String&amp;gt; {
        return timeTextRelay.asObservable()
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;NextRouter&lt;/h4&gt;
&lt;p&gt;다음 화면 정의같은 부분들이 없어서 별다른 동작이 없습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1601742750415&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import RIBs

final class NextRouter: ViewableRouter&amp;lt;NextInteractable, NextViewControllable&amp;gt; {
    override init(interactor: NextInteractable,
                  viewController: NextViewControllable) {
        super.init(interactor: interactor, viewController: viewController)
        interactor.router = self
    }
}

extension NextRouter: NextRouting {
    
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;NextBuilder&lt;/h4&gt;
&lt;pre id=&quot;code_1601742818017&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import RIBs

// MARK: - Component

protocol NextDependency: Dependency {
    var title: String { get set }
}

final class NextComponent: Component&amp;lt;NextDependency&amp;gt; {
    
}

// MARK: - Builder

protocol NextBuilable: Buildable {
    func build(with listener: NextListener, title: String) -&amp;gt; NextRouting
}

final class NextBuilder: Builder&amp;lt;NextDependency&amp;gt;, NextBuilable {

    func build(with listener: NextListener, title: String) -&amp;gt; NextRouting {
        dependency.title = title
        let component = NextComponent(dependency: dependency)
        let viewController = NextViewController()
        let interactor = NextInteractor(component: component,
                                        presenter: viewController)
        interactor.listener = listener
        
        return NextRouter(interactor: interactor, viewController: viewController)
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;다른분들과 특이하게 만들어진 부분은 NextBuilder를 build할때 title을 받아서 이전 MainRIB에서 전달하는 값을 dependency로 전달하여서 사용하도록 하였습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;종합?&lt;/h3&gt;
&lt;p&gt;저는 MVVM을 하기 때문에 다소 불편한 부분이 많습니다.&lt;/p&gt;
&lt;p&gt;결론은 저는 아마도 쓰지 않을거 같긴 합니다만&lt;/p&gt;
&lt;p&gt;하지만 이정도만 알아둬도 나중에 이 패턴을 이용하여서 더 좋은 패턴을 만들수 있지 않을까요?&lt;/p&gt;
&lt;p&gt;Dependency 부분을 어떻게 해야지 주입하기 좋을까에 대한 부분은 조금 생각을 해봐야할거 같습니다.&lt;/p&gt;
&lt;p&gt;protocol에 set까지 같이 주면 외부에서 값이 변경이 되기 때문에 좋지 않은것 같기 때문이죠.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;소스는 git에 올려두었습니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/outofcode-example/iOS-RIBsExample/tree/NextPage&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;github.com/outofcode-example/iOS-RIBsExample/tree/NextPage&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Mobile/iOS</category>
      <category>ribs</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/841</guid>
      <comments>https://mrgamza.tistory.com/841#entry841comment</comments>
      <pubDate>Tue, 6 Oct 2020 10:57:42 +0900</pubDate>
    </item>
    <item>
      <title>RIBs를 이용한 개발 - 3. Main RIBs</title>
      <link>https://mrgamza.tistory.com/840</link>
      <description>&lt;p&gt;이전까지 하게 되면 빌드는 되지만 검은 화면이 나오는 프로젝트를 만들게 될겁니다.&lt;/p&gt;
&lt;p&gt;그러면 이제 하나씩 만들어 보도록 할게요.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이전글&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://mrgamza.tistory.com/839&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2020/10/03 - [Mobile/iOS] - RIBs를 이용한 개발 - 2. RIBs Setting.&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1601697459488&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;RIBs를 이용한 개발 - 2. RIBs Setting.&quot; data-og-description=&quot;이전 글에서 RIBs가 무엇인지에 대해서 알아보았습니다. 2020/10/03 - [Mobile/iOS] - RIBs를 이용한 개발 - 1. RIBs란? RIBs를 이용한 개발 - 1. RIBs란? 저는 Rx를 이용한 MVVM을 기본으로 개발합니다. 이것도..&quot; data-og-host=&quot;mrgamza.tistory.com&quot; data-og-source-url=&quot;https://mrgamza.tistory.com/839&quot; data-og-url=&quot;https://mrgamza.tistory.com/839&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bcj1KD/hyHJCVLXJb/5CKhVyrdckHc8gmxrmIgc1/img.png?width=564&amp;amp;height=842&amp;amp;face=0_0_564_842,https://scrap.kakaocdn.net/dn/kSmER/hyHHCb3tim/Emg4PEMtRa6S7nEcKo1P60/img.png?width=564&amp;amp;height=842&amp;amp;face=0_0_564_842,https://scrap.kakaocdn.net/dn/cOBlKW/hyHHIcfuWo/CCxgTi69ZNXhWwwngYLk0k/img.png?width=564&amp;amp;height=842&amp;amp;face=0_0_564_842&quot;&gt;&lt;a href=&quot;https://mrgamza.tistory.com/839&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://mrgamza.tistory.com/839&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bcj1KD/hyHJCVLXJb/5CKhVyrdckHc8gmxrmIgc1/img.png?width=564&amp;amp;height=842&amp;amp;face=0_0_564_842,https://scrap.kakaocdn.net/dn/kSmER/hyHHCb3tim/Emg4PEMtRa6S7nEcKo1P60/img.png?width=564&amp;amp;height=842&amp;amp;face=0_0_564_842,https://scrap.kakaocdn.net/dn/cOBlKW/hyHHIcfuWo/CCxgTi69ZNXhWwwngYLk0k/img.png?width=564&amp;amp;height=842&amp;amp;face=0_0_564_842');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;RIBs를 이용한 개발 - 2. RIBs Setting.&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;이전 글에서 RIBs가 무엇인지에 대해서 알아보았습니다. 2020/10/03 - [Mobile/iOS] - RIBs를 이용한 개발 - 1. RIBs란? RIBs를 이용한 개발 - 1. RIBs란? 저는 Rx를 이용한 MVVM을 기본으로 개발합니다. 이것도..&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;mrgamza.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Sources &amp;gt; Scene &amp;gt; MainRIB 만들기&lt;/h3&gt;
&lt;p&gt;프로젝트 Group을 만들어주세요&lt;/p&gt;
&lt;p&gt;순서를 지키지 않아도 되지만 순서대로 만드는게 편안하게 만드는 방법입니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;MainViewController&lt;/h4&gt;
&lt;p&gt;Presenter에 사용되는 protocol과 ViewController를 정의합니다.&lt;/p&gt;
&lt;p&gt;MVVM에 익숙하신 분들이라면 Action은 Input과 같고 Handler는 Output과 같습니다.&lt;/p&gt;
&lt;p&gt;즉, Action은 다른곳에 전달하는 용도이고 Handler는 ViewController에서 처리하여 주어야 하는 부분입니다.&lt;/p&gt;
&lt;p&gt;Router에서 화면 전환등에 사용 하게 될 ViewControllable도 정의 하여 줍니다.&lt;/p&gt;
&lt;pre id=&quot;code_1601738058391&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import RIBs
import SnapKit
import RxSwift
import RxCocoa

// MARK: - Presenter

protocol MainPresentableAction: class {
    var didClickButton: Observable&amp;lt;Void&amp;gt; { get }
}

protocol MainPresentableHandler: class {
    var buttonText: Observable&amp;lt;String&amp;gt; { get }
}

protocol MainPresentable: Presentable {
    var action: MainPresentableAction? { get set }
    var handler: MainPresentableHandler? { get set }
}

// MARK: - ViewControllable

protocol MainViewControllable: ViewControllable {
    func present(_ viewController: ViewControllable, animated: Bool)
}

// MARK: - ViewController

final class MainViewController: UIViewController, MainPresentable {
    
    // MARK: - UI Components
    
    private lazy var button: UIButton = {
        let button = UIButton()
        button.titleLabel?.numberOfLines = 0
        button.titleLabel?.textAlignment = .center
        return button
    }()
    
    // MARK: - Properties
    
    private let disposeBag = DisposeBag()
    
    // MARK: - Presentable
    
    var action: MainPresentableAction?
    var handler: MainPresentableHandler?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        setupView()
        bindPresentable()
    }
    
    private func setupView() {
        view.addSubview(button)
        button.snp.makeConstraints { maker in
            maker.center.equalToSuperview()
        }
    }
    
    private func bindPresentable() {
        action = self
        
        guard let handler = handler else { return }
        handler.buttonText
            .bind(to: button.rx.title(for: .normal))
            .disposed(by: disposeBag)
    }
}

extension MainViewController: MainPresentableAction {
    var didClickButton: Observable&amp;lt;Void&amp;gt; {
        return button.rx.tap.asObservable()
    }
}

extension MainViewController: MainViewControllable {
    func present(_ viewController: ViewControllable, animated: Bool) {
        print(&quot;present need&quot;)
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;MainInteractor&lt;/h4&gt;
&lt;p&gt;Router와 Presenter를 연결하는 역할을 하기 때문에 Routing 관련된 protocol과 Interractable에 대한 code를 넣어줍니다.&lt;/p&gt;
&lt;pre id=&quot;code_1601738605492&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import RIBs
import RxSwift
import RxCocoa

// MARK: - Routing

protocol MainRouting: ViewableRouting {
    func presentNext()
}

// MARK: - Interactable

protocol MainInteractable: Interactable {
    var router: MainRouting? { get set }
}

// MARK: - Interactor

final class MainInteractor: PresentableInteractor&amp;lt;MainPresentable&amp;gt;,
                            MainInteractable {
    private let buttonTextRelay: BehaviorRelay&amp;lt;String&amp;gt;
    
    weak var router: MainRouting?
  
    init(buttonText: String,
         presenter: MainPresentable) {
        buttonTextRelay = .init(value: buttonText)
        super.init(presenter: presenter)
        presenter.handler = self
    }
    
    override func didBecomeActive() {
        super.didBecomeActive()
        setup()
    }
    
    private func setup() {
        presenter.action?.didClickButton
            .bind { [weak self] in
                self?.router?.presentNext()
            }
            .disposeOnDeactivate(interactor: self)
    }
}

extension MainInteractor: MainPresentableHandler {
    var buttonText: Observable&amp;lt;String&amp;gt; {
        return buttonTextRelay.asObservable()
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;MainRouter&lt;/h4&gt;
&lt;p&gt;Interactor에서 받은 신호를 통해서 viewController에 바로 정보를 전달하도록 만들어 줍니다.&lt;/p&gt;
&lt;pre id=&quot;code_1601738737521&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import RIBs

final class MainRouter: LaunchRouter&amp;lt;MainInteractable, MainViewControllable&amp;gt; {
    override init(interactor: MainInteractable,
                  viewController: MainViewControllable) {
        super.init(interactor: interactor, viewController: viewController)
        interactor.router = self
    }
}

extension MainRouter: MainRouting {
    func presentNext() {
        print(&quot;show&quot;)
        // 나중에 여기에 present를 채울겁니다.
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;MainBuilder&lt;/h4&gt;
&lt;p&gt;외부에서 주입받는 Dependency를 넣어주고 이것을 통해서 View, Interactor, Router를 만들어주는 역할을 합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1601738822661&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import RIBs

// MARK: - Component

protocol MainDependency: Dependency {
    var buttonText: String { get }
}

final class MainComponent: MainDependency {
    var buttonText: String { &quot;Hello, RIBs\nClick Button!&quot; }
}

final class MainComponentTest: MainDependency {
    var buttonText: String { &quot;Test&quot; }
}

// MARK: - Builder

protocol MainBuilable: Buildable {
    func build() -&amp;gt; LaunchRouting
}

final class MainBuilder: Builder&amp;lt;MainDependency&amp;gt;, MainBuilable {
    
    init() {
        super.init(dependency: MainComponent())
    }
    
    func build() -&amp;gt; LaunchRouting {
        let viewController = MainViewController()

        let interactor = MainInteractor(buttonText: dependency.buttonText,
                                        presenter: viewController)
        
        return MainRouter(interactor: interactor,
                          viewController: viewController)
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이렇게 하면 정상적으로 화면에 Button이 하나 나오고&lt;/p&gt;
&lt;p&gt;Hello, RIBs&lt;/p&gt;
&lt;p&gt;Click Button!&lt;/p&gt;
&lt;p&gt;이렇게 노출되고 클릭을 하면 click이 나오게 될겁니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;AppDelegate&lt;/h4&gt;
&lt;p&gt;이것을 추가한다는것을 잊고 있었습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1601739936239&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import UIKit
import RIBs

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    
    var window: UIWindow? = UIWindow(frame: UIScreen.main.bounds)
    
    lazy var launchRouter: LaunchRouting = MainBuilder().build()

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -&amp;gt; Bool {
        launchRouter.launch(from: window!)
        return true
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;소스는 올려두었는데 tag로 구분하여 두었으니 확인해보세요&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/outofcode-example/iOS-RIBsExample/tree/OnlyMain&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;github.com/outofcode-example/iOS-RIBsExample/tree/OnlyMain&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1601739703298&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;object&quot; data-og-title=&quot;outofcode-example/iOS-RIBsExample&quot; data-og-description=&quot;uber RIBs example. Contribute to outofcode-example/iOS-RIBsExample development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/outofcode-example/iOS-RIBsExample/tree/OnlyMain&quot; data-og-url=&quot;https://github.com/outofcode-example/iOS-RIBsExample&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bJpmAu/hyHJx8myyo/kVkYwKFWxSLp3rp5RE9TiK/img.png?width=400&amp;amp;height=400&amp;amp;face=75_87_272_204&quot;&gt;&lt;a href=&quot;https://github.com/outofcode-example/iOS-RIBsExample/tree/OnlyMain&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/outofcode-example/iOS-RIBsExample/tree/OnlyMain&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bJpmAu/hyHJx8myyo/kVkYwKFWxSLp3rp5RE9TiK/img.png?width=400&amp;amp;height=400&amp;amp;face=75_87_272_204');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;outofcode-example/iOS-RIBsExample&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;uber RIBs example. Contribute to outofcode-example/iOS-RIBsExample development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Mobile/iOS</category>
      <category>OnlyMain</category>
      <category>ribs</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/840</guid>
      <comments>https://mrgamza.tistory.com/840#entry840comment</comments>
      <pubDate>Sun, 4 Oct 2020 00:41:57 +0900</pubDate>
    </item>
    <item>
      <title>RIBs를 이용한 개발 - 2. RIBs Setting.</title>
      <link>https://mrgamza.tistory.com/839</link>
      <description>&lt;p&gt;이전 글에서 RIBs가 무엇인지에 대해서 알아보았습니다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://mrgamza.tistory.com/838&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;2020/10/03 - [Mobile/iOS] - RIBs를 이용한 개발 - 1. RIBs란?&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1601695233319&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;RIBs를 이용한 개발 - 1. RIBs란?&quot; data-og-description=&quot;저는 Rx를 이용한 MVVM을 기본으로 개발합니다. 이것도 뭐 회사마다 기존에 적용되어 있는 부분이랑 크게 다르지 않도록 하여 주기 때문에 확실한 MVVM이라고 할 수도 없습니다. MVC로 되어 있는 구�&quot; data-og-host=&quot;mrgamza.tistory.com&quot; data-og-source-url=&quot;https://mrgamza.tistory.com/838&quot; data-og-url=&quot;https://mrgamza.tistory.com/838&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bputz1/hyHJt5zPN9/7oYOR3gvyyJ9vvJu5ILz81/img.png?width=800&amp;amp;height=301&amp;amp;face=0_0_800_301,https://scrap.kakaocdn.net/dn/bSdvFb/hyHHPPV6SF/HVjVt1IcB8HhYc9VNl4LC1/img.png?width=800&amp;amp;height=301&amp;amp;face=0_0_800_301,https://scrap.kakaocdn.net/dn/br8zx8/hyHJzSggwE/oMoWnKKO5BsFvccJBtSj1k/img.png?width=2288&amp;amp;height=863&amp;amp;face=0_0_2288_863&quot;&gt;&lt;a href=&quot;https://mrgamza.tistory.com/838&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://mrgamza.tistory.com/838&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bputz1/hyHJt5zPN9/7oYOR3gvyyJ9vvJu5ILz81/img.png?width=800&amp;amp;height=301&amp;amp;face=0_0_800_301,https://scrap.kakaocdn.net/dn/bSdvFb/hyHHPPV6SF/HVjVt1IcB8HhYc9VNl4LC1/img.png?width=800&amp;amp;height=301&amp;amp;face=0_0_800_301,https://scrap.kakaocdn.net/dn/br8zx8/hyHJzSggwE/oMoWnKKO5BsFvccJBtSj1k/img.png?width=2288&amp;amp;height=863&amp;amp;face=0_0_2288_863');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;RIBs를 이용한 개발 - 1. RIBs란?&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;저는 Rx를 이용한 MVVM을 기본으로 개발합니다. 이것도 뭐 회사마다 기존에 적용되어 있는 부분이랑 크게 다르지 않도록 하여 주기 때문에 확실한 MVVM이라고 할 수도 없습니다. MVC로 되어 있는 구�&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;mrgamza.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;그러면 RIBs를 세팅하는 방법에 대해서 알아보도록 하겠습니다.&lt;/p&gt;
&lt;p&gt;아마도 굉장히 짧은 글이 될거 같습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;세팅하는 부분과 이것을 이용하여서 RIB를 만드는 방법까지 글을 적어볼까 합니다.&lt;/p&gt;
&lt;p&gt;나머지는 여러분들의 몫 :D&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;RIBs는 Uber의 pods를 이용하는 방법을 사용하도록 할게요&lt;/p&gt;
&lt;pre id=&quot;code_1601695402957&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ pod init&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이렇게하면 Podfile이 생성되게 됩니다.&lt;/p&gt;
&lt;p&gt;이 파일안에 다음을 추가합시다.&lt;/p&gt;
&lt;pre id=&quot;code_1601695654999&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ open -e Podfile&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;편집창이 나오면 다음의 내용을 넣고 저장하여 주세요&lt;/p&gt;
&lt;pre id=&quot;code_1601695638972&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;platform :ios, '9.0'
use_frameworks!

target 'RIBsExample' do
  pod 'RIBs', :git =&amp;gt; 'https://github.com/uber/RIBs.git', :branch =&amp;gt; 'master'
  pod 'RxCocoa'
  pod 'SnapKit'
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;다시 command 창에서 다음을 하여 줍니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1601695929740&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ pod install&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;다 설치가 되면 프로젝트를 열어주면 됩니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;저는 Storyboard 프로젝트로 생성을 하였고 이렇게 하는것이 더 편한것 같습니다.&lt;/p&gt;
&lt;p&gt;iOS13부터 나온 SwiftUI가 좋기는 하지만 아직까지는 전부 이식하기에는 어려움이 있죠.&lt;/p&gt;
&lt;p&gt;그리고 저의 xcode는 12버전이므로 제가 설명한 부분이 없는 부분은 그냥 skip 하셔도 됩니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;프로젝트 내부에 대해서는 다음과 같이 세팅합니다&lt;/p&gt;
&lt;p&gt;저는 기본적으노 Sources, Resources를 두고 그 아래에 파일들을 배치합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-10-03 오후 12.42.22.png&quot; data-origin-width=&quot;564&quot; data-origin-height=&quot;842&quot; width=&quot;391&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c3Dp6s/btqJ4GDcsfQ/rVdphgVcmpNXF3IqKQBT11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c3Dp6s/btqJ4GDcsfQ/rVdphgVcmpNXF3IqKQBT11/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c3Dp6s/btqJ4GDcsfQ/rVdphgVcmpNXF3IqKQBT11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc3Dp6s%2FbtqJ4GDcsfQ%2FrVdphgVcmpNXF3IqKQBT11%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-10-03 오후 12.42.22.png&quot; data-origin-width=&quot;564&quot; data-origin-height=&quot;842&quot; width=&quot;391&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Deployment Info의 버전은 9.0 ( 이건 개인 취향따라 하세요.) Main Interface는 비워주세요&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-10-03 오후 12.40.28.png&quot; data-origin-width=&quot;924&quot; data-origin-height=&quot;328&quot; width=&quot;598&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cxgdGl/btqJZnEHj8h/zxGQWziCSC7q1aTQwKgjO1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cxgdGl/btqJZnEHj8h/zxGQWziCSC7q1aTQwKgjO1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cxgdGl/btqJZnEHj8h/zxGQWziCSC7q1aTQwKgjO1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcxgdGl%2FbtqJZnEHj8h%2FzxGQWziCSC7q1aTQwKgjO1%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-10-03 오후 12.40.28.png&quot; data-origin-width=&quot;924&quot; data-origin-height=&quot;328&quot; width=&quot;598&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;Project setting &amp;gt; Info 파일에 있는 Application Scene Manifest를 삭제합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-10-03 오후 12.40.03.png&quot; data-origin-width=&quot;1016&quot; data-origin-height=&quot;176&quot; width=&quot;618&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lUoO3/btqJ3iJlXp5/uCq1u1rKm47rkt4TTw0dV1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lUoO3/btqJ3iJlXp5/uCq1u1rKm47rkt4TTw0dV1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lUoO3/btqJ3iJlXp5/uCq1u1rKm47rkt4TTw0dV1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlUoO3%2FbtqJ3iJlXp5%2FuCq1u1rKm47rkt4TTw0dV1%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-10-03 오후 12.40.03.png&quot; data-origin-width=&quot;1016&quot; data-origin-height=&quot;176&quot; width=&quot;618&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;AppDelegate 파일을 수정할게요&lt;/p&gt;
&lt;pre id=&quot;code_1601696939420&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//
//  AppDelegate.swift
//  RIBsExample
//
//  Created by outofcode on 2020/10/03.
//

import UIKit

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -&amp;gt; Bool {
        // Override point for customization after application launch.
        return true
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Mobile/iOS</category>
      <category>ribs</category>
      <category>Setting</category>
      <category>Uber</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/839</guid>
      <comments>https://mrgamza.tistory.com/839#entry839comment</comments>
      <pubDate>Sat, 3 Oct 2020 12:49:19 +0900</pubDate>
    </item>
    <item>
      <title>RIBs를 이용한 개발 - 1. RIBs란?</title>
      <link>https://mrgamza.tistory.com/838</link>
      <description>&lt;p&gt;저는 Rx를 이용한 MVVM을 기본으로 개발합니다.&lt;/p&gt;
&lt;p&gt;이것도 뭐 회사마다 기존에 적용되어 있는 부분이랑 크게 다르지 않도록 하여 주기 때문에 확실한 MVVM이라고 할 수도 없습니다.&lt;/p&gt;
&lt;p&gt;MVC로 되어 있는 구조를 나혼자 MVVM으로 바꾸기도 어렵고 전체 시스템을 다 변경하는것은 더 말이 안되기 때문입니다.&lt;/p&gt;
&lt;p&gt;그냥 유연하게 개발하여 주는것이 가장 좋은 방법입니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;RIBs는 Uber에서 만든 Architectural Pattern입니다.&lt;/p&gt;
&lt;p&gt;MVC패턴의 한계를 극복하고 VIPER의 복잡성을 개선한 패턴이라고 하네요.&lt;/p&gt;
&lt;p&gt;RIBs는 Router, Interactor, Builder의 약자입니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/uber/RIBs&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;github.com/uber/RIBs&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1601694558193&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;object&quot; data-og-title=&quot;uber/RIBs&quot; data-og-description=&quot;Uber's cross-platform mobile architecture framework. - uber/RIBs&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/uber/RIBs&quot; data-og-url=&quot;https://github.com/uber/RIBs&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/clgmGD/hyHHQageY7/7asdFqubSBdkGdflruM6uk/img.png?width=360&amp;amp;height=360&amp;amp;face=0_0_360_360,https://scrap.kakaocdn.net/dn/rbXsR/hyHHEOq0LX/hFJotceQG9Bac9xV75wfL0/img.png?width=733&amp;amp;height=320&amp;amp;face=0_0_733_320&quot;&gt;&lt;a href=&quot;https://github.com/uber/RIBs&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/uber/RIBs&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/clgmGD/hyHHQageY7/7asdFqubSBdkGdflruM6uk/img.png?width=360&amp;amp;height=360&amp;amp;face=0_0_360_360,https://scrap.kakaocdn.net/dn/rbXsR/hyHHEOq0LX/hFJotceQG9Bac9xV75wfL0/img.png?width=733&amp;amp;height=320&amp;amp;face=0_0_733_320');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;uber/RIBs&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;Uber's cross-platform mobile architecture framework. - uber/RIBs&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Uber RIBs의 wiki에 가면 이런게 있습니다.&lt;/p&gt;
&lt;p&gt;이 부분들에 대해서 설명해 보려고 합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;ribs.png&quot; data-origin-width=&quot;2288&quot; data-origin-height=&quot;863&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHI6Xq/btqJ0pCb1WI/U5uB4ksPWAwabkkVBIiWn0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHI6Xq/btqJ0pCb1WI/U5uB4ksPWAwabkkVBIiWn0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHI6Xq/btqJ0pCb1WI/U5uB4ksPWAwabkkVBIiWn0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHI6Xq%2FbtqJ0pCb1WI%2FU5uB4ksPWAwabkkVBIiWn0%2Fimg.png&quot; data-filename=&quot;ribs.png&quot; data-origin-width=&quot;2288&quot; data-origin-height=&quot;863&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Router&lt;/h3&gt;
&lt;p&gt;A Router listens to the Interactor and translates its outputs into attaching and detaching child RIBs. Routers exist for three simple reasons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Routers act as Humble Objects that make it easier to test complex Interactor logic without a need to to mock child Interactors or otherwise care about their existence.&lt;/li&gt;
&lt;li&gt;Routers create an additional abstraction layer between a parent Interactor and its child Interactors. This makes synchronous communication between Interactors a tiny bit harder and encourages adoption of reactive communication instead of direct coupling between the RIBs.&lt;/li&gt;
&lt;li&gt;Routers contain simple and repetitive routing logic that would otherwise be implemented by the Interactors. Factoring out this boilerplate code helps to keep the Interactors small and more focused on the core business logic provided by the RIB.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;라우터는 Interactor를 수신하고 출력을 자식 RIB 연결 및 분리로 변환하는 역할을 하게 됩니다.&lt;/p&gt;
&lt;p&gt;쉽게 말해서 attach, detach하여서 논리적인 트리 구조를 만들어 주게 됩니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Interactor&lt;/h3&gt;
&lt;p&gt;An Interactor contains business logic. This is where you perform Rx subscriptions, make state-altering decisions, decide where to store what data, and decide what other RIBs should be attached as children.&lt;/p&gt;
&lt;p&gt;All operations performed by the Interactor must be confined to its lifecycle. We have built tooling to ensure that business logic is only executed when the Interactor is active. This prevents scenarios where Interactors are deactivated, but subscriptions still fire and cause unwanted updates to the business logic or the UI state.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;비지니스 로직을 포함하고 있으며, 여기에서 Rx를 subscription 하고, State의 변경을 결정, 어떠한 Data를 저장할 위치를 결정, 자식으로 첨부해야하는 다른 RIB를 결정하게 된다고 합니다.&lt;/p&gt;
&lt;p&gt;즉, 로직을 수행하고 이것을 가지고 Router로 Routing call 그리고 RIBs의 attach와 detach를 요청하고 Presenter로 Data를 전달하는 역할을 하게 됩니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Builder&lt;/h3&gt;
&lt;p&gt;The Builder&amp;rsquo;s responsibility is to instantiate all the RIB&amp;rsquo;s constituent classes as well as the Builders for each of the RIB&amp;rsquo;s children.&lt;/p&gt;
&lt;p&gt;Separating the class creation logic in the Builder adds support for mockability on iOS and makes the rest of the RIB code indifferent to the details of DI implementation. The Builder is the only part of the RIB that should be made aware of the DI system used in the project. By implementing a different Builder, it is possible to reuse the rest of the RIB code in a project using a different DI mechanism.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;모든 RIB의 구성 클래스와 각 RIB의 하위에 대한 Builder를 인스턴스화 하는 것입니다.&lt;/p&gt;
&lt;p&gt;즉, RIBs의 모든 구성 요소를 생성하고 DI를 정의하도록 합니다. Router, Interactor, View, Component를 생성하는 역할을 합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Component&lt;/h3&gt;
&lt;p&gt;&lt;span&gt;Components are used to manage the RIB dependencies. They assist the Builders with instantiating the other units that compose a RIB. The Components provide access to the external dependencies that are needed to build a RIB as well as own the dependencies created by the RIB itself and control access to them from the other RIBs. The Component of a parent RIB is usually injected into the child RIB's Builder to give the child access to the parent RIB's dependencies.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;RIB 종속성을 관리하는 데 사용됩니다. 빌더가 RIB를 구성하는 다른 유닛을 인스턴스화 하도록 지원하여 주도록 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;부모 RIB Builder가 Component를 통해서 자식 RIB Builder에 의존성을 주입하게 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;View (Controller)&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;span&gt;Views build and update the UI. This includes instantiating and laying out UI components, handling user interaction, filling UI components with data, and animations. Views are designed to be as &amp;ldquo;dumb&amp;rdquo; as possible. They just display information. In general, they do not contain any code that needs to be unit tested.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Optional 이어서 RIBs에서는 꼭 포함되지 않아도 됩니다.&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;View는 UI를 만들고 업데이트하도록 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span&gt;Presenter&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;span&gt;&lt;span&gt;Presenters are stateless classes that translate business models into view models and vice versa. They can be used to facilitate testing of view model transformations. However, often this translation is so trivial that it doesn&amp;rsquo;t warrant the creation of a dedicated Presenter class. If the Presenter is omitted, translating the view models becomes a responsibility of a View(Controller) or an Interactor.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;Optional 이어서 RIBs에서는 꼭 포함되지 않아도 됩니다.&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;span&gt;Interactor와 View간의 통신을 담당하고 Business Model을 View Model로 변환하는 역할을 합니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;span&gt;상태를 가지고 있지 않은 것이 특징입니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;span&gt;Presenter를 생략하게 되면 View model 변환의 책임은 View또는 Interactor가 하게 됩니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>Mobile/iOS</category>
      <category>BASIC</category>
      <category>ribs</category>
      <category>Uber</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/838</guid>
      <comments>https://mrgamza.tistory.com/838#entry838comment</comments>
      <pubDate>Sat, 3 Oct 2020 12:12:20 +0900</pubDate>
    </item>
    <item>
      <title>iOS background push에 관해서</title>
      <link>https://mrgamza.tistory.com/837</link>
      <description>&lt;p&gt;Android와 iOS의 push는 다르게 동작합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Android&lt;/b&gt;는 전달되고 나서 개발자가 Notification을 표시하여주게 할지에 대해서 결정하기 때문에 background에서 동작 가능하도록 할 수 있습니다. 태생이 그러니...&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;iOS&lt;/b&gt;는 OS에서 받아서 각 앱에 전달을 하여 주는데 이 경우에 Notification을 표현을 하여 줍니다.&lt;/p&gt;
&lt;p&gt;앱이 백그라운드 일 경우에 말이죠...&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그래서 이것과 비슷하게 content-available값을 포함을 시켜서 백그라운드에 전달되도록 할 수가 있습니다.&lt;/p&gt;
&lt;p&gt;이렇게 하면 Android와 비슷하게 동작 합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;하지만 이런 기능을 마구잡이로 풀어줄리가 없죠.&lt;/p&gt;
&lt;p&gt;제약이 있는데요. 다음과 같습니다.&lt;/p&gt;
&lt;p&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;낮은 우선순위로 취급합니다.&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;알림의 전달성 보장을 하지 않습니다. (원래도 100%는 아닌데...)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;시스템 기준의 최대 제한이 초과 될 경우에 전달이 되지 않음. (Local Push의 경우에도 64개의 제한이 있습니다.)&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;이 제약은 iOS 13에서 더 강력해졌습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;13부터는 push header에 apns-push-type, apns-priority 속성을 추가해야 한다고 합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;apns-push-type은 &lt;b&gt;background&lt;/b&gt; or &lt;b&gt;alert&lt;/b&gt;를 설정 가능합니다.&lt;/li&gt;
&lt;li&gt;apns-priority은 5 or 10을 가질수 있습니다. (5가 그래도 더 보장을 하여주는 수치)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;그래서 background push의 경우에는 다음과 같이 설정하여야 합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;content-available: 1&lt;/li&gt;
&lt;li&gt;apns-push-type: &quot;background&quot;&lt;/li&gt;
&lt;li&gt;apns-priority: 5&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;참고하실 점들&lt;/p&gt;
&lt;p&gt;&lt;b&gt;apple push&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/sending_notification_requests_to_apns#2947607&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/sending_notification_requests_to_apns#2947607&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1601689056939&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Apple Developer Documentation&quot; data-og-description=&quot;&quot; data-og-host=&quot;developer.apple.com&quot; data-og-source-url=&quot;https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/sending_notification_requests_to_apns#2947607&quot; data-og-url=&quot;https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/sending_notification_requests_to_apns#2947607&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/sending_notification_requests_to_apns#2947607&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/sending_notification_requests_to_apns#2947607&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;&gt;Apple Developer Documentation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;developer.apple.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&lt;b&gt;apple background push&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/pushing_background_updates_to_your_app&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/pushing_background_updates_to_your_app&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1601689099337&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Apple Developer Documentation&quot; data-og-description=&quot;&quot; data-og-host=&quot;developer.apple.com&quot; data-og-source-url=&quot;https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/pushing_background_updates_to_your_app&quot; data-og-url=&quot;https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/pushing_background_updates_to_your_app&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/pushing_background_updates_to_your_app&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/pushing_background_updates_to_your_app&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;&gt;Apple Developer Documentation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;developer.apple.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;참고로 push receive는 다음의 delegate로 들어오게 됩니다.&lt;/p&gt;
&lt;p&gt;애플 문서에 가서 확인 해주세요.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623013-application&quot;&gt;application(_:didReceiveRemoteNotification:fetchCompletionHandler:)&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1601689146988&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Apple Developer Documentation&quot; data-og-description=&quot;&quot; data-og-host=&quot;developer.apple.com&quot; data-og-source-url=&quot;https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623013-application&quot; data-og-url=&quot;https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623013-application&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623013-application&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623013-application&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;&gt;Apple Developer Documentation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;developer.apple.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;마지막으로 한가지 용어가 헷갈릴까봐 말씀을 드리면 제가 background라고 표현을 하였지만&lt;/p&gt;
&lt;p&gt;application이 background에서 push를 받는것이 아니라 Notification이 표시되지 않도록 push를 하는 것입니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Mobile/iOS</category>
      <category>apns</category>
      <category>Background</category>
      <category>background push</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/837</guid>
      <comments>https://mrgamza.tistory.com/837#entry837comment</comments>
      <pubDate>Sat, 3 Oct 2020 10:40:33 +0900</pubDate>
    </item>
    <item>
      <title>iOS 시뮬레이터 사용할 때 coretelephony 로그가 마구 나오는 것 해결 하는 방법</title>
      <link>https://mrgamza.tistory.com/836</link>
      <description>&lt;p&gt;솔찍히 뭐하는 로그인지는 잘 모르겠지만 마구잡이로 나와서 지저분해 보이고 로딩이 지연되는 현상을 만들 수 있다고 합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이런 비슷한게 나오는 경우입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1601354040372&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;2018-09-22 10:59:40.031938+0100 xyz[1449:26262] Failed to create synchronous remote object proxy: Error Domain=NSCocoaErrorDomain Code=4099 &quot;The connection to service named com.apple.commcenter.coretelephony.xpc was invalidated.&quot; UserInfo={NSDebugDescription=The connection to service named com.apple.commcenter.coretelephony.xpc was invalidated.}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이렇게 하면 해결이 됩니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;터미널 프로그램에서 실행합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1601354101445&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ xcrun simctl spawn booted log config --mode &quot;level:off&quot; --subsystem com.apple.CoreTelephony&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Mobile/iOS</category>
      <category>Simulator</category>
      <category>Xcode</category>
      <category>xcrun</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/836</guid>
      <comments>https://mrgamza.tistory.com/836#entry836comment</comments>
      <pubDate>Tue, 29 Sep 2020 13:37:07 +0900</pubDate>
    </item>
    <item>
      <title>iOS13 이상에서 스토리보드 없이 프로젝트 시작하기</title>
      <link>https://mrgamza.tistory.com/835</link>
      <description>&lt;p&gt;애플에서 Scene을 적용하면서 이렇게 하게 되어 버렸네요.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;저는 얼마전까지는 화면이 눈에 잘 보이는 스토리보드를 좋아하였지만 지금은 그냥 화면을 코드에 만들고 있습니다.&lt;/p&gt;
&lt;p&gt;이것이 더 코드의 유지보수를 하는 방법에서 효율적이기 때문입니다.&lt;/p&gt;
&lt;p&gt;물론 SwiftUI와 비슷한 형태의 View Create 방법을 만들어서 적용해서 쓰기도 하는 이유가 있을거 같기도 하지만요.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;중요한것은 13부터는 AppDelegate에만 해주는것이 아니고 SceneDelegate에도 하여 주어야 한다는 겁니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그리고 이 세팅 부분은 multi scene의 지원에 대한 부분은 아니므로 그 부분은 나중에 추가해서 올리도록 할게요&lt;/p&gt;
&lt;p&gt;그래서 저는 파일을 하나 만들었어요.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Info.plist file 수정&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1766&quot; data-origin-height=&quot;396&quot; data-filename=&quot;스크린샷 2020-09-27 오전 10.31.14.png&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UA2V8/btqJCtTpXl4/ewfdw1DnCKVSaVgM9vCHtk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UA2V8/btqJCtTpXl4/ewfdw1DnCKVSaVgM9vCHtk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UA2V8/btqJCtTpXl4/ewfdw1DnCKVSaVgM9vCHtk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUA2V8%2FbtqJCtTpXl4%2Fewfdw1DnCKVSaVgM9vCHtk%2Fimg.png&quot; data-origin-width=&quot;1766&quot; data-origin-height=&quot;396&quot; data-filename=&quot;스크린샷 2020-09-27 오전 10.31.14.png&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;storyboard name을 삭제하여 줍니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Project setting에서 Main Interface를 삭제합니다.&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2020-09-27 오전 11.51.01.png&quot; data-origin-width=&quot;906&quot; data-origin-height=&quot;306&quot; width=&quot;560&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ypMWN/btqJHbctnoT/XmW6T3L6jK4cwKHY4MPphk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ypMWN/btqJHbctnoT/XmW6T3L6jK4cwKHY4MPphk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ypMWN/btqJHbctnoT/XmW6T3L6jK4cwKHY4MPphk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FypMWN%2FbtqJHbctnoT%2FXmW6T3L6jK4cwKHY4MPphk%2Fimg.png&quot; data-filename=&quot;스크린샷 2020-09-27 오전 11.51.01.png&quot; data-origin-width=&quot;906&quot; data-origin-height=&quot;306&quot; width=&quot;560&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;WindowManager.swift를 만들어 줍시다.&lt;/h2&gt;
&lt;p&gt;두곳에 같은 소스를 넣어주어야 하기 때문에 class를 하나 만들어서 개발하도록 합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1601173843134&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import UIKit

final class WindowManager {
    
    private var window: UIWindow
    
    init(with window: UIWindow = UIWindow()) {
        self.window = window
    }
    
    convenience init(with scene: UIWindowScene) {
        let window = UIWindow(windowScene: scene)
        self.init(with: window)
    }
    
    func setRootViewController(_ controller: UIViewController = ViewController()) {
        window.rootViewController = controller
        window.makeKeyAndVisible()
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;rootViewController로 지정한 ViewController class는 예시로 사용하시는 환경에 맞도록 수정해주세요&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;AppDelegate.swift 수정합니다.&lt;/h2&gt;
&lt;pre id=&quot;code_1601174303098&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class AppDelegate: UIResponder, UIApplicationDelegate {

    var windowManager: WindowManager?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -&amp;gt; Bool {
        if #available(iOS 13, *) {} else {
            windowManager = WindowManager()
            windowManager?.setRootViewController()
        }
        
        return true
    }
    
    // ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;13이상에서는 이곳에서 세팅하지 않습니다. avilable로 분기를 해서 진행합니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;SceneDelegate.swift 수정합니다.&lt;/h2&gt;
&lt;pre id=&quot;code_1601174515564&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var windowManager: WindowManager?

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        guard let scene = (scene as? UIWindowScene) else { return }
        windowManager = WindowManager(with: scene)
        windowManager?.setRootViewController()
    }
    
    // ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;ViewController.swift 수정하기&lt;/h2&gt;
&lt;pre id=&quot;code_1601175340286&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = .white
        
        let label = UILabel(frame: .zero)
        label.translatesAutoresizingMaskIntoConstraints = false
        label.text = &quot;Hello, test&quot;
        
        view.addSubview(label)
        
        NSLayoutConstraint.activate([
            label.centerYAnchor.constraint(equalTo: view.centerYAnchor),
            label.centerXAnchor.constraint(equalTo: view.centerXAnchor)
        ])
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이렇게 해주고 실행하면 화면중앙에 Hello, test!가 나올겁니다.&lt;/p&gt;
&lt;p&gt;궁금한점은 댓글 남겨주시기 바랍니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;source : &lt;a href=&quot;https://github.com/outofcode-example/iOS-NoStoryboard&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;github.com/outofcode-example/iOS-NoStoryboard&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1601175673973&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;object&quot; data-og-title=&quot;outofcode-example/iOS-NoStoryboard&quot; data-og-description=&quot;No use storyboard for iOS root viewcontroller. Contribute to outofcode-example/iOS-NoStoryboard development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/outofcode-example/iOS-NoStoryboard&quot; data-og-url=&quot;https://github.com/outofcode-example/iOS-NoStoryboard&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cIycEs/hyHEYxSQBw/uktKENLtWagao28u18IvGk/img.png?width=400&amp;amp;height=400&amp;amp;face=75_87_272_204&quot;&gt;&lt;a href=&quot;https://github.com/outofcode-example/iOS-NoStoryboard&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/outofcode-example/iOS-NoStoryboard&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cIycEs/hyHEYxSQBw/uktKENLtWagao28u18IvGk/img.png?width=400&amp;amp;height=400&amp;amp;face=75_87_272_204');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;outofcode-example/iOS-NoStoryboard&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;No use storyboard for iOS root viewcontroller. Contribute to outofcode-example/iOS-NoStoryboard development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Mobile/iOS</category>
      <category>AppDelegate</category>
      <category>iOS13</category>
      <category>not storyboard</category>
      <category>SceneDelegate</category>
      <category>StoryBoard</category>
      <author>out of coding</author>
      <guid isPermaLink="true">https://mrgamza.tistory.com/835</guid>
      <comments>https://mrgamza.tistory.com/835#entry835comment</comments>
      <pubDate>Sun, 27 Sep 2020 11:46:09 +0900</pubDate>
    </item>
  </channel>
</rss>