<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>수달씨의 개발공간</title>
    <link>https://terrorjang.tistory.com/</link>
    <description>여러 관심사를 가진 개발자의 공간입니다.</description>
    <language>ko</language>
    <pubDate>Sun, 2 Aug 2026 00:23:27 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>개발하는 수달씨</managingEditor>
    <image>
      <title>수달씨의 개발공간</title>
      <url>https://tistory1.daumcdn.net/tistory/1917511/attach/7d6e8ca1d73b437d8da221c3641c03fb</url>
      <link>https://terrorjang.tistory.com</link>
    </image>
    <item>
      <title>[Flutter] 디버그 모드일 때만 기능 실행하기</title>
      <link>https://terrorjang.tistory.com/entry/Flutter-%EB%94%94%EB%B2%84%EA%B7%B8-%EB%AA%A8%EB%93%9C%EC%9D%BC-%EB%95%8C%EB%A7%8C-%EA%B8%B0%EB%8A%A5-%EC%8B%A4%ED%96%89%ED%95%98%EA%B8%B0</link>
      <description>&lt;h1&gt;&lt;b&gt; ️ Flutter에서 디버그 모드일 때만 기능 실행하기&lt;/b&gt;&lt;/h1&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;b&gt;&amp;ldquo;디버그 모드에서만 실행되는 코드&amp;rdquo;&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;Flutter는 이런 상황을 위해 간단한 방법을 제공합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 &lt;span&gt;kDebugMode&lt;/span&gt;를 사용하는 거예요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;✅&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;b&gt;kDebugMode&lt;/b&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;Flutter에서 &lt;span&gt;kDebugMode&lt;/span&gt;는 &lt;span&gt;&lt;b&gt;현재 앱이 디버그 빌드 상태인지 확인&lt;/b&gt;&lt;/span&gt;하는 전역 상수입니다.&lt;/p&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;import 'package:flutter/foundation.dart';

