<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>fruits</title>
    <link>https://junsangkwon.tistory.com/</link>
    <description>iOS  </description>
    <language>ko</language>
    <pubDate>Thu, 9 Apr 2026 08:21:30 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>dev-Jun</managingEditor>
    <image>
      <title>fruits</title>
      <url>https://tistory1.daumcdn.net/tistory/3450050/attach/010a9173d7e74ca99add1e1ff1fb31a9</url>
      <link>https://junsangkwon.tistory.com</link>
    </image>
    <item>
      <title>[iOS] PhotoKit을 이용한 사진첩에서 사진 선택 시 앱 크래쉬 문제</title>
      <link>https://junsangkwon.tistory.com/61</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;iOS에서 커스텀으로 사진첩을 개발하려고 할 때 &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;보통 PhotoKit을 import 후, PHAsset으로 사진첩의 이미지를 불러와서 개발을 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_simulator_screenshot_A508D11F-273D-4FD2-A62F-B0837959B483.png&quot; data-origin-width=&quot;1179&quot; data-origin-height=&quot;2556&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/L21r2/btsfcOeoVee/2k3Xboj4xxhLRRYOazGJo1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/L21r2/btsfcOeoVee/2k3Xboj4xxhLRRYOazGJo1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/L21r2/btsfcOeoVee/2k3Xboj4xxhLRRYOazGJo1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FL21r2%2FbtsfcOeoVee%2F2k3Xboj4xxhLRRYOazGJo1%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;275&quot; height=&quot;596&quot; data-filename=&quot;edited_simulator_screenshot_A508D11F-273D-4FD2-A62F-B0837959B483.png&quot; data-origin-width=&quot;1179&quot; data-origin-height=&quot;2556&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그런데 다음과 같이 사진첩을 개발한 앱을 사용하는데 어떤 앱에서는 사진이 잘 선택되고 어떤 앱에서는 사진을 선택 시, 앱이 크래쉬가 나며 종료되었습니다. 그나마 앱 크래쉬 현상도 매번 일어나는 것이 아니라 간헐적으로 일어나더라고요..&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;몇 시간의 삽질 결과... 앱 크래쉬 현상이 일어나는 경우는 iCloud로 부터 이미지 정보를 불러오려고 할 때 오류가 발생하였습니다. iCloud에서 사진 데이터를 불러와야 하는데 Network Access가 허용되지 않아서 UIImage가 nil로 전달되는 문제였습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이를 해결하기 위해서 &lt;b&gt;PHImageRequestOptions&amp;nbsp;&lt;/b&gt;의 isNetworkAccessAllowed 를 true로 바꿔주어서 네트워크 연결이 가능하도록 설정하였더니 문제 없이 사진을 선택할 수 있었습니다...&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1684046245866&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let option = PHImageRequestOptions()
option.isNetworkAccessAllowed = true&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>iOS Programming</category>
      <category>isNetworkAccessAllowed</category>
      <category>PHAsset</category>
      <category>PHImageRequestOptions</category>
      <category>PhotoKit</category>
      <category>Photos</category>
      <author>dev-Jun</author>
      <guid isPermaLink="true">https://junsangkwon.tistory.com/61</guid>
      <comments>https://junsangkwon.tistory.com/61#entry61comment</comments>
      <pubDate>Mon, 15 May 2023 16:39:06 +0900</pubDate>
    </item>
    <item>
      <title>[iOS] WKNavigationDelegate</title>
      <link>https://junsangkwon.tistory.com/60</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;WKNavigationDelegate&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;WKNavigationDelegate 함수를 이용하여 웹 페이지 탐색을 수락하거나 거절하고, &lt;span style=&quot;background-color: #ffffff; text-align: left;&quot;&gt;웹 페이지 요청의 과정을 추적한다고 합니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;WKNavigationDelegate 함수들을 하나씩 알아보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; text-align: left;&quot;&gt;&lt;b&gt;1) decidePolicyFor&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-05-14 오후 2.44.14.png&quot; data-origin-width=&quot;1262&quot; data-origin-height=&quot;628&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3l3vA/btsfcj6KvGq/yGNo7NeslVa48oKkRV6e61/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3l3vA/btsfcj6KvGq/yGNo7NeslVa48oKkRV6e61/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3l3vA/btsfcj6KvGq/yGNo7NeslVa48oKkRV6e61/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3l3vA%2Fbtsfcj6KvGq%2FyGNo7NeslVa48oKkRV6e61%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;617&quot; height=&quot;307&quot; data-filename=&quot;스크린샷 2023-05-14 오후 2.44.14.png&quot; data-origin-width=&quot;1262&quot; data-origin-height=&quot;628&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이 메서드는 WKWebview에서 새로운 페이지를 로드하기 전에 해당 페이지 요청에 대한 네비게이션 정책을 결정합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이 메서드를 사용하여 링크가 클릭되었을 때 페이지를 로드하기 전에 해당 링크가 안전한 도메인에서 온 것인지,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;악성 스크립트를 실행하거나 불법적인 컨텐츠를 제공하는지 여부를 확인할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;webView: 이 메서드가 호출된 웹 뷰입니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;navigationAction: 네비게이션 요청에 대한 정보를 제공합니다.&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;navigationAction.navigationType &amp;rarr; 속성을 통해 페이지 요청 유형을 확인&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;navigationAction.request.url &amp;rarr; 속성을 사용하여 요청된 URL을 확인&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;decisionHandler: 이 페이지 요청에 대한 네비게이션을 허용할지 또는 거부할지 결정합니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;WKNavigationAction&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;네비게이션 요청에 대한 정보를 제공합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;어떤 URL을 요청했는지, 요청 방법 (ex: GET, POST), 요청한 페이지가 새 창에서 열렸는지, 페이지를 다운로드하는 것인지 등을 알려줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이 정보를 기반으로 앱에서 적절한 작업을 수행할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;WKNavigationActionPolicy&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;cancel : 취소&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;allow : 허용&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;2) didStartProvisionalNavigation&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-05-14 오후 2.43.30.png&quot; data-origin-width=&quot;1262&quot; data-origin-height=&quot;596&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/o05gV/btsfdb1DYIt/43mp3UEUiYXq9AQz9Jk2xK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/o05gV/btsfdb1DYIt/43mp3UEUiYXq9AQz9Jk2xK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/o05gV/btsfdb1DYIt/43mp3UEUiYXq9AQz9Jk2xK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fo05gV%2Fbtsfdb1DYIt%2F43mp3UEUiYXq9AQz9Jk2xK%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;642&quot; height=&quot;303&quot; data-filename=&quot;스크린샷 2023-05-14 오후 2.43.30.png&quot; data-origin-width=&quot;1262&quot; data-origin-height=&quot;596&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이 메서드는 WKWebView가 탐색을 시작하고 컨텐츠를 load 하기 시작했을 때 호출됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;웹뷰가 페이지를 로드하기 시작했음을 알리기 때문에, 이를 활용해 로딩 인디케이터를 보여주거나, 네비게이션 바에 주소를 업데이트하는 등의 작업을 수행할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;3) &lt;span style=&quot;text-align: left;&quot;&gt;didReceiveServerRedirectForProvisionalNavigation&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-05-14 오후 2.55.06.png&quot; data-origin-width=&quot;1262&quot; data-origin-height=&quot;628&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/baBX1G/btsffvSBoZ5/AcaKHDKCeVL94SDh8oGfTK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/baBX1G/btsffvSBoZ5/AcaKHDKCeVL94SDh8oGfTK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/baBX1G/btsffvSBoZ5/AcaKHDKCeVL94SDh8oGfTK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbaBX1G%2FbtsffvSBoZ5%2FAcaKHDKCeVL94SDh8oGfTK%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;681&quot; height=&quot;339&quot; data-filename=&quot;스크린샷 2023-05-14 오후 2.55.06.png&quot; data-origin-width=&quot;1262&quot; data-origin-height=&quot;628&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이 메서드는 WKWebView가 요청에 의해 서버 리디렉션 되었을 때, 호출됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;리디렉션된 페이지의 URL을 확인하여 해당 페이지로 다시 로드하거나, 캐시 된 페이지를 업데이트하는 등의 작업을 수행할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;text-align: left;&quot;&gt;4) didCommit&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; text-align: left;&quot;&gt;&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-05-14 오후 2.58.37.png&quot; data-origin-width=&quot;1262&quot; data-origin-height=&quot;586&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mZh0Q/btsfbyQrTW4/967ADoMDxtdK7eej3UZ6k0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mZh0Q/btsfbyQrTW4/967ADoMDxtdK7eej3UZ6k0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mZh0Q/btsfbyQrTW4/967ADoMDxtdK7eej3UZ6k0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmZh0Q%2FbtsfbyQrTW4%2F967ADoMDxtdK7eej3UZ6k0%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;660&quot; height=&quot;306&quot; data-filename=&quot;스크린샷 2023-05-14 오후 2.58.37.png&quot; data-origin-width=&quot;1262&quot; data-origin-height=&quot;586&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;text-align: left;&quot;&gt;이 메서드는 WKWebView가 컨텐츠를 수신하기 시작했을 때 호출되며 &lt;/span&gt;didStartProvisionalNavigation 다음으로 호출됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;text-align: left;&quot;&gt;5) didFinish&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-05-14 오후 3.04.27.png&quot; data-origin-width=&quot;1262&quot; data-origin-height=&quot;586&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dpRhrk/btsftKBkDhc/a9vlUHyRH8cDKD5MyyXp5K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dpRhrk/btsftKBkDhc/a9vlUHyRH8cDKD5MyyXp5K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dpRhrk/btsftKBkDhc/a9vlUHyRH8cDKD5MyyXp5K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdpRhrk%2FbtsftKBkDhc%2Fa9vlUHyRH8cDKD5MyyXp5K%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;644&quot; height=&quot;299&quot; data-filename=&quot;스크린샷 2023-05-14 오후 3.04.27.png&quot; data-origin-width=&quot;1262&quot; data-origin-height=&quot;586&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이 메서드는 WKWebView가 페이지 로드를 완료했을 때 호출됩니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;사용자는 페이지의 모든 내용을 볼 수 있게 되고 이 시점에서 웹뷰는 더 이상의 네트워크 활동이나 리소스 다운로드를 수행하지 않습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;로딩 인디케이터를 삭제하거나 로드된 페이지에서 필요한 작업을 수행할 수도 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;text-align: left;&quot;&gt;6) didFail&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-05-14 오후 3.06.45.png&quot; data-origin-width=&quot;1262&quot; data-origin-height=&quot;610&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bR8C0f/btsftGsaVTJ/qlIScWNPZpqOAohKXJoQT1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bR8C0f/btsftGsaVTJ/qlIScWNPZpqOAohKXJoQT1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bR8C0f/btsftGsaVTJ/qlIScWNPZpqOAohKXJoQT1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbR8C0f%2FbtsftGsaVTJ%2FqlIScWNPZpqOAohKXJoQT1%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;645&quot; height=&quot;312&quot; data-filename=&quot;스크린샷 2023-05-14 오후 3.06.45.png&quot; data-origin-width=&quot;1262&quot; data-origin-height=&quot;610&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이 메서드는 WKWebView가 페이지 로드를 실패했을 때 호출됩니다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Error 객체를 통해 어떤 에러가 발생했는 지 확인하고, 사용자에게 적절한 알림을 제공할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;참고&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;a href=&quot;https://developer.apple.com/documentation/webkit/wknavigationdelegate&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://developer.apple.com/documentation/webkit/wknavigationdelegate&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;a href=&quot;https://boidevelop.tistory.com/97&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://boidevelop.tistory.com/97&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>iOS Programming</category>
      <category>ios</category>
      <category>web</category>
      <category>WKNavigationDelegate</category>
      <category>WKUIDelegate</category>
      <category>wkwebview</category>
      <author>dev-Jun</author>
      <guid isPermaLink="true">https://junsangkwon.tistory.com/60</guid>
      <comments>https://junsangkwon.tistory.com/60#entry60comment</comments>
      <pubDate>Sun, 14 May 2023 15:10:50 +0900</pubDate>
    </item>
    <item>
      <title>[iOS] 카카오톡 공유하기 메시지 보내기</title>
      <link>https://junsangkwon.tistory.com/59</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;카카오톡 공유하기 기능을 구현하면서 배운 것들을 정리하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 카카오톡 공유하기 API를 사용하기 위해서는 사전에 여러 설정이 필요합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1) &lt;span style=&quot;background-color: #ffffff; color: #444444; text-align: start;&quot;&gt;Kakao SDK 설치&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #444444; text-align: start;&quot;&gt;프로젝트의 Podfile에 Kakao SDK를 전체 또는 모듈(Module) 별로 추가합니다. 저는 필요한 모듈만 추가하였습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;# 전체 추가
