<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>임다 블로그</title>
    <link>https://gallery-a.tistory.com/</link>
    <description>IT와 프로그래밍에 대한 글을 작성하는 블로그입니다.</description>
    <language>ko</language>
    <pubDate>Tue, 12 May 2026 06:32:53 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>임다</managingEditor>
    <image>
      <title>임다 블로그</title>
      <url>https://tistory1.daumcdn.net/tistory/6200750/attach/9b6c628ee1b34ef8b55fb90827adeb00</url>
      <link>https://gallery-a.tistory.com</link>
    </image>
    <item>
      <title>iframe과 통신하는 방법</title>
      <link>https://gallery-a.tistory.com/99</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;iframe이란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;iframe&lt;/code&gt;(inline frame)은 HTML 문서 내에 다른 HTML 페이지를 삽입할 수 있는 태그입니다. 주로 외부 콘텐츠를 현재 페이지에 표시하거나, 서로 다른 도메인의 콘텐츠를 불러오는 데 사용됩니다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;&amp;lt;iframe src=&quot;https://www.example.com&quot; width=&quot;600&quot; height=&quot;400&quot;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같은 코드로 외부 사이트를 현재 페이지에 삽입할 수 있습니다. 그러나 &lt;code&gt;iframe&lt;/code&gt;에 삽입된 콘텐츠와 부모 페이지 간에는 보안상의 이유로 직접적으로 &lt;code&gt;JavaScript&lt;/code&gt; 객체를 공유할 수 없습니다. 이러한 제약은 특히 서로 다른 출처(&lt;code&gt;origin&lt;/code&gt;)를 가진 경우 더 엄격해집니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;code&gt;iframe&lt;/code&gt;과의 통신 방식&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;iframe&lt;/code&gt;과 부모 페이지 간의 통신을 위해 가장 일반적으로 사용되는 방법은 &lt;code&gt;postMessage&lt;/code&gt; API입니다. 이 방법은 서로 다른 출처 간에도 안전하게 메시지를 주고받을 수 있도록 설계되었습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;code&gt;postMessage&lt;/code&gt;란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;postMessage&lt;/code&gt;는 서로 다른 윈도우 간에 안전하게 메시지를 보낼 수 있는 API입니다. 부모 페이지는 &lt;code&gt;iframe&lt;/code&gt;에 메시지를 보내고, &lt;code&gt;iframe&lt;/code&gt;은 부모 페이지로부터 메시지를 수신할 수 있습니다.&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;targetWindow.postMessage(message, targetOrigin);&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;targetWindow&lt;/code&gt;: 메시지를 보낼 대상 창(&lt;code&gt;iframe&lt;/code&gt;의 &lt;code&gt;contentWindow&lt;/code&gt; 등).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;message&lt;/code&gt;: 전송할 데이터(문자열 또는 객체).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;targetOrigin&lt;/code&gt;: 메시지를 수신할 창의 출처(&lt;code&gt;origin&lt;/code&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;code&gt;iframe&lt;/code&gt;으로 메시지 보내기&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;부모 페이지 코드&lt;/h3&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;!-- 부모 페이지 --&amp;gt;
&amp;lt;iframe id=&quot;childFrame&quot; src=&quot;child.html&quot; width=&quot;600&quot; height=&quot;400&quot;&amp;gt;&amp;lt;/iframe&amp;gt;

&amp;lt;button id=&quot;sendMessageButton&quot;&amp;gt;메시지 보내기&amp;lt;/button&amp;gt;

&amp;lt;script&amp;gt;
  const iframe = document.getElementById('childFrame');
  const sendMessageButton = document.getElementById('sendMessageButton');

  sendMessageButton.addEventListener('click', () =&amp;gt; {
    const message = { type: 'GREETING', text: '안녕하세요, iframe!' };
    iframe.contentWindow.postMessage(message, 'https://example.com'); // 정확한 출처 지정
  });
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;iframe&lt;/code&gt; 요소를 가져와 &lt;code&gt;contentWindow&lt;/code&gt;를 통해 &lt;code&gt;postMessage&lt;/code&gt;를 호출합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;message&lt;/code&gt;는 객체 형태로 전송할 수 있으며, &lt;code&gt;type&lt;/code&gt;을 활용해 메시지의 유형을 구분할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;targetOrigin&lt;/code&gt;은 반드시 &lt;code&gt;iframe&lt;/code&gt;의 정확한 출처로 지정해야 보안 사고를 예방할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;code&gt;iframe&lt;/code&gt; 페이지 코드(&lt;code&gt;child.html&lt;/code&gt;)&lt;/h3&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;!-- child.html --&amp;gt;
&amp;lt;script&amp;gt;
  window.addEventListener('message', (event) =&amp;gt; {
    // 보안: 신뢰할 수 있는 출처인지 확인
    if (event.origin !== 'https://parent.com') {
      return;
    }

    const { type, text } = event.data;

    if (type === 'GREETING') {
      console.log('부모로부터 받은 메시지:', text);
    }
  });
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;message&lt;/code&gt; 이벤트를 수신하기 위해 &lt;code&gt;addEventListener&lt;/code&gt;로 이벤트 리스너를 등록합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;event.origin&lt;/code&gt;을 확인하여 신뢰할 수 없는 출처의 메시지를 차단합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;event.data&lt;/code&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;code&gt;iframe&lt;/code&gt;에서 부모 페이지로 메시지 보내기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반대로 &lt;code&gt;iframe&lt;/code&gt;에서 부모 페이지로 메시지를 보낼 수도 있습니다. 이때는 &lt;code&gt;parent.postMessage&lt;/code&gt;를 사용합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;code&gt;iframe&lt;/code&gt; 페이지 코드(&lt;code&gt;child.html&lt;/code&gt;)&lt;/h3&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;button id=&quot;sendToParentButton&quot;&amp;gt;부모로 메시지 보내기&amp;lt;/button&amp;gt;

&amp;lt;script&amp;gt;
  const sendToParentButton = document.getElementById('sendToParentButton');

  sendToParentButton.addEventListener('click', () =&amp;gt; {
    const message = { type: 'RESPONSE', text: '안녕하세요, 부모님!' };
    parent.postMessage(message, 'https://parent.com'); // 부모 출처 지정
  });
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;parent.postMessage&lt;/code&gt;를 통해 부모 창으로 메시지를 전송합니다.&lt;/li&gt;
&lt;li&gt;보안 강화를 위해 부모 페이지의 정확한 출처를 지정합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;부모 페이지 코드&lt;/h3&gt;
&lt;pre class=&quot;mel&quot;&gt;&lt;code&gt;window.addEventListener('message', (event) =&amp;gt; {
  if (event.origin !== 'https://example.com') {
    return; // 출처 확인
  }

  const { type, text } = event.data;

  if (type === 'RESPONSE') {
    console.log('iframe으로부터 받은 메시지:', text);
  }
});&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;code&gt;postMessage&lt;/code&gt; 사용 시 보안 고려 사항&lt;/h2&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;code&gt;origin&lt;/code&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;code&gt;event.origin&lt;/code&gt;을 확인하여 신뢰할 수 있는 출처에서 온 메시지만 처리해야 합니다.&lt;/li&gt;
&lt;li&gt;예: &lt;code&gt;if (event.origin !== 'https://trusted-site.com') return;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&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;/li&gt;
&lt;li&gt;예: &lt;code&gt;if (typeof event.data === 'object' &amp;amp;&amp;amp; event.data.type) { ... }&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;code&gt;targetOrigin&lt;/code&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;code&gt;postMessage&lt;/code&gt; 호출 시 &lt;code&gt;'*'&lt;/code&gt;을 사용하지 말고, 가능한 한 정확한 출처를 지정해야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&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;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;실전 예제: 부모와 &lt;code&gt;iframe&lt;/code&gt; 간의 양방향 채팅&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;부모 페이지 (&lt;code&gt;index.html&lt;/code&gt;)&lt;/h3&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;iframe id=&quot;chatFrame&quot; src=&quot;chat.html&quot; width=&quot;400&quot; height=&quot;300&quot;&amp;gt;&amp;lt;/iframe&amp;gt;

&amp;lt;div&amp;gt;
  &amp;lt;input type=&quot;text&quot; id=&quot;parentMessage&quot; placeholder=&quot;부모 메시지 입력&quot; /&amp;gt;
  &amp;lt;button id=&quot;sendToIframe&quot;&amp;gt;보내기&amp;lt;/button&amp;gt;
&amp;lt;/div&amp;gt;

&amp;lt;script&amp;gt;
  const iframe = document.getElementById('chatFrame');
  const messageInput = document.getElementById('parentMessage');
  const sendButton = document.getElementById('sendToIframe');

  sendButton.addEventListener('click', () =&amp;gt; {
    const message = messageInput.value;
    iframe.contentWindow.postMessage({ type: 'PARENT_MESSAGE', text: message }, 'https://example.com');
    messageInput.value = '';
  });

  window.addEventListener('message', (event) =&amp;gt; {
    if (event.origin !== 'https://example.com') return;

    const { type, text } = event.data;
    if (type === 'IFRAME_MESSAGE') {
      console.log('iframe 메시지:', text);
    }
  });
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;code&gt;iframe&lt;/code&gt; 페이지 (&lt;code&gt;chat.html&lt;/code&gt;)&lt;/h3&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;div&amp;gt;
  &amp;lt;input type=&quot;text&quot; id=&quot;iframeMessage&quot; placeholder=&quot;iframe 메시지 입력&quot; /&amp;gt;
  &amp;lt;button id=&quot;sendToParent&quot;&amp;gt;부모로 보내기&amp;lt;/button&amp;gt;
&amp;lt;/div&amp;gt;

&amp;lt;script&amp;gt;
  const messageInput = document.getElementById('iframeMessage');
  const sendButton = document.getElementById('sendToParent');

  sendButton.addEventListener('click', () =&amp;gt; {
    const message = messageInput.value;
    parent.postMessage({ type: 'IFRAME_MESSAGE', text: message }, 'https://parent.com');
    messageInput.value = '';
  });

  window.addEventListener('message', (event) =&amp;gt; {
    if (event.origin !== 'https://parent.com') return;

    const { type, text } = event.data;
    if (type === 'PARENT_MESSAGE') {
      console.log('부모 메시지:', text);
    }
  });