if (kDebugMode) {
  print('디버그 모드입니다!');
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;디버그 빌드일 때만 &lt;span&gt;true&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;릴리즈 빌드나 프로파일 모드에서는 &lt;span&gt;false&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;코드 트리밍으로 인해 &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;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  언제 사용할 수 있을까?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;상황&lt;/b&gt;&lt;b&gt;예시&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;개발자 전용 기능 실행&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;개발 중에만 보이는 버튼/토스트&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;로그 출력&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;디버그 중에만 &lt;span&gt;print()&lt;/span&gt; 사용&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;테스트 데이터 주입&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;가짜 계정으로 자동 로그인&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;저장소 초기화&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;SharedPreferences 강제 리셋 등&lt;/span&gt;&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;  실전 예시&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;  1. 디버그일 때만 실행 횟수 초기화&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;Future&amp;lt;void&amp;gt; resetLaunchCountIfDebug() async {
  final prefs = await SharedPreferences.getInstance();

  if (kDebugMode) {
    await prefs.setInt('launchCount', 0); // 디버깅 중엔 무조건 0부터 시작
  }

  int count = prefs.getInt('launchCount') ?? 0;
  await prefs.setInt('launchCount', count + 1);

  print('앱 실행 횟수: ${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;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;  2. 디버그 모드에서만 개발자용 버튼 표시&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;if (kDebugMode)
  TextButton(
    onPressed: () =&amp;gt; print('디버그용 기능 실행'),
    child: Text('개발자 전용 버튼'),
  ),&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;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;❗주의할 점&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;kDebugMode&lt;span&gt;는 &lt;/span&gt;package:flutter/foundation.dart&lt;span&gt;에서 제공됩니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;릴리즈 빌드에서는 조건문 자체가 포함되지 않기 때문에 성능에도 영향 없음&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;kReleaseMode&lt;span&gt;, &lt;/span&gt;kProfileMode&lt;span&gt;도 함께 활용 가능해요.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;✨ 마무리&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;Flutter 앱을 개발할 때, 디버깅 전용 기능을 안전하게 분리하고 싶다면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;kDebugMode&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&gt;기능 테스트가 깔끔해지고&lt;/li&gt;
&lt;li&gt;실수로 릴리즈 빌드에 들어가는 걸 방지할 수 있어요.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  이 글이 도움이 됐다면 공감 &amp;amp; 댓글 부탁드립니다 :)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Flutter 실전 팁, 상태관리, 배포 전략 등 계속 업데이트할게요!&lt;/p&gt;</description>
      <category>programing/App</category>
      <category>flutter</category>
      <category>kdebugmode</category>
      <category>디버그모드</category>
      <author>개발하는 수달씨</author>
      <guid isPermaLink="true">https://terrorjang.tistory.com/267</guid>
      <comments>https://terrorjang.tistory.com/entry/Flutter-%EB%94%94%EB%B2%84%EA%B7%B8-%EB%AA%A8%EB%93%9C%EC%9D%BC-%EB%95%8C%EB%A7%8C-%EA%B8%B0%EB%8A%A5-%EC%8B%A4%ED%96%89%ED%95%98%EA%B8%B0#entry267comment</comments>
      <pubDate>Mon, 21 Apr 2025 15:45:36 +0900</pubDate>
    </item>
    <item>
      <title>[Flutter macOS] 앱 아이콘 적용 방법</title>
      <link>https://terrorjang.tistory.com/entry/Flutter-macOS-%EC%95%B1-%EC%95%84%EC%9D%B4%EC%BD%98-%EC%A0%81%EC%9A%A9-%EB%B0%A9%EB%B2%95</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;Flutter로 만든 macOS 앱의 기본 아이콘은 Flutter 로고입니다.&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;.icns&lt;/span&gt;&lt;span&gt; 방식 없이, &lt;/span&gt;&lt;b&gt;PNG 파일과 Contents.json 수정만으로 완전히 반영된 방법&lt;/b&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;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;아이콘 이미지 준비&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;아이콘 이미지는 다음과 같이 &lt;span&gt;&lt;b&gt;정사각형 PNG 파일&lt;/b&gt;&lt;/span&gt;로 준비합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;크기는 Apple에서 요구하는 해상도에 맞춰 리사이징합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;파일 이름&lt;/b&gt;&lt;b&gt;크기(px)&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;icon_16x16.png&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;16&amp;times;16&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;icon_16x16@2x.png&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;32&amp;times;32&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;icon_32x32.png&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;32&amp;times;32&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;icon_32x32@2x.png&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;64&amp;times;64&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;icon_128x128.png&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;128&amp;times;128&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;icon_128x128@2x.png&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;256&amp;times;256&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;icon_256x256.png&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;256&amp;times;256&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;icon_256x256@2x.png&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;512&amp;times;512&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;icon_512x512.png&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;512&amp;times;512&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;icon_512x512@2x.png&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span&gt;1024&amp;times;1024&lt;/span&gt;&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;파일 위치&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;생성한 PNG 파일들을 모두 아래 경로로 복사합니다:&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;macos/Runner/Assets.xcassets/AppIcon.appiconset/&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에 있던 Flutter 아이콘 파일들은 덮어쓰거나 삭제해도 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Contents.json 수정&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;같은 폴더에 있는 &lt;span&gt;Contents.json&lt;/span&gt; 파일을 아래와 같이 수정합니다:&lt;/p&gt;
&lt;pre class=&quot;json&quot;&gt;&lt;code&gt;{
  &quot;images&quot;: [
    { &quot;idiom&quot;: &quot;mac&quot;, &quot;size&quot;: &quot;16x16&quot;, &quot;scale&quot;: &quot;1x&quot;, &quot;filename&quot;: &quot;icon_16x16.png&quot; },
    { &quot;idiom&quot;: &quot;mac&quot;, &quot;size&quot;: &quot;16x16&quot;, &quot;scale&quot;: &quot;2x&quot;, &quot;filename&quot;: &quot;icon_16x16@2x.png&quot; },
    { &quot;idiom&quot;: &quot;mac&quot;, &quot;size&quot;: &quot;32x32&quot;, &quot;scale&quot;: &quot;1x&quot;, &quot;filename&quot;: &quot;icon_32x32.png&quot; },
    { &quot;idiom&quot;: &quot;mac&quot;, &quot;size&quot;: &quot;32x32&quot;, &quot;scale&quot;: &quot;2x&quot;, &quot;filename&quot;: &quot;icon_32x32@2x.png&quot; },
    { &quot;idiom&quot;: &quot;mac&quot;, &quot;size&quot;: &quot;128x128&quot;, &quot;scale&quot;: &quot;1x&quot;, &quot;filename&quot;: &quot;icon_128x128.png&quot; },
    { &quot;idiom&quot;: &quot;mac&quot;, &quot;size&quot;: &quot;128x128&quot;, &quot;scale&quot;: &quot;2x&quot;, &quot;filename&quot;: &quot;icon_128x128@2x.png&quot; },
    { &quot;idiom&quot;: &quot;mac&quot;, &quot;size&quot;: &quot;256x256&quot;, &quot;scale&quot;: &quot;1x&quot;, &quot;filename&quot;: &quot;icon_256x256.png&quot; },
    { &quot;idiom&quot;: &quot;mac&quot;, &quot;size&quot;: &quot;256x256&quot;, &quot;scale&quot;: &quot;2x&quot;, &quot;filename&quot;: &quot;icon_256x256@2x.png&quot; },
    { &quot;idiom&quot;: &quot;mac&quot;, &quot;size&quot;: &quot;512x512&quot;, &quot;scale&quot;: &quot;1x&quot;, &quot;filename&quot;: &quot;icon_512x512.png&quot; },
    { &quot;idiom&quot;: &quot;mac&quot;, &quot;size&quot;: &quot;512x512&quot;, &quot;scale&quot;: &quot;2x&quot;, &quot;filename&quot;: &quot;icon_512x512@2x.png&quot; }
  ],
  &quot;info&quot;: {
    &quot;version&quot;: 1,
    &quot;author&quot;: &quot;xcode&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;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;빌드 및 확인&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;설정이 완료되면 앱을 다시 빌드합니다:&lt;/p&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;flutter clean
flutter build macos&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빌드가 완료된 &lt;span&gt;.app&lt;/span&gt; 파일을 실행하거나 Finder, Dock, Spotlight에서 확인했을 때&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;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;마무리&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;Flutter macOS 앱에 아이콘을 적용하는 가장 간단하고 확실한 방법은&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;.icns&lt;/span&gt; 없이 PNG와 Contents.json을 정확히 구성하는 것입니다.&lt;/p&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 프로젝트를 수정할 필요도 없고, Flutter 기본 구조 내에서 완전히 동작합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아이콘 적용이 막히셨다면 이 방식으로 시도해보시길 추천드립니다.&lt;/p&gt;</description>
      <category>programing/App</category>
      <author>개발하는 수달씨</author>
      <guid isPermaLink="true">https://terrorjang.tistory.com/266</guid>
      <comments>https://terrorjang.tistory.com/entry/Flutter-macOS-%EC%95%B1-%EC%95%84%EC%9D%B4%EC%BD%98-%EC%A0%81%EC%9A%A9-%EB%B0%A9%EB%B2%95#entry266comment</comments>
      <pubDate>Tue, 15 Apr 2025 21:19:21 +0900</pubDate>
    </item>
    <item>
      <title>[Flutter/macOS]  .dmg 설치 파일 만들기 (create-dmg)</title>
      <link>https://terrorjang.tistory.com/entry/FluttermacOS-dmg-%EC%84%A4%EC%B9%98-%ED%8C%8C%EC%9D%BC-%EB%A7%8C%EB%93%A4%EA%B8%B0-create-dmg</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Flutter로 만든 macOS 앱을 &lt;span&gt;.dmg&lt;/span&gt; 형식으로 만들어 사용자가 쉽게 설치할 수 있도록 배포하려면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;create-dmg&lt;/span&gt;라는 유틸리티를 사용하면 깔끔한 드래그 앤 드롭 설치 UI를 만들 수 있습니다.&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;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;앱 빌드 완료 후 준비&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;먼저 Flutter 앱을 macOS 용으로 빌드합니다:&lt;/p&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;flutter build macos&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;빌드가 끝나면 &lt;span&gt;.app&lt;/span&gt; 파일이 아래 경로에 생깁니다:&lt;/p&gt;
&lt;pre class=&quot;awk&quot;&gt;&lt;code&gt;build/macos/Build/Products/Release/YourAppName.app&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 이 &lt;span&gt;.app&lt;/span&gt;을 &lt;span&gt;.dmg&lt;/span&gt;로 포장해 보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. 설치에 필요한 폴더 구성&lt;/b&gt;&lt;/h2&gt;
&lt;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;.dmg&lt;/span&gt; 안에는 앱 외에 &lt;span&gt;/Applications&lt;/span&gt;로 연결되는 링크가 필요합니다.&lt;/p&gt;
&lt;pre class=&quot;awk&quot;&gt;&lt;code&gt;mkdir -p dist
cp -R build/macos/Build/Products/Release/YourAppName.app dist/
ln -s /Applications dist/Applications&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote style=&quot;color: #0e0e0e;&quot; data-ke-style=&quot;style1&quot;&gt;&lt;span&gt;dist/&lt;/span&gt; 폴더 안에는 두 개가 있어야 합니다:&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;YourAppName.app&lt;/li&gt;
&lt;li&gt;Applications&lt;span&gt; (심볼릭 링크)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. create-dmg 설치 (처음 한 번만)&lt;/b&gt;&lt;/h2&gt;
&lt;pre class=&quot;mipsasm&quot;&gt;&lt;code&gt;brew install create-dmg&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설치가 완료되면, 어디서든 &lt;span&gt;create-dmg&lt;/span&gt; 명령을 사용할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3.&lt;span&gt; &amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;b&gt;.dmg &lt;/b&gt;&lt;b&gt;파일 생성&lt;/b&gt;&lt;/h2&gt;
&lt;pre class=&quot;dsconfig&quot;&gt;&lt;code&gt;create-dmg \
  --volname &quot;YourAppName&quot; \
  --window-size 500 300 \
  --icon-size 100 \
  --icon &quot;YourAppName.app&quot; 125 150 \
  --hide-extension &quot;YourAppName.app&quot; \
  --app-drop-link 375 150 \
  YourAppName.dmg \
  dist/&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote style=&quot;color: #0e0e0e;&quot; data-ke-style=&quot;style1&quot;&gt;✅ 가장 중요한 포인트:&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;출력 파일 (YourAppName.dmg) 은 마지막에서 두 번째&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;소스 폴더 (dist/) 는 가장 마지막 인자&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시 결과:&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;SimpleFitLog.dmg
├── YourAppName.app
├── Applications (&amp;rarr; /Applications)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;.dmg&lt;/span&gt;를 열면 macOS에서 친숙한 드래그 앤 드롭 설치 UI가 뜹니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4. 자주 발생하는 오류 및 해결&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt; &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;b&gt;cd: --: invalid option&lt;/b&gt;&lt;/h3&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;rarr; &lt;span&gt;--output&lt;/span&gt; 옵션을 쓰면 안 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; &lt;span&gt;.dmg&lt;/span&gt; 파일 이름은 항상 마지막 두 번째 인자로 넣어야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;잘못된 예:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;dsconfig&quot;&gt;&lt;code&gt;create-dmg ... --output YourAppName.dmg dist/&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;올바른 예:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;dsconfig&quot;&gt;&lt;code&gt;create-dmg ... YourAppName.dmg dist/&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;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;5. 추가 팁 (선택 사항)&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;배경 이미지 넣기&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;--background &quot;background.png&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;PNG만 지원&lt;/li&gt;
&lt;li&gt;이미지 크기는 창 크기보다 크거나 같아야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;아이콘 위치 조정&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아이콘 좌표는 픽셀 단위로 조정 가능:&lt;/p&gt;
&lt;pre class=&quot;lsl&quot;&gt;&lt;code&gt;--icon &quot;YourAppName.app&quot; 125 150
--app-drop-link 375 150&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;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;마무리&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;이제 완성된 &lt;span&gt;.dmg&lt;/span&gt; 파일은 다른 사용자에게 배포하거나 웹사이트에 업로드해 사용할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앱 실행 시 Gatekeeper 경고가 뜰 경우, 터미널에서 아래 명령어로 실행 제한을 해제할 수 있습니다:&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;sudo xattr -rd com.apple.quarantine /Applications/YourAppName.app&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 과정을 통해 보다 전문적이고 신뢰감 있는 macOS 앱 배포가 가능해집니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>programing/App</category>
      <author>개발하는 수달씨</author>
      <guid isPermaLink="true">https://terrorjang.tistory.com/265</guid>
      <comments>https://terrorjang.tistory.com/entry/FluttermacOS-dmg-%EC%84%A4%EC%B9%98-%ED%8C%8C%EC%9D%BC-%EB%A7%8C%EB%93%A4%EA%B8%B0-create-dmg#entry265comment</comments>
      <pubDate>Tue, 15 Apr 2025 19:13:24 +0900</pubDate>
    </item>
    <item>
      <title>[VSCode] Vim 사용 시 키 연속 입력이 안 되는 문제 해결 (macOS 기준)</title>
      <link>https://terrorjang.tistory.com/entry/VSCode-Vim-%EC%82%AC%EC%9A%A9-%EC%8B%9C-%ED%82%A4-%EC%97%B0%EC%86%8D-%EC%9E%85%EB%A0%A5%EC%9D%B4-%EC%95%88-%EB%90%98%EB%8A%94-%EB%AC%B8%EC%A0%9C-%ED%95%B4%EA%B2%B0-macOS-%EA%B8%B0%EC%A4%80</link>
      <description>&lt;h1&gt;  VSCode에서 Vim 사용 시 키 연속 입력이 안 되는 문제 해결 (macOS 기준)&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;h, j, k, l 키를 누르면서 방향 이동하는 게 Vim의 핵심인데, VSCode에서 Vim 확장 플러그인을 사용할 때 이 키들이 &lt;b&gt;연속으로 입력되지 않는 문제&lt;/b&gt;가 발생할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글에서는 그 원인과 해결 방법을 자세히 정리해봅니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  문제 현상&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;h, j, k, l 키를 &lt;b&gt;길게 눌러도 한 글자만 입력됨&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;Vim 모드에서 커서가 연속으로 움직이지 않음&lt;/li&gt;
&lt;li&gt;일반적인 키보드 타이핑은 이상 없음&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  원인: macOS의 Press and Hold 기능&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;macOS는 기본적으로 키를 길게 누르면 &quot;특수 문자 선택 팝업&quot;이 뜨도록 설정돼 있습니다. 이 기능이 Vim에서는 방해가 되죠.&lt;br /&gt;VSCode에서도 이 기능이 활성화되어 있다면, 키를 꾹 눌러도 연속 입력이 되지 않습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 해결 방법&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. VSCode에 한해서 Press and Hold 끄기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;터미널을 열고 아래 명령어를 입력하세요:&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;defaults write com.microsoft.VSCode ApplePressAndHoldEnabled -bool false
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 VSCode를&lt;b&gt; 완전히 종료한 후&lt;/b&gt; 다시 실행합니다. - 창닫기만 할 시 적용 안됨.&lt;br /&gt;이제 h, j, k, l 키를 꾹 눌렀을 때 &lt;b&gt;연속 입력이 정상 동작&lt;/b&gt;합니다!&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 시스템 전체에 적용하고 싶다면 (선택)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 앱에서도 연속 입력이 안 되는 경우, 아래 명령어로 전역 설정을 바꿀 수 있어요:&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;defaults write -g ApplePressAndHoldEnabled -bool false
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ 주의: 이 설정은 시스템 전체에 영향을 미치므로, 일부 앱에서는 부작용이 생길 수도 있습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 키 반복 속도 빠르게 조절하기 (추가 팁)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;더 쾌적한 Vim 사용을 위해 키보드 입력 속도도 아래처럼 조절해보세요.&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;시스템 설정 &amp;gt; 키보드&lt;/b&gt;에서
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;키 반복 속도&lt;/b&gt;: 빠르게&lt;/li&gt;
&lt;li&gt;&lt;b&gt;반복 시작 지연 시간&lt;/b&gt;: 짧게&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 하면 j, k로 커서 이동할 때 더 빠르고 자연스럽습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✨ 마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VSCode에서 Vim을 제대로 사용하려면 &lt;b&gt;연속 키 입력 설정&lt;/b&gt;은 필수입니다.&lt;br /&gt;이 문제는 macOS에서 자주 발생하는 이슈지만, 간단한 설정으로 쉽게 해결할 수 있어요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;혹시 위 방법으로도 해결되지 않거나 QMK 키보드 설정과 관련된 문제가 있다면 댓글로 남겨주세요!  &lt;/p&gt;</description>
      <category>ETC/기타</category>
      <category>MacOS</category>
      <category>vim 연속 키</category>
      <category>vscode vim</category>
      <author>개발하는 수달씨</author>
      <guid isPermaLink="true">https://terrorjang.tistory.com/264</guid>
      <comments>https://terrorjang.tistory.com/entry/VSCode-Vim-%EC%82%AC%EC%9A%A9-%EC%8B%9C-%ED%82%A4-%EC%97%B0%EC%86%8D-%EC%9E%85%EB%A0%A5%EC%9D%B4-%EC%95%88-%EB%90%98%EB%8A%94-%EB%AC%B8%EC%A0%9C-%ED%95%B4%EA%B2%B0-macOS-%EA%B8%B0%EC%A4%80#entry264comment</comments>
      <pubDate>Thu, 3 Apr 2025 16:16:25 +0900</pubDate>
    </item>
    <item>
      <title>[Flutter]UUID 사용법 완벽 정리 &amp;ndash; v1, v4, v5 차이점과 예제까지</title>
      <link>https://terrorjang.tistory.com/entry/FlutterUUID-%EC%82%AC%EC%9A%A9%EB%B2%95-%EC%99%84%EB%B2%BD-%EC%A0%95%EB%A6%AC-%E2%80%93-v1-v4-v5-%EC%B0%A8%EC%9D%B4%EC%A0%90%EA%B3%BC-%EC%98%88%EC%A0%9C%EA%B9%8C%EC%A7%80</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;앱에서 고유 ID(Unique ID)를 생성해야 할 때, 가장 널리 쓰이는 방식이 바로 &lt;b&gt;UUID (Universally Unique Identifier)&lt;/b&gt;입니다.&lt;br /&gt;Flutter에서는 uuid&amp;nbsp;패키지를 통해 간편하게 다양한 방식의 UUID를 생성할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글에서는:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;uuid 패키지 설치 방법&lt;/li&gt;
&lt;li&gt;UUID 버전(v1, v4, v5)의 차이점&lt;/li&gt;
&lt;li&gt;실전 예제와 사용 팁&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;까지 하나씩 정리해보겠습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  1. uuid 패키지 설치하기&lt;/h2&gt;
&lt;pre class=&quot;dockerfile&quot;&gt;&lt;code&gt;flutter pub add uuid
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;혹은 pubspec.yaml에 직접 추가:&lt;/p&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;dependencies:
  uuid: ^4.2.1  # 최신 버전 확인
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 import:&lt;/p&gt;
&lt;pre class=&quot;actionscript&quot;&gt;&lt;code&gt;import 'package:uuid/uuid.dart';
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  2. UUID 버전별 차이점 정리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;버전 방식 설명 특징&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;v1&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Time-based&lt;/td&gt;
&lt;td&gt;시간 + 기기(MAC 주소) 기반&lt;/td&gt;
&lt;td&gt;순차적 생성 가능, MAC 유출 위험&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;v2&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;DCE Security&lt;/td&gt;
&lt;td&gt;v1 + 사용자/그룹 ID&lt;/td&gt;
&lt;td&gt;거의 사용되지 않음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;v3&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Name-based (MD5)&lt;/td&gt;
&lt;td&gt;문자열 + 네임스페이스 &amp;rarr; MD5 해시&lt;/td&gt;
&lt;td&gt;입력이 같으면 UUID도 같음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;v4&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Random&lt;/td&gt;
&lt;td&gt;무작위(random) 값 기반&lt;/td&gt;
&lt;td&gt;일반적으로 가장 많이 사용됨&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;v5&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Name-based (SHA-1)&lt;/td&gt;
&lt;td&gt;v3와 동일하나 SHA-1 해시 사용&lt;/td&gt;
&lt;td&gt;더 강력한 보안 해시&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;⚙️ 3. UUID 생성 예제 (Dart 코드)&lt;/h2&gt;
&lt;pre class=&quot;rust&quot;&gt;&lt;code&gt;final uuid = Uuid();

// ✅ v1 &amp;ndash; 시간 + MAC 주소 기반
String idV1 = uuid.v1(); // 예: 'f64c8b26-3e46-11ec-8d3d-0242ac130003'

// ✅ v4 &amp;ndash; 랜덤 기반 (가장 많이 사용)
String idV4 = uuid.v4(); // 예: 'c3c3bc94-b070-4787-9f7d-b2592b4d51ef'

// ✅ v5 &amp;ndash; 고정된 문자열로 UUID 생성 (SHA-1)
String idV5 = uuid.v5(Uuid.NAMESPACE_URL, 'https://example.com');
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  v3도 동일 방식으로 가능:&lt;/h3&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;String idV3 = uuid.v3(Uuid.NAMESPACE_URL, 'https://example.com'); // MD5 기반
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&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;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;단순한 고유 ID가 필요할 때&lt;/td&gt;
&lt;td&gt;v4&lt;/td&gt;
&lt;td&gt;간단하고 충돌 확률 매우 낮음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;시간 순서대로 정렬이 필요할 때&lt;/td&gt;
&lt;td&gt;v1&lt;/td&gt;
&lt;td&gt;생성 시간 정보 포함됨&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;입력값이 항상 같을 때 동일한 ID가 필요할 때&lt;/td&gt;
&lt;td&gt;v5 (또는 v3)&lt;/td&gt;
&lt;td&gt;해시 기반 고정 UUID 생성&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;❗️주의할 점 (v1의 MAC 주소 노출)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;v1 UUID는 내부적으로 &lt;b&gt;기기의 MAC 주소&lt;/b&gt;를 사용합니다.&lt;/li&gt;
&lt;li&gt;이 정보는 유출되면 &lt;b&gt;기기 식별 가능성&lt;/b&gt;이 있으므로 보안이 중요한 앱에서는 피하는 것이 좋습니다.&lt;/li&gt;
&lt;li&gt;대부분의 경우 v4를 사용하는 것이 안전하고 충분합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✨ 실전 사용 예: 모델 ID 생성&lt;/h2&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;class Task {
  final String id;
  final String title;

  Task({required this.title}) : id = const Uuid().v4();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 매 Task 인스턴스를 생성할 때 자동으로 &lt;b&gt;고유한 UUID&lt;/b&gt;를 부여합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  요약&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;uuid 패키지를 설치하면 다양한 방식으로 고유 식별자를 생성할 수 있음&lt;/li&gt;
&lt;li&gt;대부분의 경우 v4 (랜덤 기반)가 안정적이고 보편적&lt;/li&gt;
&lt;li&gt;v5는 &lt;b&gt;동일 입력 &amp;rarr; 동일 UUID&lt;/b&gt;가 필요할 때 매우 유용&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>programing/App</category>
      <category>dart</category>
      <category>flutter</category>
      <category>UUID</category>
      <category>uuid 패키지</category>
      <category>고유 식별자</category>
      <author>개발하는 수달씨</author>
      <guid isPermaLink="true">https://terrorjang.tistory.com/263</guid>
      <comments>https://terrorjang.tistory.com/entry/FlutterUUID-%EC%82%AC%EC%9A%A9%EB%B2%95-%EC%99%84%EB%B2%BD-%EC%A0%95%EB%A6%AC-%E2%80%93-v1-v4-v5-%EC%B0%A8%EC%9D%B4%EC%A0%90%EA%B3%BC-%EC%98%88%EC%A0%9C%EA%B9%8C%EC%A7%80#entry263comment</comments>
      <pubDate>Thu, 3 Apr 2025 09:33:17 +0900</pubDate>
    </item>
    <item>
      <title>[Dart/LeetCode 209] Minimum Size Subarray Sum &amp;mdash; 슬라이딩 윈도우 알고리즘으로 푸는 최단 부분합 문제</title>
      <link>https://terrorjang.tistory.com/entry/DartLeetCode-209-Minimum-Size-Subarray-Sum-%E2%80%94-%EC%8A%AC%EB%9D%BC%EC%9D%B4%EB%94%A9-%EC%9C%88%EB%8F%84%EC%9A%B0-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%EC%9C%BC%EB%A1%9C-%ED%91%B8%EB%8A%94-%EC%B5%9C%EB%8B%A8-%EB%B6%80%EB%B6%84%ED%95%A9-%EB%AC%B8%EC%A0%9C</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;부분합이 특정 값을 넘는 &lt;b&gt;가장 짧은 연속된 부분 배열&lt;/b&gt;의 길이를 구하는 문제입니다.&lt;br /&gt;단순히 합만 구하는 것이 아니라, &lt;b&gt;길이까지 고려&lt;/b&gt;해야 하기에 효율적인 알고리즘이 필요합니다.&lt;br /&gt;이 글에서는 &lt;b&gt;Brute-force 접근 &amp;rarr; 슬라이딩 윈도우 최적화&lt;/b&gt; 과정을 거쳐,&lt;br /&gt;Dart로 완성도 높은 코드를 작성하고 이해하는 과정을 함께합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  문제 설명&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;양의 정수 배열 nums와 목표값 target이 주어질 때,&lt;br /&gt;합이 target 이상이 되는 &lt;b&gt;연속된 부분 배열(subarray)&lt;/b&gt; 중에서&lt;br /&gt;&lt;b&gt;가장 짧은 길이&lt;/b&gt;를 반환하라.&lt;br /&gt;없으면 0을 반환한다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;❌ Brute-force 접근 (비효율)&lt;/h2&gt;
&lt;pre class=&quot;matlab&quot;&gt;&lt;code&gt;int minLength = nums.length + 1;

for (int i = 0; i &amp;lt; nums.length; i++) {
  int sum = 0;
  for (int j = i; j &amp;lt; nums.length; j++) {
    sum += nums[j];
    if (sum &amp;gt;= target) {
      minLength = min(minLength, j - i + 1);
      break;
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;시간복잡도: O(n&amp;sup2;)&lt;/b&gt; &amp;rarr; 큰 입력에서는 시간 초과 가능성 있음&lt;/li&gt;
&lt;li&gt;매 i마다 전체 탐색 &amp;rarr; 비효율적&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 최적화: 슬라이딩 윈도우&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;슬라이딩 윈도우는 &lt;b&gt;합이 기준 이상일 때 길이를 최소화하는 문제&lt;/b&gt;에 딱 적합합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  Dart 코드&lt;/h2&gt;
&lt;pre class=&quot;excel&quot;&gt;&lt;code&gt;class Solution {
  int minSubArrayLen(int target, List&amp;lt;int&amp;gt; nums) {
    int n = nums.length;
    int left = 0;
    int sum = 0;
    int minLength = n + 1;

    for (int right = 0; right &amp;lt; n; right++) {
      sum += nums[right];

      while (sum &amp;gt;= target) {
        minLength = minLength &amp;lt; (right - left + 1) ? minLength : (right - left + 1);
        sum -= nums[left];
        left++;
      }
    }

    return minLength == n + 1 ? 0 : minLength;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&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;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;sum += nums[right]&lt;/td&gt;
&lt;td&gt;윈도우 오른쪽 확장하며 합 누적&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;while (sum &amp;gt;= target)&lt;/td&gt;
&lt;td&gt;조건 만족 시 길이 갱신 시도&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;minLength = ...&lt;/td&gt;
&lt;td&gt;현재 길이가 기존 최소보다 짧으면 갱신&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;sum -= nums[left]; left++&lt;/td&gt;
&lt;td&gt;왼쪽을 줄이며 더 짧은 조합 시도&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;종료 후 리턴&lt;/td&gt;
&lt;td&gt;조건 만족한 적 없으면 0, 있으면 최소 길이&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  슬라이딩 윈도우 흐름 예시&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력: target = 7, nums = [2,3,1,2,4,3]&lt;/p&gt;
&lt;div&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1026&quot; data-start=&quot;165&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style14&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;step&lt;/td&gt;
&lt;td&gt;left&lt;/td&gt;
&lt;td&gt;right&lt;/td&gt;
&lt;td&gt;sum&lt;/td&gt;
&lt;td&gt;조건 만족&lt;/td&gt;
&lt;td&gt;윈도우 길이&lt;/td&gt;
&lt;td&gt;minLength&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;371&quot; data-start=&quot;299&quot;&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;&amp;infin;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;444&quot; data-start=&quot;372&quot;&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;&amp;infin;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;517&quot; data-start=&quot;445&quot;&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;&amp;infin;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;590&quot; data-start=&quot;518&quot;&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;663&quot; data-start=&quot;591&quot;&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;736&quot; data-start=&quot;664&quot;&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;4 &amp;rarr; 3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;809&quot; data-start=&quot;737&quot;&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;3 &amp;rarr; 2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;882&quot; data-start=&quot;810&quot;&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;953&quot; data-start=&quot;883&quot;&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;유지&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1026&quot; data-start=&quot;954&quot;&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;⏱ 시간 &amp;amp; 공간 복잡도&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;항목 복잡도 설명&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;시간&lt;/td&gt;
&lt;td&gt;O(n)&lt;/td&gt;
&lt;td&gt;각 포인터가 최대 한 번씩만 이동&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;공간&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;td&gt;추가 공간 없음&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✨ 실전 팁 요약&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;ldquo;조건 만족하는 최소 길이&amp;rdquo; 문제는 무조건 &lt;b&gt;슬라이딩 윈도우&lt;/b&gt; 먼저 떠올릴 것&lt;/li&gt;
&lt;li&gt;오른쪽으로 확장하면서 합을 만들고, 왼쪽을 줄여가며 최소 길이 갱신&lt;/li&gt;
&lt;li&gt;투 포인터 + 조건 기반 줄이기 전략은 여러 문제에 응용 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LeetCode,&amp;nbsp;Dart&amp;nbsp;알고리즘,&amp;nbsp;슬라이딩&amp;nbsp;윈도우,&amp;nbsp;투&amp;nbsp;포인터,&amp;nbsp;부분합&amp;nbsp;문제&lt;/p&gt;</description>
      <category>Algorithm/LeetCode</category>
      <category>dart 알고리즘</category>
      <category>leetcode</category>
      <category>부분합 문제</category>
      <category>슬라이딩 윈도우</category>
      <category>투 포인터</category>
      <author>개발하는 수달씨</author>
      <guid isPermaLink="true">https://terrorjang.tistory.com/262</guid>
      <comments>https://terrorjang.tistory.com/entry/DartLeetCode-209-Minimum-Size-Subarray-Sum-%E2%80%94-%EC%8A%AC%EB%9D%BC%EC%9D%B4%EB%94%A9-%EC%9C%88%EB%8F%84%EC%9A%B0-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%EC%9C%BC%EB%A1%9C-%ED%91%B8%EB%8A%94-%EC%B5%9C%EB%8B%A8-%EB%B6%80%EB%B6%84%ED%95%A9-%EB%AC%B8%EC%A0%9C#entry262comment</comments>
      <pubDate>Thu, 3 Apr 2025 09:02:50 +0900</pubDate>
    </item>
    <item>
      <title>Dart-LeetCode 11번: Container With Most Water &amp;mdash; 투 포인터 전략으로 풀어보기</title>
      <link>https://terrorjang.tistory.com/entry/Dart-LeetCode-11%EB%B2%88-Container-With-Most-Water-%E2%80%94-%ED%88%AC-%ED%8F%AC%EC%9D%B8%ED%84%B0-%EC%A0%84%EB%9E%B5%EC%9C%BC%EB%A1%9C-%ED%92%80%EC%96%B4%EB%B3%B4%EA%B8%B0</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;물통에 가장 많은 물을 담는 방법은?&lt;br /&gt;LeetCode의 11번 문제 &lt;b&gt;&quot;Container With Most Water&quot;&lt;/b&gt;는 그리디한 사고와 &lt;b&gt;투 포인터 알고리즘&lt;/b&gt;을 적절히 활용할 수 있는 대표 문제입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글에서는 Dart로 문제를 풀이하며,&lt;br /&gt;&lt;b&gt;왜 투 포인터가 최적인지&lt;/b&gt;,&lt;br /&gt;&lt;b&gt;어떻게 중복 계산 없이 최대값을 구하는지&lt;/b&gt;&lt;br /&gt;명확히 설명합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  문제 요약&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;height[i]는 위치 i에서 세운 수직선의 높이입니다.&lt;/li&gt;
&lt;li&gt;두 선을 골라, 그 사이를 x축으로 막아 생기는 &lt;b&gt;컨테이너의 물 저장 용량&lt;/b&gt;을 구해야 합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;조건&lt;/b&gt;: 컨테이너는 기울일 수 없습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  핵심 아이디어: 투 포인터 (Two Pointers)&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;❌ 브루트 포스 접근 (비효율)&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;int max = 0;
for (int i = 0; i &amp;lt; height.length; i++) {
  for (int j = i + 1; j &amp;lt; height.length; j++) {
    int area = (j - i) * min(height[i], height[j]);
    max = max &amp;gt; area ? max : area;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시간 복잡도: &lt;b&gt;O(n&amp;sup2;)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&amp;rarr; 모든 경우를 비교 = 너무 느림!&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ 최적화: 투 포인터 전략&lt;/h3&gt;
&lt;pre class=&quot;swift&quot;&gt;&lt;code&gt;import 'dart:math';

class Solution {
  int maxArea(List&amp;lt;int&amp;gt; height) {
    int left = 0, right = height.length - 1, answer = 0;

    while (left &amp;lt; right) {
      int width = right - left;
      int water = width * min(height[left], height[right]);
      answer = max(answer, water);

      if (height[left] &amp;lt; height[right]) {
        left++;  // 더 낮은 쪽을 안쪽으로 이동
      } else {
        right--;
      }
    }

    return answer;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  왜 투 포인터인가?&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;물의 양 = &lt;b&gt;너비 &amp;times; 높이&lt;/b&gt;&lt;/li&gt;
&lt;li&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;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; 즉, &lt;b&gt;낮은 쪽을 안쪽으로 이동시키며 최댓값 갱신&lt;/b&gt;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  예제 설명&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력: [1,8,6,2,5,4,8,3,7]&lt;br /&gt;&amp;rarr; 최댓값은 49: height[1]=8, height[8]=7, 거리 7 &amp;rarr; 7 &amp;times; 7 = 49&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&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;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;O(n) &amp;mdash; 포인터 한 번씩만 움직임&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;공간&lt;/td&gt;
&lt;td&gt;O(1) &amp;mdash; 추가 배열 없이 변수만 사용&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✨ 실전 팁&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 문제는 투 포인터 개념을 익히기에 아주 좋아요.&lt;/li&gt;
&lt;li&gt;리스트의 양 끝에서 출발하여, &lt;b&gt;내려오면서 갱신&lt;/b&gt;하는 방식은 다양한 문제에 응용 가능&lt;/li&gt;
&lt;li&gt;슬라이딩 윈도우 / 그리디 문제에서도 자주 등장하는 패턴입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;Container With Most Water&quot;는 단순해보이지만,&lt;br /&gt;&lt;b&gt;투 포인터의 본질적인 사고법&lt;/b&gt;을 배울 수 있는 문제입니다.&lt;br /&gt;이 문제 하나만 확실히 이해해도, 이후 LeetCode 문제에서 유사 패턴을 빠르게 인식하게 됩니다.&lt;/p&gt;</description>
      <category>Algorithm/LeetCode</category>
      <category>dart</category>
      <category>leetcode</category>
      <category>알고리즘 문제풀이</category>
      <category>최적화 전략</category>
      <category>투포인터 알고리즘</category>
      <author>개발하는 수달씨</author>
      <guid isPermaLink="true">https://terrorjang.tistory.com/261</guid>
      <comments>https://terrorjang.tistory.com/entry/Dart-LeetCode-11%EB%B2%88-Container-With-Most-Water-%E2%80%94-%ED%88%AC-%ED%8F%AC%EC%9D%B8%ED%84%B0-%EC%A0%84%EB%9E%B5%EC%9C%BC%EB%A1%9C-%ED%92%80%EC%96%B4%EB%B3%B4%EA%B8%B0#entry261comment</comments>
      <pubDate>Wed, 2 Apr 2025 09:08:54 +0900</pubDate>
    </item>
    <item>
      <title>[Flutter macOS] 앱을 항상 위에 고정(Always on Top) + 기본 창 크기 설정하는 방법</title>
      <link>https://terrorjang.tistory.com/entry/Flutter-macOS-%EC%95%B1%EC%9D%84-%ED%95%AD%EC%83%81-%EC%9C%84%EC%97%90-%EA%B3%A0%EC%A0%95Always-on-Top-%EA%B8%B0%EB%B3%B8-%EC%B0%BD-%ED%81%AC%EA%B8%B0-%EC%84%A4%EC%A0%95%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;  요약 설명&amp;nbsp;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Flutter로 macOS 앱을 개발할 때 기본 창 크기를 설정하고, 앱을 &quot;항상 위에 고정(Always on Top)&quot;으로 띄우는 방법을 소개합니다. 에디터와 앱을 나란히 띄우기 위한 실사용 팁!&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt; ️ 문제 상황&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Flutter로 macOS 앱을 개발할 때, 앱을 항상 에디터 옆에 띄워놓고 싶었어요.&lt;br /&gt;하지만 앱을 실행하면 매번 이상한 위치에 뜨거나 다른 창 뒤로 가버리는 게 너무 불편했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 &lt;b&gt;macOS 앱을 항상 위에 고정&lt;/b&gt;시키고, &lt;b&gt;기본 창 크기도 지정&lt;/b&gt;하는 방법을 정리해봤습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  해결 방법 요약&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;MainFlutterWindow.swift에서 macOS 앱의 창 속성을 직접 설정할 수 있습니다.&lt;/li&gt;
&lt;li&gt;여기서 창 크기, 창 위치, 항상 위에 고정(floating)을 커스터마이징하면 됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  수정할 파일&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;macos/Runner/MainFlutterWindow.swift&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✅ 최종 코드 예시&lt;/h2&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;import Cocoa
import FlutterMacOS

class MainFlutterWindow: NSWindow {
  override func awakeFromNib() {
    let flutterViewController = FlutterViewController()

    // 원하는 창 크기
    let windowWidth: CGFloat = 800
    let windowHeight: CGFloat = 600

    // 화면 중앙에 창 위치 설정
    if let screenFrame = NSScreen.main?.frame {
      let originX = (screenFrame.width - windowWidth) / 2
      let originY = (screenFrame.height - windowHeight) / 2
      let newFrame = NSRect(x: originX, y: originY, width: windowWidth, height: windowHeight)
      self.setFrame(newFrame, display: true)
    }

    // 항상 위에 설정
    self.level = .floating

    self.contentViewController = flutterViewController

    RegisterGeneratedPlugins(registry: flutterViewController)

    super.awakeFromNib()
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;  추가 팁&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;self.level = .floating &amp;rarr; 이걸 설정하면 앱 창이 항상 다른 창 위에 떠 있어요.&lt;br /&gt;특히 &lt;b&gt;코드 에디터 + 앱 창 나란히 테스트할 때&lt;/b&gt; 엄청 편합니다.&lt;/li&gt;
&lt;li&gt;self.setFrame(...) &amp;rarr; 앱의 기본 위치와 크기를 지정할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;revenue_unit_wrap&quot;&gt;
  &lt;div class=&quot;revenue_unit_item adsense responsive&quot;&gt;
    &lt;div class=&quot;revenue_unit_info&quot;&gt;반응형&lt;/div&gt;
    &lt;script src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot; async=&quot;async&quot;&gt;&lt;/script&gt;
    &lt;ins class=&quot;adsbygoogle&quot; style=&quot;display: block;&quot; data-ad-host=&quot;ca-host-pub-9691043933427338&quot; data-ad-client=&quot;ca-pub-7208889806864928&quot; data-ad-format=&quot;auto&quot;&gt;&lt;/ins&gt;
    &lt;script&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/script&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;✨ 마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에디터와 앱을 동시에 띄워놓고 작업할 때, 이 설정 하나로 스트레스가 확 줄었어요.&lt;br /&gt;macOS 앱에서 UI 디버깅 자주 하시는 분들께 꼭 추천드립니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필요하면 이미지나 gif 첨부용 예시도 만들어줄 수 있어.&lt;br /&gt;티스토리에 바로 붙여넣을 HTML 포맷도 원해?&lt;/p&gt;</description>
      <category>programing/App</category>
      <category>flutter macos always on top</category>
      <category>flutter macos floating window</category>
      <category>flutter macos window size</category>
      <category>flutter macos 기본 창 크기</category>
      <category>flutter macos 창 고정</category>
      <category>flutter 앱 항상 위에 고정</category>
      <author>개발하는 수달씨</author>
      <guid isPermaLink="true">https://terrorjang.tistory.com/260</guid>
      <comments>https://terrorjang.tistory.com/entry/Flutter-macOS-%EC%95%B1%EC%9D%84-%ED%95%AD%EC%83%81-%EC%9C%84%EC%97%90-%EA%B3%A0%EC%A0%95Always-on-Top-%EA%B8%B0%EB%B3%B8-%EC%B0%BD-%ED%81%AC%EA%B8%B0-%EC%84%A4%EC%A0%95%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95#entry260comment</comments>
      <pubDate>Tue, 1 Apr 2025 16:32:44 +0900</pubDate>
    </item>
    <item>
      <title>[LeetCode 167] Two Sum II - Input Array Is Sorted﻿</title>
      <link>https://terrorjang.tistory.com/entry/LeetCode-167-Two-Sum-II-Input-Array-Is-Sorted</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://leetcode.com/problems/two-sum-ii-input-array-is-sorted/&quot;&gt;LeetCode 167: Two Sum II - Input Array Is Sorted&lt;/a&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  문제 설명&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;주어진 정렬된 배열&lt;/b&gt;에서 &lt;b&gt;두 숫자의 합&lt;/b&gt;이 &lt;b&gt;주어진 target과 일치하는 인덱스&lt;/b&gt;를 반환하는 문제입니다.&lt;br /&gt;배열의 &lt;b&gt;인덱스는 1부터 시작&lt;/b&gt;하고, 합이 일치하는 두 숫자의 &lt;b&gt;인덱스를 1-based로 반환&lt;/b&gt;해야 합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ 풀이 아이디어: Two Pointers 알고리즘&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제는 &lt;b&gt;Two Pointers&lt;/b&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;을 이용해 left 포인터는 배열의 앞에서 시작하고, right 포인터는 배열의 끝에서 시작합니다.&lt;/li&gt;
&lt;li&gt;두 포인터의 합이 target보다 작으면 left를 증가시키고, 합이 크면 right를 감소시킵니다.&lt;/li&gt;
&lt;li&gt;두 포인터가 가리키는 값이 합이 target과 같다면 그 인덱스를 반환합니다.&lt;/li&gt;
&lt;li&gt;이러한 방식으로 한 번 순회하여 문제를 해결할 수 있습니다. 이때 **시간 복잡도는 O(n)**입니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ 구현 코드 (TypeScript)&lt;/h3&gt;
&lt;pre class=&quot;coq&quot;&gt;&lt;code&gt;export function twoSum(numbers: number[], target: number): number[] {
  let left = 0;
  let right = numbers.length - 1;

  while (left &amp;lt; right) {
    const sum = numbers[left] + numbers[right];

    if (sum === target) {
      return [left + 1, right + 1]; // 1-based index
    }

    if (sum &amp;lt; target) {
      left++; // 합이 target보다 작으면 left 포인터를 증가
    } else {
      right--; // 합이 target보다 크면 right 포인터를 감소
    }
  }

  return [];
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ 테스트 코드 (Jest)&lt;/h3&gt;
&lt;pre class=&quot;lisp&quot;&gt;&lt;code&gt;describe(&quot;Medium 167: Two Sum II&quot;, () =&amp;gt; {
  it(&quot;should return [1, 2] for [2, 7, 11, 15] and target 9&quot;, () =&amp;gt; {
    expect(twoSum([2, 7, 11, 15], 9)).toEqual([1, 2]);
  });

  it(&quot;should return [1, 2] for [-1, 0] and target -1&quot;, () =&amp;gt; {
    expect(twoSum([-1, 0], -1)).toEqual([1, 2]);
  });

  it(&quot;should return [1, 3] for [2, 3, 4] and target 6&quot;, () =&amp;gt; {
    expect(twoSum([2, 3, 4], 6)).toEqual([1, 3]);
  });
});
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ 시간 복잡도&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;시간 복잡도&lt;/b&gt;: O(n)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배열을 한 번만 순회하므로, 시간 복잡도는 배열의 길이에 비례하여 &lt;b&gt;선형&lt;/b&gt;입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;공간 복잡도&lt;/b&gt;: O(1)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;추가적인 공간을 사용하지 않으므로 공간 복잡도는 &lt;b&gt;상수&lt;/b&gt;입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ 마무리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제를 풀면서 &lt;b&gt;중간 난이도 문제도 이제는 한 번에 풀 수 있게 된 것 같다는 자신감&lt;/b&gt;이 생겼습니다.&lt;br /&gt;Two Pointers 알고리즘을 통해 &lt;b&gt;정렬된 배열에서 빠르게 답을 찾는 기법&lt;/b&gt;을 잘 활용한 문제였습니다. 이제는 이런 유형의 문제를 더 잘 풀 수 있을 것 같아요.&lt;/p&gt;</description>
      <category>Algorithm/LeetCode</category>
      <category>leetcode</category>
      <category>TwoPointers</category>
      <category>typescript</category>
      <category>배열문제</category>
      <category>알고리즘</category>
      <author>개발하는 수달씨</author>
      <guid isPermaLink="true">https://terrorjang.tistory.com/259</guid>
      <comments>https://terrorjang.tistory.com/entry/LeetCode-167-Two-Sum-II-Input-Array-Is-Sorted#entry259comment</comments>
      <pubDate>Fri, 28 Mar 2025 08:26:52 +0900</pubDate>
    </item>
    <item>
      <title>[React] key를 분명히 넣었는데도 Warning이 뜬다면? (Fragment 주의!)</title>
      <link>https://terrorjang.tistory.com/entry/React-key%EB%A5%BC-%EB%B6%84%EB%AA%85%ED%9E%88-%EB%84%A3%EC%97%88%EB%8A%94%EB%8D%B0%EB%8F%84-Warning%EC%9D%B4-%EB%9C%AC%EB%8B%A4%EB%A9%B4-Fragment-%EC%A3%BC%EC%9D%98</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-size: 1.44em; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;  문제 상황&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React에서 컴포넌트 리스트를 .map()으로 렌더링할 때, 다음과 같은 에러가 자주 발생합니다:&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;Warning: Each child in a list should have a unique 'key' prop.
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 보통은 아래처럼 key를 추가하죠.&lt;/p&gt;
&lt;pre class=&quot;xquery&quot;&gt;&lt;code&gt;items.map((item) =&amp;gt; (
  &amp;lt;MyComponent key={item.id} item={item} /&amp;gt;
))
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만! &lt;b&gt;정상적으로 key를 넣었음에도 불구하고&lt;/b&gt; 위와 같은 경고가 계속 발생하는 경우가 있습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;❓ 대체 왜?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제의 진짜 원인은&amp;hellip; 바로 &lt;b&gt;Fragment (&amp;lt;&amp;gt;...&amp;lt;/&amp;gt;) 때문&lt;/b&gt;입니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  문제 코드 예시&lt;/h3&gt;
&lt;pre class=&quot;xquery&quot;&gt;&lt;code&gt;items.map((item) =&amp;gt; (
  &amp;lt;&amp;gt;
    &amp;lt;MyComponent key={item.id} item={item} /&amp;gt;
  &amp;lt;/&amp;gt;
))
&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드는 MyComponent에 key를 넣었지만,&lt;br /&gt;&lt;b&gt;사실상 무시&lt;/b&gt;되고 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜냐하면, React는 .map()으로 &lt;b&gt;직접 리턴하는 최상위 노드&lt;/b&gt;에 key가 있는지를 보기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 위의 코드는:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Fragment가 최상위인데 key 없음 &amp;rarr; ❌&lt;/li&gt;
&lt;li&gt;내부 MyComponent에 있는 key &amp;rarr; 무시됨 &amp;rarr; ❌ 경고 발생&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ 해결 방법&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;방법 1: Fragment 없애기 (권장)&lt;/h4&gt;
&lt;pre class=&quot;xquery&quot;&gt;&lt;code&gt;items.map((item) =&amp;gt; (
  &amp;lt;MyComponent key={item.id} item={item} /&amp;gt;
))
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;방법 2: Fragment에 key 넣기 (가능하지만 비권장)&lt;/h4&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;items.map((item) =&amp;gt; (
  &amp;lt;React.Fragment key={item.id}&amp;gt;
    &amp;lt;MyComponent item={item} /&amp;gt;
  &amp;lt;/React.Fragment&amp;gt;
))
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  실전 예: React Native ScrollView 안에서 발생한 사례&lt;/h3&gt;
&lt;pre class=&quot;xquery&quot;&gt;&lt;code&gt;&amp;lt;ScrollView&amp;gt;
  {items.map((item) =&amp;gt; (
    &amp;lt;&amp;gt;
      &amp;lt;TimelineItem key={item.id} item={item} /&amp;gt;
    &amp;lt;/&amp;gt;
  ))}
&amp;lt;/ScrollView&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 구조에서 Fragment가 key를 무시하면서 경고가 발생했습니다.&lt;br /&gt;&amp;rarr; Fragment를 제거하거나, key를 Fragment로 올리면 해결됩니다!&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;  정리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구조 key 인식 여부 추천 여부&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;&amp;lt;Component key={...} /&amp;gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅ 강력 추천&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;lt;&amp;gt;&amp;lt;Component key={...} /&amp;gt;&amp;lt;/&amp;gt;&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌ 경고 발생&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;lt;Fragment key={...}&amp;gt;&amp;lt;Component /&amp;gt;&amp;lt;/Fragment&amp;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;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;✅ 마무리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React에서 key 경고가 사라지지 않을 때는&lt;br /&gt;&lt;b&gt;&quot;내가 넣은 key가 최상위 엘리먼트에 있는가?&quot;&lt;/b&gt; 를 꼭 확인하세요!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히, 아무 생각 없이 쓴 &amp;lt;&amp;gt; ... &amp;lt;/&amp;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>programing/App</category>
      <category>React</category>
      <category>react fragment</category>
      <category>react key warning</category>
      <category>react 개발 팁</category>
      <category>리액트 map key 에러</category>
      <author>개발하는 수달씨</author>
      <guid isPermaLink="true">https://terrorjang.tistory.com/257</guid>
      <comments>https://terrorjang.tistory.com/entry/React-key%EB%A5%BC-%EB%B6%84%EB%AA%85%ED%9E%88-%EB%84%A3%EC%97%88%EB%8A%94%EB%8D%B0%EB%8F%84-Warning%EC%9D%B4-%EB%9C%AC%EB%8B%A4%EB%A9%B4-Fragment-%EC%A3%BC%EC%9D%98#entry257comment</comments>
      <pubDate>Thu, 27 Mar 2025 19:12:03 +0900</pubDate>
    </item>
  </channel>
</rss>