pod 'KakaoSDK'

# 필요한 모듈만 추가
pod 'KakaoSDKShare'  
pod 'KakaoSDKTemplate'&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2)  Kakao Developer 로그인 후, 애플리케이션 추가&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Kakao Developer 로그인 &amp;gt; 내 어플리케이션 &amp;gt; 애플리케이션 추가를 진행합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-05-13 오후 6.20.48.png&quot; data-origin-width=&quot;1330&quot; data-origin-height=&quot;1198&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/boDcc7/btsfjJ3zYn5/oXq5V2bNPRCJehplrKK790/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/boDcc7/btsfjJ3zYn5/oXq5V2bNPRCJehplrKK790/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/boDcc7/btsfjJ3zYn5/oXq5V2bNPRCJehplrKK790/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FboDcc7%2FbtsfjJ3zYn5%2FoXq5V2bNPRCJehplrKK790%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;553&quot; height=&quot;1198&quot; data-filename=&quot;스크린샷 2023-05-13 오후 6.20.48.png&quot; data-origin-width=&quot;1330&quot; data-origin-height=&quot;1198&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3) iOS 플랫폼 등록&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;플랫폼 &amp;gt; 플랫폼 설정하기 버튼 &amp;gt; iOS 플랫폼 등록&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-05-13 오후 6.29.01.png&quot; data-origin-width=&quot;1330&quot; data-origin-height=&quot;1364&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/o8G5c/btsfdpSBWII/eDhk5KuPCyvI6Y373ZMshK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/o8G5c/btsfdpSBWII/eDhk5KuPCyvI6Y373ZMshK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/o8G5c/btsfdpSBWII/eDhk5KuPCyvI6Y373ZMshK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fo8G5c%2FbtsfdpSBWII%2FeDhk5KuPCyvI6Y373ZMshK%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;454&quot; height=&quot;1364&quot; data-filename=&quot;스크린샷 2023-05-13 오후 6.29.01.png&quot; data-origin-width=&quot;1330&quot; data-origin-height=&quot;1364&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 간단하게 테스트만 진행할 것이기 때문에 번들 ID만 등록하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미 앱스토어에 등록되어있는 앱이라면 ID까지 적어주세요!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4) 앱 키 확인 후, Xcode 진입&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네이티브 앱 키를 설정해줘야하기 때문에 이 값을 복사해 주고 Xcode로 돌아옵니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-05-13 오후 6.31.25.png&quot; data-origin-width=&quot;1336&quot; data-origin-height=&quot;812&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SZ4t7/btsfg3nFuHX/6pYVVOvynm5WpRaLkkkwlk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SZ4t7/btsfg3nFuHX/6pYVVOvynm5WpRaLkkkwlk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SZ4t7/btsfg3nFuHX/6pYVVOvynm5WpRaLkkkwlk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSZ4t7%2Fbtsfg3nFuHX%2F6pYVVOvynm5WpRaLkkkwlk%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;561&quot; height=&quot;812&quot; data-filename=&quot;스크린샷 2023-05-13 오후 6.31.25.png&quot; data-origin-width=&quot;1336&quot; data-origin-height=&quot;812&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;5) 앱 실행 허용 목록 설정&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Xcode 프로젝트 파일 &amp;gt; Info &amp;gt; Custom iOS Target Properties에 Array 타입 키(Key)인 &lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot; data-token-index=&quot;1&quot;&gt;LSApplicationQueriesSchemes&lt;/span&gt;&lt;/b&gt;를 추가하고, 해당 키의 Item으로 &lt;span&gt;커스텀 URL 스킴&lt;/span&gt;에 사용할 값인 &lt;b&gt;&quot;kakaokompassauth&quot;, &quot;kakaolink&quot;&lt;/b&gt;를 추가합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-05-13 오후 6.43.44.png&quot; data-origin-width=&quot;1378&quot; data-origin-height=&quot;758&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ms84T/btsfaMgLjj7/1HsvPMwFDByifElTppBa0k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ms84T/btsfaMgLjj7/1HsvPMwFDByifElTppBa0k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ms84T/btsfaMgLjj7/1HsvPMwFDByifElTppBa0k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fms84T%2FbtsfaMgLjj7%2F1HsvPMwFDByifElTppBa0k%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;605&quot; height=&quot;758&quot; data-filename=&quot;스크린샷 2023-05-13 오후 6.43.44.png&quot; data-origin-width=&quot;1378&quot; data-origin-height=&quot;758&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;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;6)&lt;span&gt;&amp;nbsp;&lt;/span&gt;URL Schemes 설정&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카카오계정을 통한 인증과 카카오톡 메시지를 통한 앱 실행을 위해 URL Schemes 설정을 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Info &amp;gt; URL Types &amp;gt; URL Schemes 항목에 네이티브 앱 키(Native App Key)를 &amp;nbsp;형식으로 등록합니다. 예를 들어 네이티브 앱 키가 &quot;123456789&quot;라면 [URL Schemes]에 &quot;kakao123456789&quot;를 입력합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-05-13 오후 6.44.06.png&quot; data-origin-width=&quot;1278&quot; data-origin-height=&quot;822&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eNM654/btsfdXuZ9hB/WyyTHiFNZc7DhnrHNHXmfK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eNM654/btsfdXuZ9hB/WyyTHiFNZc7DhnrHNHXmfK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eNM654/btsfdXuZ9hB/WyyTHiFNZc7DhnrHNHXmfK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeNM654%2FbtsfdXuZ9hB%2FWyyTHiFNZc7DhnrHNHXmfK%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;675&quot; height=&quot;822&quot; data-filename=&quot;스크린샷 2023-05-13 오후 6.44.06.png&quot; data-origin-width=&quot;1278&quot; data-origin-height=&quot;822&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;7)&lt;span&gt;&amp;nbsp;초기화&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;import KakaoSDKCommon 을 해주고, 네이티브 앱 키를 사용해 iOS SDK를 초기화하는 과정이 필요합니다. AppDelegate.swift에 Kakao SDK를 초기화하는 코드를 추가합니다.&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-13 오후 7.23.41.png&quot; data-origin-width=&quot;2004&quot; data-origin-height=&quot;368&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ccydde/btsfdXV47vG/k6YkBkXEGC8969lRKblyxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ccydde/btsfdXV47vG/k6YkBkXEGC8969lRKblyxK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ccydde/btsfdXV47vG/k6YkBkXEGC8969lRKblyxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fccydde%2FbtsfdXV47vG%2Fk6YkBkXEGC8969lRKblyxK%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;2004&quot; height=&quot;368&quot; data-filename=&quot;스크린샷 2023-05-13 오후 7.23.41.png&quot; data-origin-width=&quot;2004&quot; data-origin-height=&quot;368&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기까지가 기본 세팅입니다... 기본 세팅이 더 빡세네요&lt;/p&gt;
&lt;figure contenteditable=&quot;false&quot; data-ke-type=&quot;emoticon&quot; data-ke-align=&quot;alignCenter&quot; data-emoticon-type=&quot;friends1&quot; data-emoticon-name=&quot;016&quot; data-emoticon-isanimation=&quot;false&quot; data-emoticon-src=&quot;https://t1.daumcdn.net/keditor/emoticon/friends1/large/016.gif&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/keditor/emoticon/friends1/large/016.gif&quot; width=&quot;150&quot; /&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 카카오톡 공유하기 기능을 따로 템플릿을 만들지 않고 코드로 커스텀하는 방식으로 구현하였습니다.&lt;/p&gt;
&lt;pre class=&quot;swift&quot; data-ke-language=&quot;swift&quot;&gt;&lt;code&gt;@objc func kakao() {
    // 웹 링크입니다. 카카오톡 인앱 브라우저에서 열립니다.
    let link = Link(webUrl: URL(string: &quot;https://developers.kakao.com&quot;),
                    mobileWebUrl: URL(string: &quot;https://developers.kakao.com&quot;))

    // 앱 링크입니다. 파라미터를 함께 전달하여 앱으로 들어왔을 때 특정 페이지로 이동할 수 있는 역할을 합니다.
    let appLink = Link(androidExecutionParams: [&quot;key1&quot;: &quot;value1&quot;, &quot;key2&quot;: &quot;value2&quot;],
                       iosExecutionParams: [&quot;key1&quot;: &quot;value1&quot;, &quot;key2&quot;: &quot;value2&quot;])
    
    // 버튼들 입니다.
    let webButton = Button(title: &quot;웹으로 보기&quot;, link: link)
    let appButton = Button(title: &quot;앱으로 보기&quot;, link: appLink)
    
    // 메인이 되는 사진, 이미지 URL, 클릭 시 이동하는 링크를 설정합니다.
    let content = Content(title: &quot;딸기 치즈 케익&quot;,
                          imageUrl: URL(string: &quot;https://mud-kage.kakao.com/dn/Q2iNx/btqgeRgV54P/VLdBs9cvyn8BJXB3o7N8UK/kakaolink40_original.png&quot;)!,
                          link: link)
        
    let template = FeedTemplate(content: content, buttons: [webButton, appButton])
        
    // 메시지 템플릿 encode
    if let templateJsonData = (try? SdkJSONEncoder.custom.encode(template)) {
        // 생성한 메시지 템플릿 객체를 jsonObject로 변환
        if let templateJsonObject = SdkUtils.toJsonObject(templateJsonData) {
            // 카카오톡 앱이 있는지 체크합니다.
            if ShareApi.isKakaoTalkSharingAvailable() {
                ShareApi.shared.shareDefault(templateObject:templateJsonObject) {(linkResult, error) in
                    if let error = error {
                        print(&quot;error : \(error)&quot;)
                    }
                    else {
                        print(&quot;defaultLink(templateObject:templateJsonObject) success.&quot;)
                        guard let linkResult = linkResult else { return }
                        UIApplication.shared.open(linkResult.url, options: [:], completionHandler: nil)
                    }
                }
            } else {
            	// 없을 경우 카카오톡 앱스토어로 이동합니다. (이거 하려면 URL Scheme에 itms-apps 추가 해야함)
                let url = &quot;itms-apps://itunes.apple.com/app/362057947&quot;
                if let url = URL(string: url), UIApplication.shared.canOpenURL(url) {
                    if #available(iOS 10.0, *) {
                        UIApplication.shared.open(url, options: [:], completionHandler: nil)
                    } else {
                        UIApplication.shared.openURL(url)
                    }
                }
            }
        }
    }
}&lt;/code&gt;&lt;/pre&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;IMG_C70F2953487A-1.jpeg&quot; data-origin-width=&quot;828&quot; data-origin-height=&quot;1023&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GjHtl/btsffuy6lRS/lAz3peMZ8NoTzk9gGhRA41/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GjHtl/btsffuy6lRS/lAz3peMZ8NoTzk9gGhRA41/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GjHtl/btsffuy6lRS/lAz3peMZ8NoTzk9gGhRA41/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGjHtl%2Fbtsffuy6lRS%2FlAz3peMZ8NoTzk9gGhRA41%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;275&quot; height=&quot;1023&quot; data-filename=&quot;IMG_C70F2953487A-1.jpeg&quot; data-origin-width=&quot;828&quot; data-origin-height=&quot;1023&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 아직 남은 것이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 &lt;b&gt;앱으로 보기&lt;/b&gt;를 클릭했을 때, 앱의 특정 부분으로 이동하거나 어떤 작업을 진행하고 싶을 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;iOS 앱에서 URL Scheme을 이용해 앱으로 진입할 때, 실행되는 메서드의 순서는 다음과 같습니다.&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;if) AppDelegate만 사용하는 경우&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;1. 앱이 실행되고, 'UIApplicationDelegate' 프로토콜을 구현한 객체의 'application(_:didFinishLaunchingWithOptions:)' 메서드가 호출됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1683980480679&quot; class=&quot;swift&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -&amp;gt; Bool {
    return true
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 메서드에서는 앱이 처음 실행될 때 필요한 초기화 작업을 수행합니다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 만약 앱이 이미 실행 중이었다면, 'UIApplicationDelegate' 프로토콜을 구현한 객체의 'application(_:open:options:)' 메서드가 호출됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1683980580618&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -&amp;gt; Bool {
	if let components = URLComponents(url: url, resolvingAgainstBaseURL: false) {
        var queryItems = components.queryItems ?? []
        for queryItem in queryItems {
            if queryItem.name == &quot;key1&quot;, let value = queryItem.value {
                print(value)
            } else if queryItem.name == &quot;key2&quot;, let value = queryItem.value {
                print(value)
            }
        }
    }
    return true
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 메서드에서는 URL Scheme에 대한 처리 작업을 수행합니다.&lt;/li&gt;
&lt;li&gt;이때, URL Scheme에 전달된 매개변수를 이용하여 적절한 화면으로 이동하는 작업 등을 수행할 수 있습니다.&lt;/li&gt;
&lt;li&gt;URL을 URLComponents로 변환 후, &lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;queryItem 프로퍼티로 파라미터에 접근 가능합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;오는 URL 값 : &lt;/span&gt;&lt;b&gt;kakao${네이티브 앱 키}://kakaolink?key1=value1&lt;b&gt;&amp;amp;&lt;/b&gt;&lt;b&gt;key2=value2&lt;/b&gt;&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. URL Scheme을 이용해 앱을 진입한 경우, 앱이 실행된 후 'UIApplicationDelegate' 프로토콜을 구현한 객체의 'applicationDidBecomeActive(_:)' 메서드가 호출됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1683980696324&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;func applicationDidBecomeActive(_ application: UIApplication)&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 메서드에서는 앱이 Active 상태가 되었을 때 수행해야 할 작업을 수행합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;if) SceneDelegate가 있는 경우&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앱으로 진입 시, application(_:open:options:) 메서드가 호출되지 않고 &lt;span&gt;scene&lt;/span&gt;(&lt;span&gt;_&lt;/span&gt; scene:&lt;span&gt;openURLContexts&lt;/span&gt;) 메서드를 사용합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1683980408161&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;func scene(_ scene: UIScene, openURLContexts URLContexts: Set&amp;lt;UIOpenURLContext&amp;gt;) {
    guard let url = URLContexts.first?.url else { return }
    if let components = URLComponents(url: url, resolvingAgainstBaseURL: false) {
        var queryItems = components.queryItems ?? []
        for queryItem in queryItems {
            if queryItem.name == &quot;key1&quot;, let value = queryItem.value {
                print(value)
            } else if queryItem.name == &quot;key2&quot;, let value = queryItem.value {
                print(value)
            }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 메서드에서 대신 URL Scheme에 대한 처리 작업을 수행합니다.&lt;/li&gt;
&lt;li&gt;URL을 URLComponents로 변환 후,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;queryItem 프로퍼티로 파라미터에 접근 가능합니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;마지막으로 &lt;b&gt;웹으로 보기&lt;/b&gt; 클릭 시, 지정한 URL로 가게 하기 위해선 Web 플랫폼을 설정해야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;아까 iOS 플랫폼 등록했던 곳으로 가서 Web 플랫폼에 지정한 URL을 등록하시면 됩니다.&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: left;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-05-13 오후 10.00.30.png&quot; data-origin-width=&quot;1288&quot; data-origin-height=&quot;1316&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VxnmD/btsfeAGm6ea/HzBby5Elv2Bs11R1kWWpRk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VxnmD/btsfeAGm6ea/HzBby5Elv2Bs11R1kWWpRk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VxnmD/btsfeAGm6ea/HzBby5Elv2Bs11R1kWWpRk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVxnmD%2FbtsfeAGm6ea%2FHzBby5Elv2Bs11R1kWWpRk%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;410&quot; height=&quot;1316&quot; data-filename=&quot;스크린샷 2023-05-13 오후 10.00.30.png&quot; data-origin-width=&quot;1288&quot; data-origin-height=&quot;1316&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;a href=&quot;https://developers.kakao.com/docs/latest/ko/getting-started/sdk-ios#set-up-plist&quot;&gt;https://developers.kakao.com/docs/latest/ko/getting-started/sdk-ios#set-up-plist&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developers.kakao.com/docs/latest/ko/message/ios-link&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://developers.kakao.com/docs/latest/ko/message/ios-link&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@rbw/iOS-%EC%B9%B4%EC%B9%B4%EC%98%A4%ED%86%A1-%EA%B3%B5%EC%9C%A0%ED%95%98%EA%B8%B0-%EC%82%AC%EC%9A%A9%EB%B0%A9%EB%B2%95&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://velog.io/@rbw/iOS-%EC%B9%B4%EC%B9%B4%EC%98%A4%ED%86%A1-%EA%B3%B5%EC%9C%A0%ED%95%98%EA%B8%B0-%EC%82%AC%EC%9A%A9%EB%B0%A9%EB%B2%95&lt;/a&gt;&lt;/p&gt;</description>
      <category>iOS Programming</category>
      <category>API</category>
      <category>ios</category>
      <category>Swift</category>
      <category>uikit</category>
      <category>URLComponents</category>
      <category>공유하기</category>
      <category>카카오톡</category>
      <category>카카오톡 공유</category>
      <category>커스텀 템플릿</category>
      <author>dev-Jun</author>
      <guid isPermaLink="true">https://junsangkwon.tistory.com/59</guid>
      <comments>https://junsangkwon.tistory.com/59#entry59comment</comments>
      <pubDate>Sat, 13 May 2023 22:02:08 +0900</pubDate>
    </item>
    <item>
      <title>[iOS] GCD (Grand Central Dispatch)</title>
      <link>https://junsangkwon.tistory.com/58</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;GCD (Grand Central Dispatch)&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;동시성을 제공하기 위해 사용하는&amp;nbsp;API&lt;/li&gt;
&lt;li&gt;Queue에 작업을 보내면&amp;nbsp;알아서 스레드를 할당하고 안전하게 수행&lt;/li&gt;
&lt;li&gt;GCD에서 사용하는 Queue의 이름이 Dispatch Queue&lt;/li&gt;
&lt;li&gt;즉, DispatchQueue에 작업을 추가하면 GCD는 작업에 맞는 스레드를 자동으로 생성해서 실행하고, 작업이 종료되면 스레드를 제거&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;동시성 프로그래밍&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;- 싱글 코어(멀티 코어에서도 가능)에서 멀티스레드를 동작시키키 위한 방식&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;queue.sync { task } 동기 vs queue.async { task } 비동기&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;동기는 데이터의 요청과 결과가 한 자리에서 동시에 일어나는 것을 의미&lt;/li&gt;
&lt;li&gt;비동기는 데이터의 요청과 결과가 동시에 일어나지 않는다는 의미&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Serial (직렬) vs Concurrent (동시)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Serial Queue&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;분산 처리 시킨 작업을 &quot;한개의 스레드에서&quot; 처리하는 큐&lt;/li&gt;
&lt;li&gt;task의 시작과 종료에 대한 순서 예측이 가능&lt;/li&gt;
&lt;li&gt;늦게 실행 된 것이 먼저 끝나는 상황 방지&lt;/li&gt;
&lt;li&gt;느림&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Concurrent Queue&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;분산 처리 시킨 작업을 &quot;여러 개의 스레드에서&quot; 처리하는 큐&lt;/li&gt;
&lt;li&gt;끝나는 순서는 알 수 없음&lt;/li&gt;
&lt;li&gt;빠름&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;DispatchQueue의 타입&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;(1) Main Queue&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메인 쓰레드에서 작동하는 큐로, UI 요소와 관련된 부분들을 담당&lt;/li&gt;
&lt;li&gt;Serial Queue&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;(2) Global Queue&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 시스템에 공유되는 Concurrent Queue&lt;/li&gt;
&lt;li&gt;QoS를 통해 우선순위를 관리 할 수 있음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;userInteractive : 애니메이션, 이벤트 처리나 지연이 적은 작업 등에 사용 (사용자와 직접 상호작용 하는 작업)&lt;/li&gt;
&lt;li&gt;userInitiated: 사용자가 즉각적인 결과를 기다리고 있고 UI 상호 작용을 계속하는 데 필요한 작업에 사용 (거의 바로 수행)&lt;/li&gt;
&lt;li&gt;default:userInitiated보다 덜 중요한 일반적인 작업&lt;/li&gt;
&lt;li&gt;utility : Progress indicator가 보이는 것과 같은 오래 걸리느(수초 ~ 수분 걸리는 작업)&lt;/li&gt;
&lt;li&gt;background : 사용자 인식에 관계없는 작업(영상 다운로드 등)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;(3) Custom Queue&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;직접 만드는 Queue&lt;/li&gt;
&lt;li&gt;디폴트로&amp;nbsp;serial 특성을 가진 Queue지만 concurrent로 설정 가능&lt;/li&gt;
&lt;li&gt;Qos 설정 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;GCD 사용 시 주의 사항&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1) UI는 main 스레드에서 처리함&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2-1) Main Queue에서 다른 Queue로 작업을 보낼 때 sync를 사용하면 안됨&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메인 스레드는 UI를 업데이트 해야하는데, 다른 작업들이 끝날 때까지 기다린다면 해당 작업이 끝날 때까지 UI업데이트가 지연되기 때문에 안됨&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2-2) 현재와 같은 Queue에 sync로 작업을 보내면 안됨&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;같은 Queue에 보내면 같은 스레드에 배치될 수 있는데, 해당 스레드가 sync로 인해 멈춰있는 상황이라면 데드락 상황이 발생함&lt;/li&gt;
&lt;li&gt;다른 Qos 큐라면 데드락 발생 가능성이 없음&lt;/li&gt;
&lt;li&gt;따라서 메인 스레드에서 DispatchQueue.main.sync를 사용하면 안됨&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Reference :&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://sujinnaljin.medium.com/ios-%EC%B0%A8%EA%B7%BC%EC%B0%A8%EA%B7%BC-%EC%8B%9C%EC%9E%91%ED%95%98%EB%8A%94-gcd-grand-dispatch-queue-1-397db16d0305&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://sujinnaljin.medium.com/ios-%EC%B0%A8%EA%B7%BC%EC%B0%A8%EA%B7%BC-%EC%8B%9C%EC%9E%91%ED%95%98%EB%8A%94-gcd-grand-dispatch-queue-1-397db16d0305&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1676193321503&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[iOS] 차근차근 시작하는 GCD &amp;mdash; 1&quot; data-og-description=&quot;이번엔 제발 이해하고 싶다 GCD.. &quot; data-og-host=&quot;sujinnaljin.medium.com&quot; data-og-source-url=&quot;https://sujinnaljin.medium.com/ios-%EC%B0%A8%EA%B7%BC%EC%B0%A8%EA%B7%BC-%EC%8B%9C%EC%9E%91%ED%95%98%EB%8A%94-gcd-grand-dispatch-queue-1-397db16d0305&quot; data-og-url=&quot;https://sujinnaljin.medium.com/ios-%EC%B0%A8%EA%B7%BC%EC%B0%A8%EA%B7%BC-%EC%8B%9C%EC%9E%91%ED%95%98%EB%8A%94-gcd-grand-dispatch-queue-1-397db16d0305&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/qhUhD/hyRAp1wAFy/dRUiKlKKv4RTdWVwkCSJUk/img.png?width=1200&amp;amp;height=552&amp;amp;face=0_0_1200_552&quot;&gt;&lt;a href=&quot;https://sujinnaljin.medium.com/ios-%EC%B0%A8%EA%B7%BC%EC%B0%A8%EA%B7%BC-%EC%8B%9C%EC%9E%91%ED%95%98%EB%8A%94-gcd-grand-dispatch-queue-1-397db16d0305&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://sujinnaljin.medium.com/ios-%EC%B0%A8%EA%B7%BC%EC%B0%A8%EA%B7%BC-%EC%8B%9C%EC%9E%91%ED%95%98%EB%8A%94-gcd-grand-dispatch-queue-1-397db16d0305&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/qhUhD/hyRAp1wAFy/dRUiKlKKv4RTdWVwkCSJUk/img.png?width=1200&amp;amp;height=552&amp;amp;face=0_0_1200_552');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[iOS] 차근차근 시작하는 GCD &amp;mdash; 1&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;이번엔 제발 이해하고 싶다 GCD.. &lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;sujinnaljin.medium.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>iOS Programming</category>
      <author>dev-Jun</author>
      <guid isPermaLink="true">https://junsangkwon.tistory.com/58</guid>
      <comments>https://junsangkwon.tistory.com/58#entry58comment</comments>
      <pubDate>Mon, 13 Feb 2023 19:15:50 +0900</pubDate>
    </item>
    <item>
      <title>[iOS] Delegate Pattern</title>
      <link>https://junsangkwon.tistory.com/57</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;정의&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위임자를 갖고 있는 객체가 다른 객체에게 일을 위임하는 형태의 디자인 패턴&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;패턴 요소&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;delegate를 필요로 하는 인스턴스 (UITableView)&lt;/li&gt;
&lt;li&gt;delegate 요구사항을 정의한 프로토콜 (UITableViewDelegate)&lt;/li&gt;
&lt;li&gt;delegate로서 동작하는 인스턴스 (UIViewController)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;사용하는 이유&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;UI요소(TableView)에서 Delegate 패턴을 사용하는 이유
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Cell이 탭되었을 때 어떤 행동을 할지는 상황에 따라 다르므로 개발자가 코드를 작성해야함&lt;/li&gt;
&lt;li&gt;개발자가 UI요소의 내부 코드를 수정할 수 없음&lt;/li&gt;
&lt;li&gt;따라서 다른 객체에서 해당 코드를 작성한 뒤, 테이블 뷰가 그 객체의 코드를 호출해줘야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;커스텀으로 Delegate 패턴을 사용하는 이유
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;코드의 유연성과 재사용성을 높일 수 있음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;만약 delegate 패턴을 사용하지 않고 처리한다면, 이 기능이 필요한 객체마다 직접 구현을 해서 넘겨줘야함 (상황에 따라서 어떻게 처리할지 다르기 때문)&lt;/li&gt;
&lt;li&gt;사용한다면, 가지고 있는 delegate를 통해서 시키기만 하면 됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>iOS Programming</category>
      <author>dev-Jun</author>
      <guid isPermaLink="true">https://junsangkwon.tistory.com/57</guid>
      <comments>https://junsangkwon.tistory.com/57#entry57comment</comments>
      <pubDate>Sun, 12 Feb 2023 18:05:24 +0900</pubDate>
    </item>
    <item>
      <title>[파이썬] 리스트 요소 제거</title>
      <link>https://junsangkwon.tistory.com/56</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬에서 리스트의 요소를 제거하는 방법을 알아보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. 인덱스로 제거&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;(1) del&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;del 리스트명 [인덱스]&lt;/h4&gt;
&lt;pre id=&quot;code_1655970580453&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;nums = [1, 2, 3, 4]

del nums[2]
print(nums)
# [1, 2, 4]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;(2) pop&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;리스트명.pop(인덱스)&lt;/h4&gt;
&lt;pre id=&quot;code_1655970638178&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;nums = [1, 2, 3, 4]

nums.pop(2)
print(nums)
# [1, 2, 4]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pop 안에 인덱스를 적지 않으면 자동으로 -1이 들어가서 맨 뒤의 요소가 사라지게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. 값으로 제거&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;(1) remove&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;리스트명.remove(값)&lt;/h4&gt;
&lt;pre id=&quot;code_1655970787285&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;nums = [1, 2, 3, 4, 2]

nums.remove(2)
print(nums)
# [1, 3, 4, 2]&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1655970940650&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;nums = [1, 2, 3, 4, 2]

while 2 in nums:
    nums.remove(2)

print(nums)
# [1, 3, 4]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같은 방식으로 해당 값을 가진 모든 요소를 삭제 할 수 있습니다.&lt;/p&gt;</description>
      <category>Algorithm</category>
      <author>dev-Jun</author>
      <guid isPermaLink="true">https://junsangkwon.tistory.com/56</guid>
      <comments>https://junsangkwon.tistory.com/56#entry56comment</comments>
      <pubDate>Thu, 23 Jun 2022 16:56:10 +0900</pubDate>
    </item>
    <item>
      <title>[파이썬] 프로그래머스 - [1차] 프렌즈4블록</title>
      <link>https://junsangkwon.tistory.com/55</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;문제 설명&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-06-22 오후 11.21.25.png&quot; data-origin-width=&quot;1312&quot; data-origin-height=&quot;748&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsX8ws/btrFvVdxl8v/OaffzbWZAoWR1YZkuUSzk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsX8ws/btrFvVdxl8v/OaffzbWZAoWR1YZkuUSzk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsX8ws/btrFvVdxl8v/OaffzbWZAoWR1YZkuUSzk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsX8ws%2FbtrFvVdxl8v%2FOaffzbWZAoWR1YZkuUSzk0%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;1312&quot; height=&quot;748&quot; data-filename=&quot;스크린샷 2022-06-22 오후 11.21.25.png&quot; data-origin-width=&quot;1312&quot; data-origin-height=&quot;748&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-06-22 오후 11.21.55.png&quot; data-origin-width=&quot;1368&quot; data-origin-height=&quot;668&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ccoQpe/btrFvWwIjrG/T15eKiZa38vEa9kRawOHL1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ccoQpe/btrFvWwIjrG/T15eKiZa38vEa9kRawOHL1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ccoQpe/btrFvWwIjrG/T15eKiZa38vEa9kRawOHL1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FccoQpe%2FbtrFvWwIjrG%2FT15eKiZa38vEa9kRawOHL1%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;1368&quot; height=&quot;668&quot; data-filename=&quot;스크린샷 2022-06-22 오후 11.21.55.png&quot; data-origin-width=&quot;1368&quot; data-origin-height=&quot;668&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-06-22 오후 11.22.15.png&quot; data-origin-width=&quot;1176&quot; data-origin-height=&quot;624&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/u6WdB/btrFvqSmN3z/6pUelCljv9x02aRCyYLf7k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/u6WdB/btrFvqSmN3z/6pUelCljv9x02aRCyYLf7k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/u6WdB/btrFvqSmN3z/6pUelCljv9x02aRCyYLf7k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fu6WdB%2FbtrFvqSmN3z%2F6pUelCljv9x02aRCyYLf7k%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;1176&quot; height=&quot;624&quot; data-filename=&quot;스크린샷 2022-06-22 오후 11.22.15.png&quot; data-origin-width=&quot;1176&quot; data-origin-height=&quot;624&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-06-22 오후 11.22.32.png&quot; data-origin-width=&quot;1196&quot; data-origin-height=&quot;624&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cqBOJJ/btrFsYC4lAz/r3GKZJ1LFYqO59MuONkgU0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cqBOJJ/btrFsYC4lAz/r3GKZJ1LFYqO59MuONkgU0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cqBOJJ/btrFsYC4lAz/r3GKZJ1LFYqO59MuONkgU0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcqBOJJ%2FbtrFsYC4lAz%2Fr3GKZJ1LFYqO59MuONkgU0%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;1196&quot; height=&quot;624&quot; data-filename=&quot;스크린샷 2022-06-22 오후 11.22.32.png&quot; data-origin-width=&quot;1196&quot; data-origin-height=&quot;624&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-06-22 오후 11.23.09.png&quot; data-origin-width=&quot;1116&quot; data-origin-height=&quot;482&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Q4voH/btrFsZhF49V/sotQ2eHUb61VKH7NYi5X91/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Q4voH/btrFsZhF49V/sotQ2eHUb61VKH7NYi5X91/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Q4voH/btrFsZhF49V/sotQ2eHUb61VKH7NYi5X91/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQ4voH%2FbtrFsZhF49V%2FsotQ2eHUb61VKH7NYi5X91%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;1116&quot; height=&quot;482&quot; data-filename=&quot;스크린샷 2022-06-22 오후 11.23.09.png&quot; data-origin-width=&quot;1116&quot; data-origin-height=&quot;482&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-06-22 오후 11.23.30.png&quot; data-origin-width=&quot;1372&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/coJjF5/btrFvVdxr2Z/4DWsSeMjHR9DK8yEjh7BC1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/coJjF5/btrFvVdxr2Z/4DWsSeMjHR9DK8yEjh7BC1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/coJjF5/btrFvVdxr2Z/4DWsSeMjHR9DK8yEjh7BC1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcoJjF5%2FbtrFvVdxr2Z%2F4DWsSeMjHR9DK8yEjh7BC1%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;1372&quot; height=&quot;1024&quot; data-filename=&quot;스크린샷 2022-06-22 오후 11.23.30.png&quot; data-origin-width=&quot;1372&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;처음 생각한 풀이&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 게임판의 값이 '*'이 아니라면, 해당 좌표, 좌, 하, 대각(왼아) 좌표를 탐색하고 값이 모두 같다면 그 좌표들을 리스트에 담는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 사라질 좌표들의 중복을 없애고, 그 좌표의 값을 '*'로 대체한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. '*' 위의 문자들을 밑으로 내리고, 사라질 좌표들이 하나도 없을 때까지 1부터 반복한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;문제점&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;풀이 방식을 떠올리는 건 쉽지만, 좌표의 값을 '*'로 대체하고, '*' 위의 문자를 밑으로 내리는 걸 구현하는게 어려웠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1655908297166&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;for i in range(n):
    for j in range(m-1):
    	if board_list[j][i] != '*' and board_list[j+1][i] == '*':
     	    board_list[j][i], board_list[j+1][i] = board_list[j+1][i], board_list[j][i]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1) 처음엔 단순히 현재 좌표의 값이 '*'이 아니고, 바로 밑 좌표의 값이 '*'이면 값을 바꾸라는 식으로 구현하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2) 그러나 이럴경우엔&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;T&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;T&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;C&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;*&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; -&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; *&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; C&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;A&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;밑에있는 C만 내려가고, T는 밑 좌표가 '*'이 아니었기 때문에 그대로 있게 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1655908607197&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;for i in range(n):
    for j in range(m-1, 0, -1):
        if board_list[j][i] == '*' and board_list[j-1][i] != '*':
            board_list[j][i], board_list[j-1][i] = board_list[j-1][i], board_list[j][i]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3) 2번의 경우를 커버하기 위해서 밑에서 부터 for문을 도는 식으로 변경하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4) 그러나 이 경우에도&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;T&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;*&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;C&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;T&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; -&amp;gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; C&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; *&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;A&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 칸씩 밖에 안내려가게 됩니다. 그렇기 때문에 여기에 while문을 추가하여 내리는 것을 해결 하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;코드&lt;/h3&gt;
