<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>개발을개발로할태니</title>
    <link>https://delightpip.tistory.com/</link>
    <description>세상에는 나쁜 색깔도,

잘못된 색깔도 없어.

그저 좋아하는 색깔로만

물들일거야  </description>
    <language>ko</language>
    <pubDate>Thu, 9 Apr 2026 01:37:29 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>태애니</managingEditor>
    <image>
      <title>개발을개발로할태니</title>
      <url>https://tistory1.daumcdn.net/tistory/4193702/attach/71e5e417751142618a7a07ad9603799b</url>
      <link>https://delightpip.tistory.com</link>
    </image>
    <item>
      <title>왜 UI 처리는 MainThread 에서 처리하는가?</title>
      <link>https://delightpip.tistory.com/394</link>
      <description>&lt;h1 style=&quot;color: #000000; text-align: start;&quot; data-end=&quot;114&quot; data-start=&quot;80&quot;&gt;&amp;nbsp;&lt;/h1&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;나는 이 질문에 대해서 딱히 생각해본적이 없었다..!&lt;br&gt;&amp;nbsp;&lt;br&gt;마치 그냥 밥 먹으면 이닦아야징 하는 것처럼 + 엄마가 자꾸 밥 먹으면 이닦으라 하듯이 알아서 XCode 에서 알려주니까(으휴ㅠ 으휴!)&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;공부하는 내용을 공유하는 시간이 있었는데, 이때 받은 질문 덕분에 어? 그러네.. 왜 밥 먹고 이 닦는 거지? 라는 생각이 그제야 든 것이다.&lt;br&gt;&amp;nbsp;&lt;br&gt;나는 생각해보다가&lt;br&gt;GUI 처리 - 렌더링이 필요하다 + 애니메이션도 있지... + GPU를 처리해야한다 이런 생각에&lt;br&gt;UI 처리 자체가 너무 무거워서..? 라고 생각했다.&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;840&quot; data-origin-height=&quot;582&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cMSdcc/btsPXAxlq1K/I9m4X6KVwsJpDDVC1iZYr1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cMSdcc/btsPXAxlq1K/I9m4X6KVwsJpDDVC1iZYr1/img.png&quot; data-alt=&quot;아닌데요!!&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cMSdcc/btsPXAxlq1K/I9m4X6KVwsJpDDVC1iZYr1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcMSdcc%2FbtsPXAxlq1K%2FI9m4X6KVwsJpDDVC1iZYr1%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;200&quot; height=&quot;139&quot; data-origin-width=&quot;840&quot; data-origin-height=&quot;582&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;아닌데요!!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;&lt;b&gt;완전 정반대였다.&lt;/b&gt;&lt;br&gt;&amp;nbsp;&lt;br&gt;UI 처리라는 것 자체는 무거운 처리가 아니다&lt;b&gt;.&lt;/b&gt;&lt;br&gt;&lt;b&gt;내가 생각하는 렌더링, 애니메이션 처리는 다른 곳에서 하고 있다.&lt;/b&gt;&lt;br&gt;&lt;b&gt;Render Server&lt;/b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;라는 별도의 프로세스에서 처리된다는 것..&lt;/span&gt;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;좀 더 정리를 해보자면..&lt;/p&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;화면에 어떤 UI가 진행될 때 이런 순서로 진행된다.&lt;/p&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. Main Thread: 작업 준비&lt;/h3&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;메인 스레드는 UI 이벤트 처리, 레이아웃 계산, 그리고 레이어 트리(Layer Tree)를 업데이트함.&lt;/p&gt;&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;&lt;li&gt;&lt;b&gt;Layer Tree 업데이트&lt;/b&gt;:&amp;nbsp;UIView의&amp;nbsp;frame,&amp;nbsp;bounds,&amp;nbsp;backgroundColor&amp;nbsp;같은 속성을 변경하면, 이 변경 사항들이 해당 뷰의 백킹 레이어인 &lt;b&gt;CALayer&lt;/b&gt;에 반영됨.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Commit Transaction&lt;/b&gt;: 개발자가 애니메이션을 설정하거나 레이어의 속성을 변경하면, Core Animation은 이러한 변경 사항들을&amp;nbsp;&lt;b&gt;트랜잭션&lt;/b&gt;으로 묶어준다. 이 트랜잭션이&amp;nbsp;&lt;b&gt;렌더 서버&lt;/b&gt;로 전송되고, 이 과정을 커밋(commit) 이라고 한다. 보통&amp;nbsp;&lt;b&gt;메인 스레드&lt;/b&gt;의 RunLoop 주기에 맞춰 자동으로 발생한다.&lt;/li&gt;&lt;/ol&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. Render Server: 렌더링 지시&amp;nbsp;&lt;/h3&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;i&gt;Render Server는 iOS 시스템의 중요한 부분으로,&lt;/i&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;i&gt;&amp;nbsp;&lt;/i&gt;&lt;/span&gt;&lt;i&gt;&lt;b&gt;앱과는 완전히 분리된 별도의 프로세스&lt;/b&gt;&lt;/i&gt;.&lt;/p&gt;&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;&lt;li&gt;&lt;b&gt;트랜잭션 수신&lt;/b&gt;: 렌더 서버는 앱의 메인 스레드로부터 커밋된 레이어 트리를 수신한다.&lt;/li&gt;&lt;li&gt;&lt;b&gt;GPU 명령 변환&lt;/b&gt;: 렌더 서버는 수신한 레이어 데이터를 바탕으로 GPU가 이해할 수 있는 GPU 명령어(GPU Commands)를 생성해준다. 예를 들어,&amp;nbsp;backgroundColor&amp;nbsp;속성은 GPU의&amp;nbsp;clear&amp;nbsp;명령으로,&amp;nbsp;transform은&amp;nbsp;matrix multiplication&amp;nbsp;명령으로 변환된다.&lt;/li&gt;&lt;li&gt;&lt;b&gt;GPU 전달&lt;/b&gt;: 이렇게 생성된 명령어는 Metal(또는 OpenGL ES)과 같은 그래픽 API를 통해 GPU로 전달.&lt;/li&gt;&lt;/ol&gt;&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. GPU: 최종 렌더링&lt;/h3&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;GPU는 렌더 서버가 넘겨준 명령어를 받아서 실제 렌더링 작업을 수행해준다.&lt;/p&gt;&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;&lt;li&gt;&lt;b&gt;레이어 렌더링&lt;/b&gt;: GPU는 각&amp;nbsp;CALayer를 개별적으로 렌더링해준다.&amp;nbsp;bounds,&amp;nbsp;backgroundColor,&amp;nbsp;contents&amp;nbsp;같은 속성이 여기서 처리된다.&lt;/li&gt;&lt;li&gt;&lt;b&gt;합성(Compositing)&lt;/b&gt;: 렌더링된 각 레이어는 GPU의 하드웨어 합성기(hardware compositor)를 이용해 최종 이미지로 합쳐진다. 이 과정에서&amp;nbsp;transform,&amp;nbsp;opacity,&amp;nbsp;shadow&amp;nbsp;같은 속성이 적용된다.&lt;/li&gt;&lt;li&gt;&lt;b&gt;화면 표시&lt;/b&gt;: 최종적으로 합성된 이미지는 화면의 프레임 버퍼에 쓰여지고, 디스플레이의&amp;nbsp;&lt;b&gt;수직 동기화(V-Sync)&lt;/b&gt;&amp;nbsp;주기에 맞춰 화면에 보여준다.&lt;/li&gt;&lt;/ol&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&lt;b&gt;결론적으로!!! UI 라는 것은 이런 것을 말한다&lt;/b&gt;&lt;br&gt;- UILabel에 텍스트 바꾸기 → 그냥 속성 값 세팅 정도&lt;br&gt;- 버튼 색상 바꾸기 → 속성 플래그만 변경&lt;br&gt;- “다음 프레임에 이 뷰 다시 그려야겠다~” 표시만 해두는 수준이 바로 UI 처리이고,&lt;br&gt;&amp;nbsp;&lt;br&gt;내가 생각 했던&amp;nbsp;실제 무거운 일(렌더링, 픽셀 그리기, GPU 처리)은 Core Animation이나 RenderThread가 뒤에서 하고 있었다.&lt;/p&gt;&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;그러고보니 MainThread 라는 말도 자주 쓰면서 정확한 정의를 몰랐다.&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;h4 data-ke-size=&quot;size20&quot;&gt;MainThread(메인 스레드)란?&lt;/h4&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;MainThread&lt;/b&gt;는 앱에서&amp;nbsp;&lt;b&gt;UI 이벤트와 화면 업데이트를 처리하는 주 스레드&lt;/b&gt;.&lt;br&gt;iOS, macOS, Android 등 대부분의 UI 프레임워크는&amp;nbsp;&lt;b&gt;UI 관련 작업은 메인 스레드에서만 안전하게 수행&lt;/b&gt;할 수 있도록 설계되어 있다.&lt;br&gt;&amp;nbsp;&lt;br&gt;그러니까!! 제일 중요하고, 제일 무겁고 중요한 처리를 하는 곳이 아니라&lt;br&gt;&lt;span style=&quot;color: #000000;&quot;&gt;애플리케이션에서&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;UI 이벤트 처리와 화면 업데이트를 담당 &lt;/b&gt;하고 있던 것.&lt;br&gt;&amp;nbsp;&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-end=&quot;491&quot; data-start=&quot;148&quot; data-ke-list-type=&quot;disc&quot;&gt; 
 &lt;li data-end=&quot;289&quot; data-start=&quot;148&quot;&gt;&lt;b&gt;역할&lt;/b&gt; 
  &lt;ol style=&quot;list-style-type: decimal;&quot; data-end=&quot;289&quot; data-start=&quot;161&quot; data-ke-list-type=&quot;decimal&quot;&gt; 
   &lt;li data-end=&quot;197&quot; data-start=&quot;161&quot;&gt;사용자 입력 이벤트 처리 (터치, 제스처, 키 입력 등)&lt;/li&gt; 
   &lt;li data-end=&quot;246&quot; data-start=&quot;200&quot;&gt;UI 요소(View, Label, Button 등) 속성 변경과 화면 갱신&lt;/li&gt; 
   &lt;li data-end=&quot;289&quot; data-start=&quot;249&quot;&gt;RunLoop를 통해 이벤트, 타이머, UI 렌더링 스케줄 관리&lt;/li&gt; 
  &lt;/ol&gt; &lt;/li&gt; 
 &lt;li data-end=&quot;476&quot; data-start=&quot;291&quot;&gt;&lt;b&gt;특징&lt;/b&gt; 
  &lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;476&quot; data-start=&quot;304&quot; data-ke-list-type=&quot;disc&quot;&gt; 
   &lt;li data-end=&quot;375&quot; data-start=&quot;304&quot;&gt;UI 작업은 MainThread에서만 안전하게 수행 가능 (UIKit / SwiftUI / Android View 모두)&lt;/li&gt; 
   &lt;li data-end=&quot;425&quot; data-start=&quot;378&quot;&gt;MainThread에서 무거운 작업을 실행하면 앱 UI가 멈추거나 버벅임 발생&lt;/li&gt; 
   &lt;li data-end=&quot;476&quot; data-start=&quot;428&quot;&gt;백그라운드 연산은 별도의 스레드에서 처리하고, 결과만 MainThread로 전달&lt;/li&gt; 
  &lt;/ul&gt; &lt;/li&gt; 