&amp;lt;/script&amp;gt;&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;code&gt;iframe&lt;/code&gt;과 부모 페이지 간의 통신은 &lt;code&gt;postMessage&lt;/code&gt; API를 통해 안전하고 효율적으로 처리할 수 있습니다.&lt;/li&gt;
&lt;li&gt;반드시 &lt;code&gt;origin&lt;/code&gt; 검증과 데이터 유효성 검사를 통해 보안 위협을 방지해야 합니다.&lt;/li&gt;
&lt;li&gt;실시간 데이터 교환, 채팅 기능, 외부 서비스 통합 등 다양한 활용이 가능합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;postMessage&lt;/code&gt;의 활용 방법과 보안 지침을 잘 숙지하면 복잡한 웹 애플리케이션에서도 안전한 &lt;code&gt;iframe&lt;/code&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;1868&quot; data-origin-height=&quot;1038&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/H4cfQ/btsL4b2eMsX/WaMbFhmmg1XZM7dkIzHUak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/H4cfQ/btsL4b2eMsX/WaMbFhmmg1XZM7dkIzHUak/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/H4cfQ/btsL4b2eMsX/WaMbFhmmg1XZM7dkIzHUak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FH4cfQ%2FbtsL4b2eMsX%2FWaMbFhmmg1XZM7dkIzHUak%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;1868&quot; height=&quot;1038&quot; data-origin-width=&quot;1868&quot; data-origin-height=&quot;1038&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>취미/개발</category>
      <category>frontend</category>
      <category>iframe</category>
      <category>inline frame</category>
      <category>JavaScript</category>
      <category>PostMessage</category>
      <category>web</category>
      <author>임다</author>
      <guid isPermaLink="true">https://gallery-a.tistory.com/99</guid>
      <comments>https://gallery-a.tistory.com/99#entry99comment</comments>
      <pubDate>Mon, 3 Feb 2025 15:31:05 +0900</pubDate>
    </item>
    <item>
      <title>Web Worker란 무엇인가?</title>
      <link>https://gallery-a.tistory.com/98</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;Web Worker 개념&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Web Worker&lt;/code&gt;는 웹 애플리케이션에서 메인 스레드와 별도로 백그라운드에서 자바스크립트 코드를 실행할 수 있는 방법을 제공합니다. 이를 통해 CPU 집약적인 작업을 메인 스레드의 렌더링이나 사용자 인터페이스(UI) 처리에 영향을 주지 않고 수행할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 브라우저의 자바스크립트는 기본적으로 단일 스레드로 동작합니다. 이로 인해 무거운 계산 작업이나 데이터 처리 로직이 실행될 경우 페이지가 멈추거나 느려지는 현상이 발생할 수 있습니다. 이러한 문제를 해결하기 위해 &lt;code&gt;Web Worker&lt;/code&gt;를 사용합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Web Worker의 주요 특징&lt;/h2&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;: 무거운 연산이나 대용량 데이터 처리 작업을 백그라운드에서 실행하여 UI의 부드러운 동작 유지&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;code&gt;postMessage()&lt;/code&gt;와 &lt;code&gt;onmessage&lt;/code&gt; 이벤트 리스너를 통해 메인 스레드와 데이터를 주고받을 수 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DOM 접근 불가&lt;/b&gt;: &lt;code&gt;Web Worker&lt;/code&gt;는 브라우저의 DOM에 직접 접근할 수 없음 (렌더링 관련 작업은 메인 스레드에서 처리해야 함)&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Web Worker 기본 사용법&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. Worker 파일 생성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 &lt;code&gt;worker.js&lt;/code&gt;라는 파일을 만듭니다.&lt;/p&gt;
&lt;pre class=&quot;php&quot;&gt;&lt;code&gt;// worker.js
self.onmessage = function(event) {
    const receivedData = event.data;
    const result = receivedData * 2; // 받은 값을 2배로 처리
    self.postMessage(result); // 결과를 메인 스레드로 반환
};&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;self&lt;/code&gt;는 워커 자체를 가리키며, &lt;code&gt;onmessage&lt;/code&gt; 이벤트 리스너를 통해 메인 스레드로부터 메시지를 수신합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;postMessage()&lt;/code&gt;를 통해 메인 스레드로 처리된 데이터를 다시 전달합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 메인 스레드에서 Worker 사용&lt;/h3&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;// main.js
const worker = new Worker('worker.js');

worker.onmessage = function(event) {
    console.log('Worker로부터 받은 결과:', event.data);
};

worker.postMessage(10); // Worker로 값 전달&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;new Worker('worker.js')&lt;/code&gt;로 워커 인스턴스를 생성합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;postMessage(10)&lt;/code&gt;을 사용해 &lt;code&gt;worker.js&lt;/code&gt;로 데이터를 보냅니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;worker.onmessage&lt;/code&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;Web Worker의 실제 활용 예제&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;대규모 데이터 처리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, 대규모 배열에서 소수를 찾는 작업은 CPU 부하가 큰 작업입니다. 이 작업을 &lt;code&gt;Web Worker&lt;/code&gt;로 처리해 보겠습니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. Worker 파일 (primeWorker.js)&lt;/h4&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;self.onmessage = function(event) {
    const maxNumber = event.data;
    const primeNumbers = [];

    function isPrime(number) {
        if (number &amp;lt; 2) return false;
        for (let i = 2; i &amp;lt;= Math.sqrt(number); i++) {
            if (number % i === 0) return false;
        }
        return true;
    }

    for (let i = 2; i &amp;lt;= maxNumber; i++) {
        if (isPrime(i)) {
            primeNumbers.push(i);
        }
    }

    self.postMessage(primeNumbers);
};&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. 메인 스레드&lt;/h4&gt;
&lt;pre class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot;&gt;&lt;code&gt;const primeWorker = new Worker('primeWorker.js');

primeWorker.onmessage = function(event) {
    console.log('찾은 소수 목록:', event.data);
};

primeWorker.postMessage(100000); // 10만까지의 소수 찾기 요청&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;h2 data-ke-size=&quot;size26&quot;&gt;Web Worker의 한계와 주의사항&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;DOM 접근 불가&lt;/b&gt;: &lt;code&gt;Web Worker&lt;/code&gt;는 DOM 요소를 직접 조작할 수 없습니다. DOM 업데이트는 반드시 메인 스레드에서 처리해야 합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;파일 경로 제한&lt;/b&gt;: &lt;code&gt;Worker&lt;/code&gt;는 동일 출처 정책(same-origin policy)을 따르므로 다른 도메인의 스크립트는 로드할 수 없습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;비용이 큰 초기화&lt;/b&gt;: &lt;code&gt;Worker&lt;/code&gt; 생성에는 비용이 들기 때문에 너무 많은 워커를 생성하는 것은 오히려 성능을 저하시킬 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;복잡한 데이터 전송&lt;/b&gt;: 데이터는 직렬화되어 전송되므로 대용량 데이터를 빈번히 주고받으면 성능 저하가 발생할 수 있습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Shared Worker와 Service Worker&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;Shared Worker&lt;/b&gt;: 여러 탭이나 윈도우에서 공유할 수 있는 워커입니다. 예를 들어 여러 탭에서 동일한 데이터 소스를 공유해야 할 때 유용합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Service Worker&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;Web Worker와 멀티스레딩의 차이점&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Web Worker&lt;/code&gt;는 자바스크립트에서 제한적으로 제공되는 멀티스레딩 기능과 유사하지만, 진정한 멀티스레딩과는 다소 차이가 있습니다. &lt;code&gt;Web Worker&lt;/code&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;&lt;code&gt;Web Worker&lt;/code&gt;는 자바스크립트의 싱글 스레드 한계를 극복하고, 무거운 작업을 효율적으로 처리할 수 있는 강력한 도구입니다. 특히 대규모 데이터 처리, 이미지 처리, 암호화 작업 등 CPU 집약적인 작업을 수행할 때 매우 유용합니다. 다만 DOM 접근 불가, 초기화 비용 등 한계점을 잘 이해하고 사용해야 합니다.&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;1890&quot; data-origin-height=&quot;1048&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxs7Of/btsL4YgNqad/rpTATR35lgcvktjLlP5fkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxs7Of/btsL4YgNqad/rpTATR35lgcvktjLlP5fkk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxs7Of/btsL4YgNqad/rpTATR35lgcvktjLlP5fkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbxs7Of%2FbtsL4YgNqad%2FrpTATR35lgcvktjLlP5fkk%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;1890&quot; height=&quot;1048&quot; data-origin-width=&quot;1890&quot; data-origin-height=&quot;1048&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>취미/개발</category>
      <category>frontend</category>
      <category>JavaScript</category>
      <category>web</category>
      <category>Web Worker</category>
      <category>웹 워커</category>
      <author>임다</author>
      <guid isPermaLink="true">https://gallery-a.tistory.com/98</guid>
      <comments>https://gallery-a.tistory.com/98#entry98comment</comments>
      <pubDate>Sun, 2 Feb 2025 15:16:10 +0900</pubDate>
    </item>
    <item>
      <title>URL과 URLSearchParams 활용법</title>
      <link>https://gallery-a.tistory.com/97</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;URL과 URLSearchParams 개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 개발을 하다 보면 브라우저의 주소창에 보이는 URL을 다루거나, URL의 쿼리 문자열을 분석해야 하는 경우가 많습니다. 이때 유용하게 사용할 수 있는 것이 &lt;code&gt;URL&lt;/code&gt;과 &lt;code&gt;URLSearchParams&lt;/code&gt;입니다. 이 두 가지는 자바스크립트에서 제공하는 내장 객체로, URL을 쉽고 직관적으로 다룰 수 있도록 도와줍니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;URL 객체의 기본 사용법&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;URL&lt;/code&gt; 객체는 전체 URL을 분해하거나 조작할 때 사용됩니다. &lt;code&gt;URL&lt;/code&gt; 생성자는 전체 URL 문자열을 받아 객체를 생성합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;URL 객체 생성하기&lt;/h3&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;const siteUrl = new URL('https://www.example.com:8080/path/to/page?category=books&amp;amp;sort=asc#section2');