&lt;pre id=&quot;code_1655909287673&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 붙어있는 4개의 블록이 있는지 확인 후, 있다면 좌표를 가져옴
def search(bi, bj, board_list, m, n):
    di = [1, 1, 0]  # 하, 대각(오아), 우 탐색시 사용
    dj = [0, 1, 1]  # 하, 대각(오아), 우 탐색시 사용 
    is_valid = True # 유효하지 않을 때 거르는 bool 변수
    coor = []
    for k in range(3):
        ki = bi + di[k]
        kj = bj + dj[k]
        if ki &amp;gt;= m or kj &amp;gt;= n or board_list[ki][kj] != board_list[bi][bj]:
            is_valid = False
            break
    if is_valid:
        coor.append([bi, bj])
        for k in range(3):
            ki = bi + di[k]
            kj = bj + dj[k]
            coor.append([ki, kj])
    
    return coor
    
def solution(m, n, board):
    answer = 0          # 최종 '*'의 개수
    board_list = []     # 문자열 자체는 인덱스로 해당값을 수정할 수 없기 때문에 list로 변경
    vanish_coor = []    # 사라질 좌표
    
    # 문자열을 담은 list를 2차원 list로 수정
    for i in range(m):
        board_list.append(list(board[i]))

    while True:
        # 4개의 블록 탐색하기
        for i in range(m):
            for j in range(n):
                if board_list[i][j] != '*':
                    vanish_coor += search(i, j, board_list, m, n)
        
        # 사라질 블록이 없다면 종료
        if len(vanish_coor) == 0:
            break
                
        # 사라질 블록에 '*' 대입
        for i in range(len(vanish_coor)):
            board_list[vanish_coor[i][0]][vanish_coor[i][1]] = '*'
    
        # '*' 위의 문자들 다시 밑으로 내려오게 수정
        for i in range(n):
            for j in range(m-1, 0, -1):
                if board_list[j][i] == '*' and board_list[j-1][i] != '*':
                    index = j
                    while index &amp;lt;= m - 1 and board_list[index][i] == '*':
                        board_list[index][i], board_list[index-1][i] = board_list[index-1][i], board_list[index][i]
                        index += 1
        
        # 사라질 블록 좌표 클리어
        vanish_coor.clear()
        
    # '*'의 개수 세기
    for i in range(m):
        for j in range(n):
            if board_list[i][j] == '*':
                answer += 1
            
    return answer&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Algorithm</category>
      <author>dev-Jun</author>
      <guid isPermaLink="true">https://junsangkwon.tistory.com/55</guid>
      <comments>https://junsangkwon.tistory.com/55#entry55comment</comments>
      <pubDate>Wed, 22 Jun 2022 23:48:15 +0900</pubDate>
    </item>
    <item>
      <title>[파이썬] 프로그래머스 - 방금그곡</title>
      <link>https://junsangkwon.tistory.com/54</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;문제 설명&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-06-22 오후 10.46.10.png&quot; data-origin-width=&quot;2252&quot; data-origin-height=&quot;728&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cc5goF/btrFqcg3v53/L1Ys8csakLYJ11aD9Akzs0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cc5goF/btrFqcg3v53/L1Ys8csakLYJ11aD9Akzs0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cc5goF/btrFqcg3v53/L1Ys8csakLYJ11aD9Akzs0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcc5goF%2FbtrFqcg3v53%2FL1Ys8csakLYJ11aD9Akzs0%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;2252&quot; height=&quot;728&quot; data-filename=&quot;스크린샷 2022-06-22 오후 10.46.10.png&quot; data-origin-width=&quot;2252&quot; data-origin-height=&quot;728&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-06-22 오후 10.46.54.png&quot; data-origin-width=&quot;1784&quot; data-origin-height=&quot;960&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dmyZR4/btrFq8ZN8Tb/O5Jn4uu8sbQ9acpNlrDUp1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dmyZR4/btrFq8ZN8Tb/O5Jn4uu8sbQ9acpNlrDUp1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dmyZR4/btrFq8ZN8Tb/O5Jn4uu8sbQ9acpNlrDUp1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdmyZR4%2FbtrFq8ZN8Tb%2FO5Jn4uu8sbQ9acpNlrDUp1%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;1784&quot; height=&quot;960&quot; data-filename=&quot;스크린샷 2022-06-22 오후 10.46.54.png&quot; data-origin-width=&quot;1784&quot; data-origin-height=&quot;960&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;처음 생각한 풀이&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. musicinfos에서 시간을 추출해서 몇 분 동안 연주됐는지 계산한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 계산한 시간만큼 악보를 늘려준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. m이 musicinfos에 포함되는지 확인한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 기타 다른 조건들을 만족 시킨다. &lt;span style=&quot;background-color: #263747; color: #b2c0cc;&quot;&gt;(라디오에서 재생된 시간이 제일 긴 음악 제목을 반환한다. 재생된 시간도 같을 경우 먼저 입력된 음악 제목을 반환한다)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;결과&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런식으로 간단하게 생각하고 풀었는데 계속 테스트 케이스 3이 통과가 되지 않았습니다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고 보니 m과 musicinfo의 악보를 비교할 때, C#인데 C라고 생각하고 풀고 있었어서 안됬던 거였습니다.&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;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;다시 생각한 풀이&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. m을 입력받았을 때, 문자열의 뒷 인덱스 값이 '#'이면 합쳐서 새로운 리스트에 추가한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. musicinfos에서 시간을 추출해서 몇 분 동안 연주됐는지 계산한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 계산한 시간만큼 악보를 늘려준다. (늘려 줄 때도 '#'을 고려해줌)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. m_list를 늘려준 악보와 비교를 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. 기타 다른 조건들을 만족시킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;코드&lt;/h3&gt;