&lt;/ul&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;s&gt;&lt;br&gt;&lt;/s&gt;&lt;s&gt;엄마가...이 닦으라고...늘 알려줬었지요....&lt;/s&gt;&lt;/p&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot;&gt;&lt;code&gt;DispatchQueue.main.async {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.label.text = &quot;바ㅏㅏ꾸자&quot;
}&lt;/code&gt;&lt;/pre&gt;&lt;pre data-ke-type=&quot;codeblock&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot;&gt;&lt;code&gt;@MainActor
func updateUI() {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;label.text = &quot;변경될 값&quot;
}

Task {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;await updateUI()
}&lt;/code&gt;&lt;/pre&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;그럼 RunLoop 는 뭐지?&lt;br&gt;- RunLoop는 스레드 내부에서&amp;nbsp;&lt;b&gt;이벤트를 처리하고 스레드의 생명주기를 유지&lt;/b&gt;하는 구조체&lt;br&gt;- MainThread는&lt;u&gt; 앱 시작 시 자동으로 생성되는&lt;/u&gt;&lt;u&gt;&amp;nbsp;&lt;/u&gt;&lt;u&gt;&lt;b&gt;RunLoop를 갖고 있는 thread&lt;/b&gt;&lt;/u&gt;.&lt;/p&gt;&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;&lt;li&gt;Input Source 처리 (터치, 키 입력, 네트워크 이벤트 등)&lt;/li&gt;&lt;li&gt;Timer 처리&lt;/li&gt;&lt;li&gt;Deferred work 처리 (performSelector, DispatchQueue.main.async 작업)&lt;/li&gt;&lt;li&gt;UI 렌더링 요청 처리 (setNeedsDisplay, layout 업데이트)&lt;/li&gt;&lt;/ol&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;RunLoop는&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;Modes&lt;/b&gt;:&amp;nbsp;NSDefaultRunLoopMode,&amp;nbsp;UITrackingRunLoopMode,&amp;nbsp;NSRunLoopCommonModes&lt;/li&gt;&lt;li&gt;Mode에 따라 이벤트 큐가 다르게 처리되어, 스크롤 중 UI 업데이트, 타이머 등 충돌 방지한다.&lt;/li&gt;&lt;li&gt;RunLoop가 없으면 MainThread는 이벤트를 처리할 수 없고, 앱이 멈추게 되는 것이다.&lt;/li&gt;&lt;/ul&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;&lt;b&gt;RunLoop 관찰하려면??&lt;/b&gt;&lt;/p&gt;&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;&lt;li&gt;개발자용: Instruments → Main Thread Activity 확인&lt;/li&gt;&lt;li&gt;UI가 버벅이면 MainThread가 블로킹 상태인지 확인 가능&lt;/li&gt;&lt;/ul&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2526&quot; data-origin-height=&quot;1558&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dK9YfX/btsPYIPdv16/d9uvDNSBikFVBur17Zo3ak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dK9YfX/btsPYIPdv16/d9uvDNSBikFVBur17Zo3ak/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dK9YfX/btsPYIPdv16/d9uvDNSBikFVBur17Zo3ak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdK9YfX%2FbtsPYIPdv16%2Fd9uvDNSBikFVBur17Zo3ak%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;2526&quot; height=&quot;1558&quot; data-origin-width=&quot;2526&quot; data-origin-height=&quot;1558&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;br&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>iOS/SwiftUI</category>
      <category>MainThread</category>
      <category>SWiFT</category>
      <category>UI</category>
      <author>태애니</author>
      <guid isPermaLink="true">https://delightpip.tistory.com/394</guid>
      <comments>https://delightpip.tistory.com/394#entry394comment</comments>
      <pubDate>Wed, 20 Aug 2025 11:13:02 +0900</pubDate>
    </item>
    <item>
      <title>[Apple Developer Academy @ POSTECH] 챌린지1 회고 - 질문하는 법</title>
      <link>https://delightpip.tistory.com/393</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;504&quot; data-origin-height=&quot;954&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/88kYq/btsPIgrbj8y/4eOf0GJA3r7WwQjkeHhwyk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/88kYq/btsPIgrbj8y/4eOf0GJA3r7WwQjkeHhwyk/img.png&quot; data-alt=&quot;챌린지 내용이 상세히 보이는 건 다 숨겼어요.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/88kYq/btsPIgrbj8y/4eOf0GJA3r7WwQjkeHhwyk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F88kYq%2FbtsPIgrbj8y%2F4eOf0GJA3r7WwQjkeHhwyk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;757&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;504&quot; data-origin-height=&quot;954&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;i&gt;자세한 챌린지 과정은 적지 않았습니다.&lt;/i&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;&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;a href=&quot;https://education.apple.com&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://education.apple.com&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1754310584804&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;Education Community - Apple Education Community&quot; data-og-description=&quot;Join the professional learning hub for educators using Apple technology. Learn new skills and connect with others for collaboration and inspiration.&quot; data-og-host=&quot;education.apple.com&quot; data-og-source-url=&quot;https://education.apple.com&quot; data-og-url=&quot;https://education.apple.com&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/jBIuS/hyZuFurxca/VmUqY01Ax7CbRHodU6OGQk/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://education.apple.com&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://education.apple.com&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/jBIuS/hyZuFurxca/VmUqY01Ax7CbRHodU6OGQk/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&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;Education Community - Apple Education Community&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Join the professional learning hub for educators using Apple technology. Learn new skills and connect with others for collaboration and inspiration.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;education.apple.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Challenged Based Learning,&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;p data-ke-size=&quot;size16&quot;&gt;&quot;당신은 개발을 잘하는가?&quot; 라는 질문을 들었을 때&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당당히 &quot;네&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나에게 Question은 그런 존재였다.&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;p data-ke-size=&quot;size16&quot;&gt;질문하는 사고방식이 꽉꽉 막혀있었던 나는 처음 CBL을 경험했던 파운데이션 세션에서 과정을 따라가지 못하고 왜 자꾸 물음표를 다는 거지? 하며 혼란스러워했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이상해.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫날 세션을 하고 물음표 폭탄을 맞은 나는 머리가 터질 듯한 경험을 했었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇게 &lt;span&gt;Foundation Program&lt;/span&gt;&amp;nbsp;을 마치고도 다시 내가 Developer Academy 로 찾아간건&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아직 스스로에 대한 질문에 답을 하지 못해서가 아니였을까.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고, 좌절이 아니라 다시 Question 을 해볼 수 있는 힘이 생겨서가 아닐까?&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;&quot;개발을 잘 한다는 것은, 어떤 것을 말하는 걸까요?&quot;&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;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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1244&quot; data-origin-height=&quot;758&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bm6U8F/btsPFEAf6gt/GeLLLkaoqS0sOEAHqKDAV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bm6U8F/btsPFEAf6gt/GeLLLkaoqS0sOEAHqKDAV0/img.png&quot; data-alt=&quot;개명 완ㅎ_ㅎ&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bm6U8F/btsPFEAf6gt/GeLLLkaoqS0sOEAHqKDAV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbm6U8F%2FbtsPFEAf6gt%2FGeLLLkaoqS0sOEAHqKDAV0%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;1244&quot; height=&quot;758&quot; data-origin-width=&quot;1244&quot; data-origin-height=&quot;758&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;개명 완ㅎ_ㅎ&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Apple Developer Academy - Challenge 01&lt;/b&gt;&lt;/h4&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은 CBL 자체를 경험하고 배울 수 있는 기간이였다.&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;span style=&quot;color: #333333; text-align: start;&quot;&gt;운이 좋게&lt;span&gt; &lt;/span&gt;&lt;/span&gt;분위기가 참 좋았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모두 열정이 넘치고, 많은 발산을 통해 아이디어가 모여졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 더 열심히 했던 것 같다. 팀원들의 에너지가 나를 더 몰입하게 해줬다.&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2170&quot; data-origin-height=&quot;1090&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/duDegS/btsPHlfGdM6/Qgc0Z3sPDuiXJjhJsPkKa0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/duDegS/btsPHlfGdM6/Qgc0Z3sPDuiXJjhJsPkKa0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/duDegS/btsPHlfGdM6/Qgc0Z3sPDuiXJjhJsPkKa0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FduDegS%2FbtsPHlfGdM6%2FQgc0Z3sPDuiXJjhJsPkKa0%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;2170&quot; height=&quot;1090&quot; data-origin-width=&quot;2170&quot; data-origin-height=&quot;1090&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;br /&gt;앱을 만들어도 되나, 만들지 않아도 된다는 조건이 주어졌고&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;우리&lt;span&gt;&amp;nbsp;&lt;/span&gt;팀은&lt;span&gt;&amp;nbsp;&amp;lsquo;&lt;/span&gt;어차피&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;나중에&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;주구장창&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;앱을&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;만들건데&lt;span&gt;, Non-App&lt;/span&gt;으로&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;가자&lt;span&gt;&amp;rsquo;&lt;/span&gt;로&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;의견이&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;모여졌다&lt;span&gt;.&lt;/span&gt;&lt;span&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;&amp;lsquo;서로 돌보고 지지하는 아카데미를 만들자!&amp;rsquo; 라는 Challenge 아래에서&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;lsquo;실패를 유쾌하게 받아들이는 아카데미를 만들자&amp;rsquo; 로 수렴하고 다시 발산하는 과정을 거치게 됐다.&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;lsquo;실패&amp;rsquo;는 정말 각양각색이라는 걸 알게 됐다.&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;lsquo;실패&amp;rsquo;는 어떤 것이였나.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&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;&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;s&gt;답정너&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;나를 앞으로 나아갈 수 없게 한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;두렵게 만들고, 불안하게 만든다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;도전 조차 할 수 없게 만든다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&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;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&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;p style=&quot;color: #333333; text-align: start;&quot; 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;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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정말 온전한 나의 GQ, 그리고 나를 움직이게 할 수 있는 질문들.&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2892&quot; data-origin-height=&quot;1538&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XxcEB/btsPGGLbqOn/EvRNGCNlQ4iDR0vqbRz88k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XxcEB/btsPGGLbqOn/EvRNGCNlQ4iDR0vqbRz88k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XxcEB/btsPGGLbqOn/EvRNGCNlQ4iDR0vqbRz88k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXxcEB%2FbtsPGGLbqOn%2FEvRNGCNlQ4iDR0vqbRz88k%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;2892&quot; height=&quot;1538&quot; data-origin-width=&quot;2892&quot; data-origin-height=&quot;1538&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;이번&lt;span&gt; &lt;/span&gt;챌린지를&lt;span&gt; &lt;/span&gt;하면서&lt;span&gt; &lt;/span&gt;나는&lt;span&gt; &amp;lsquo;&lt;/span&gt;실패&lt;span&gt;&amp;rsquo;&lt;/span&gt;도&lt;span&gt; &lt;/span&gt;결국&lt;span&gt; &lt;/span&gt;도전의&lt;span&gt; &lt;/span&gt;결과물이고&lt;span&gt;, &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그것은&lt;span&gt; &lt;/span&gt;내가&lt;span&gt; &lt;/span&gt;다음번에&lt;span&gt; &lt;/span&gt;실패&lt;span&gt; &lt;/span&gt;하지&lt;span&gt; &lt;/span&gt;않고&lt;span&gt; &lt;/span&gt;도전하는&lt;span&gt; &lt;/span&gt;법&lt;span&gt; &lt;/span&gt;중&lt;span&gt; &lt;/span&gt;하나를&lt;span&gt; &lt;/span&gt;배우는&lt;span&gt; &lt;/span&gt;것이라는&lt;span&gt; &lt;/span&gt;걸&lt;span&gt; &lt;/span&gt;알았다&lt;span&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 요즘도 '&lt;b&gt;오실완~!&lt;/b&gt;'을 외치고 다닌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘 실패를 했다는 건, 나는 오늘 무언가를 도전했다는 뜻이니까.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;s&gt;오늘도 회식해서 지갑 아끼기 실패ㅎ&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>회고/개발할태니</category>
      <category>Apple Developer Academy</category>
      <category>CBL</category>
      <category>오실완</category>
      <author>태애니</author>
      <guid isPermaLink="true">https://delightpip.tistory.com/393</guid>
      <comments>https://delightpip.tistory.com/393#entry393comment</comments>
      <pubDate>Mon, 4 Aug 2025 22:40:06 +0900</pubDate>
    </item>
    <item>
      <title>[watchOS] 애플워치 개발자 모드 설정 뜨게 하는 방법</title>
      <link>https://delightpip.tistory.com/392</link>
      <description>&lt;p style=&quot;position: absolute;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1436&quot; data-origin-height=&quot;1170&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9EHa3/btsPfidMF8t/aFCqPzQGnuja0DOHZMiBOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9EHa3/btsPfidMF8t/aFCqPzQGnuja0DOHZMiBOk/img.png&quot; data-alt=&quot;이걸로 한번에 된 분들이 계신다면 정말 축하드립니다!!&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9EHa3/btsPfidMF8t/aFCqPzQGnuja0DOHZMiBOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9EHa3%2FbtsPfidMF8t%2FaFCqPzQGnuja0DOHZMiBOk%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;1436&quot; height=&quot;1170&quot; data-origin-width=&quot;1436&quot; data-origin-height=&quot;1170&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;&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;b&gt;설정 &amp;gt; 개인정보 보호 및 보안 &amp;gt; 개발자 모드&amp;nbsp;&lt;/b&gt;&lt;b&gt;&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 이후에는 XCode 에 이 창을 보며 기다리기만 하면 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;908&quot; data-origin-height=&quot;298&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bs9u0w/btsPfHjLZ6u/gKSD7IqlPKDkEUHKTlajq0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bs9u0w/btsPfHjLZ6u/gKSD7IqlPKDkEUHKTlajq0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bs9u0w/btsPfHjLZ6u/gKSD7IqlPKDkEUHKTlajq0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbs9u0w%2FbtsPfHjLZ6u%2FgKSD7IqlPKDkEUHKTlajq0%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;908&quot; height=&quot;298&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;908&quot; data-origin-height=&quot;298&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;h2 style=&quot;text-align: center;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;이 방법은 모두에게 적용되지 않을 것이다.&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아주 쉽게 애플워치에 개발자모드가 뜨는 사람들이 있는가하면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나처럼 고생하는 사람도 분명 있을 것 같아서 기록해본다.&lt;/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;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;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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;352&quot; data-origin-height=&quot;430&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dNqnh6/btsPgUWH5MS/JUGYrz4K0ygDGhbq6uCbh0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dNqnh6/btsPgUWH5MS/JUGYrz4K0ygDGhbq6uCbh0/img.png&quot; data-alt=&quot;될지어다 될지어다  &quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dNqnh6/btsPgUWH5MS/JUGYrz4K0ygDGhbq6uCbh0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdNqnh6%2FbtsPgUWH5MS%2FJUGYrz4K0ygDGhbq6uCbh0%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;352&quot; height=&quot;430&quot; data-origin-width=&quot;352&quot; data-origin-height=&quot;430&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;일단 애플 디벨로퍼 프로그램 없으신분..?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애플 디벨로퍼 프로그램부터 가입하세요. 개발자 계정 없으면 안됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;s&gt;연 129,000원입니다.&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.apple.com/account&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://developer.apple.com/account&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1752356556126&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;로그인 - Apple&quot; data-og-description=&quot;&quot; data-og-host=&quot;idmsa.apple.com&quot; data-og-source-url=&quot;https://developer.apple.com/account&quot; data-og-url=&quot;https://idmsa.apple.com/IDMSWebAuth/signin?appIdKey=891bd3417a7776362562d2197f89480a8547b108fd934911bcbea0110d07f757&amp;amp;path=%2Faccount%2F&amp;amp;rv=1&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://developer.apple.com/account&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.apple.com/account&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;로그인 - Apple&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;idmsa.apple.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 일단 깊게 숨을 쉬고 마음의 준비를 한다.  &amp;zwj; &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;iOS용 프로젝트에 target 을 설정하여 watch 용 프로젝트를 하나 판다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;534&quot; data-origin-height=&quot;680&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VapVw/btsPfjjoCLJ/ExRyDGdUK3Kq4JI4RbwO3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VapVw/btsPfjjoCLJ/ExRyDGdUK3Kq4JI4RbwO3k/img.png&quot; data-alt=&quot;watchOS 앱 프로젝트 파실줄 아시죠.....? 타겟 설정해서 iOS 프로젝트에 watchOS 앱 추가해주세요.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VapVw/btsPfjjoCLJ/ExRyDGdUK3Kq4JI4RbwO3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVapVw%2FbtsPfjjoCLJ%2FExRyDGdUK3Kq4JI4RbwO3k%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;534&quot; height=&quot;680&quot; data-origin-width=&quot;534&quot; data-origin-height=&quot;680&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;watchOS 앱 프로젝트 파실줄 아시죠.....? 타겟 설정해서 iOS 프로젝트에 watchOS 앱 추가해주세요.&lt;/figcaption&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;2. 아이폰에 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;3. 아이폰에서 Watch 앱을 켜보면 이렇게 워치에서 설치할 수 있는 앱이 나온다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1179&quot; data-origin-height=&quot;2556&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lTDoB/btsPgXMyrtP/lpAsQw7te9it0FlrRTpULk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lTDoB/btsPgXMyrtP/lpAsQw7te9it0FlrRTpULk/img.png&quot; data-alt=&quot;여기서 설치를 시도해보시고, 안된다면 다음 단계 (전 안됐어요)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lTDoB/btsPgXMyrtP/lpAsQw7te9it0FlrRTpULk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlTDoB%2FbtsPgXMyrtP%2FlpAsQw7te9it0FlrRTpULk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;867&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1179&quot; data-origin-height=&quot;2556&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이쯤 느꼈다.&lt;/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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1520&quot; data-origin-height=&quot;68&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TZl0I/btsPgW7WCDi/khGv3OpKk5hGfeXGcy7Aik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TZl0I/btsPgW7WCDi/khGv3OpKk5hGfeXGcy7Aik/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TZl0I/btsPgW7WCDi/khGv3OpKk5hGfeXGcy7Aik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTZl0I%2FbtsPgW7WCDi%2FkhGv3OpKk5hGfeXGcy7Aik%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;1520&quot; height=&quot;68&quot; data-origin-width=&quot;1520&quot; data-origin-height=&quot;68&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;670&quot; data-origin-height=&quot;356&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c1XD8I/btsPgucZ4ug/Vyyle2u2IAnmVe5Z3Ng7Z1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c1XD8I/btsPgucZ4ug/Vyyle2u2IAnmVe5Z3Ng7Z1/img.png&quot; data-alt=&quot;window &amp;amp;gt; Devices and Simulators 에 가서&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c1XD8I/btsPgucZ4ug/Vyyle2u2IAnmVe5Z3Ng7Z1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc1XD8I%2FbtsPgucZ4ug%2FVyyle2u2IAnmVe5Z3Ng7Z1%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;670&quot; height=&quot;356&quot; data-origin-width=&quot;670&quot; data-origin-height=&quot;356&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;window &amp;gt; Devices and Simulators 에 가서&lt;/figcaption&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;3-1 시작. 기존 연결했던 아이폰 디바이스를 삭제해버린다.&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;3. 아이폰은 Devices 에 아주 쉽게 설치가 될 것이다&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;5. 아래 이미지처럼 개발자 모드를 켜라고 안내메세지가 뜬다.&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;blob&quot; data-origin-width=&quot;2302&quot; data-origin-height=&quot;664&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rNIkC/btsPfMyM2By/kKTpkwrEkhg6chtMQkGkXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rNIkC/btsPfMyM2By/kKTpkwrEkhg6chtMQkGkXk/img.png&quot; data-alt=&quot;Settings 에서 Privacy &amp;amp;amp; Security 에 가서 개발자모드 켜달라고 뜸&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rNIkC/btsPfMyM2By/kKTpkwrEkhg6chtMQkGkXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrNIkC%2FbtsPfMyM2By%2FkKTpkwrEkhg6chtMQkGkXk%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;2302&quot; height=&quot;664&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2302&quot; data-origin-height=&quot;664&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Settings 에서 Privacy &amp;amp; Security 에 가서 개발자모드 켜달라고 뜸&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;352&quot; data-origin-height=&quot;430&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AYwWh/btsPfs1Ss4p/N735UHmXd5mP7qvl5LWF01/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AYwWh/btsPfs1Ss4p/N735UHmXd5mP7qvl5LWF01/img.png&quot; data-alt=&quot;떴다!&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AYwWh/btsPfs1Ss4p/N735UHmXd5mP7qvl5LWF01/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAYwWh%2FbtsPfs1Ss4p%2FN735UHmXd5mP7qvl5LWF01%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;352&quot; height=&quot;430&quot; data-origin-width=&quot;352&quot; data-origin-height=&quot;430&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러고 나서 테스트 해보면&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;아이폰의 Watch 앱에서 설치해도 되고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 WatchApp 을 XCode 에서 빌드해도 설치가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;몇년 전 우당탕탕 XCode와 밀당을 해보면서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뭔가 어딘가가 꼬여서겠거니 하며&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;막 해봤는데 운 좋게 설치 됨...b&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 방법이 도움이 되길 바라면서...!&lt;/p&gt;</description>
      <category>iOS/App</category>
      <category>apple watch developer mode</category>
      <category>Applewatch</category>
      <category>Developer Mode</category>
      <category>ios</category>
      <category>watch developer mode</category>
      <category>watchos xcode</category>
      <category>애플워치 개발자모드</category>
      <category>애플워치 개발자모드 안보임</category>
      <category>워치 개발자모드</category>
      <author>태애니</author>
      <guid isPermaLink="true">https://delightpip.tistory.com/392</guid>
      <comments>https://delightpip.tistory.com/392#entry392comment</comments>
      <pubDate>Sun, 13 Jul 2025 09:02:36 +0900</pubDate>
    </item>
    <item>
      <title>[HealthKit] HKObserverQueryCompletionHandler</title>
      <link>https://delightpip.tistory.com/391</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://delightpip.tistory.com/390&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://delightpip.tistory.com/390&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1752070331551&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;[HealthKit] enableBackgroundDelivery&quot; data-og-description=&quot;HealthKit Capabilities Entitlementcom.apple.developer.healthkit.access 앱이 포그라운드/백그라운드 상태로 실행되면, HealthKit은 해당하는 HKObserverQuery의 핸들러를 즉시 실행시킨다. 백그라운드에서도 작동하려면&quot; data-og-host=&quot;delightpip.tistory.com&quot; data-og-source-url=&quot;https://delightpip.tistory.com/390&quot; data-og-url=&quot;https://delightpip.tistory.com/390&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cHq9qF/hyZfAPihrV/Khd6UDLC2pYzWKKP0a4V81/img.png?width=800&amp;amp;height=457&amp;amp;face=0_0_800_457,https://scrap.kakaocdn.net/dn/YNjMb/hyZjc66bM7/YOoQtKK44MW3dFjAlhwA5k/img.png?width=800&amp;amp;height=457&amp;amp;face=0_0_800_457,https://scrap.kakaocdn.net/dn/JckiZ/hyZfvN0zc4/7stZvDr9l2hXMuZeEASws0/img.png?width=2194&amp;amp;height=1254&amp;amp;face=0_0_2194_1254&quot;&gt;&lt;a href=&quot;https://delightpip.tistory.com/390&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://delightpip.tistory.com/390&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cHq9qF/hyZfAPihrV/Khd6UDLC2pYzWKKP0a4V81/img.png?width=800&amp;amp;height=457&amp;amp;face=0_0_800_457,https://scrap.kakaocdn.net/dn/YNjMb/hyZjc66bM7/YOoQtKK44MW3dFjAlhwA5k/img.png?width=800&amp;amp;height=457&amp;amp;face=0_0_800_457,https://scrap.kakaocdn.net/dn/JckiZ/hyZfvN0zc4/7stZvDr9l2hXMuZeEASws0/img.png?width=2194&amp;amp;height=1254&amp;amp;face=0_0_2194_1254');&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;[HealthKit] enableBackgroundDelivery&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;HealthKit Capabilities Entitlementcom.apple.developer.healthkit.access 앱이 포그라운드/백그라운드 상태로 실행되면, HealthKit은 해당하는 HKObserverQuery의 핸들러를 즉시 실행시킨다. 백그라운드에서도 작동하려면&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;delightpip.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;백그라운드 전달에 사용되는 completion handle&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1752070229403&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;typealias HKObserverQueryCompletionHandler = () -&amp;gt; Void&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;이 completion handler는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;백그라운드 전달에 응답할 때 호출해야 하는 클로저&lt;/b&gt;를 정의한다.&lt;br /&gt;앱이 백그라운드 전달을 등록한 경우,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;HealthKit은 새로운 데이터가 저장되었을 때 앱을 깨운다(wake)&lt;/b&gt;.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-end=&quot;624&quot; data-start=&quot;431&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;500&quot; data-start=&quot;431&quot;&gt;&lt;b&gt;앱은 백그라운드에서 깨어난 후&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;HKObserverQuery에 등록된 update handler가 호출됨.&lt;/li&gt;