console.log(siteUrl);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 생성된 &lt;code&gt;URL&lt;/code&gt; 객체는 여러 속성을 제공합니다.&lt;/p&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;code&gt;href&lt;/code&gt;: 전체 URL 문자열&lt;/li&gt;
&lt;li&gt;&lt;code&gt;protocol&lt;/code&gt;: URL의 프로토콜 (예: &lt;code&gt;https:&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;hostname&lt;/code&gt;: 도메인 이름 (예: &lt;code&gt;www.example.com&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;port&lt;/code&gt;: 포트 번호 (예: &lt;code&gt;8080&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pathname&lt;/code&gt;: 경로 (예: &lt;code&gt;/path/to/page&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;search&lt;/code&gt;: 쿼리 문자열 (예: &lt;code&gt;?category=books&amp;amp;sort=asc&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;hash&lt;/code&gt;: 해시 (예: &lt;code&gt;#section2&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;예제: URL 속성 확인&lt;/h3&gt;
&lt;pre class=&quot;openscad&quot;&gt;&lt;code&gt;console.log(siteUrl.href);       // &quot;https://www.example.com:8080/path/to/page?category=books&amp;amp;sort=asc#section2&quot;
console.log(siteUrl.protocol);   // &quot;https:&quot;
console.log(siteUrl.hostname);   // &quot;www.example.com&quot;
console.log(siteUrl.port);       // &quot;8080&quot;
console.log(siteUrl.pathname);   // &quot;/path/to/page&quot;
console.log(siteUrl.search);     // &quot;?category=books&amp;amp;sort=asc&quot;
console.log(siteUrl.hash);       // &quot;#section2&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이처럼 URL의 각 부분을 손쉽게 추출할 수 있습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;URLSearchParams의 활용&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;URLSearchParams&lt;/code&gt;는 URL의 쿼리 문자열을 조작하는 데 특화된 객체입니다. &lt;code&gt;URL&lt;/code&gt; 객체의 &lt;code&gt;searchParams&lt;/code&gt; 속성을 통해 쉽게 사용할 수 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;URLSearchParams 객체 생성하기&lt;/h3&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;const queryParams = new URLSearchParams('category=books&amp;amp;sort=asc');&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또는 &lt;code&gt;URL&lt;/code&gt; 객체와 함께 사용하면 더 편리합니다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;const siteUrl = new URL('https://www.example.com/path?category=books&amp;amp;sort=asc');
const queryParams = siteUrl.searchParams;&lt;/code&gt;&lt;/pre&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;code&gt;get(key)&lt;/code&gt;: 특정 쿼리 매개변수의 값을 가져옵니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;set(key, value)&lt;/code&gt;: 특정 쿼리 매개변수의 값을 설정합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;append(key, value)&lt;/code&gt;: 동일한 키에 새로운 값을 추가합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;has(key)&lt;/code&gt;: 특정 쿼리 매개변수가 존재하는지 확인합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;delete(key)&lt;/code&gt;: 특정 쿼리 매개변수를 삭제합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;toString()&lt;/code&gt;: 쿼리 문자열로 변환합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;예제: 쿼리 매개변수 조작하기&lt;/h3&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;console.log(queryParams.get('category')); // &quot;books&quot;
queryParams.set('sort', 'desc');          // sort=desc로 변경
queryParams.append('page', '2');          // page=2 추가
queryParams.delete('category');           // category 삭제

console.log(queryParams.toString());      // &quot;sort=desc&amp;amp;page=2&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;URL과 URLSearchParams를 활용한 실전 예제&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;예제 1: 사용자가 선택한 필터를 URL에 반영하기&lt;/h3&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;function updateURL(category, sort, page) {
    const currentUrl = new URL(window.location.href);
    currentUrl.searchParams.set('category', category);
    currentUrl.searchParams.set('sort', sort);
    currentUrl.searchParams.set('page', page);

    window.history.pushState({}, '', currentUrl);
}

updateURL('movies', 'popular', 3);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 하면 브라우저의 주소창이 &lt;code&gt;?category=movies&amp;amp;sort=popular&amp;amp;page=3&lt;/code&gt;로 변경됩니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;예제 2: URL에서 쿼리 매개변수 읽어오기&lt;/h3&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;function getQueryParam(key) {
    const currentUrl = new URL(window.location.href);
    return currentUrl.searchParams.get(key);
}

const selectedCategory = getQueryParam('category');
console.log(selectedCategory); // 현재 URL에 따라 출력값이 달라짐&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;URL과 URLSearchParams의 장점&lt;/h2&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; 문자열 파싱 없이 직관적으로 URL과 쿼리 매개변수를 다룰 수 있습니다.&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;code&gt;URLSearchParams&lt;/code&gt;는 HTTP 요청을 보낼 때 유용합니다.&lt;/li&gt;
&lt;/ol&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;브라우저 호환성:&lt;/b&gt; 구형 브라우저(특히 Internet Explorer)에서는 &lt;code&gt;URLSearchParams&lt;/code&gt;가 지원되지 않습니다. 필요한 경우 폴리필을 사용해야 합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;URL 인코딩:&lt;/b&gt; &lt;code&gt;URLSearchParams&lt;/code&gt;는 자동으로 URL 인코딩을 처리합니다. 그러나 서버와의 호환성을 위해 추가적인 처리가 필요할 수 있습니다.&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;code&gt;URL&lt;/code&gt;과 &lt;code&gt;URLSearchParams&lt;/code&gt;는 URL을 다루는 과정을 매우 간단하고 직관적으로 만들어줍니다. 웹 개발에서 URL 파싱, 쿼리 문자열 조작, 상태 관리 등 다양한 상황에서 활용할 수 있으며, 코드의 가독성과 유지 보수성을 높이는 데 큰 도움이 됩니다.&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;1876&quot; data-origin-height=&quot;1044&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MvJAg/btsL4I6vj0O/oiEgohRPYdxRu1tqrWHo31/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MvJAg/btsL4I6vj0O/oiEgohRPYdxRu1tqrWHo31/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MvJAg/btsL4I6vj0O/oiEgohRPYdxRu1tqrWHo31/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMvJAg%2FbtsL4I6vj0O%2FoiEgohRPYdxRu1tqrWHo31%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;1876&quot; height=&quot;1044&quot; data-origin-width=&quot;1876&quot; data-origin-height=&quot;1044&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>취미/개발</category>
      <category>frontend</category>
      <category>JavaScript</category>
      <category>web</category>
      <author>임다</author>
      <guid isPermaLink="true">https://gallery-a.tistory.com/97</guid>
      <comments>https://gallery-a.tistory.com/97#entry97comment</comments>
      <pubDate>Sat, 1 Feb 2025 20:14:05 +0900</pubDate>
    </item>
    <item>
      <title>MutationObserver란?</title>
      <link>https://gallery-a.tistory.com/96</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;MutationObserver란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;MutationObserver&lt;/code&gt;는 DOM(Document Object Model) 요소의 변화(변경 사항)를 비동기적으로 감지할 수 있는 기능을 제공합니다. 예를 들어, 웹 페이지에서 특정 요소의 속성, 자식 노드, 텍스트 콘텐츠가 변경될 때 이를 실시간으로 감지하고 대응할 수 있게 해주는 도구입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;MutationObserver&lt;/code&gt;는 이전에 사용되던 &lt;code&gt;Mutation Events&lt;/code&gt;의 한계를 보완하기 위해 도입된 API입니다. &lt;code&gt;Mutation Events&lt;/code&gt;는 성능이 저하되는 문제가 있었지만, &lt;code&gt;MutationObserver&lt;/code&gt;는 더 나은 성능과 효율성을 제공합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;MutationObserver의 주요 기능&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DOM 요소의 추가, 삭제 감지&lt;/li&gt;
&lt;li&gt;요소의 속성(&lt;code&gt;attribute&lt;/code&gt;) 변경 감지&lt;/li&gt;
&lt;li&gt;텍스트 콘텐츠의 변경 감지&lt;/li&gt;
&lt;li&gt;하위 트리(&lt;code&gt;subtree&lt;/code&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;MutationObserver의 기본 구조&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;MutationObserver&lt;/code&gt;를 사용하기 위해서는 다음과 같은 단계를 거쳐야 합니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&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;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;옵저버 중지 (필요 시)&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;기본 코드 예제&lt;/h3&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;// 1. MutationObserver 인스턴스 생성
const observer = new MutationObserver((mutationRecords, observer) =&amp;gt; {
  mutationRecords.forEach((mutation) =&amp;gt; {
    console.log('변경 사항 감지:', mutation);
  });
});

// 2. 감시할 대상 요소 선택
const targetElement = document.getElementById('target');

// 3. 감시 옵션 설정
const config = {
  childList: true,       // 자식 노드의 추가 또는 제거 감지
  attributes: true,      // 속성 변경 감지
  characterData: true,   // 텍스트 콘텐츠 변경 감지
  subtree: true          // 하위 트리까지 감지
};

// 4. 옵저버 시작
observer.observe(targetElement, config);

// 5. 변경 테스트를 위한 코드
targetElement.setAttribute('data-status', 'active'); // 속성 변경
targetElement.textContent = '새로운 텍스트';         // 텍스트 콘텐츠 변경
const newElement = document.createElement('div');    // 자식 노드 추가
targetElement.appendChild(newElement);&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;결과&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 코드를 실행하면 콘솔에는 다음과 같은 메시지가 출력됩니다.&lt;/p&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;변경 사항 감지: [MutationRecord 객체]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 &lt;code&gt;MutationRecord&lt;/code&gt; 객체에는 변경된 내용에 대한 상세 정보가 포함됩니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;MutationObserver의 설정 옵션&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;옵저버의 감시 동작을 설정하기 위해 &lt;code&gt;observe&lt;/code&gt; 메서드에서 사용하는 설정 객체(&lt;code&gt;config&lt;/code&gt;)는 다음과 같은 속성을 가집니다.&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;옵션&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;th&gt;데이터 타입&lt;/th&gt;
&lt;th&gt;기본값&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;childList&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;자식 노드의 추가/제거 감지&lt;/td&gt;
&lt;td&gt;&lt;code&gt;boolean&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;attributes&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;속성의 변경 감지&lt;/td&gt;
&lt;td&gt;&lt;code&gt;boolean&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;characterData&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;텍스트 콘텐츠의 변경 감지&lt;/td&gt;
&lt;td&gt;&lt;code&gt;boolean&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;subtree&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;하위 트리까지 감지&lt;/td&gt;
&lt;td&gt;&lt;code&gt;boolean&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;attributeFilter&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;감시할 속성 목록 지정&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Array&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;null&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;attributeOldValue&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;변경 전 속성 값 저장&lt;/td&gt;
&lt;td&gt;&lt;code&gt;boolean&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;characterDataOldValue&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;변경 전 텍스트 콘텐츠 저장&lt;/td&gt;
&lt;td&gt;&lt;code&gt;boolean&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;예제: 특정 속성만 감지하기&lt;/h3&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;observer.observe(targetElement, {
  attributes: true,
  attributeFilter: ['data-status'] // 특정 속성만 감지
});

targetElement.setAttribute('data-status', 'inactive'); // 감지됨
targetElement.setAttribute('class', 'new-class');      // 감지되지 않음&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 설정은 &lt;code&gt;data-status&lt;/code&gt; 속성의 변경만 감지하고, 다른 속성 변경은 무시합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;MutationRecord 객체 이해하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;옵저버 콜백 함수로 전달되는 &lt;code&gt;mutationRecords&lt;/code&gt; 배열은 각 변경 사항을 나타내는 &lt;code&gt;MutationRecord&lt;/code&gt; 객체로 구성되어 있습니다. 이 객체는 다음과 같은 속성을 가집니다.&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;속성&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;type&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;변경 유형 (&lt;code&gt;attributes&lt;/code&gt;, &lt;code&gt;childList&lt;/code&gt;, &lt;code&gt;characterData&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;target&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;변경이 발생한 요소&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;addedNodes&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;새로 추가된 노드 목록&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;removedNodes&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;제거된 노드 목록&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;attributeName&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;변경된 속성 이름 (속성 변경 시)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;oldValue&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;변경 전 값 (옵션 설정 시)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;예제: MutationRecord 속성 확인&lt;/h3&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;const observer = new MutationObserver((mutations) =&amp;gt; {
  mutations.forEach((mutation) =&amp;gt; {
    console.log('변경 유형:', mutation.type);
    console.log('변경된 요소:', mutation.target);
    if (mutation.type === 'attributes') {
      console.log('변경된 속성:', mutation.attributeName);
      console.log('이전 값:', mutation.oldValue);
    }
  });
});

observer.observe(targetElement, {
  attributes: true,
  attributeOldValue: true
});

targetElement.setAttribute('data-status', 'completed');&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;MutationObserver의 성능 고려 사항&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;MutationObserver&lt;/code&gt;는 성능이 최적화되어 있지만, 과도한 감시 설정은 여전히 성능 저하를 초래할 수 있습니다. 특히 대규모 DOM 구조나 빈번한 변경이 발생하는 요소를 감시할 때 주의해야 합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;성능 최적화 팁&lt;/h3&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;code&gt;childList&lt;/code&gt;, &lt;code&gt;attributes&lt;/code&gt;, &lt;code&gt;characterData&lt;/code&gt; 중 필요한 옵션만 설정합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;code&gt;subtree&lt;/code&gt; 사용 최소화:&lt;/b&gt; 하위 트리 감시는 범위가 넓어져 성능에 영향을 줄 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;옵저버 중지:&lt;/b&gt; 필요 없는 경우 &lt;code&gt;disconnect()&lt;/code&gt; 메서드로 감시를 중지합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;// 옵저버 중지
observer.disconnect();&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;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;div id=&quot;comments&quot;&amp;gt;
  &amp;lt;p&amp;gt;첫 번째 댓글&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;button id=&quot;addComment&quot;&amp;gt;댓글 추가&amp;lt;/button&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;const commentSection = document.getElementById('comments');
const addCommentButton = document.getElementById('addComment');

const observer = new MutationObserver((mutations) =&amp;gt; {
  mutations.forEach((mutation) =&amp;gt; {
    if (mutation.type === 'childList') {
      console.log('새로운 댓글이 추가되었습니다.');
    }
  });
});

observer.observe(commentSection, { childList: true });

addCommentButton.addEventListener('click', () =&amp;gt; {
  const newComment = document.createElement('p');
  newComment.textContent = '새로운 댓글입니다!';
  commentSection.appendChild(newComment);
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 예제에서는 버튼 클릭 시 새로운 댓글이 추가되고, &lt;code&gt;MutationObserver&lt;/code&gt;가 이를 감지하여 콘솔에 메시지를 출력합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;MutationObserver의 활용 사례&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;/li&gt;
&lt;li&gt;로딩 상태 관리 (비동기 요소 렌더링 감지)&lt;/li&gt;
&lt;li&gt;광고 차단기 탐지 (DOM 변조 감지)&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;code&gt;MutationObserver&lt;/code&gt;는 DOM의 변화에 민감하게 반응해야 하는 웹 애플리케이션에서 매우 유용한 도구입니다. 성능과 효율성을 고려하여 필요한 부분만 감시하고, 콜백 함수를 적절히 활용하면 더 나은 사용자 경험을 제공할 수 있습니다.&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;1884&quot; data-origin-height=&quot;1050&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDINbu/btsL2A9R9Um/YigAD1YTDSnUL2SMKh83TK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDINbu/btsL2A9R9Um/YigAD1YTDSnUL2SMKh83TK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDINbu/btsL2A9R9Um/YigAD1YTDSnUL2SMKh83TK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDINbu%2FbtsL2A9R9Um%2FYigAD1YTDSnUL2SMKh83TK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1884&quot; height=&quot;1050&quot; data-origin-width=&quot;1884&quot; data-origin-height=&quot;1050&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>취미/개발</category>
      <category>DOM</category>
      <category>JavaScript</category>
      <category>mutation observer</category>
      <category>web</category>
      <author>임다</author>
      <guid isPermaLink="true">https://gallery-a.tistory.com/96</guid>
      <comments>https://gallery-a.tistory.com/96#entry96comment</comments>
      <pubDate>Sat, 1 Feb 2025 14:11:08 +0900</pubDate>
    </item>
    <item>
      <title>Flutter AdMob 가족 정책 위반 해결 방법</title>
      <link>https://gallery-a.tistory.com/95</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Google Play에서 Flutter 애플리케이션에 &lt;code&gt;AdMob&lt;/code&gt;을 연동한 경우, &quot;가족 정책&quot; 위반으로 앱이 삭제되거나 경고를 받는 경우가 종종 발생합니다. 이는 &lt;code&gt;AdMob&lt;/code&gt; 광고를 통해 &lt;b&gt;어린이 및 가족을 대상으로 부적절한 데이터가 수집되거나 전송&lt;/b&gt;되는 상황 때문입니다. 이 글에서는 이러한 문제를 진단하고 해결하는 방법을 단계별로 안내하겠습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Google 가족 정책과 &lt;code&gt;AdMob&lt;/code&gt;의 관계&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Google의 &quot;가족 정책&quot;은 어린이를 대상으로 하는 앱에 대해 엄격한 데이터 보호 요구 사항을 적용합니다. 특히 아래와 같은 항목이 위반 사례로 꼽힙니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;사용자 연령을 판별할 수 없는 데이터 전송&lt;/li&gt;
&lt;li&gt;어린이를 대상으로 하면서 부적절한 광고 노출&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Advertising ID&lt;/code&gt;와 같은 식별자 전송&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위반 사례는 대부분 &lt;code&gt;AdMob&lt;/code&gt; 광고에서 발생하며, 아래 두 가지 이유로 분류됩니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;AdMob&lt;/code&gt;이 연령에 적합하지 않은 광고를 노출.&lt;/li&gt;
&lt;li&gt;연령을 알 수 없는 데이터(예: &lt;code&gt;Advertising ID&lt;/code&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;해결 방법: Flutter 애플리케이션 수정&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 단계들을 따라 앱을 수정하고 정책 위반 문제를 해결하세요.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;code&gt;AdMob&lt;/code&gt;에 가족 정책 설정 추가&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;AdMob&lt;/code&gt;에서 Google의 가족 정책을 준수하려면 &lt;code&gt;TagForChildDirectedTreatment&lt;/code&gt; 또는 &lt;code&gt;TagForUnderAgeOfConsent&lt;/code&gt; 설정을 반드시 적용해야 합니다. &lt;code&gt;GoogleMobileAds&lt;/code&gt; 플러그인을 사용하는 경우 아래와 같이 구현할 수 있습니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;초기화 시 가족 친화 설정 적용&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 &lt;code&gt;GoogleMobileAds&lt;/code&gt; 초기화 시 가족 친화 설정을 추가하는 방법입니다.&lt;/p&gt;
&lt;pre class=&quot;scala&quot;&gt;&lt;code&gt;import 'package:google_mobile_ads/google_mobile_ads.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // Google Mobile Ads 초기화
  await MobileAds.instance.initialize();

  // AdRequest에 가족 친화 광고 설정 추가
  final adRequest = AdRequest(
    childDirected: true, // 어린이 대상 여부
    underAgeOfConsent: true, // 연령 제한 동의 여부
  );

  runApp(MyApp(adRequest: adRequest));
}

class MyApp extends StatelessWidget {
  final AdRequest adRequest;

  MyApp({required this.adRequest});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('AdMob Family Policy Example')),
        body: AdBanner(adRequest: adRequest),
      ),
    );
  }
}

class AdBanner extends StatelessWidget {
  final AdRequest adRequest;

  AdBanner({required this.adRequest});

  @override
  Widget build(BuildContext context) {
    return Container(
      height: 50,
      child: AdWidget(
        ad: BannerAd(
          adUnitId: '&amp;lt;YOUR_AD_UNIT_ID&amp;gt;',
          size: AdSize.banner,
          request: adRequest,
          listener: BannerAdListener(),
        )..load(),
      ),
    );
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;주요 설정 값&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;childDirected&lt;/code&gt;: &lt;code&gt;true&lt;/code&gt;로 설정 시 앱이 어린이를 대상으로 한다고 Google에 명시합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;underAgeOfConsent&lt;/code&gt;: &lt;code&gt;true&lt;/code&gt;로 설정하면 앱이 GDPR의 연령 제한 사용자도 고려한다고 알려줍니다.&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;code&gt;Ad Unit ID&lt;/code&gt;)가 가족 정책에 적합한지 확인하세요.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;광고 네트워크&lt;/b&gt;: Google AdMob 대시보드에서 &quot;광고 형식 및 네트워크&quot; 옵션을 검토합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;광고 단위 설정&lt;/b&gt;: &quot;가족 정책 프로그램&quot;에 적합한 단위인지 확인합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;광고 단위 설정 변경 방법&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;code&gt;AdMob&lt;/code&gt; 콘솔에 로그인합니다.&lt;/li&gt;
&lt;li&gt;문제된 광고 단위를 클릭합니다.&lt;/li&gt;
&lt;li&gt;&quot;가족 정책 설정&quot;에서 적합한 옵션으로 설정합니다.&lt;/li&gt;
&lt;/ol&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;code&gt;Advertising ID&lt;/code&gt;가 앱 외부로 전송되는지 확인해야 합니다. 이는 대부분의 제3자 SDK에서 자동으로 발생하므로 아래 단계를 따르세요.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;code&gt;flutter pubspec.yaml&lt;/code&gt;에 사용된 모든 제3자 플러그인을 검토합니다.&lt;/li&gt;
&lt;li&gt;해당 플러그인의 데이터 전송 규정을 확인합니다.&lt;/li&gt;
&lt;li&gt;불필요하거나 데이터 전송이 명확하지 않은 플러그인을 제거하거나 대체합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;불필요한 데이터 전송 방지&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필요하다면 광고 요청 시 데이터 전송을 제한하는 설정을 추가할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;actionscript&quot;&gt;&lt;code&gt;final adRequest = AdRequest(
  nonPersonalizedAds: true, // 비개인화 광고 설정
);&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;p data-ke-size=&quot;size16&quot;&gt;Google의 가족 정책 준수 여부를 테스트하려면 &lt;code&gt;Google Play Console&lt;/code&gt;의 내부 테스트를 활용하세요.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;테스트 절차&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;앱을 새롭게 빌드하고 내부 테스트 트랙에 업로드합니다.&lt;/li&gt;
&lt;li&gt;앱에서 광고가 올바르게 작동하는지 확인합니다.&lt;/li&gt;
&lt;li&gt;정책 위반 경고가 없는지 검토합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;디버깅 힌트&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 명령어로 &lt;code&gt;AdMob&lt;/code&gt; 광고 요청을 디버깅할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;applescript&quot;&gt;&lt;code&gt;flutter run --debug&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;logcat&lt;/code&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;위와 같은 설정을 완료한 뒤 Google에 앱을 다시 제출하면 대부분의 &quot;가족 정책 위반&quot; 문제가 해결됩니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;정책에 대한 의문점이 있으면 Google 개발자 지원 팀에 문의하세요.&lt;/li&gt;
&lt;li&gt;앱이 가족 정책에 적합한지 여부를 사전 테스트하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1392&quot; data-origin-height=&quot;768&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/okERC/btsL2baakFe/yHqGsKzfCtw28yU3IkvmcK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/okERC/btsL2baakFe/yHqGsKzfCtw28yU3IkvmcK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/okERC/btsL2baakFe/yHqGsKzfCtw28yU3IkvmcK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FokERC%2FbtsL2baakFe%2FyHqGsKzfCtw28yU3IkvmcK%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;1392&quot; height=&quot;768&quot; data-origin-width=&quot;1392&quot; data-origin-height=&quot;768&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>취미/개발</category>
      <category>Admob</category>
      <category>Android</category>
      <category>Flutter</category>
      <category>GOOGLE PLAY</category>
      <author>임다</author>
      <guid isPermaLink="true">https://gallery-a.tistory.com/95</guid>
      <comments>https://gallery-a.tistory.com/95#entry95comment</comments>
      <pubDate>Mon, 27 Jan 2025 17:51:34 +0900</pubDate>
    </item>
    <item>
      <title>Dart 함수 및 클래스 문법</title>
      <link>https://gallery-a.tistory.com/94</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Dart는 Google이 개발한 프로그래밍 언어로, 특히 Flutter 프레임워크의 기본 언어로 사용됩니다. Dart의 핵심 요소 중 하나는 함수와 클래스입니다. 이 글에서는 Dart에서 함수와 클래스를 작성하고 사용하는 방법을 기본부터 고급 개념까지 상세히 설명합니다. 함수와 클래스는 각각 프로그램의 동작과 구조를 담당하는 중요한 역할을 하므로, 이를 잘 이해하면 Dart를 효과적으로 활용할 수 있습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;함수(Function)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수는 특정 작업을 수행하는 코드 블록입니다. Dart에서 함수는 &lt;code&gt;main()&lt;/code&gt; 함수로 시작하며, 이는 프로그램의 진입점입니다. 함수는 매개변수, 반환 값, 그리고 다양한 함수 타입을 지원합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;함수 선언과 호출&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Dart에서 함수를 선언하려면 &lt;code&gt;return&lt;/code&gt; 타입, 함수 이름, 그리고 매개변수를 정의합니다. 다음은 간단한 함수 선언과 호출 예제입니다.&lt;/p&gt;
&lt;pre class=&quot;aspectj&quot;&gt;&lt;code&gt;// 두 숫자를 더한 값을 반환하는 함수
int addNumbers(int number1, int number2) {
  return number1 + number2;
}

void main() {
  int result = addNumbers(10, 20);
  print('두 숫자의 합: $result'); // 출력: 두 숫자의 합: 30
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드에서 &lt;code&gt;addNumbers&lt;/code&gt; 함수는 두 개의 &lt;code&gt;int&lt;/code&gt; 값을 매개변수로 받아서 합계를 반환합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;선택적 매개변수(Optional Parameters)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Dart에서는 매개변수를 선택적으로 만들 수 있습니다. 이를 구현하려면 &lt;code&gt;[]&lt;/code&gt; 또는 &lt;code&gt;{}&lt;/code&gt;를 사용합니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;위치 기반 선택적 매개변수&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위치 기반 선택적 매개변수는 &lt;code&gt;[]&lt;/code&gt;로 정의하며, 기본값을 지정할 수도 있습니다.&lt;/p&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;String greet(String name, [String? title]) {
  return title != null ? '$title $name 님, 안녕하세요!' : '$name 님, 안녕하세요!';
}

void main() {
  print(greet('홍길동')); // 출력: 홍길동 님, 안녕하세요!
  print(greet('홍길동', '박사')); // 출력: 박사 홍길동 님, 안녕하세요!
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;이름 기반 선택적 매개변수&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이름 기반 선택적 매개변수는 &lt;code&gt;{}&lt;/code&gt;로 정의하며, 매개변수를 명시적으로 전달할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;String greet(String name, {String? title}) {
  return title != null ? '$title $name 님, 반갑습니다!' : '$name 님, 반갑습니다!';
}

void main() {
  print(greet('이순신')); // 출력: 이순신 님, 반갑습니다!
  print(greet('이순신', title: '장군')); // 출력: 장군 이순신 님, 반갑습니다!
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;클래스(Class)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스는 객체 지향 프로그래밍(OOP)에서 중요한 개념으로, 객체의 설계도를 정의합니다. Dart는 객체 지향 언어로서 클래스와 객체를 사용하여 프로그램을 구조화할 수 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;클래스 선언과 객체 생성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Dart에서 클래스를 선언하려면 &lt;code&gt;class&lt;/code&gt; 키워드를 사용합니다. 생성된 클래스는 인스턴스를 통해 사용됩니다.&lt;/p&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;class User {
  String name;
  int age;

  // 생성자(Constructor)
  User(this.name, this.age);

  // 메서드(Method)
  void introduce() {
    print('안녕하세요! 저는 $name이고, 나이는 $age살입니다.');
  }
}

void main() {
  User user = User('김유신', 30); // User 객체 생성
  user.introduce(); // 출력: 안녕하세요! 저는 김유신이고, 나이는 30살입니다.
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드에서 &lt;code&gt;User&lt;/code&gt; 클래스는 &lt;code&gt;name&lt;/code&gt;과 &lt;code&gt;age&lt;/code&gt;라는 두 개의 속성을 가집니다. &lt;code&gt;introduce&lt;/code&gt; 메서드를 사용하여 자기소개 메시지를 출력할 수 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;네임드 생성자(Named Constructor)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Dart에서는 여러 생성자를 정의하기 위해 네임드 생성자를 사용할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;class User {
  String name;
  int age;

  // 기본 생성자
  User(this.name, this.age);

  // 네임드 생성자
  User.withDefaultName(this.age) : name = '기본 이름';

  void introduce() {
    print('안녕하세요! 저는 $name이고, 나이는 $age살입니다.');
  }
}

void main() {
  User user1 = User('강감찬', 40);
  User user2 = User.withDefaultName(25);

  user1.introduce(); // 출력: 안녕하세요! 저는 강감찬이고, 나이는 40살입니다.
  user2.introduce(); // 출력: 안녕하세요! 저는 기본 이름이고, 나이는 25살입니다.
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Getter와 Setter&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스 속성을 안전하게 접근하고 수정하려면 &lt;code&gt;getter&lt;/code&gt;와 &lt;code&gt;setter&lt;/code&gt;를 사용합니다.&lt;/p&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;class User {
  String _name; // 프라이빗 속성
  int _age;

  User(this._name, this._age);

  // Getter
  String get name =&amp;gt; _name;

  // Setter
  set name(String newName) {
    _name = newName;
  }

  void introduce() {
    print('안녕하세요! 저는 $_name이고, 나이는 $_age살입니다.');
  }
}

void main() {
  User user = User('을지문덕', 50);
  print(user.name); // 출력: 을지문덕

  user.name = '안중근';
  user.introduce(); // 출력: 안녕하세요! 저는 안중근이고, 나이는 50살입니다.
}&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Dart에서는 위치 기반 매개변수와 이름 기반 매개변수를 지원합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;클래스는 데이터를 캡슐화하고, 메서드와 속성을 활용하여 객체를 조작할 수 있게 합니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;네임드 생성자와 &lt;code&gt;getter&lt;/code&gt;, &lt;code&gt;setter&lt;/code&gt;를 통해 클래스의 유연성을 높일 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1790&quot; data-origin-height=&quot;1000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Klddh/btsL0GoFmXn/2rSwp6qfA184pKIwfEKjmK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Klddh/btsL0GoFmXn/2rSwp6qfA184pKIwfEKjmK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Klddh/btsL0GoFmXn/2rSwp6qfA184pKIwfEKjmK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKlddh%2FbtsL0GoFmXn%2F2rSwp6qfA184pKIwfEKjmK%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;1790&quot; height=&quot;1000&quot; data-origin-width=&quot;1790&quot; data-origin-height=&quot;1000&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>취미/개발</category>
      <category>CLASS</category>
      <category>DART</category>
      <category>Flutter</category>
      <category>function</category>
      <author>임다</author>
      <guid isPermaLink="true">https://gallery-a.tistory.com/94</guid>
      <comments>https://gallery-a.tistory.com/94#entry94comment</comments>
      <pubDate>Sat, 25 Jan 2025 03:08:41 +0900</pubDate>
    </item>
    <item>
      <title>Dart에서 비동기 처리 (Future와 async/await)</title>
      <link>https://gallery-a.tistory.com/93</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;비동기 프로그래밍은 프로그램의 실행 흐름을 중단시키지 않고 작업을 처리하는 방식입니다. Dart에서 비동기 프로그래밍은 &lt;code&gt;Future&lt;/code&gt;와 &lt;code&gt;async/await&lt;/code&gt;를 통해 이루어집니다. 이번 글에서는 &lt;code&gt;Future&lt;/code&gt;와 &lt;code&gt;async/await&lt;/code&gt;를 이해하고 실무에서 효과적으로 활용할 수 있는 방법을 다룹니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Future란 무엇인가?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Future&lt;/code&gt;는 미래에 완료될 비동기 작업을 나타내는 객체입니다. 예를 들어, 서버에서 데이터를 받아오는 작업이나 파일을 읽는 작업과 같이 시간이 오래 걸릴 수 있는 작업을 처리할 때 사용됩니다. &lt;code&gt;Future&lt;/code&gt;는 작업이 완료되기 전까지는 &lt;b&gt;미래의 값&lt;/b&gt;을 약속(promise)하고, 작업이 완료되면 그 결과값을 반환하거나, 실패한 경우 에러를 반환합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Future의 주요 상태&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Future&lt;/code&gt;는 아래와 같은 두 가지 상태를 가집니다:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;Uncompleted (미완료 상태)&lt;/b&gt;&lt;br /&gt;작업이 아직 진행 중이거나 결과가 준비되지 않은 상태입니다. 이 상태에서는 결과값이 없습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Completed (완료 상태)&lt;/b&gt;&lt;br /&gt;작업이 성공적으로 완료되거나 에러가 발생해 작업이 끝난 상태입니다. 완료 상태에서는 결과값 또는 에러가 반환됩니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Future 사용 방법&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Future&lt;/code&gt;를 생성하고 사용하는 방법을 살펴보겠습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Future의 기본 생성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Future&lt;/code&gt;는 다음과 같이 생성할 수 있습니다:&lt;/p&gt;
&lt;pre class=&quot;julia&quot;&gt;&lt;code&gt;Future&amp;lt;String&amp;gt; fetchCelebrityName() {
  return Future.delayed(Duration(seconds: 2), () {
    return &quot;아이유&quot;;
  });
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드는 2초 후에 &quot;아이유&quot;라는 문자열을 반환하는 &lt;code&gt;Future&lt;/code&gt;를 생성합니다. &lt;code&gt;Future.delayed&lt;/code&gt;를 사용해 지연된 작업을 모의로 만든 것입니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;then()으로 결과 처리하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Future&lt;/code&gt;는 작업이 완료되면 &lt;code&gt;then()&lt;/code&gt;을 통해 결과를 처리할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;void main() {
  fetchCelebrityName().then((name) {
    print(&quot;받아온 연예인 이름: $name&quot;);
  });
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행 결과:&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;받아온 연예인 이름: 아이유&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;catchError()로 에러 처리하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;catchError()&lt;/code&gt;를 사용해 비동기 작업 중 발생한 에러를 처리할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;Future&amp;lt;String&amp;gt; fetchWithError() {
  return Future.delayed(Duration(seconds: 1), () {
    throw Exception(&quot;연예인 정보를 가져오는 중 오류 발생!&quot;);
  });
}

void main() {
  fetchWithError()
      .then((name) {
        print(&quot;연예인 이름: $name&quot;);
      })
      .catchError((error) {
        print(&quot;에러 발생: $error&quot;);
      });
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행 결과:&lt;/p&gt;
&lt;pre class=&quot;ada&quot;&gt;&lt;code&gt;에러 발생: Exception: 연예인 정보를 가져오는 중 오류 발생!&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;async/await를 활용한 Future 처리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;async/await&lt;/code&gt;는 비동기 프로그래밍을 더 간결하고 읽기 쉽게 만들어주는 문법입니다. &lt;code&gt;await&lt;/code&gt;를 사용하면 &lt;code&gt;Future&lt;/code&gt;가 완료될 때까지 기다린 후 결과값을 반환받을 수 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;async 키워드&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;async&lt;/code&gt;는 함수가 비동기 작업을 수행한다는 것을 나타냅니다. &lt;code&gt;async&lt;/code&gt; 함수는 항상 &lt;code&gt;Future&lt;/code&gt;를 반환합니다.&lt;/p&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;Future&amp;lt;void&amp;gt; printCelebrityName() async {
  String name = await fetchCelebrityName();
  print(&quot;연예인 이름: $name&quot;);
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;await 키워드&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;await&lt;/code&gt;는 &lt;code&gt;Future&lt;/code&gt;가 완료될 때까지 기다린 후 결과값을 반환합니다. 이를 통해 비동기 코드를 마치 동기 코드처럼 작성할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;void main() async {
  await printCelebrityName();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행 결과:&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;연예인 이름: 아이유&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;async/await와 예외 처리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;try-catch&lt;/code&gt; 문을 사용해 &lt;code&gt;async/await&lt;/code&gt; 비동기 작업 중 발생한 에러를 처리할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;Future&amp;lt;void&amp;gt; fetchAndPrintCelebrityName() async {
  try {
    String name = await fetchWithError();
    print(&quot;연예인 이름: $name&quot;);
  } catch (error) {
    print(&quot;에러 발생: $error&quot;);
  }
}

void main() async {
  await fetchAndPrintCelebrityName();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행 결과:&lt;/p&gt;
&lt;pre class=&quot;ada&quot;&gt;&lt;code&gt;에러 발생: Exception: 연예인 정보를 가져오는 중 오류 발생!&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Future와 async/await을 함께 사용할 때 주의사항&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;await는 항상 async 함수 안에서 사용해야 합니다.&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;await&lt;/code&gt;를 사용할 때, 해당 함수가 &lt;code&gt;async&lt;/code&gt;로 선언되지 않았다면 컴파일 에러가 발생합니다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;// 컴파일 에러 예시
void main() {
    String name = await fetchCelebrityName(); // 에러 발생
}&lt;/code&gt;&lt;/pre&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; start=&quot;2&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;Future 병렬 처리&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 &lt;code&gt;Future&lt;/code&gt;를 동시에 실행하고 기다릴 때는 &lt;code&gt;Future.wait&lt;/code&gt;를 사용할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;Future&amp;lt;void&amp;gt; fetchMultipleData() async {
    Future&amp;lt;String&amp;gt; nameFuture = fetchCelebrityName();
    Future&amp;lt;String&amp;gt; anotherNameFuture = fetchCelebrityName();

    List&amp;lt;String&amp;gt; names = await Future.wait([nameFuture, anotherNameFuture]);
    print(&quot;받아온 이름들: ${names.join(&quot;, &quot;)}&quot;);
}

void main() async {
    await fetchMultipleData();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행 결과:&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;받아온 이름들: 아이유, 아이유&lt;/code&gt;&lt;/pre&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; start=&quot;3&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;UI 차단 방지&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비동기 작업이 오래 걸리는 경우 &lt;code&gt;await&lt;/code&gt;를 잘못 사용하면 UI가 멈춘 것처럼 보일 수 있습니다. 이런 경우에는 &lt;code&gt;await&lt;/code&gt;를 최소화하고, 적절히 &lt;code&gt;Future&lt;/code&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;Dart의 &lt;code&gt;Future&lt;/code&gt;와 &lt;code&gt;async/await&lt;/code&gt;는 비동기 프로그래밍을 강력하면서도 간단하게 처리할 수 있는 도구입니다. &lt;code&gt;then()&lt;/code&gt;과 같은 메서드를 통해 &lt;code&gt;Future&lt;/code&gt;를 다룰 수도 있지만, &lt;code&gt;async/await&lt;/code&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;1786&quot; data-origin-height=&quot;994&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bo6KRT/btsL0Pk16th/qSkpc2v2BKrgDl5DJ1Ktk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bo6KRT/btsL0Pk16th/qSkpc2v2BKrgDl5DJ1Ktk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bo6KRT/btsL0Pk16th/qSkpc2v2BKrgDl5DJ1Ktk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbo6KRT%2FbtsL0Pk16th%2FqSkpc2v2BKrgDl5DJ1Ktk0%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;1786&quot; height=&quot;994&quot; data-origin-width=&quot;1786&quot; data-origin-height=&quot;994&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>취미/개발</category>
      <category>async</category>
      <category>await</category>
      <category>DART</category>
      <category>Flutter</category>
      <category>Future</category>
      <author>임다</author>
      <guid isPermaLink="true">https://gallery-a.tistory.com/93</guid>
      <comments>https://gallery-a.tistory.com/93#entry93comment</comments>
      <pubDate>Sat, 25 Jan 2025 03:02:12 +0900</pubDate>
    </item>
    <item>
      <title>Dart 연산자와 조건문, 반복문</title>
      <link>https://gallery-a.tistory.com/92</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;프로그래밍 언어를 사용하다 보면 가장 기본적으로 활용되는 개념은 &lt;b&gt;연산자&lt;/b&gt;, &lt;b&gt;조건문&lt;/b&gt;, 그리고 &lt;b&gt;반복문&lt;/b&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;p data-ke-size=&quot;size16&quot;&gt;Dart는 여러 연산자를 제공하여 수학적 계산, 조건 비교, 논리 연산 등을 할 수 있도록 지원합니다. 각각의 연산자는 특정한 목적에 맞게 사용됩니다. 이 섹션에서는 &lt;b&gt;산술 연산자&lt;/b&gt;, &lt;b&gt;비교 연산자&lt;/b&gt;, 그리고 &lt;b&gt;논리 연산자&lt;/b&gt;에 대해 설명합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;산술 연산자&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;산술 연산자는 숫자 계산에 사용됩니다. Dart는 다음과 같은 기본 산술 연산자를 제공합니다:&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;연산자&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;th&gt;예제&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;+&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;더하기&lt;/td&gt;
&lt;td&gt;&lt;code&gt;3 + 2&lt;/code&gt; 결과는 &lt;code&gt;5&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;빼기&lt;/td&gt;
&lt;td&gt;&lt;code&gt;5 - 2&lt;/code&gt; 결과는 &lt;code&gt;3&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;*&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;곱하기&lt;/td&gt;
&lt;td&gt;&lt;code&gt;4 * 3&lt;/code&gt; 결과는 &lt;code&gt;12&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;나누기(결과는 실수)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;10 / 3&lt;/code&gt; 결과는 &lt;code&gt;3.3333&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;~/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;나누기(결과는 정수)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;10 ~/ 3&lt;/code&gt; 결과는 &lt;code&gt;3&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;%&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;나머지 계산&lt;/td&gt;
&lt;td&gt;&lt;code&gt;10 % 3&lt;/code&gt; 결과는 &lt;code&gt;1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;코드 예시&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 Dart에서 산술 연산자를 사용하는 예제입니다:&lt;/p&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;void main() {
  int appleCount = 10;
  int peopleCount = 3;

  print('사과 개수: $appleCount');
  print('사람 수: $peopleCount');

  int applesPerPerson = appleCount ~/ peopleCount; // 정수 나누기
  int remainingApples = appleCount % peopleCount; // 나머지

  print('사람당 사과 개수: $applesPerPerson');
  print('남은 사과 개수: $remainingApples');
}&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;비교 연산자&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비교 연산자는 두 값을 비교하여 결과로 &lt;code&gt;true&lt;/code&gt; 또는 &lt;code&gt;false&lt;/code&gt;를 반환합니다. Dart에서 제공하는 비교 연산자는 다음과 같습니다:&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;연산자&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;th&gt;예제&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;==&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;두 값이 같은지 비교&lt;/td&gt;
&lt;td&gt;&lt;code&gt;5 == 5&lt;/code&gt; 결과는 &lt;code&gt;true&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;!=&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;두 값이 다른지 비교&lt;/td&gt;
&lt;td&gt;&lt;code&gt;5 != 3&lt;/code&gt; 결과는 &lt;code&gt;true&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;왼쪽 값이 큰지 비교&lt;/td&gt;
&lt;td&gt;&lt;code&gt;5 &amp;gt; 3&lt;/code&gt; 결과는 &lt;code&gt;true&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;왼쪽 값이 작은지 비교&lt;/td&gt;
&lt;td&gt;&lt;code&gt;3 &amp;lt; 5&lt;/code&gt; 결과는 &lt;code&gt;true&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;gt;=&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;왼쪽 값이 크거나 같은지 비교&lt;/td&gt;
&lt;td&gt;&lt;code&gt;5 &amp;gt;= 5&lt;/code&gt; 결과는 &lt;code&gt;true&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;=&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;왼쪽 값이 작거나 같은지 비교&lt;/td&gt;
&lt;td&gt;&lt;code&gt;3 &amp;lt;= 5&lt;/code&gt; 결과는 &lt;code&gt;true&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;코드 예시&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 Dart에서 비교 연산자를 사용하는 예제입니다:&lt;/p&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;void main() {
  int temperature = 30;
  int freezingPoint = 0;

  if (temperature &amp;gt; freezingPoint) {
    print('현재 온도는 $temperature도입니다. 물은 액체 상태입니다.');
  } else {
    print('현재 온도는 $temperature도입니다. 물은 얼음 상태입니다.');
  }
}&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;논리 연산자&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;논리 연산자는 여러 조건을 결합하거나 조건을 반전시킬 때 사용됩니다. Dart에서 제공하는 주요 논리 연산자는 다음과 같습니다:&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;연산자&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;th&gt;예제&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;두 조건이 모두 참이면 참을 반환&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(5 &amp;gt; 3) &amp;amp;&amp;amp; (2 &amp;lt; 4)&lt;/code&gt; 결과는 &lt;code&gt;true&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;`&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;`&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;!&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;조건의 참/거짓 값을 반전시킴&lt;/td&gt;
&lt;td&gt;&lt;code&gt;!(5 &amp;gt; 3)&lt;/code&gt; 결과는 &lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;코드 예시&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 논리 연산자를 활용한 예제입니다:&lt;/p&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;void main() {
  bool isWeekend = true;
  bool isSunny = false;

  if (isWeekend &amp;amp;&amp;amp; isSunny) {
    print('주말이고 날씨가 좋으니 밖에 나갑시다!');
  } else if (isWeekend || isSunny) {
    print('조건 중 하나는 만족하니 상황에 따라 결정합시다.');
  } else {
    print('주말도 아니고 날씨도 안 좋으니 집에 있읍시다.');
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;조건문 (if, else if, else)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조건문은 특정 조건에 따라 실행할 코드 블록을 선택할 수 있게 합니다. Dart의 조건문은 &lt;code&gt;if&lt;/code&gt;, &lt;code&gt;else if&lt;/code&gt;, 그리고 &lt;code&gt;else&lt;/code&gt;를 통해 다양한 조건을 처리할 수 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;if 문&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;if&lt;/code&gt; 문은 조건이 &lt;code&gt;true&lt;/code&gt;일 때 코드 블록을 실행합니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;코드 예시&lt;/h4&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;void main() {
  int age = 18;

  if (age &amp;gt;= 18) {
    print('성인입니다.');
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;if-else 문&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;if-else&lt;/code&gt; 문은 조건이 &lt;code&gt;true&lt;/code&gt;일 때와 &lt;code&gt;false&lt;/code&gt;일 때 각각 다른 코드 블록을 실행합니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;코드 예시&lt;/h4&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;void main() {
  int age = 15;

  if (age &amp;gt;= 18) {
    print('성인입니다.');
  } else {
    print('미성년자입니다.');
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;else if 문&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;else if&lt;/code&gt; 문은 여러 조건을 연달아 처리할 때 사용됩니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;코드 예시&lt;/h4&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;void main() {
  int score = 85;

  if (score &amp;gt;= 90) {
    print('등급: A');
  } else if (score &amp;gt;= 80) {
    print('등급: B');
  } else if (score &amp;gt;= 70) {
    print('등급: C');
  } else {
    print('등급: F');
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;반복문 (for, while, do-while)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Dart에서는 반복적인 작업을 수행할 때 반복문을 사용합니다. 주요 반복문으로는 &lt;code&gt;for&lt;/code&gt;, &lt;code&gt;while&lt;/code&gt;, 그리고 &lt;code&gt;do-while&lt;/code&gt;이 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;for 문&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;for&lt;/code&gt; 문은 반복 횟수가 명확할 때 주로 사용됩니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;코드 예시&lt;/h4&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;void main() {
  for (int i = 1; i &amp;lt;= 5; i++) {
    print('반복 횟수: $i');
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;while 문&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;while&lt;/code&gt; 문은 조건이 &lt;code&gt;true&lt;/code&gt;인 동안 반복을 수행합니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;코드 예시&lt;/h4&gt;
&lt;pre class=&quot;gradle&quot;&gt;&lt;code&gt;void main() {
  int count = 1;

  while (count &amp;lt;= 5) {
    print('현재 카운트: $count');
    count++;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;do-while 문&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;do-while&lt;/code&gt; 문은 조건 검사 전에 코드를 최소 한 번 실행합니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;코드 예시&lt;/h4&gt;
&lt;pre class=&quot;gradle&quot;&gt;&lt;code&gt;void main() {
  int count = 1;

  do {
    print('현재 카운트: $count');
    count++;
  } while (count &amp;lt;= 5);
}&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;1778&quot; data-origin-height=&quot;980&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blvucZ/btsL1jFRXid/dbVyFEYtK5OiR4BkZz41a0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blvucZ/btsL1jFRXid/dbVyFEYtK5OiR4BkZz41a0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blvucZ/btsL1jFRXid/dbVyFEYtK5OiR4BkZz41a0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblvucZ%2FbtsL1jFRXid%2FdbVyFEYtK5OiR4BkZz41a0%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;1778&quot; height=&quot;980&quot; data-origin-width=&quot;1778&quot; data-origin-height=&quot;980&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>취미/개발</category>
      <category>DART</category>
      <category>Programming</category>
      <author>임다</author>
      <guid isPermaLink="true">https://gallery-a.tistory.com/92</guid>
      <comments>https://gallery-a.tistory.com/92#entry92comment</comments>
      <pubDate>Mon, 20 Jan 2025 06:32:50 +0900</pubDate>
    </item>
    <item>
      <title>Dart 변수와 데이터 타입</title>
      <link>https://gallery-a.tistory.com/91</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Dart는 구글이 개발한 프로그래밍 언어로, 특히 플러터(Flutter) 프레임워크를 통해 모바일, 웹, 데스크톱 애플리케이션 개발에 널리 사용되고 있습니다. Dart 언어를 사용하면서 가장 기본이 되는 개념 중 하나는 &lt;b&gt;변수와 데이터 타입&lt;/b&gt;입니다. 이 글에서는 Dart의 변수 선언 방식과 주요 데이터 타입인 숫자, 문자열, 불리언에 대해 자세히 설명하고, 이를 활용하는 방법을 코드 예제와 함께 알아보겠습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;변수 선언: &lt;code&gt;var&lt;/code&gt;, &lt;code&gt;final&lt;/code&gt;, &lt;code&gt;const&lt;/code&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Dart에서 변수를 선언하는 방법은 다양하지만, 크게 &lt;code&gt;var&lt;/code&gt;, &lt;code&gt;final&lt;/code&gt;, &lt;code&gt;const&lt;/code&gt; 키워드를 사용합니다. 각각의 키워드는 변수의 특성과 변경 가능 여부에 따라 적절히 사용됩니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;code&gt;var&lt;/code&gt; 키워드&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;var&lt;/code&gt;는 Dart에서 가장 일반적인 변수 선언 방식입니다. &lt;code&gt;var&lt;/code&gt;로 선언한 변수는 초기화 시점에 데이터 타입이 자동으로 추론되며, 추후에 값을 변경할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;void main() {
  var userName = '홍길동'; // 문자열로 타입이 추론됨
  var userAge = 30; // 정수로 타입이 추론됨

  print(userName); // 출력: 홍길동
  print(userAge); // 출력: 30

  // 값 변경 가능
  userName = '이몽룡';
  userAge = 35;

  print(userName); // 출력: 이몽룡
  print(userAge); // 출력: 35
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;요약&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;var&lt;/code&gt;는 초기화 시점에 타입이 자동으로 결정됩니다.&lt;/li&gt;
&lt;li&gt;한 번 타입이 결정되면 다른 타입으로 변경할 수 없습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;void main() {
  var isActive = true; // 타입: bool
  isActive = false; // 같은 타입으로 변경 가능

  // isActive = '활성화'; // 오류: `String` 타입은 할당할 수 없음
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;code&gt;final&lt;/code&gt; 키워드&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;final&lt;/code&gt;은 변수 선언 시 값을 한 번만 설정할 수 있습니다. 즉, &lt;code&gt;final&lt;/code&gt; 변수는 변경할 수 없는 값을 저장하는 데 사용됩니다. 다만, &lt;code&gt;final&lt;/code&gt; 변수의 값은 런타임(runtime) 시에 결정됩니다.&lt;/p&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;void main() {
  final pi = 3.14; // final로 선언
  final currentTime = DateTime.now(); // 런타임에 값 결정

  print(pi); // 출력: 3.14
  print(currentTime); // 출력: 현재 시간

  // pi = 3.14159; // 오류: final 변수는 값을 변경할 수 없음
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;요약&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;final&lt;/code&gt;은 값을 한 번만 설정할 수 있습니다.&lt;/li&gt;
&lt;li&gt;런타임 시점에 값을 결정할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;code&gt;const&lt;/code&gt; 키워드&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;const&lt;/code&gt;는 컴파일 타임(compile-time) 상수를 정의하는 데 사용됩니다. 즉, &lt;code&gt;const&lt;/code&gt;로 선언된 변수는 &lt;b&gt;컴파일 시점&lt;/b&gt;에 값이 고정되어야 합니다. 따라서 런타임에 값을 설정하는 것은 불가능합니다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;void main() {
  const maxUsers = 100; // 컴파일 타임 상수
  // const currentTime = DateTime.now(); // 오류: const는 런타임 값을 가질 수 없음

  print(maxUsers); // 출력: 100
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;요약&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;const&lt;/code&gt;는 컴파일 타임 상수를 정의합니다.&lt;/li&gt;
&lt;li&gt;모든 &lt;code&gt;const&lt;/code&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;Dart는 &lt;b&gt;정적 타입 언어&lt;/b&gt;로, 변수에 저장되는 값의 타입을 정확히 지정하거나 자동으로 추론합니다. Dart에서 지원하는 주요 데이터 타입은 다음과 같습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;숫자(&lt;code&gt;Number&lt;/code&gt;)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Dart에서 숫자는 &lt;code&gt;int&lt;/code&gt;(정수)와 &lt;code&gt;double&lt;/code&gt;(실수) 두 가지 타입으로 나뉩니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;code&gt;int&lt;/code&gt; (정수)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;int&lt;/code&gt;는 정수를 저장할 때 사용됩니다. 예를 들어, 사람의 나이나 인구 수와 같은 정수를 표현할 때 적합합니다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;void main() {
  int age = 25; // 정수 타입
  int population = 1000000;

  print(age); // 출력: 25
  print(population); // 출력: 1000000
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;code&gt;double&lt;/code&gt; (실수)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;double&lt;/code&gt;은 소수점을 포함한 실수를 저장할 때 사용됩니다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;void main() {
  double temperature = 36.5; // 실수 타입
  double pi = 3.14159;

  print(temperature); // 출력: 36.5
  print(pi); // 출력: 3.14159
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;숫자 타입 활용 예제&lt;/h4&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;void main() {
  int appleCount = 5;
  double pricePerApple = 1.5;

  double totalPrice = appleCount * pricePerApple;

  print('총 가격은 $totalPrice원입니다.'); // 출력: 총 가격은 7.5원입니다.
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;문자열(&lt;code&gt;String&lt;/code&gt;)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Dart에서 문자열은 &lt;code&gt;String&lt;/code&gt; 타입으로 표현됩니다. 문자열은 작은따옴표(&lt;code&gt;'&lt;/code&gt;)나 큰따옴표(&lt;code&gt;&quot;&lt;/code&gt;)로 감싸서 정의할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;void main() {
  String greeting = '안녕하세요';
  String name = &quot;홍길동&quot;;

  print('$greeting, $name!'); // 출력: 안녕하세요, 홍길동!
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;여러 줄 문자열&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Dart는 여러 줄 문자열을 표현하기 위해 삼중 따옴표(&lt;code&gt;'''&lt;/code&gt; 또는 &lt;code&gt;&quot;&quot;&quot;&lt;/code&gt;)를 사용합니다.&lt;/p&gt;
&lt;pre class=&quot;python&quot;&gt;&lt;code&gt;void main() {
  String description = '''
  이것은 여러 줄로 이루어진
  문자열입니다.
  ''';

  print(description);
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;불리언(&lt;code&gt;Boolean&lt;/code&gt;)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;불리언(&lt;code&gt;bool&lt;/code&gt;)은 참(&lt;code&gt;true&lt;/code&gt;)과 거짓(&lt;code&gt;false&lt;/code&gt;) 값을 저장하는 데 사용됩니다. 조건문과 논리 연산에서 자주 사용됩니다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;void main() {
  bool isAvailable = true;
  bool isClosed = false;

  print(isAvailable); // 출력: true
  print(isClosed); // 출력: false
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;불리언 활용 예제&lt;/h4&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;void main() {
  int stock = 0;
  bool isInStock = stock &amp;gt; 0;

  if (isInStock) {
    print('재고가 있습니다.');
  } else {
    print('재고가 없습니다.');
  }
}&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;code&gt;var&lt;/code&gt;, &lt;code&gt;final&lt;/code&gt;, &lt;code&gt;const&lt;/code&gt; 비교 표&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;키워드&lt;/th&gt;
&lt;th&gt;값 변경 가능 여부&lt;/th&gt;
&lt;th&gt;값 결정 시점&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;var&lt;/code&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;&lt;code&gt;final&lt;/code&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;&lt;code&gt;const&lt;/code&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;h2 data-ke-size=&quot;size26&quot;&gt;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Dart의 변수 선언 방식(&lt;code&gt;var&lt;/code&gt;, &lt;code&gt;final&lt;/code&gt;, &lt;code&gt;const&lt;/code&gt;)과 주요 데이터 타입(&lt;code&gt;int&lt;/code&gt;, &lt;code&gt;double&lt;/code&gt;, &lt;code&gt;String&lt;/code&gt;, &lt;code&gt;bool&lt;/code&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;1790&quot; data-origin-height=&quot;992&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mtO9K/btsL0ptJob0/xx6e1Jxl4Xc2YzNgk2lBeK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mtO9K/btsL0ptJob0/xx6e1Jxl4Xc2YzNgk2lBeK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mtO9K/btsL0ptJob0/xx6e1Jxl4Xc2YzNgk2lBeK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmtO9K%2FbtsL0ptJob0%2Fxx6e1Jxl4Xc2YzNgk2lBeK%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;1790&quot; height=&quot;992&quot; data-origin-width=&quot;1790&quot; data-origin-height=&quot;992&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>취미/개발</category>
      <category>DART</category>
      <category>data types</category>
      <category>variables</category>
      <author>임다</author>
      <guid isPermaLink="true">https://gallery-a.tistory.com/91</guid>
      <comments>https://gallery-a.tistory.com/91#entry91comment</comments>
      <pubDate>Mon, 20 Jan 2025 06:31:56 +0900</pubDate>
    </item>
    <item>
      <title>Dart란?</title>
      <link>https://gallery-a.tistory.com/90</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;소프트웨어 개발자라면 다양한 프로그래밍 언어를 접하게 됩니다. 그중에서도 &lt;code&gt;Dart&lt;/code&gt;는 상대적으로 최근에 주목받기 시작한 언어로, 특히 &lt;b&gt;Google의 크로스 플랫폼 프레임워크인 Flutter&lt;/b&gt;와 함께 사용되면서 인기를 얻고 있습니다. 이번 글에서는 &lt;code&gt;Dart&lt;/code&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;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Dart&lt;/code&gt;는 Google에서 개발한 오픈소스 프로그래밍 언어입니다. 주로 &lt;b&gt;모바일 앱 개발&lt;/b&gt;(Android 및 iOS), &lt;b&gt;웹 개발&lt;/b&gt;, &lt;b&gt;데스크탑 애플리케이션&lt;/b&gt;, &lt;b&gt;서버 개발&lt;/b&gt; 등 다양한 플랫폼에서 사용됩니다. 이 언어는 간결한 문법과 높은 생산성을 제공하며, 컴파일러를 통해 네이티브 코드로 변환되어 뛰어난 실행 속도를 자랑합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Google은 &lt;code&gt;Dart&lt;/code&gt;를 개발하면서 &lt;b&gt;빠른 속도&lt;/b&gt;, &lt;b&gt;안전한 코드 작성&lt;/b&gt;, 그리고 &lt;b&gt;개발자 친화성&lt;/b&gt;을 염두에 두었습니다. 특히, &lt;code&gt;Dart&lt;/code&gt;는 &lt;b&gt;Flutter&lt;/b&gt;와 함께 사용하기 위해 설계되었기 때문에 UI 개발에 특화된 기능을 많이 제공합니다.&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;p data-ke-size=&quot;size16&quot;&gt;많은 프로그래밍 언어가 존재하는데, 왜 굳이 &lt;code&gt;Dart&lt;/code&gt;를 선택해야 할까요? 다음은 &lt;code&gt;Dart&lt;/code&gt;를 사용하는 몇 가지 주요 이유입니다:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;크로스 플랫폼 개발&lt;/b&gt;:&lt;br /&gt;&lt;code&gt;Dart&lt;/code&gt;는 하나의 코드베이스로 Android, iOS, 웹, 데스크탑 애플리케이션을 개발할 수 있는 &lt;b&gt;크로스 플랫폼 개발&lt;/b&gt;을 지원합니다. 이는 Flutter와의 통합을 통해 더욱 강력하게 발현됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;빠른 성능&lt;/b&gt;:&lt;br /&gt;&lt;code&gt;Dart&lt;/code&gt;는 두 가지 방식으로 코드를 실행합니다:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;AOT 컴파일(앞서 컴파일)&lt;/b&gt;: 코드를 네이티브 바이너리로 변환해 높은 실행 속도를 제공합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;JIT 컴파일(실시간 컴파일)&lt;/b&gt;: 개발 중에는 빠른 수정과 테스트가 가능하도록 지원합니다.&lt;br /&gt;이 두 가지 방식의 조합은 생산성과 성능을 모두 만족시킵니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;간결하고 읽기 쉬운 문법&lt;/b&gt;:&lt;br /&gt;&lt;code&gt;Dart&lt;/code&gt;의 문법은 &lt;code&gt;Java&lt;/code&gt;, &lt;code&gt;C++&lt;/code&gt;, &lt;code&gt;JavaScript&lt;/code&gt;와 유사하여 배우기 쉽습니다. 또한 불필요한 코드 작성을 줄이고, 직관적으로 작성할 수 있도록 설계되었습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Flutter와의 완벽한 통합&lt;/b&gt;:&lt;br /&gt;&lt;code&gt;Dart&lt;/code&gt;는 Flutter의 기본 언어로, Flutter의 위젯 시스템과 완벽하게 통합됩니다. 이를 통해 UI를 유연하고 쉽게 설계할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;강력한 타입 시스템&lt;/b&gt;:&lt;br /&gt;&lt;code&gt;Dart&lt;/code&gt;는 정적 타입과 동적 타입을 모두 지원합니다. 강력한 타입 추론(type inference)을 통해 개발자의 실수를 방지하면서도 코드의 가독성을 유지합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Dart의 주요 특징&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Dart&lt;/code&gt;는 개발자 친화적인 다양한 기능을 제공하며, 이러한 특징들은 &lt;code&gt;Dart&lt;/code&gt;를 매력적인 언어로 만듭니다. 아래는 그 주요 특징들입니다:&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 타입 시스템&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Dart&lt;/code&gt;는 정적 타입 언어로서, 변수와 객체의 타입을 명시적으로 선언하거나 타입 추론을 활용할 수 있습니다. 예를 들어:&lt;/p&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;void main() {
  // 명시적 타입 선언
  int age = 25; 
  String name = &quot;홍길동&quot;;

  // 타입 추론 사용
  var height = 175.5; // double로 추론됨
  var isStudent = true; // bool로 추론됨

  print(&quot;나이: $age, 이름: $name, 키: $height, 학생 여부: $isStudent&quot;);
}&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;2. Null Safety&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Dart&lt;/code&gt;는 &lt;b&gt;Null Safety(널 안정성)&lt;/b&gt;를 지원하여, 런타임 오류를 방지합니다. Null Safety를 통해 null 값이 들어갈 가능성이 있는 변수는 컴파일 단계에서 에러를 발생시킵니다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;void main() {
  String? nullableString = null; // null을 허용하는 변수
  String nonNullableString = &quot;안녕하세요&quot;; // null을 허용하지 않는 변수

  print(nullableString); // 출력: null
  print(nonNullableString);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Null Safety는 프로그램이 실행 중에 null 관련 에러를 발생시키는 것을 방지하는 데 큰 도움이 됩니다.&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;&lt;code&gt;Dart&lt;/code&gt;는 &lt;b&gt;비동기 프로그래밍&lt;/b&gt;을 쉽게 처리할 수 있도록 &lt;code&gt;async&lt;/code&gt;와 &lt;code&gt;await&lt;/code&gt; 키워드를 제공합니다. 이를 통해 복잡한 비동기 작업을 간단하게 구현할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;Future&amp;lt;String&amp;gt; fetchUserData() async {
  await Future.delayed(Duration(seconds: 2)); // 2초 대기
  return &quot;유저 데이터 로드 완료&quot;;
}

void main() async {
  print(&quot;데이터 로드 시작&quot;);
  String data = await fetchUserData();
  print(data);
}&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;4. 컬렉션(Collection) 활용&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Dart&lt;/code&gt;는 리스트(&lt;code&gt;List&lt;/code&gt;), 맵(&lt;code&gt;Map&lt;/code&gt;), 집합(&lt;code&gt;Set&lt;/code&gt;) 등 다양한 컬렉션 자료형을 제공합니다. 특히, 컬렉션에 대해 유용한 메서드와 기능들이 많아 데이터를 손쉽게 다룰 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;void main() {
  // 리스트 생성
  List&amp;lt;String&amp;gt; fruits = [&quot;사과&quot;, &quot;바나나&quot;, &quot;딸기&quot;];
  fruits.add(&quot;포도&quot;); // 요소 추가
  print(fruits);

  // 맵 생성
  Map&amp;lt;String, int&amp;gt; scores = {&quot;철수&quot;: 90, &quot;영희&quot;: 85};
  scores[&quot;민수&quot;] = 95; // 새로운 키-값 추가
  print(scores);

  // Set 생성
  Set&amp;lt;int&amp;gt; uniqueNumbers = {1, 2, 3};
  uniqueNumbers.add(2); // 중복 값 추가 시 무시됨
  print(uniqueNumbers);
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. 함수형 프로그래밍 지원&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;Dart&lt;/code&gt;는 함수형 프로그래밍 스타일을 지원하며, 이를 통해 코드를 간결하게 작성할 수 있습니다. 예를 들어, 리스트의 각 요소를 변환하거나 필터링하는 작업을 손쉽게 수행할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;void main() {
  List&amp;lt;int&amp;gt; numbers = [1, 2, 3, 4, 5];

  // 맵핑: 각 숫자에 2를 곱하기
  var doubledNumbers = numbers.map((num) =&amp;gt; num * 2);
  print(doubledNumbers.toList());

  // 필터링: 짝수만 남기기
  var evenNumbers = numbers.where((num) =&amp;gt; num % 2 == 0);
  print(evenNumbers.toList());
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Dart와 다른 언어의 비교&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Dart는 여러 면에서 기존 언어들과 비슷하지만, 몇 가지 독특한 점도 있습니다. 아래는 &lt;code&gt;Dart&lt;/code&gt;와 다른 언어를 비교한 간단한 표입니다:&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;특징&lt;/th&gt;
&lt;th&gt;Dart&lt;/th&gt;
&lt;th&gt;JavaScript&lt;/th&gt;
&lt;th&gt;Java&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;크로스 플랫폼&lt;/td&gt;
&lt;td&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;AOT 컴파일&lt;/td&gt;
&lt;td&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;JIT 컴파일&lt;/td&gt;
&lt;td&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;Null Safety&lt;/td&gt;
&lt;td&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;Flutter와의 통합&lt;/td&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;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;code&gt;Dart&lt;/code&gt;는 현대 애플리케이션 개발에 적합한 강력한 언어입니다. 특히, Flutter와 함께 사용하면 &lt;b&gt;UI 중심의 크로스 플랫폼 개발&lt;/b&gt;에서 탁월한 생산성을 제공합니다. 또한, 간결하고 안전한 문법과 강력한 타입 시스템, 그리고 비동기 프로그래밍 지원 등은 개발자에게 큰 매력을 줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1788&quot; data-origin-height=&quot;994&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JvW9X/btsL2nUZIKt/QOpdOcdn9tIrROhfcBmJ80/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JvW9X/btsL2nUZIKt/QOpdOcdn9tIrROhfcBmJ80/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JvW9X/btsL2nUZIKt/QOpdOcdn9tIrROhfcBmJ80/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJvW9X%2FbtsL2nUZIKt%2FQOpdOcdn9tIrROhfcBmJ80%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;1788&quot; height=&quot;994&quot; data-origin-width=&quot;1788&quot; data-origin-height=&quot;994&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>취미/개발</category>
      <category>DART</category>
      <category>Flutter</category>
      <author>임다</author>
      <guid isPermaLink="true">https://gallery-a.tistory.com/90</guid>
      <comments>https://gallery-a.tistory.com/90#entry90comment</comments>
      <pubDate>Mon, 20 Jan 2025 06:31:20 +0900</pubDate>
    </item>
  </channel>
</rss>