&lt;pre id=&quot;code_1655906837179&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(m, musicinfos):
    answers = []         # 정답 배열
    m_list = []          # '#'을 고려해서 새로 만든 멜로디 리스트
    new_music_infos = [] # 사용하기 쉽게 만든 musicinfos 리스트
    
    # m_list 만들기
    for i in range(len(m) - 1):
            if m[i+1] == '#':
                m_list.append(m[i] + '#')
            elif m[i] == '#':
                if i+1 == len(m) - 1:
                    m_list.append(m[i+1])
                else:
                    continue
            elif m[i+1] != '#' and i+1 == len(m) - 1:
                m_list.append(m[i])
                m_list.append(m[i+1])
            else:
                m_list.append(m[i])
    
    # 시간 계산하기
    for n in range(len(musicinfos)):
        musicinfo = musicinfos[n].split(',')
        music_sheet = []
        total_music = []
        
        hour1, hour2 = musicinfo[0][0:2], musicinfo[1][0:2]
        min1, min2 = musicinfo[0][3:], musicinfo[1][3:]
        play_hour, play_minute = int(hour2) - int(hour1), int(min2) - int(min1)

        if play_minute &amp;lt; 0:
            play_hour -= 1
            play_minute += 60
        for h in range(play_hour):
            play_minute += 60
        
        # 재생되었던 악보 계산하기
        for i in range(len(musicinfo[3]) - 1):
            if musicinfo[3][i+1] == '#':
                music_sheet.append(musicinfo[3][i] + '#')
            elif musicinfo[3][i] == '#':
                if i+1 == len(musicinfo[3]) - 1:
                    music_sheet.append(musicinfo[3][i+1])
                else:
                    continue
            elif musicinfo[3][i+1] != '#' and i+1 == len(musicinfo[3]) - 1:
                music_sheet.append(musicinfo[3][i])
                music_sheet.append(musicinfo[3][i+1])
            else:
                music_sheet.append(musicinfo[3][i])
        
        repeat_count = play_minute // len(music_sheet)
        repeat_remain = play_minute % len(music_sheet)
        
        for i in range(repeat_count):
            total_music += music_sheet
            
        for i in range(repeat_remain):
            total_music.append(music_sheet[i])
        
        # 사용하기 좋게 [음악 이름, 총 악보, 재생 시간, 들어온 순서] 를 담는다.
        new_music_infos.append([musicinfo[2], total_music, play_minute, n])
            
    # 총 악보와 기억한 멜로디를 비교
    for i in range(len(new_music_infos)):
        tmp_list = []
        index = 0
        for j in range(len(new_music_infos[i][1])):
            if index &amp;gt;= len(m_list):
                break
            if m_list[index] == new_music_infos[i][1][j]:
                tmp_list.append(m_list[index])
                index += 1
            else:
                tmp_list.clear()
                index = 0
                if m_list[index] == new_music_infos[i][1][j]:
                    tmp_list.append(m_list[index])
                    index += 1
        
        # 조건이 일치하는 음악이 여러 개일 때를 대비해서 여러 조건 추가
        if m_list == tmp_list:
            answers.append([new_music_infos[i][0], new_music_infos[i][2], new_music_infos[i][3]]) 

    if len(answers) == 0:
        return &quot;(None)&quot;
    else:
        answers.sort(key=lambda x: (-x[1], x[2]))
        return answers[0][0]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Algorithm</category>
      <author>dev-Jun</author>
      <guid isPermaLink="true">https://junsangkwon.tistory.com/54</guid>
      <comments>https://junsangkwon.tistory.com/54#entry54comment</comments>
      <pubDate>Wed, 22 Jun 2022 23:08:08 +0900</pubDate>
    </item>
    <item>
      <title>[파이썬] 프로그래머스 - [1차] 뉴스 클러스터링</title>
      <link>https://junsangkwon.tistory.com/53</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;문제 설명&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-06-22 오후 10.09.40.png&quot; data-origin-width=&quot;2262&quot; data-origin-height=&quot;1198&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b73rzb/btrFwwdp0GL/DNX5m1oSvEL0Pkt1vBZXNK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b73rzb/btrFwwdp0GL/DNX5m1oSvEL0Pkt1vBZXNK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b73rzb/btrFwwdp0GL/DNX5m1oSvEL0Pkt1vBZXNK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb73rzb%2FbtrFwwdp0GL%2FDNX5m1oSvEL0Pkt1vBZXNK%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;2262&quot; height=&quot;1198&quot; data-filename=&quot;스크린샷 2022-06-22 오후 10.09.40.png&quot; data-origin-width=&quot;2262&quot; data-origin-height=&quot;1198&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-06-22 오후 10.10.11.png&quot; data-origin-width=&quot;2242&quot; data-origin-height=&quot;938&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/n9f0l/btrFufDNWpf/KURwc5Z1e7IXcq2XIIEoA0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/n9f0l/btrFufDNWpf/KURwc5Z1e7IXcq2XIIEoA0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/n9f0l/btrFufDNWpf/KURwc5Z1e7IXcq2XIIEoA0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fn9f0l%2FbtrFufDNWpf%2FKURwc5Z1e7IXcq2XIIEoA0%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;2242&quot; height=&quot;938&quot; data-filename=&quot;스크린샷 2022-06-22 오후 10.10.11.png&quot; data-origin-width=&quot;2242&quot; data-origin-height=&quot;938&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;h4 data-ke-size=&quot;size20&quot;&gt;생각한 문제 풀이법&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. str1 집합, str2 집합을 구현한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 교집합과 합집합을 규칙에 맞게 구현한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 다중 원소 규칙을 지키기 위해서 교집합과 합집합을 만들 때 겹치는 값의 최소 빈도 값은 교집합에 넣고, 최다 빈도 값은 합집합에 넣는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 빈도 값을 더해서 집합의 크기를 구해 계산한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1655903691172&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(str1, str2):
    # 규칙 : 대문자와 소문자 차이는 무시한다.
    str1 = str1.lower()
    str2 = str2.lower()
    str1_set = []           # str1의 집합
    str2_set = []           # str2의 집합
    intersection = []       # 교집합
    union = []              # 합집합
    previous_word_i = []    # 교집합 구할 때, 중복 방지
    previous_word_u = []    # 합집합 구할 때, 중복 방지
    intersection_count = 0  # 교집합 크기
    union_count = 0         # 합집합 크기
    
    # 집합을 구하는 과정
    for i in range(len(str1)-1):
        if str1[i].isalpha() and str1[i+1].isalpha():
            str1_set.append(str1[i] + str1[i+1])
    
    for i in range(len(str2)-1):
        if str2[i].isalpha() and str2[i+1].isalpha():
            str2_set.append(str2[i] + str2[i+1])

    # 집합 두개가 모두 공집합일 경우
    if len(str1_set) == 0 and len(str2_set) == 0:
        return 65536
    # 둘 중 작은 집합을 str1_set으로 설정
    elif len(str1_set) &amp;gt; len(str2_set):
        str1_set, str2_set = str2_set, str1_set

    # 교집합을 구하는 과정
    for i in range(len(str1_set)):
        if str1_set[i] in str2_set:
            if str1_set[i] in previous_word_i:
                continue
            str1_count = str1_set.count(str1_set[i])
            str2_count = str2_set.count(str1_set[i])
            intersection.append([str1_set[i], min(str1_count, str2_count)])
            previous_word_i.append(str1_set[i])

    # 합집합을 구하는 과정
    for i in range(len(str1_set)):
        if str1_set[i] in str2_set:
            if str1_set[i] in previous_word_u:
                continue
            str1_count = str1_set.count(str1_set[i])
            str2_count = str2_set.count(str1_set[i])
            union.append([str1_set[i], max(str1_count, str2_count)])
            previous_word_u.append(str1_set[i])
        else:
            union.append([str1_set[i], 1])
    
    
    for i in range(len(str2_set)):
        if str2_set[i] not in previous_word_u:
            union.append([str2_set[i], 1])
    
    # 교집합 크기 구하기
    for i in range(len(intersection)):
        intersection_count += intersection[i][1]
    
    # 합집합 크기 구하기
    for i in range(len(union)):
        union_count += union[i][1]    
    
    return int(intersection_count / union_count * 65536)&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Algorithm</category>
      <author>dev-Jun</author>
      <guid isPermaLink="true">https://junsangkwon.tistory.com/53</guid>
      <comments>https://junsangkwon.tistory.com/53#entry53comment</comments>
      <pubDate>Wed, 22 Jun 2022 22:15:16 +0900</pubDate>
    </item>
    <item>
      <title>[파이썬] 프로그래머스 - 신고 결과 받기</title>
      <link>https://junsangkwon.tistory.com/52</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;문제 설명&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-06-22 오후 9.20.01.png&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;450&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cQwMgJ/btrFun23OuN/VidgCPJA5Q7CC009MiDwak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cQwMgJ/btrFun23OuN/VidgCPJA5Q7CC009MiDwak/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cQwMgJ/btrFun23OuN/VidgCPJA5Q7CC009MiDwak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcQwMgJ%2FbtrFun23OuN%2FVidgCPJA5Q7CC009MiDwak%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1600&quot; height=&quot;450&quot; data-filename=&quot;스크린샷 2022-06-22 오후 9.20.01.png&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;450&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-06-22 오후 9.20.49.png&quot; data-origin-width=&quot;1692&quot; data-origin-height=&quot;1078&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NCqjA/btrFuerm1st/QDrGPZbj1jIaWDdL1ZARw1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NCqjA/btrFuerm1st/QDrGPZbj1jIaWDdL1ZARw1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NCqjA/btrFuerm1st/QDrGPZbj1jIaWDdL1ZARw1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNCqjA%2FbtrFuerm1st%2FQDrGPZbj1jIaWDdL1ZARw1%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;1692&quot; height=&quot;1078&quot; data-filename=&quot;스크린샷 2022-06-22 오후 9.20.49.png&quot; data-origin-width=&quot;1692&quot; data-origin-height=&quot;1078&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-06-22 오후 9.21.47.png&quot; data-origin-width=&quot;1870&quot; data-origin-height=&quot;984&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b746Rm/btrFtkZV5oW/1ALBbITFktXRjc3pnmyl30/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b746Rm/btrFtkZV5oW/1ALBbITFktXRjc3pnmyl30/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b746Rm/btrFtkZV5oW/1ALBbITFktXRjc3pnmyl30/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb746Rm%2FbtrFtkZV5oW%2F1ALBbITFktXRjc3pnmyl30%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;1870&quot; height=&quot;984&quot; data-filename=&quot;스크린샷 2022-06-22 오후 9.21.47.png&quot; data-origin-width=&quot;1870&quot; data-origin-height=&quot;984&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2022-06-22 오후 9.22.23.png&quot; data-origin-width=&quot;1720&quot; data-origin-height=&quot;242&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KteSZ/btrFuC6KDR7/otPc5PHOQ9BMA5LpvkLrV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KteSZ/btrFuC6KDR7/otPc5PHOQ9BMA5LpvkLrV0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KteSZ/btrFuC6KDR7/otPc5PHOQ9BMA5LpvkLrV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKteSZ%2FbtrFuC6KDR7%2FotPc5PHOQ9BMA5LpvkLrV0%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;1720&quot; height=&quot;242&quot; data-filename=&quot;스크린샷 2022-06-22 오후 9.22.23.png&quot; data-origin-width=&quot;1720&quot; data-origin-height=&quot;242&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;처음 생각한 풀이&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 유저의 신고 당한 횟수를 담는 딕셔너리를 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. &lt;span&gt;report를 돌면서&lt;span&gt; 신고 당한 횟수를 딕셔너리에 저장하고,&amp;nbsp;&lt;/span&gt;&lt;/span&gt;횟수가 k번 이상일 경우, 블랙 리스트에 추가한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. report를 다시 돌면서 신고 당한 사람이 블랙 리스트에 속해 있다면, 그 사람을 신고 한사람을 다시 신고자 리스트에 추가한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. id_list를 돌면서 해당 이름이 신고자 리스트에 몇개 있는지 count 해서 세본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;결과&lt;/h4&gt;