&lt;li data-end=&quot;582&quot; data-start=&quot;501&quot;&gt;이 때,&lt;span&gt;&amp;nbsp;&lt;/span&gt;update handler는&lt;span&gt;&amp;nbsp;&lt;/span&gt;HKObserverQueryCompletionHandler라는 블록(클로저)을 함께 전달.&lt;/li&gt;
&lt;li data-end=&quot;624&quot; data-start=&quot;583&quot;&gt; &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;이 클로저는 데이터를 처리한 후에 반드시 호출!!!&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;color: #000000; text-align: start; border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style8&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;항목&lt;/td&gt;
&lt;td&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;정의&lt;/td&gt;
&lt;td&gt;HKObserverQueryCompletionHandler = () -&amp;gt; Void&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;사용 시점&lt;/td&gt;
&lt;td&gt;HKObserverQuery의 update handler 내부에서&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;해야 할 일&lt;/td&gt;
&lt;td&gt;데이터를 모두 처리한 후 반드시&lt;span&gt;&amp;nbsp;&lt;/span&gt;completionHandler()&lt;span&gt;&amp;nbsp;&lt;/span&gt;호출&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;호출 안 하면&lt;/td&gt;
&lt;td&gt;HealthKit이 점점 재시도 간격 증가 &amp;rarr; 3회 실패 시 업데이트 중단&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;백그라운드 처리 유지 조건&lt;/td&gt;
&lt;td&gt;매번&lt;span&gt;&amp;nbsp;&lt;/span&gt;completionHandler를 정확히 호출해야 함&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>iOS/Swift</category>
      <category>completionhandler</category>
      <category>HealthKit</category>
      <category>hkobserverquerycompletionhandler</category>
      <author>태애니</author>
      <guid isPermaLink="true">https://delightpip.tistory.com/391</guid>
      <comments>https://delightpip.tistory.com/391#entry391comment</comments>
      <pubDate>Fri, 11 Jul 2025 10:13:47 +0900</pubDate>
    </item>
    <item>
      <title>[HealthKit] enableBackgroundDelivery</title>
      <link>https://delightpip.tistory.com/390</link>
      <description>&lt;div style=&quot;color: #f5f5f7; text-align: left;&quot; data-v-535cd656=&quot;&quot; data-v-d39b7f7c=&quot;&quot; data-v-fa32733e=&quot;&quot;&gt;