&lt;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;report의 길이가 200000 이하였기 때문에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;report를 돌면서 신고 당한 사람이 블랙리스트에 속해 있는지 확인하는 부분에서 시간이 오바된 것 같았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;다시 생각한 풀이&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선, 신고 당한 사람이 블랙 리스트에 속해 있는지 확인 하는 과정을 없애고 싶었기 때문에,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에 횟수를 담기 위해서 돌 때, 신고자까지 기억을 해야겠다고 생각했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 딕셔너리를 하나 더 추가했습니다!&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. 유저의 신고 당한 횟수를 담는 딕셔너리, 해당 유저를 신고 한 유저들을 담는 딕셔너리를 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;report를 돌면서&lt;span&gt;&lt;span&gt;&amp;nbsp;유저의&amp;nbsp;&lt;/span&gt;신고 당한 횟수를 딕셔너리에 저장하고, 그 유저를 신고한 신고자들 또한 딕셔너리에 리스트 형태로 저장한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 그렇게 횟수가 k번이상일 경우 블랙 리스트에 추가한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 받을 결과 메일의 수를 담는 딕셔너리를 하나 더 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;5. 유저를 신고한 신고자 정보가 담긴 딕셔너리에 &lt;span&gt;블랙 리스트 값(키)을&lt;/span&gt; 넣어서 &lt;/span&gt;&lt;span&gt;신고자들이 담긴 리스트를 돌면서 받을 메일 수를 count한다. (조금 복잡하게 푼듯)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;6. 정답 배열에 id_list 순서대로 받을 결과 메일의 수를 담은 딕셔너리에 접근해서 메일 수를 추가한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1655902330019&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(id_list, report, k):
    report_dic = {}     # 신고 횟수를 담은 딕셔너리
    mail_dic = {}       # 해당 유저를 신고한 신고자를 담은 딕셔너리
    mail_count_dic = {} # 받을 결과 메일 수를 담은 딕셔너리
    answer = []         # 정답 리스트
    black_list = []     # 차단당한 유저를 담은 리스트
    
    # 중복 신고 제거
    report = list(set(report))

    # 딕셔너리 초기화
    for i in range(len(id_list)):
        report_dic[id_list[i]] = 0
        mail_dic[id_list[i]] = []
        mail_count_dic[id_list[i]] = 0
    
    # 신고 당한 횟수 기록, 신고자도 같이 기록
    for i in range(len(report)):
        info = report[i].split(&quot; &quot;)
        report_dic[info[1]] += 1
        mail_dic[info[1]].append(info[0])
        if report_dic[info[1]] &amp;gt;= k:
            black_list.append(info[1])
    
    black_list = list(set(black_list))
    
    # 신고자가 받을 메일 횟수 계산
    for black in black_list:
        for i in range(len(mail_dic[black])):
            mail_count_dic[mail_dic[black][i]] += 1
    
    for i in range(len(id_list)):
        answer.append(mail_count_dic[id_list[i]])
        
    return answer&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Algorithm</category>
      <author>dev-Jun</author>
      <guid isPermaLink="true">https://junsangkwon.tistory.com/52</guid>
      <comments>https://junsangkwon.tistory.com/52#entry52comment</comments>
      <pubDate>Wed, 22 Jun 2022 21:53:02 +0900</pubDate>
    </item>
  </channel>
</rss>