&lt;h1 style=&quot;color: #000000;&quot; data-v-fa32733e=&quot;&quot;&gt;&lt;span data-v-fa32733e=&quot;&quot; data-v-d39b7f7c=&quot;&quot;&gt;HealthKit Capabilities Entitlement&lt;/span&gt;&lt;/h1&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;com.apple.developer.healthkit.access&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앱이 포그라운드/백그라운드 상태로 실행되면&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;HealthKit은 해당하는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;HKObserverQuery&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;의 핸들러를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;즉시 실행시킨다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;color: #000000;&quot; data-end=&quot;842&quot; data-start=&quot;786&quot;&gt;백그라운드에서도 작동하려면,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;앱 실행 시점에 observer query를 등록&lt;/b&gt;해야 한다.&lt;/li&gt;
&lt;li style=&quot;color: #000000;&quot; data-end=&quot;920&quot; data-start=&quot;843&quot;&gt;보통&lt;span&gt;&amp;nbsp;&lt;/span&gt;AppDelegate나&lt;span&gt;&amp;nbsp;&lt;/span&gt;SceneDelegate의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;앱 초기화 지점&lt;/b&gt;에서 설정해야 백그라운드 전달이 제대로 작동한다&lt;br /&gt;&lt;span style=&quot;color: #333333; letter-spacing: 0px;&quot;&gt;AppDelegate&lt;/span&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;의&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #333333; letter-spacing: 0px;&quot;&gt;application(_:didFinishLaunchingWithOptions:)&lt;/span&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;에서 설정&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;color: #000000;&quot; data-end=&quot;920&quot; data-start=&quot;843&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;쿼리가 등록되어 있지 않으면, HealthKit이 데이터를 보내도&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;앱이 무시하니까 주의&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;color: #000000;&quot; data-end=&quot;920&quot; data-start=&quot;843&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;b&gt;HKObserverQuery&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;안에서 제공되는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;completionHandler()&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;는 반드시&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;호출!! 그래야만 시스템에서 &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;응답을 확인함.&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;color: #000000;&quot; data-end=&quot;920&quot; data-start=&quot;843&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;completion handler를 호출하지 않으면, HealthKit은 앱을 다시 실행시키려 시도하되, 점점&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;지연 간격을 늘리는 backoff 알고리즘&lt;/b&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;을 사용함&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;color: #000000;&quot; data-end=&quot;920&quot; data-start=&quot;843&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;앱이 3번 연속 응답에 실패하면, HealthKit은 앱이 데이터를 받을 수 없다고 간주하고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;더 이상 백그라운드 업데이트를 보내지 않는다.&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1752069988359&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;private func setupBackgroundDelivery() {
        let query = HKObserverQuery(sampleType: daylightType, predicate: nil) { [weak self] _, completionHandler, error in
            if let error = error {
                DispatchQueue.main.async {
                    self?.addLog(eventType: .backgroundUpdate, message: &quot;Background delivery error: \(error.localizedDescription)&quot;)
                }
            } else {
                DispatchQueue.main.async {
                    self?.addLog(eventType: .backgroundUpdate, message: &quot;  Real background delivery triggered - app woken by HealthKit&quot;)
                    self?.fetchCurrentDaylight(isAppLaunch: false)
                }
            }
            completionHandler()
        }
        
        backgroundDeliveryQuery = query
        healthStore.execute(query)
        
        healthStore.enableBackgroundDelivery(for: daylightType, frequency: .immediate) { [weak self] success, error in
            DispatchQueue.main.async {
                if success {
                    self?.addLog(eventType: .manualUpdate, message: &quot;Background delivery enabled successfully&quot;)
                } else {
                    self?.addLog(eventType: .manualUpdate, message: &quot;Failed to enable background delivery: \(error?.localizedDescription ?? &quot;Unknown error&quot;)&quot;)
                }
            }
        }
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;HKObserverQueryCompletionHandler 참조&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;a href=&quot;https://developer.apple.com/documentation/healthkit/hkobserverquerycompletionhandler&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://developer.apple.com/documentation/healthkit/hkobserverquerycompletionhandler&lt;/a&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1752070077268&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;HKObserverQueryCompletionHandler | Apple Developer Documentation&quot; data-og-description=&quot;The completion handler for background deliveries.&quot; data-og-host=&quot;developer.apple.com&quot; data-og-source-url=&quot;https://developer.apple.com/documentation/healthkit/hkobserverquerycompletionhandler&quot; data-og-url=&quot;https://docs.developer.apple.com/documentation/healthkit/hkobserverquerycompletionhandler&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dzCfFs/hyZjBZ8smA/sCQftxmR5NO3bK8x5rYKT1/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/TuC9w/hyZfo9bOUs/KvZXY94AJN7yDKsMgbu1UK/img.jpg?width=1024&amp;amp;height=512&amp;amp;face=0_0_1024_512&quot;&gt;&lt;a href=&quot;https://developer.apple.com/documentation/healthkit/hkobserverquerycompletionhandler&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.apple.com/documentation/healthkit/hkobserverquerycompletionhandler&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dzCfFs/hyZjBZ8smA/sCQftxmR5NO3bK8x5rYKT1/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/TuC9w/hyZfo9bOUs/KvZXY94AJN7yDKsMgbu1UK/img.jpg?width=1024&amp;amp;height=512&amp;amp;face=0_0_1024_512');&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;HKObserverQueryCompletionHandler | Apple Developer Documentation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;The completion handler for background deliveries.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developer.apple.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Executing&amp;nbsp;Observer&amp;nbsp;Queries&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.apple.com/documentation/healthkit/executing-observer-queries&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://developer.apple.com/documentation/healthkit/executing-observer-queries&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1752070101662&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;Executing Observer Queries | Apple Developer Documentation&quot; data-og-description=&quot;Create and run observer queries.&quot; data-og-host=&quot;developer.apple.com&quot; data-og-source-url=&quot;https://developer.apple.com/documentation/healthkit/executing-observer-queries&quot; data-og-url=&quot;https://docs.developer.apple.com/documentation/healthkit/executing-observer-queries&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/XLk2h/hyZfZO6U5J/ETkOP0f71JPKAWkD88kdX1/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bZX76y/hyZf0mWkGZ/7isQRaAx56ywj2F0Chu4W0/img.jpg?width=1024&amp;amp;height=512&amp;amp;face=0_0_1024_512&quot;&gt;&lt;a href=&quot;https://developer.apple.com/documentation/healthkit/executing-observer-queries&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.apple.com/documentation/healthkit/executing-observer-queries&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/XLk2h/hyZfZO6U5J/ETkOP0f71JPKAWkD88kdX1/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bZX76y/hyZf0mWkGZ/7isQRaAx56ywj2F0Chu4W0/img.jpg?width=1024&amp;amp;height=512&amp;amp;face=0_0_1024_512');&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;Executing Observer Queries | Apple Developer Documentation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Create and run observer queries.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developer.apple.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2194&quot; data-origin-height=&quot;1254&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIx0pr/btsPb2gpN3n/Lhm9PqFfzCprE4Fikewzo1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIx0pr/btsPb2gpN3n/Lhm9PqFfzCprE4Fikewzo1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIx0pr/btsPb2gpN3n/Lhm9PqFfzCprE4Fikewzo1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIx0pr%2FbtsPb2gpN3n%2FLhm9PqFfzCprE4Fikewzo1%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;2194&quot; height=&quot;1254&quot; data-origin-width=&quot;2194&quot; data-origin-height=&quot;1254&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>iOS/Swift</category>
      <category>Background</category>
      <category>enablebackgrounddelivery</category>
      <category>HealthKit</category>
      <author>태애니</author>
      <guid isPermaLink="true">https://delightpip.tistory.com/390</guid>
      <comments>https://delightpip.tistory.com/390#entry390comment</comments>
      <pubDate>Wed, 9 Jul 2025 23:08:56 +0900</pubDate>
    </item>
    <item>
      <title>[Foundation/Class] NotificationCenter</title>
      <link>https://delightpip.tistory.com/388</link>
      <description>&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;NotificationCenter 란?&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체 간 느슨한 통신(loose coupling)을 가능하게 하는 event broadcast system&lt;/li&gt;
&lt;li&gt;다수의 객체에 이벤트 상태변화를 알리는 방송이라고 생각하면 됨&lt;/li&gt;
&lt;li&gt;단일 프로그램 내에서만 동작 (프로세스 간 통신은&lt;span&gt;&amp;nbsp;&lt;/span&gt;DistributedNotificationCenter&lt;span&gt;&amp;nbsp;&lt;/span&gt;사용)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;Notification 이란?&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;NotificationCenter가 전달하는 단일 이벤트의 데이터 단위&lt;/li&gt;
&lt;li&gt;앱 내부의 객체 간 메시지를 전달하는 역할로, 옵저버 패턴의 일부이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote style=&quot;color: #000000; text-align: start;&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[!NOTE] Notification과 User Notification(UNNotification)은 다른 개념임.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;NotificationCenter의 내부구조&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;swift&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;swift&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;class NotificationCenter {
    private var observers: [NotificationName: [WeakObserver]] = [:]
    private let lock = NSLock() // 스레드 안전성
    
    // 실제 내부 구조 (단순화)
    private struct WeakObserver {
        weak var observer: AnyObject?
        let selector: Selector?
        let block: ((Notification) -&amp;gt; Void)?
        let queue: OperationQueue?
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;Notification vs User Notification 비교&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;항목NotificationUser Notification (UNNotification)&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&gt;소속 프레임워크&lt;/td&gt;
&lt;td&gt;Foundation (NotificationCenter)&lt;/td&gt;
&lt;td&gt;UserNotifications (UNUserNotificationCenter)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;주요 클래스&lt;/td&gt;
&lt;td&gt;Notification, NotificationCenter&lt;/td&gt;
&lt;td&gt;UNNotification, UNUserNotificationCenter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;이벤트 대상&lt;/td&gt;
&lt;td&gt;앱 내부 객체 (코드)&lt;/td&gt;
&lt;td&gt;사용자 (시스템 알림 UI)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;발생 위치&lt;/td&gt;
&lt;td&gt;앱 내부에서 직접 post&lt;/td&gt;
&lt;td&gt;시스템이 푸시/로컬 알림을 표시할 때&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;용도&lt;/td&gt;
&lt;td&gt;코드 간 통신 (모듈 간, VC &amp;harr; VM 등)&lt;/td&gt;
&lt;td&gt;사용자에게 알림을 보내고 응답 처리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;인터넷 필요 여부&lt;/td&gt;
&lt;td&gt;필요없음&lt;/td&gt;
&lt;td&gt;로컬일 경우 필요없음, 원격일 경우 필요&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;swift&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;less&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;// UserNotification을 이용해 알림을 하면서, 처리 후 내부 Notification으로 전달하는 예시
// 푸시 알림 후 앱 내부에서 이벤트를 처리하는 예시임
// 사용자가 알림을 탭했을 때 &amp;rarr; 앱 내부에 Notification 전달
func userNotificationCenter(_: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -&amp;gt; Void) {
    NotificationCenter.default.post(name: .didTapReminderNotification, object: nil, userInfo: response.notification.request.content.userInfo)
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;GQ1. NotificationCenter의 처리 과정&lt;/h2&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;1. 관찰자 등록 (addObserver)&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;옵저버 객체는 특정&lt;span&gt;&amp;nbsp;&lt;/span&gt;Notification.Name에 대해 알림을 수신하겠다고 등록&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;2. 알림 게시 (post)&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;알림 이름, 옵셔널한 발신자(sender),&lt;span&gt;&amp;nbsp;&lt;/span&gt;userInfo를 포함한 알림을 게시&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;3. 알림 전달&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;등록된 모든 observer에게&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;동기적으로&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;알림이 전달 옵저버는 등록 시 설정한 selector/closure를 통해 콜백을 받음&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;swift&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;swift&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;// 셀렉터 기반 등록
NotificationCenter.default.addObserver(
    self,
    selector: #selector(handleKeyboardWillShow),
    name: UIResponder.keyboardWillShowNotification,
    object: nil
)

// 클로저 기반 등록
let observer = NotificationCenter.default.addObserver(
    forName: .customEvent,
    object: nil,
    queue: .main
) { [weak self] notification in
    self?.handleCustomEvent(notification)
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;처리 순서 상세&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;등록 단계&lt;/b&gt;: 옵저버가 특정 알림 이름에 대해 콜백 등록&lt;/li&gt;
&lt;li&gt;&lt;b&gt;발송 단계&lt;/b&gt;:&lt;span&gt;&amp;nbsp;&lt;/span&gt;post&lt;span&gt;&amp;nbsp;&lt;/span&gt;메서드 호출 시 해당 알림 이름의 모든 옵저버 검색&lt;/li&gt;
&lt;li&gt;&lt;b&gt;전달 단계&lt;/b&gt;: 등록된 순서대로 각 옵저버의 콜백 실행 (동기적)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;완료 단계&lt;/b&gt;: 모든 옵저버 처리 완료 후&lt;span&gt;&amp;nbsp;&lt;/span&gt;post&lt;span&gt;&amp;nbsp;&lt;/span&gt;메서드 반환&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;Observer Pattern&lt;/h2&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;옵저버 패턴은 한 객체의 상태 변화를 감지 후, 다른 객체들이 자동으로 반응하도록 연결하는 패턴&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;어떤 일이 발생했을 때, 관심있는 객체들에게 자동으로 알려주는 구조&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;변화가 발생하면 자동으로 반응하게 하는 시스템&lt;/li&gt;
&lt;li&gt;여러 객체가 한 이벤트에 대해 동시에 반응한다 (1:N)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;옵저버 패턴 구현 예시&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;swift&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;// Subject의 상태가 바뀔 때마다, 모든 Observer가 자동으로 반응함
protocol Observer {
    func update(value: Int)
}

class Subject {
    private var observers = [Observer]()
    private var value = 0

    func addObserver(_ observer: Observer) {
        observers.append(observer)
    }

    func changeValue(to newValue: Int) {
        value = newValue
        notifyObservers()
    }

    private func notifyObservers() {
        observers.forEach { $0.update(value: value) }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;NotificationCenter로 보는 옵저버 패턴&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;NotificationCenter&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;자체가 Subject&lt;/li&gt;
&lt;li&gt;&lt;b&gt;ViewController, ViewModel&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;= Observer&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Notification&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;= Event&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;swift&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;reasonml&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;NotificationCenter.default.addObserver(self, selector: #selector(...), name: .eventHappened, object: nil)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;옵저버 패턴의 장점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;느슨한 결합&lt;/b&gt;: 주체와 반응하는 객체가 서로 모른 채로 동작&lt;/li&gt;
&lt;li&gt;&lt;b&gt;유연성&lt;/b&gt;: 여러 객체가 같은 이벤트에 반응 가능 (1:N 구조)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;확장성&lt;/b&gt;: 옵저버를 자유롭게 추가/제거 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;옵저버 패턴의 단점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;순환 참조 위험&lt;/b&gt;: 클로저 내부에서 self를 강하게 참조할 경우 &amp;rarr; 해결방안&lt;span&gt;&amp;nbsp;&lt;/span&gt;[weak self]&lt;span&gt;&amp;nbsp;&lt;/span&gt;사용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;메모리 누수 가능성&lt;/b&gt;: 옵저버 제거 누락 시 &amp;rarr; deinit에서 removeObserver 호출 처리&lt;/li&gt;
&lt;li&gt;&lt;b&gt;디버깅 어려움&lt;/b&gt;: 이벤트 흐름 추적이 복잡 &amp;rarr; 네이밍 전략, 구조화 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;GQ2. NotificationCenter의 메모리 관리&lt;/h2&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;중요한 수정사항&amp;nbsp;&lt;/h3&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;iOS 9+ 부터는 셀렉터 기반 옵저버도 자동으로 해제된다.&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;swift&quot; style=&quot;color: #abb2bf; text-align: left;&quot; data-ke-language=&quot;swift&quot;&gt;&lt;code&gt;// iOS 9+ 에서는 자동 해제됨
NotificationCenter.default.addObserver(self, selector: #selector(handle), name: .custom, object: nil)

// deinit에서 수동 제거 불필요 (하지만 명시적으로 하는 것이 좋음)
deinit {
    NotificationCenter.default.removeObserver(self) // 권장사항
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;클로저 기반 옵저버 관리&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;swift&quot; style=&quot;color: #abb2bf; text-align: left;&quot; data-ke-language=&quot;swift&quot;&gt;&lt;code&gt;class ViewController: UIViewController {
    private var observers: [NSObjectProtocol] = []
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // 순환 참조 위험
        let badObserver = NotificationCenter.default.addObserver(
            forName: .dataUpdate,
            object: nil,
            queue: .main
        ) { notification in
            self.handleUpdate() // strong reference cycle!
        }
        
        // 안전한 방법
        let safeObserver = NotificationCenter.default.addObserver(
            forName: .dataUpdate,
            object: nil,
            queue: .main
        ) { [weak self] notification in
            self?.handleUpdate() // weak reference
        }
        
        observers.append(safeObserver)
    }
    
    deinit {
        // 클로저 기반은 명시적 제거 필요
        observers.forEach { NotificationCenter.default.removeObserver($0) }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;메모리 관리 베스트 프랙티스&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;항상&lt;span&gt;&amp;nbsp;&lt;/span&gt;[weak self]&lt;span&gt;&amp;nbsp;&lt;/span&gt;사용&lt;/b&gt;: 클로저 기반 옵저버에서 순환 참조 방지&lt;/li&gt;
&lt;li&gt;&lt;b&gt;토큰 저장&lt;/b&gt;: 클로저 기반 옵저버의 반환 토큰을 저장하여 수동 해제 가능하게 함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;명시적 해제&lt;/b&gt;: deinit에서 명시적으로 옵저버 제거&lt;/li&gt;
&lt;li&gt;&lt;b&gt;적절한 생명주기&lt;/b&gt;: 옵저버의 등록/해제 시점을 명확히 함&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;스레드 안전성&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;less&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;class ThreadSafeExample {
    func postFromBackground() {
        DispatchQueue.global().async {
            // 백그라운드에서 알림 발송 - 안전함
            NotificationCenter.default.post(name: .backgroundTask, object: nil)
        }
    }
    
    func observeWithSpecificQueue() {
        // 특정 큐에서 옵저버 실행
        NotificationCenter.default.addObserver(
            forName: .customEvent,
            object: nil,
            queue: .main // UI 업데이트용
        ) { notification in
            // 항상 메인 큐에서 실행됨
            print(&quot;현재 스레드: \(Thread.current)&quot;)
        }
        
        NotificationCenter.default.addObserver(
            forName: .heavyTask,
            object: nil,
            queue: OperationQueue() // 백그라운드 큐
        ) { notification in
            // 백그라운드에서 무거운 작업 처리
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;GQ3. NotificationCenter를 어떻게 관리해야 하는가?&lt;/h2&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;주요 기능 + 적절한 활용 시점&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;1. 여러 객체가 한 이벤트에 반응할 때&lt;/h4&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;pgsql&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;// 로그인 이벤트 &amp;rarr; 여러 화면이 동시에 업데이트
extension Notification.Name {
    static let userDidLogin = Notification.Name(&quot;userDidLogin&quot;)
}

class UserManager {
    func login(user: User) {
        authenticateUser(user)
        
        // 여러 화면에 로그인 완료 알림
        NotificationCenter.default.post(
            name: .userDidLogin,
            object: user,
            userInfo: [&quot;loginTime&quot;: Date()]
        )
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;2. 이벤트 소스를 모를 때&lt;/h4&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;누가 이벤트를 발생시켰는지 확인할 필요 없이, 이벤트 발생 여부만 알면 됨&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;3. 시스템 이벤트 처리&lt;/h4&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;objectivec&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;// 키보드 이벤트 - 시스템에서 직접 발송
NotificationCenter.default.addObserver(
    forName: UIResponder.keyboardWillShowNotification,
    object: nil,
    queue: .main
) { [weak self] notification in
    if let keyboardFrame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect {
        self?.adjustUI(for: keyboardFrame.height)
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;4. 깊은 뷰 계층에서의 전역 이벤트&lt;/h4&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;groovy&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;// 5단계 깊이의 뷰 구조에서 최하단 &amp;rarr; 최상단 통신
struct DeepNestedComponent: View {
    var body: some View {
        Button(&quot;전역 새로고침&quot;) {
            // @Binding으로 5단계 전달하기엔 너무 복잡
            NotificationCenter.default.post(name: .globalRefresh, object: nil)
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;언제 사용하지 말아야 하는가?&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;NotificationCenter 사용하지 말아야 하는 경우&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal; color: #000000; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;단순한 1:1 통신&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;swift&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;// 대신 protocol/delegate 사용
protocol DataSource {
    func fetchData() -&amp;gt; [Item]
}&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;2. &amp;nbsp;&lt;b&gt;SwiftUI에서 상태 관리&lt;/b&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;golo&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;// 대신 @StateObject, @ObservableObject 사용
@StateObject var viewModel = ViewModel()&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;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 직접적인 부모-자식 관계&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;kotlin&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;struct ParentView: View {
    @State private var data = &quot;&quot;
    
    var body: some View {
        ChildView(data: $data) // 직접 전달
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;실제 코드 예시&lt;/h2&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;SwiftUI에서의 사용&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;reasonml&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;struct ContentView: View {
    @State private var message = &quot;&quot;
    @State private var isKeyboardVisible = false
    
    var body: some View {
        VStack {
            Text(message)
            TextField(&quot;입력&quot;, text: .constant(&quot;&quot;))
        }
        .padding(.bottom, isKeyboardVisible ? 250 : 0)
        .onReceive(NotificationCenter.default.publisher(for: .messageUpdate)) { notification in
            if let newMessage = notification.object as? String {
                message = newMessage
            }
        }
        .onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillShowNotification)) { _ in
            isKeyboardVisible = true
        }
        .onReceive(NotificationCenter.default.publisher(for: UIResponder.keyboardWillHideNotification)) { _ in
            isKeyboardVisible = false
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;커스텀 Notification Name 정의&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;swift&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;extension Notification.Name {
    static let userDidLogin = Notification.Name(&quot;userDidLogin&quot;)
    static let dataDidUpdate = Notification.Name(&quot;dataDidUpdate&quot;)
    static let networkStatusChanged = Notification.Name(&quot;networkStatusChanged&quot;)
    static let messageUpdate = Notification.Name(&quot;messageUpdate&quot;)
    static let globalRefresh = Notification.Name(&quot;globalRefresh&quot;)
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;타입 안전한 NotificationCenter 래퍼&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;swift&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;protocol TypedNotification {
    associatedtype Payload
    static var name: NSNotification.Name { get }
}

struct UserLoginNotification: TypedNotification {
    typealias Payload = User
    static let name = NSNotification.Name(&quot;user.login&quot;)
}

extension NotificationCenter {
    func post&amp;lt;T: TypedNotification&amp;gt;(_ type: T.Type, payload: T.Payload) {
        post(name: T.name, object: payload)
    }
    
    func observe&amp;lt;T: TypedNotification&amp;gt;(
        _ type: T.Type,
        queue: OperationQueue? = .main,
        handler: @escaping (T.Payload) -&amp;gt; Void
    ) -&amp;gt; NSObjectProtocol {
        return addObserver(forName: T.name, object: nil, queue: queue) { notification in
            guard let payload = notification.object as? T.Payload else { return }
            handler(payload)
        }
    }
}

// 타입 안전한 사용
NotificationCenter.default.post(UserLoginNotification.self, payload: user)
NotificationCenter.default.observe(UserLoginNotification.self) { user in
    print(&quot;사용자 로그인: \(user.name)&quot;)
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;성능 고려사항&lt;/h2&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;최적화 팁&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;swift&quot; style=&quot;color: #abb2bf; text-align: left;&quot; data-ke-language=&quot;swift&quot;&gt;&lt;code&gt;class OptimizedNotificationManager {
    // 효율적 방식 : 한 번 등록하고 조건부 처리
    func setupOptimizedObserver() {
        NotificationCenter.default.addObserver(
            forName: .frequentEvent,
            object: nil,
            queue: nil
        ) { [weak self] notification in
            guard let self = self,
                  self.shouldHandle(notification) else { return }
            self.handleNotification(notification)
        }
    }
    
    // 비효율적: 자주 등록/해제
    func inefficientPattern() {
        let observer = NotificationCenter.default.addObserver(/*...*/)
        // 짧은 시간 후
        NotificationCenter.default.removeObserver(observer)
    }
    
    // 효율적: 필요한 데이터만 전달
    func optimizedPosting() {
        NotificationCenter.default.post(
            name: .dataUpdate,
            object: nil,
            userInfo: [&quot;id&quot;: dataId] // 최소한의 식별자만
        )
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;디버깅 도구&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;swift&quot; style=&quot;color: #abb2bf; text-align: left;&quot; data-ke-language=&quot;swift&quot;&gt;&lt;code&gt;// 디버깅용 NotificationCenter 모니터링
class NotificationDebugger {
    static func enableGlobalMonitoring() {
        NotificationCenter.default.addObserver(
            forName: nil, // 모든 알림 감지
            object: nil,
            queue: nil
        ) { notification in
            print(&quot;   알림: \(notification.name)&quot;)
            print(&quot;   발신자: \(notification.object ?? &quot;nil&quot;)&quot;)
            print(&quot;   정보: \(notification.userInfo ?? [:])&quot;)
            print(&quot;   스레드: \(Thread.current)&quot;)
            print(&quot;---&quot;)
        }
    }
}

// 사용법
#if DEBUG
NotificationDebugger.enableGlobalMonitoring()
#endif&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;최신 기능 (iOS 15+)&lt;/h2&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;AsyncSequence 활용&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;swift&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;// 비동기 스트림으로 알림 처리
class AsyncNotificationHandler {
    func startListening() async {
        for await notification in NotificationCenter.default.notifications(
            named: .dataUpdate,
            object: nil
        ) {
            await handleDataUpdate(notification)
        }
    }
    
    private func handleDataUpdate(_ notification: Notification) async {
        // 비동기 처리
    }
}&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;/div&gt;
&lt;/div&gt;</description>
      <category>iOS/Swift</category>
      <category>class</category>
      <category>foundation</category>
      <category>Notification</category>
      <category>NotificationCenter</category>
      <category>SWiFT</category>
      <author>태애니</author>
      <guid isPermaLink="true">https://delightpip.tistory.com/388</guid>
      <comments>https://delightpip.tistory.com/388#entry388comment</comments>
      <pubDate>Wed, 2 Jul 2025 00:10:13 +0900</pubDate>
    </item>
    <item>
      <title>블로그에 글 안쓰고 뭘 했냐면은</title>
      <link>https://delightpip.tistory.com/387</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실.. 비공개 글은 쫌 있다....&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뭔가.. 근데 그걸 공개 못한 이유는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇게 써둔 글들이 다 내 머릿속에 있는가..? 이게 공부가 맞나..?하는 회의감이 들어서였다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;744&quot; data-origin-height=&quot;820&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eKygt0/btsOWDujX7p/v6mf0IYSWFXRxMNdMxxuW1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eKygt0/btsOWDujX7p/v6mf0IYSWFXRxMNdMxxuW1/img.png&quot; data-alt=&quot;진짜임ㅎㅎㅎㅎ&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eKygt0/btsOWDujX7p/v6mf0IYSWFXRxMNdMxxuW1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeKygt0%2FbtsOWDujX7p%2Fv6mf0IYSWFXRxMNdMxxuW1%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;522&quot; height=&quot;575&quot; data-origin-width=&quot;744&quot; data-origin-height=&quot;820&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;깊은 확신이 들지 않았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 블로그에 안쓰고 메모장에 휘갈기며...&lt;/p&gt;
&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;424&quot; data-origin-height=&quot;910&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d9yCrV/btsOUATiYsf/Vmqn8yhUGGCgonifTKIe01/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d9yCrV/btsOUATiYsf/Vmqn8yhUGGCgonifTKIe01/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d9yCrV/btsOUATiYsf/Vmqn8yhUGGCgonifTKIe01/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd9yCrV%2FbtsOUATiYsf%2FVmqn8yhUGGCgonifTKIe01%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;424&quot; height=&quot;910&quot; data-origin-width=&quot;424&quot; data-origin-height=&quot;910&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;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;그리고 Swift 딥다이브 스터디를 하는 중인데&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;CS 라기보다는 거의 진짜 무슨.. 언어처럼 생각하고 접근하고 있는데&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;좀 더 스스로 잘 판단해보려고 한다. GPT한테도 물어보고...&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;p data-ke-size=&quot;size16&quot;&gt;블로그에는 어떻게 풀어 쓸지 모르겠어서 ~_~&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비공개글 좀 써둔 것도... 아마 공개는 안할 것 같고(&lt;s&gt;진짜 일기장처럼 쓰네 지금 나..&lt;/s&gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6월 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;&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;7월에 진짜로 돌 아 오 겠 음!&lt;/p&gt;</description>
      <category>회고</category>
      <author>태애니</author>
      <guid isPermaLink="true">https://delightpip.tistory.com/387</guid>
      <comments>https://delightpip.tistory.com/387#entry387comment</comments>
      <pubDate>Fri, 27 Jun 2025 22:41:49 +0900</pubDate>
    </item>
    <item>
      <title>한달만에 블로그 글쓰기 창 앞에 앉아서</title>
      <link>https://delightpip.tistory.com/386</link>
      <description>&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;컴퓨터, 인터넷? 하면 쇼핑이나 할 줄 알았던 내가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;9개월만에 갑자기 웹개발자로 스카웃이 됐고&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;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;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;내가 이걸 할 수 있을까?&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;그게 반복되면서 나는 또 회피했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;난 그거 관심 없어서 안한거야.&quot;&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ytv79/btsOVw3wJHj/IKYTN6ZKv2xpQugNJeGuck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ytv79/btsOVw3wJHj/IKYTN6ZKv2xpQugNJeGuck/img.png&quot; data-origin-width=&quot;580&quot; data-origin-height=&quot;347&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;48.46&quot; style=&quot;width: 47.895491%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ytv79/btsOVw3wJHj/IKYTN6ZKv2xpQugNJeGuck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYtv79%2FbtsOVw3wJHj%2FIKYTN6ZKv2xpQugNJeGuck%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;580&quot; height=&quot;347&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/K6msS/btsOWicChJf/C5QnMDq8tCndXr8qdTKuXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/K6msS/btsOWicChJf/C5QnMDq8tCndXr8qdTKuXk/img.png&quot; data-origin-width=&quot;656&quot; data-origin-height=&quot;369&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;51.54&quot; style=&quot;width: 50.941718%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/K6msS/btsOWicChJf/C5QnMDq8tCndXr8qdTKuXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FK6msS%2FbtsOWicChJf%2FC5QnMDq8tCndXr8qdTKuXk%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;656&quot; height=&quot;369&quot;/&gt;&lt;/span&gt;&lt;/div&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;너무 서론이 어두워서....ㅎㅎㅎㅎㅋㅋㅋ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아니 그래서 지금 하고 싶은 말은,&lt;/p&gt;
&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;저 사람은 저런 방법을 썼다고 한다.&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;/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;실패를 하다보면 실패를 버티는 근육이 생긴다. 이건 진짜 맞는 것 같다. 이번 2025년에 진짜 크게 교체된 내 생각의 문장.&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;&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;&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;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;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;766&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wGtNW/btsOUyVnirz/n8tgkekrOpxiok2FW6yU3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wGtNW/btsOUyVnirz/n8tgkekrOpxiok2FW6yU3k/img.png&quot; data-alt=&quot;2019년 김태인은 2024년 김태인 보다 훨 멋졌네..ㅜ 몰라몰라 2025년부터 더 멋져지면 됨!&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wGtNW/btsOUyVnirz/n8tgkekrOpxiok2FW6yU3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwGtNW%2FbtsOUyVnirz%2Fn8tgkekrOpxiok2FW6yU3k%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;640&quot; height=&quot;766&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;766&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;2019년 김태인은 2024년 김태인 보다 훨 멋졌네..ㅜ 몰라몰라 2025년부터 더 멋져지면 됨!&lt;/figcaption&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;흑역사 작성 완 &lt;/p&gt;</description>
      <category>회고</category>
      <author>태애니</author>
      <guid isPermaLink="true">https://delightpip.tistory.com/386</guid>
      <comments>https://delightpip.tistory.com/386#entry386comment</comments>
      <pubDate>Fri, 27 Jun 2025 22:20:27 +0900</pubDate>
    </item>
    <item>
      <title>[문법/키워드] Computed Property / Extension</title>
      <link>https://delightpip.tistory.com/380</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-end=&quot;274&quot; data-start=&quot;241&quot; data-ke-size=&quot;size26&quot;&gt;1. Computed Property (계산 속성)&lt;/h2&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-end=&quot;274&quot; data-start=&quot;241&quot; data-ke-size=&quot;size14&quot;&gt;속성처럼 보이지만,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;내부적으로 계산&lt;/b&gt;해서 값을 반환함.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-end=&quot;274&quot; data-start=&quot;241&quot; data-ke-size=&quot;size14&quot;&gt;보통&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;다른 속성을 기반으로&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;동작&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-end=&quot;274&quot; data-start=&quot;241&quot; data-ke-size=&quot;size14&quot;&gt;get,&lt;span&gt;&amp;nbsp;&lt;/span&gt;set&lt;span&gt;&amp;nbsp;&lt;/span&gt;블럭 사용 가능.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-end=&quot;274&quot; data-start=&quot;241&quot; data-ke-size=&quot;size14&quot;&gt;저장공간을 갖지 않음 (값을 &quot;가지고 있는&quot; 게 아니라 &quot;계산&quot;함)&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-end=&quot;274&quot; data-start=&quot;241&quot; data-ke-size=&quot;size14&quot;&gt;읽기 전용도 가능, 읽기/쓰기 모두 가능.&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-end=&quot;274&quot; data-start=&quot;241&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-end=&quot;274&quot; data-start=&quot;241&quot; data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;struct 안에 있는 값을 활용하여 어떤 계산식을 통해 값을 리턴시켜줌.&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #000000; text-align: start;&quot; data-end=&quot;274&quot; data-start=&quot;241&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1747751191222&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;struct Circle {
    var radius: Double
    
    // 계산 속성 (읽기 전용)
    var area: Double {
        return .pi * radius * radius
    }
    
    // 계산 속성 (읽기 &amp;amp; 쓰기)
    var diameter: Double {
        get {
            return radius * 2
        }
        set {
            radius = newValue / 2
        }
    }
}

var c = Circle(radius: 5)
print(c.area)     // 78.54...
print(c.diameter) // 10.0

c.diameter = 20
print(c.radius)   // 10.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;예시&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;Date() 값만 들어오면 자동으로 yyyy년 mm월 dd일로 바꾸고 싶어.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 숫자가 들어오면 어떤 공식이나 계산으로 값을 받고 싶어.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 값을 display 용으로 보여주고 싶어. (struct 값이 바뀌지는 않지만 보여줄 때만 바꾸고 싶을 때)&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;span style=&quot;color: #000000; text-align: start;&quot;&gt;2. Method (메서드)&lt;/span&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;기능&lt;/b&gt;이나&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;동작을 수행하는 함수&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;mutating&lt;span&gt;&amp;nbsp;&lt;/span&gt;키워드를 통해 값 변경 가능 (struct,&lt;span&gt;&amp;nbsp;&lt;/span&gt;enum에서만 필요)&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;struct, enum에서는 내부 값을 변경할 수 없으나, mutating 을 이용해 self 값 또는 내부 속성을 바꿀 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1747751616916&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;struct BankAccount {
    var balance: Double

    mutating func deposit(_ amount: Double) {
        balance += amount
    }

    mutating func withdraw(_ amount: Double) {
        balance -= amount
    }
    
    func isRich(threshold: Double) -&amp;gt; Bool {
        return balance &amp;gt; threshold
    }
}

var account = BankAccount(balance: 1000)
account.deposit(500)
account.withdraw(200)
print(account.balance) // 1300
print(account.isRich(threshold: 1000)) // true&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1592&quot; data-origin-height=&quot;476&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgpcyR/btsN6nFBRsw/wMdZCGg450O4xVYusZZKwk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgpcyR/btsN6nFBRsw/wMdZCGg450O4xVYusZZKwk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgpcyR/btsN6nFBRsw/wMdZCGg450O4xVYusZZKwk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbgpcyR%2FbtsN6nFBRsw%2FwMdZCGg450O4xVYusZZKwk%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;1592&quot; height=&quot;476&quot; data-origin-width=&quot;1592&quot; data-origin-height=&quot;476&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;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; text-align: start;&quot;&gt;3. Extension&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 타입(내가 만든 struct/class뿐 아니라 Swift 내장 타입들까지)에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;기능을 추가&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;원래 코드를 수정하지 않고도 기능 추가 가능&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드 분리 및 모듈화 가능&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;실무에서 정말 자주 씀 (UIKit 커스터마이징, 공통 기능 분리 등)&lt;/b&gt;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-end=&quot;2224&quot; data-start=&quot;2208&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-end=&quot;2224&quot; data-start=&quot;2208&quot; data-ke-size=&quot;size23&quot;&gt;확장 가능한 요소&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc; color: #000000; text-align: start;&quot; data-end=&quot;2299&quot; data-start=&quot;2225&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2239&quot; data-start=&quot;2225&quot;&gt;method (메서드)&lt;/li&gt;
&lt;li data-end=&quot;2259&quot; data-start=&quot;2240&quot;&gt;computed property&lt;/li&gt;
&lt;li data-end=&quot;2273&quot; data-start=&quot;2260&quot;&gt;initializer&lt;/li&gt;
&lt;li data-end=&quot;2285&quot; data-start=&quot;2274&quot;&gt;subscript&lt;/li&gt;
&lt;li data-end=&quot;2299&quot; data-start=&quot;2286&quot;&gt;protocol 준수&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1747751931115&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;extension String {
    var isEmail: Bool {
        return self.contains(&quot;@&quot;) &amp;amp;&amp;amp; self.contains(&quot;.&quot;)
    }

    func repeated(count: Int) -&amp;gt; String {
        return String(repeating: self, count: count)
    }
}

let email = &quot;test@example.com&quot;
print(email.isEmail) // true
print(&quot;hi &quot;.repeated(count: 3)) // hi hi hi&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1048&quot; data-origin-height=&quot;304&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/brEmVz/btsN4KB1Uk3/J3dNnBrCL97kgT4nwLkRc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/brEmVz/btsN4KB1Uk3/J3dNnBrCL97kgT4nwLkRc1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/brEmVz/btsN4KB1Uk3/J3dNnBrCL97kgT4nwLkRc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbrEmVz%2FbtsN4KB1Uk3%2FJ3dNnBrCL97kgT4nwLkRc1%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;1048&quot; height=&quot;304&quot; data-origin-width=&quot;1048&quot; data-origin-height=&quot;304&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>iOS/Swift</category>
      <category>computedproperty</category>
      <category>extension</category>
      <category>SWiFT</category>
      <author>태애니</author>
      <guid isPermaLink="true">https://delightpip.tistory.com/380</guid>
      <comments>https://delightpip.tistory.com/380#entry380comment</comments>
      <pubDate>Wed, 21 May 2025 00:39:40 +0900</pubDate>
    </item>
    <item>
      <title>[문법/키워드] mutating, Associated Value (연관 값)</title>
      <link>https://delightpip.tistory.com/379</link>
      <description>&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;1. mutating&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;mutating&lt;span&gt;&amp;nbsp;&lt;/span&gt;키워드는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;구조체(struct)나 열거형(enum)에서 인스턴스 자신의 속성을 변경하고자 할 때&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;사용한다.&lt;/p&gt;
&lt;blockquote style=&quot;color: #000000; text-align: start;&quot; data-end=&quot;336&quot; data-start=&quot;204&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-end=&quot;336&quot; data-start=&quot;206&quot; data-ke-size=&quot;size16&quot;&gt;클래스(class)는 참조 타입이라서 메서드 내에서 속성 수정이 자유롭지만,&lt;br /&gt;구조체/열거형은 값 타입이라 기본적으로 메서드 내에서 속성 변경이 금지됩니다.&lt;br /&gt;이를 허용하기 위해&lt;span&gt;&amp;nbsp;&lt;/span&gt;mutating&lt;span&gt;&amp;nbsp;&lt;/span&gt;키워드를 사용합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1747749769671&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;struct Counter {
    var count = 0

    mutating func increment() {
        count += 1
    }
}

var c = Counter()
c.increment()
print(c.count) // 1&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;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span&gt;2. Associated Value (연관값)&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;열거형(enum) 에서 각 case에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;값을 함께 저장&lt;/b&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;하고 싶을 때 사용. 마치&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;case&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;가 값과 함께 동작하는 것처럼 만들어줌.&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_1747750044524&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;enum NetworkResult {
    case success(data: String)
    case failure(errorCode: Int, message: String)
}

let result = NetworkResult.failure(errorCode: 404, message: &quot;Not Found&quot;)

switch result {
case .success(let data):
    print(&quot;성공: \(data)&quot;)
case .failure(let code, let message):
    print(&quot;실패: \(code) - \(message)&quot;)
}

// 실패: 404 - Not Found&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1747750109192&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;enum LoginState {
    case loggedOut
    case loggingIn(username: String)
    case loggedIn(userID: Int, nickname: String)
}

let state = LoginState.loggedIn(userID: 122, nickname: &quot;taenee&quot;)

switch state {
case .loggedOut:
    print(&quot;로그아웃 상태입니다.&quot;)
case .loggingIn(let username):
    print(&quot;\(username)님 로그인 중...&quot;)
case .loggedIn(let id, let name):
    print(&quot;\(name)(\(id))님 로그인되었습니다.&quot;)
}

// taenee(122)님 로그인되었습니다.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1594&quot; data-origin-height=&quot;968&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0usi3/btsN4b7T4jm/h6tPI2wHOZjDknW049k8hK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0usi3/btsN4b7T4jm/h6tPI2wHOZjDknW049k8hK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0usi3/btsN4b7T4jm/h6tPI2wHOZjDknW049k8hK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0usi3%2FbtsN4b7T4jm%2Fh6tPI2wHOZjDknW049k8hK%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;1594&quot; height=&quot;968&quot; data-origin-width=&quot;1594&quot; data-origin-height=&quot;968&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>iOS/Swift</category>
      <category>Associated</category>
      <category>associatedvalue</category>
      <category>Mutating</category>
      <category>SWiFT</category>
      <author>태애니</author>
      <guid isPermaLink="true">https://delightpip.tistory.com/379</guid>
      <comments>https://delightpip.tistory.com/379#entry379comment</comments>
      <pubDate>Tue, 20 May 2025 23:09:14 +0900</pubDate>
    </item>
  </channel>
</rss>