<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>hayo_dev.log</title>
        <link>https://velog.io/</link>
        <description>flutter 개발자(진)</description>
        <lastBuildDate>Thu, 08 Aug 2024 12:52:32 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>hayo_dev.log</title>
            <url>https://velog.velcdn.com/images/hayo_dev/profile/ecd6db77-9ef7-4337-bcf5-aa6388ca2e34/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. hayo_dev.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/hayo_dev" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[On 100% 개인정보처리방침]]></title>
            <link>https://velog.io/@hayo_dev/On-100-%EA%B0%9C%EC%9D%B8%EC%A0%95%EB%B3%B4%EC%B2%98%EB%A6%AC%EB%B0%A9%EC%B9%A8</link>
            <guid>https://velog.io/@hayo_dev/On-100-%EA%B0%9C%EC%9D%B8%EC%A0%95%EB%B3%B4%EC%B2%98%EB%A6%AC%EB%B0%A9%EC%B9%A8</guid>
            <pubDate>Thu, 08 Aug 2024 12:52:32 GMT</pubDate>
            <description><![CDATA[<h3 id="개인정보-처리방침">개인정보 처리방침</h3>
<p><strong>마지막 업데이트 날짜</strong>: 2024년 8월 8일</p>
<p>이 개인정보 처리방침은 귀하가 서비스 이용 시 귀하의 정보 수집, 사용 및 공개에 대한 당사의 정책과 절차를 설명하며, 귀하의 개인정보 보호 권리 및 관련 법률이 귀하를 어떻게 보호하는지 알려줍니다.</p>
<p>당사는 귀하의 개인 데이터를 서비스 제공 및 개선을 위해 사용합니다. 서비스를 이용함으로써 귀하는 이 개인정보 처리방침에 따라 정보 수집 및 사용에 동의하게 됩니다. 이 개인정보 처리방침은 <a href="https://www.freeprivacypolicy.com/free-privacy-policy-generator/">무료 개인정보 처리방침 생성기</a>의 도움으로 작성되었습니다.</p>
<h3 id="해석-및-정의">해석 및 정의</h3>
<h4 id="해석">해석</h4>
<p>첫 글자가 대문자인 단어는 다음 조건에서 정의된 의미를 가집니다. 이 정의는 단수형 또는 복수형으로 나타나더라도 동일한 의미를 가집니다.</p>
<h4 id="정의">정의</h4>
<p>이 개인정보 처리방침의 목적을 위해:</p>
<ul>
<li><strong>계정</strong>은 귀하가 당사의 서비스 또는 서비스의 일부에 접근할 수 있도록 만든 고유한 계정을 의미합니다.</li>
<li><strong>계열사</strong>는 한 당사자가 소유하거나, 통제하거나, 당사자와 공통적으로 통제되는 법인을 의미하며, 여기서 &quot;통제&quot;란 이사 또는 기타 관리 권한을 선출할 수 있는 주식, 지분 또는 기타 유가증권의 50% 이상을 소유하는 것을 의미합니다.</li>
<li><strong>애플리케이션</strong>은 회사에서 제공하는 소프트웨어 프로그램인 &quot;On 100%&quot;를 의미합니다.</li>
<li><strong>회사</strong>(이 약관에서 &quot;회사&quot;, &quot;당사&quot;, &quot;우리&quot; 또는 &quot;당사의&quot;로 언급됨)는 &quot;On 100%&quot;를 의미합니다.</li>
<li><strong>국가</strong>는 대한민국을 의미합니다.</li>
<li><strong>기기</strong>는 컴퓨터, 휴대전화 또는 디지털 태블릿과 같이 서비스를 이용할 수 있는 모든 장치를 의미합니다.</li>
<li><strong>개인 데이터</strong>는 식별되었거나 식별 가능한 개인과 관련된 모든 정보를 의미합니다.</li>
<li><strong>서비스</strong>는 애플리케이션을 의미합니다.</li>
<li><strong>서비스 제공자</strong>는 회사를 대신하여 데이터를 처리하는 모든 자연인 또는 법인을 의미합니다. 이는 회사를 대신하여 서비스를 제공하거나, 서비스와 관련된 서비스를 수행하거나, 서비스 사용을 분석하는 데 도움을 주는 제3자 회사 또는 개인을 의미합니다.</li>
<li><strong>사용 데이터</strong>는 서비스 사용 중 자동으로 수집된 데이터로, 예를 들어 페이지 방문 시간 등 서비스 인프라에서 생성된 데이터를 의미합니다.</li>
<li><strong>귀하</strong>는 서비스를 접근하거나 사용하는 개인 또는 해당 개인이 서비스를 접근하거나 사용하는 회사나 기타 법적 단체를 의미합니다.</li>
</ul>
<h3 id="개인-데이터의-수집-및-사용">개인 데이터의 수집 및 사용</h3>
<h4 id="수집된-데이터의-유형">수집된 데이터의 유형</h4>
<h5 id="개인-데이터">개인 데이터</h5>
<p>당사 서비스 이용 시, 귀하에게 연락하거나 귀하를 식별할 수 있는 일부 개인 식별 정보를 제공하도록 요청할 수 있습니다. 개인 식별 정보에는 다음이 포함될 수 있지만 이에 국한되지는 않습니다:</p>
<ul>
<li>사용 데이터</li>
</ul>
<h5 id="사용-데이터">사용 데이터</h5>
<p>사용 데이터는 서비스 이용 중 자동으로 수집됩니다.</p>
<p>사용 데이터는 귀하의 기기의 인터넷 프로토콜 주소(예: IP 주소), 브라우저 유형, 브라우저 버전, 귀하가 방문한 서비스 페이지, 방문 시간 및 날짜, 해당 페이지에서 보낸 시간, 고유 기기 식별자 및 기타 진단 데이터와 같은 정보를 포함할 수 있습니다.</p>
<p>모바일 장치를 통해 서비스에 접근하는 경우, 당사는 귀하의 모바일 장치 유형, 고유한 모바일 장치 ID, 모바일 장치의 IP 주소, 모바일 운영 체제, 모바일 인터넷 브라우저 유형, 고유 기기 식별자 및 기타 진단 데이터를 포함하여 특정 정보를 자동으로 수집할 수 있습니다.</p>
<p>또한 귀하가 당사 서비스 방문 시 또는 모바일 장치를 통해 서비스에 접근할 때 브라우저에서 보낸 정보를 수집할 수 있습니다.</p>
<h4 id="개인-데이터의-사용">개인 데이터의 사용</h4>
<p>회사는 개인 데이터를 다음과 같은 목적으로 사용할 수 있습니다:</p>
<ul>
<li><strong>서비스 제공 및 유지 관리</strong>: 서비스 사용을 모니터링하기 위해 포함됩니다.</li>
<li><strong>계정 관리</strong>: 서비스 사용자로서 귀하의 등록을 관리하기 위해. 귀하가 제공한 개인 데이터는 귀하가 등록된 사용자로서 접근할 수 있는 서비스의 다양한 기능에 접근할 수 있도록 합니다.</li>
<li><strong>계약 이행</strong>: 귀하가 구매한 제품, 항목 또는 서비스에 대한 구매 계약 이행, 준수 및 수행을 위해 또는 서비스를 통해 당사와의 다른 계약에 대해.</li>
<li><strong>귀하와의 연락</strong>: 이메일, 전화 통화, SMS 또는 서비스 기능, 제품 또는 계약된 서비스에 관한 업데이트 또는 정보 제공 커뮤니케이션, 보안 업데이트 등을 포함한 모바일 애플리케이션의 푸시 알림과 같은 전자적 커뮤니케이션 형태로 귀하에게 연락하기 위해.</li>
<li><strong>뉴스 제공</strong>: 귀하가 이미 구매했거나 문의한 것과 유사한 다른 상품, 서비스 및 이벤트에 관한 뉴스, 특별 행사 및 일반 정보 제공을 위해(귀하가 이러한 정보를 받지 않기로 선택하지 않은 경우).</li>
<li><strong>요청 관리</strong>: 당사에 대한 귀하의 요청을 참석하고 관리하기 위해.</li>
<li><strong>비즈니스 이전</strong>: 당사는 합병, 분할, 구조조정, 조직 개편, 해산 또는 기타 형태의 자산 이전의 일환으로, 파산, 청산 또는 이와 유사한 절차의 일환으로 귀하의 개인 데이터를 사용할 수 있습니다. 이 경우 서비스 사용자에 대한 개인 데이터는 이전 자산 중 하나로 포함될 수 있습니다.</li>
<li><strong>기타 목적</strong>: 데이터 분석, 사용 경향 파악, 당사 홍보 캠페인의 효과 결정 및 서비스, 제품, 서비스, 마케팅 및 귀하의 경험을 평가하고 개선하기 위해 귀하의 정보를 사용할 수 있습니다.</li>
</ul>
<h3 id="귀하의-개인-데이터-공유">귀하의 개인 데이터 공유</h3>
<p>회사는 다음과 같은 상황에서 귀하의 개인 정보를 공유할 수 있습니다:</p>
<ul>
<li><strong>서비스 제공자와 함께</strong>: 서비스 제공자와 함께 서비스 사용을 모니터링하고 분석하기 위해 귀하의 개인 정보를 공유할 수 있습니다.</li>
<li><strong>비즈니스 이전</strong>: 회사 자산의 합병, 매각, 금융 또는 전체 또는 일부의 인수 협상 중 또는 관련하여 귀하의 개인 정보를 공유하거나 이전할 수 있습니다.</li>
<li><strong>계열사와 함께</strong>: 당사는 귀하의 정보를 계열사와 공유할 수 있으며, 이 경우 해당 계열사에게 이 개인정보 처리방침을 준수하도록 요구합니다. 계열사에는 당사의 모회사와 기타 자회사, 합작 파트너 또는 당사가 통제하거나 당사와 공동 통제하에 있는 기타 회사가 포함됩니다.</li>
<li><strong>비즈니스 파트너와 함께</strong>: 당사는 귀하에게 특정 제품, 서비스 또는 프로모션을 제공하기 위해 귀하의 정보를 비즈니스 파트너와 공유할 수 있습니다.</li>
<li><strong>다른 사용자와 함께</strong>: 귀하가 다른 사용자와 상호작용하는 경우, 해당 정보는 다른 모든 사용자에게 볼 수 있으며 외부에 공개될 수 있습니다.</li>
<li><strong>귀하의 동의 하에</strong>: 당사는 귀하의 동의 하에 다른 목적으로 귀하의 개인 정보를 공개할 수 있습니다.</li>
</ul>
<h3 id="귀하의-개인-데이터-보유">귀하의 개인 데이터 보유</h3>
<p>회사는 이 개인정보 처리방침에 명시된 목적을 위해 필요한 기간 동안만 귀하의 개인 데이터를 보유합니다. 당사는 법적 의무를 준수하기 위해(예: 해당 법률을 준수하기 위해 귀하의 데이터를 보유해야 하는 경우), 분쟁을 해결하고, 당사의 법적 계약 및 정책을 집행하기 위해 필요한 범위 내에서 귀하의 개인 데이터를 보유하고 사용할 것입니다.</p>
<p>회사는 내부 분석 목적으로도 사용 데이터를 보유합니다. 사용 데이터는 일반적으로 더 짧은 기간 동안 보관되지만, 이 데이터가 당사의 서비스 보안을 강화하거나 기능 개선에 사용되거나 법적으로 더 오랜 기간 보관해야 하는 경우에는 더 오랜 기간 보유될 수 있습니다.</p>
<h3 id="귀하의-개인-데이터-전송">귀하의 개인 데이터 전송</h3>
<p>귀하의 정보, 포함 개인 데이터는 회사의 운영 사무소 및 처리에 관여하는 당사자가 위치한 기타 장소에서 처리됩니다. 이는 귀하의 정보가 귀하의 주, 지방, 국가 또는 기타 정부 관할 구역 외부에 위치한 컴퓨터로 전송되어 보관될 수 있음을 의미합니다.</p>
<p>귀하의 동의를 받은 후 이러한 정보를 제출함으로써 귀하는 해당 전송에 동의하게 됩니다.</p>
<p>회사는 귀하의 데이터를 이 개인정보 처리방침에 따라 안전하게 처리하고 귀하의 개인 데이터가 안전하게 처리될 수 있도록 합리적으로 필요한 모든 조치를 취할 것입니다.</p>
<h3 id="귀하의-개인-데이터-삭제">귀하의 개인 데이터 삭제</h3>
<p>귀하는 귀하에 대해 수집한 개인 데이터를 삭제하거나 당사가 해당 데이터를 삭제하도록 요청할 권리가 있습니다.</p>
<p>당사의 서비스는 귀하가 서비스 내에서 특정 정보를 삭제할 수 있는 기능을 제공할 수 있습니다.</p>
<p>귀하는 계정에 로그인하여 귀하의 정보를 언제든지 업데이트, 수정 또는 삭제할 수 있으며, 계정 설정 섹션에서 귀하의 개인 정보를 관리할 수 있습니다. 또한 당사에 연락하여 귀하가 제공한 개인 정보에 대한 접근, 수정 또는 삭제를 요청할 수</p>
<p> 있습니다.</p>
<p>그러나 법적 의무 또는 합법적인 근거가 있는 경우, 당사는 특정 정보를 보유해야 할 수 있습니다.</p>
<h3 id="귀하의-개인-데이터-공개">귀하의 개인 데이터 공개</h3>
<h4 id="비즈니스-거래">비즈니스 거래</h4>
<p>회사가 합병, 인수 또는 자산 매각에 관여하는 경우 귀하의 개인 데이터가 이전될 수 있습니다. 당사는 귀하의 개인 데이터가 이전되기 전에 이를 통지하고, 다른 개인정보 처리방침이 적용되기 전에 이를 알릴 것입니다.</p>
<h4 id="법-집행">법 집행</h4>
<p>회사는 법률에 따라 또는 공공 기관의 유효한 요청에 따라 귀하의 개인 데이터를 공개해야 할 수 있습니다(예: 법원 또는 정부 기관의 요청).</p>
<h4 id="기타-법적-요구-사항">기타 법적 요구 사항</h4>
<p>회사는 다음과 같은 경우 귀하의 개인 데이터를 공개할 수 있습니다:</p>
<ul>
<li>법적 의무를 준수하기 위해</li>
<li>회사의 권리나 재산을 보호하고 방어하기 위해</li>
<li>서비스와 관련된 잠재적인 부정행위를 예방하거나 조사하기 위해</li>
<li>서비스 사용자 또는 공공의 개인 안전을 보호하기 위해</li>
<li>법적 책임으로부터 보호하기 위해</li>
</ul>
<h3 id="귀하의-개인-데이터-보안">귀하의 개인 데이터 보안</h3>
<p>귀하의 개인 데이터 보안은 당사에게 중요하지만, 인터넷을 통한 전송 방법 또는 전자 저장 방법은 100% 안전하지 않다는 점을 기억해 주십시오. 당사는 귀하의 개인 데이터를 보호하기 위해 상업적으로 수용 가능한 수단을 사용하기 위해 노력하고 있지만, 절대적인 보안을 보장할 수는 없습니다.</p>
<h3 id="아동의-개인정보">아동의 개인정보</h3>
<p>당사 서비스는 13세 미만의 누구에게도 제공되지 않습니다. 당사는 13세 미만의 사람으로부터 개인 식별 정보를 고의로 수집하지 않습니다. 귀하가 부모나 보호자이고 귀하의 자녀가 당사에게 개인 데이터를 제공했다는 사실을 알고 있다면 당사에 연락해 주십시오. 당사가 부모의 동의 없이 13세 미만의 사람으로부터 개인 데이터를 수집한 사실을 알게 되면, 당사는 해당 정보를 당사의 서버에서 삭제하기 위한 조치를 취합니다.</p>
<p>당사가 귀하의 정보를 처리하는 법적 근거로서 동의에 의존해야 하고, 귀하의 국가에서 부모의 동의가 요구되는 경우, 당사는 귀하의 정보를 수집하고 사용하기 전에 부모의 동의를 요구할 수 있습니다.</p>
<h3 id="다른-웹사이트로의-링크">다른 웹사이트로의 링크</h3>
<p>당사 서비스는 당사가 운영하지 않는 다른 웹사이트에 대한 링크를 포함할 수 있습니다. 제3자 링크를 클릭하면 해당 제3자의 사이트로 이동합니다. 당사는 귀하가 방문하는 모든 사이트의 개인정보 처리방침을 검토할 것을 강력히 권장합니다.</p>
<p>당사는 제3자 사이트 또는 서비스의 콘텐츠, 개인정보 처리방침 또는 관행에 대해 어떠한 통제도 하지 않으며 책임을 지지 않습니다.</p>
<h3 id="개인정보-처리방침-변경">개인정보 처리방침 변경</h3>
<p>당사는 때때로 개인정보 처리방침을 업데이트할 수 있습니다. 당사는 이 페이지에 새로운 개인정보 처리방침을 게시하여 귀하에게 모든 변경 사항을 통지할 것입니다.</p>
<p>당사는 변경 사항이 적용되기 전에 이메일 또는 당사 서비스의 중요한 공지를 통해 귀하에게 통지하고, 이 개인정보 처리방침의 상단에 있는 &quot;마지막 업데이트&quot; 날짜를 업데이트할 것입니다.</p>
<p>귀하는 주기적으로 이 개인정보 처리방침을 검토하여 변경 사항이 있는지 확인하는 것이 좋습니다. 이 개인정보 처리방침에 대한 변경 사항은 이 페이지에 게시될 때 유효합니다.</p>
<h3 id="문의하기">문의하기</h3>
<p>이 개인정보 처리방침에 대해 궁금한 사항이 있으시면 다음 방법으로 저희에게 연락할 수 있습니다:</p>
<ul>
<li>이메일: <a href="mailto:hayo970323@gmail.com">hayo970323@gmail.com</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[DataBase]]></title>
            <link>https://velog.io/@hayo_dev/DataBase</link>
            <guid>https://velog.io/@hayo_dev/DataBase</guid>
            <pubDate>Sun, 21 Jul 2024 06:54:01 GMT</pubDate>
            <description><![CDATA[<h2 id="체계적인-데이터-관리-시스템-database">체계적인 데이터 관리 시스템: Database</h2>
<p>데이터베이스는 데이터를 체계적으로 저장하고 관리하는 시스템으로, 효율적인 데이터의 저장, 수정, 검색 및 삭제를 가능하게 합니다. 데이터베이스 관리 시스템(DBMS)을 통해 데이터베이스를 정의하고 관리할 수 있습니다.</p>
<h3 id="주요-개념">주요 개념</h3>
<h3 id="데이터베이스란">데이터베이스란?</h3>
<ul>
<li>데이터를 체계적으로 저장하고 관리하는 시스템.</li>
<li>효율적인 저장, 수정, 검색 및 삭제를 가능하게 함.</li>
</ul>
<h3 id="데이터와-정보">데이터와 정보</h3>
<ul>
<li><strong>데이터</strong>: 현실 세계에서 수집된 단순한 사실과 값들의 모음.</li>
<li><strong>정보</strong>: 데이터를 특정 목적에 의해 해석하거나 가공한 형태.</li>
</ul>
<h3 id="데이터베이스의-필요성">데이터베이스의 필요성</h3>
<ul>
<li><strong>무결성</strong>: 데이터가 정확하고 일관된 형태로 유지됨.</li>
<li><strong>파일 처리 시스템의 한계</strong>: 데이터 종속, 데이터 중복, 데이터 무결성 문제 해결.</li>
</ul>
<h3 id="데이터베이스의-특징">데이터베이스의 특징</h3>
<ul>
<li><strong>실시간 접근성</strong>: 사용자가 원할 때 언제든지 접근 가능.</li>
<li><strong>지속적인 변화</strong>: 데이터의 삽입, 삭제, 갱신을 통해 최신 데이터를 유지.</li>
<li><strong>동시 공유</strong>: 여러 사용자가 동시에 이용 가능.</li>
<li><strong>내용에 대한 참조</strong>: 데이터의 물리적 위치가 아닌 값을 가지고 검색.</li>
</ul>
<h3 id="데이터베이스-종류">데이터베이스 종류</h3>
<h3 id="관계형-데이터베이스-rdb">관계형 데이터베이스 (RDB)</h3>
<ul>
<li>데이터를 테이블 형식으로 저장.</li>
<li>각 테이블은 행(row)과 열(column)로 구성.</li>
<li>SQL을 사용하여 데이터 관리.<ul>
<li><strong>예</strong>: MySQL, PostgreSQL, MariaDB</li>
</ul>
</li>
</ul>
<h3 id="비관계형-데이터베이스-nosql">비관계형 데이터베이스 (NoSQL)</h3>
<ul>
<li>데이터 간의 관계를 정의하지 않음.</li>
<li>유연한 데이터 모델 제공.<ul>
<li><strong>예</strong>: MongoDB, Redis, Apache Cassandra</li>
</ul>
</li>
</ul>
<h3 id="sql-structured-query-language">SQL (Structured Query Language)</h3>
<h3 id="데이터-정의어-ddl">데이터 정의어 (DDL)</h3>
<p>데이터베이스 객체(테이블, 인덱스 등)를 정의하는 데 사용됩니다.</p>
<ul>
<li><strong>CREATE</strong>: 테이블을 생성합니다.</li>
</ul>
<pre><code class="language-sql">CREATE TABLE Member (
    ID VARCHAR(50) PRIMARY KEY,
    이름 VARCHAR(100),
    비밀번호 VARCHAR(100),
    전화번호 VARCHAR(20),
    생년월일 DATE
);
</code></pre>
<ul>
<li><strong>ALTER</strong>: 테이블 구조를 변경합니다.</li>
</ul>
<pre><code class="language-sql">ALTER TABLE Member ADD COLUMN 이메일 VARCHAR(100);
</code></pre>
<ul>
<li><strong>DROP</strong>: 테이블을 삭제합니다.</li>
</ul>
<pre><code class="language-sql">DROP TABLE Member;
</code></pre>
<h3 id="데이터-조작어-dml">데이터 조작어 (DML)</h3>
<p>데이터베이스 내의 데이터를 조작하는 데 사용됩니다.</p>
<ul>
<li><strong>SELECT</strong>: 데이터를 조회합니다.</li>
</ul>
<pre><code class="language-sql">SELECT * FROM Member;
</code></pre>
<ul>
<li><strong>INSERT</strong>: 데이터를 삽입합니다.</li>
</ul>
<pre><code class="language-sql">INSERT INTO Member (ID, 이름, 비밀번호, 전화번호, 생년월일)
VALUES (&#39;user123&#39;, &#39;홍길동&#39;, &#39;password&#39;, &#39;010-1234-5678&#39;, &#39;1990-01-01&#39;);
</code></pre>
<ul>
<li><strong>UPDATE</strong>: 데이터를 수정합니다.</li>
</ul>
<pre><code class="language-sql">UPDATE Member
SET 전화번호 = &#39;010-9876-5432&#39;
WHERE ID = &#39;user123&#39;;
</code></pre>
<ul>
<li><strong>DELETE</strong>: 데이터를 삭제합니다.</li>
</ul>
<pre><code class="language-sql">DELETE FROM Member WHERE ID = &#39;user123&#39;;
</code></pre>
<h3 id="데이터-제어어-dcl">데이터 제어어 (DCL)</h3>
<p>데이터베이스에 대한 접근 권한을 제어하는 데 사용됩니다.</p>
<ul>
<li><strong>GRANT</strong>: 사용자에게 권한을 부여합니다.</li>
</ul>
<pre><code class="language-sql">GRANT SELECT ON Member TO &#39;username&#39;@&#39;localhost&#39;;
</code></pre>
<ul>
<li><strong>REVOKE</strong>: 사용자에게서 권한을 회수합니다.</li>
</ul>
<pre><code class="language-sql">REVOKE SELECT ON Member FROM &#39;username&#39;@&#39;localhost&#39;;
</code></pre>
<h3 id="키-key와-제약-조건">키 (Key)와 제약 조건</h3>
<h3 id="키-key">키 (Key)</h3>
<ul>
<li><strong>기본키 (Primary Key)</strong>: 테이블 내에서 각 튜플을 유일하게 식별할 수 있는 속성입니다.</li>
<li><strong>외래키 (Foreign Key)</strong>: 다른 테이블의 기본키를 참조하는 속성으로 테이블 간의 관계를 정의합니다.</li>
<li><strong>후보키 (Candidate Key)</strong>: 기본키가 될 수 있는 모든 속성을 말합니다.</li>
<li><strong>대체키 (Alternate Key)</strong>: 후보키 중 기본키가 아닌 속성입니다.</li>
<li><strong>슈퍼키 (Super Key)</strong>: 한 테이블에서 튜플을 유일하게 식별할 수 있는 속성의 집합입니다.</li>
</ul>
<h3 id="제약-조건">제약 조건</h3>
<p>제약 조건은 테이블에 저장되는 데이터의 정확성과 일관성을 유지하기 위해 사용됩니다.</p>
<ul>
<li><strong>NOT NULL</strong>: 컬럼에 NULL 값을 허용하지 않습니다.</li>
</ul>
<pre><code class="language-sql">CREATE TABLE Member (
    ID VARCHAR(50) PRIMARY KEY,
    이름 VARCHAR(100) NOT NULL,
    비밀번호 VARCHAR(100) NOT NULL,
    전화번호 VARCHAR(20),
    생년월일 DATE
);
</code></pre>
<ul>
<li><strong>UNIQUE</strong>: 컬럼의 모든 값이 고유하도록 보장합니다.</li>
</ul>
<pre><code class="language-sql">CREATE TABLE Member (
    ID VARCHAR(50) PRIMARY KEY,
    이메일 VARCHAR(100) UNIQUE,
    이름 VARCHAR(100) NOT NULL,
    비밀번호 VARCHAR(100) NOT NULL,
    전화번호 VARCHAR(20),
    생년월일 DATE
);
</code></pre>
<ul>
<li><strong>DEFAULT</strong>: 컬럼의 기본값을 지정합니다.</li>
</ul>
<pre><code class="language-sql">CREATE TABLE Member (
    ID VARCHAR(50) PRIMARY KEY,
    이름 VARCHAR(100) NOT NULL,
    비밀번호 VARCHAR(100) NOT NULL,
    전화번호 VARCHAR(20) DEFAULT &#39;010-0000-0000&#39;,
    생년월일 DATE
);
</code></pre>
<ul>
<li><strong>CHECK</strong>: 컬럼에 저장될 값의 조건을 지정합니다.</li>
</ul>
<pre><code class="language-sql">CREATE TABLE Member (
    ID VARCHAR(50) PRIMARY KEY,
    이름 VARCHAR(100) NOT NULL,
    비밀번호 VARCHAR(100) NOT NULL,
    전화번호 VARCHAR(20),
    생년월일 DATE,
    CHECK (연식 &gt; 2000)
);
</code></pre>
<ul>
<li><strong>FOREIGN KEY</strong>: 외래키를 설정하여 다른 테이블의 기본키와 연결합니다.</li>
</ul>
<pre><code class="language-sql">CREATE TABLE Rental (
    대여ID INT PRIMARY KEY AUTO_INCREMENT,
    회원ID VARCHAR(50),
    킥보드ID VARCHAR(50),
    대여 시간 DATETIME,
    대여 위치 VARCHAR(100),
    FOREIGN KEY (회원ID) REFERENCES Member(ID),
    FOREIGN KEY (킥보드ID) REFERENCES Scooter(킥보드ID)
);
</code></pre>
<h3 id="코드-예제">코드 예제</h3>
<h3 id="테이블-생성">테이블 생성</h3>
<pre><code class="language-sql">CREATE TABLE Scooter (
    킥보드ID VARCHAR(50) PRIMARY KEY,
    브랜드 VARCHAR(100),
    연식 INT CHECK (연식 &gt; 2000),
    기본료 DECIMAL(10, 2) DEFAULT 100.00
);
</code></pre>
<h3 id="데이터-삽입">데이터 삽입</h3>
<pre><code class="language-sql">INSERT INTO Scooter (킥보드ID, 브랜드, 연식, 기본료)
VALUES (&#39;scooter001&#39;, &#39;Xiaomi&#39;, 2020, 100.00);
</code></pre>
<h3 id="데이터-조회">데이터 조회</h3>
<pre><code class="language-sql">SELECT * FROM Scooter WHERE 브랜드 = &#39;Xiaomi&#39;;
</code></pre>
<h3 id="데이터-수정">데이터 수정</h3>
<pre><code class="language-sql">UPDATE Scooter
SET 기본료 = 120.00
WHERE 킥보드ID = &#39;scooter001&#39;;
</code></pre>
<h3 id="데이터-삭제">데이터 삭제</h3>
<pre><code class="language-sql">DELETE FROM Scooter WHERE 킥보드ID = &#39;scooter001&#39;;
</code></pre>
<h3 id="주요-활용도">주요 활용도</h3>
<h3 id="테이블-생성-및-관리">테이블 생성 및 관리</h3>
<p>데이터베이스 내에서 테이블을 생성하고, 데이터를 삽입, 수정, 삭제하는 작업을 통해 데이터를 체계적으로 관리할 수 있습니다. 예를 들어, 회원 정보를 저장하는 Member 테이블을 생성하고 관리할 수 있습니다.</p>
<h3 id="데이터-조작-및-조회">데이터 조작 및 조회</h3>
<p>SQL을 사용하여 데이터를 삽입, 수정, 삭제하며, 필요할 때 데이터를 조회할 수 있습니다. 이는 데이터의 일관성과 무결성을 유지하는 데 중요합니다.</p>
<h3 id="접근-권한-관리">접근 권한 관리</h3>
<p>데이터 제어어를 사용하여 사용자에게 접근 권한을 부여하거나 회수할 수 있습니다. 이는 데이터베이스의 보안을 유지하는 데 중요합니다.</p>
<h3 id="추가-참고-리소스">추가 참고 리소스</h3>
<ul>
<li><a href="https://www.w3schools.com/sql/"><strong>SQL 튜토리얼</strong></a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[LifeCycle]]></title>
            <link>https://velog.io/@hayo_dev/LifeCycle</link>
            <guid>https://velog.io/@hayo_dev/LifeCycle</guid>
            <pubDate>Sun, 21 Jul 2024 05:51:01 GMT</pubDate>
            <description><![CDATA[<h2 id="flutter에서-효과적인-상태-관리와-성능-최적화-lifecycle">Flutter에서 효과적인 상태 관리와 성능 최적화: LifeCycle</h2>
<p>애플리케이션의 사용자 인터페이스가 효과적으로 동작하도록 하기 위해서는 위젯의 생명주기를 이해하고 관리하는 것이 중요합니다. Flutter에서 위젯은 UI를 구성하는 기본 단위로, 상태 관리 방식에 따라 다양한 종류로 나눌 수 있습니다. 위젯의 생명주기를 이해하면 애플리케이션의 상태와 UI 업데이트를 효과적으로 처리할 수 있습니다.</p>
<h3 id="위젯의-상태-관리와-생명주기">위젯의 상태 관리와 생명주기</h3>
<p>Flutter에서는 위젯을 크게 두 가지로 나눌 수 있습니다: <code>StatelessWidget</code>과 <code>StatefulWidget</code>. 이들의 차이점은 &quot;State&quot;를 가지는지의 여부입니다. State는 위젯의 생명주기 동안 변할 수 있는 데이터를 의미합니다.</p>
<h2 id="stateless-widget">Stateless Widget</h2>
<p><code>StatelessWidget</code>은 상태가 변하지 않는 위젯을 말합니다. 이러한 위젯은 초기 설정 값에 따라 UI를 그리며, 이후 상태 변경이 발생하지 않습니다. 주로 단순히 데이터를 표시하는 데 사용됩니다.</p>
<h3 id="stateless-widget의-생명주기">Stateless Widget의 생명주기</h3>
<ol>
<li><strong>Constructor</strong>: 위젯이 생성될 때 호출되며, 초기 데이터를 설정합니다.</li>
<li><strong>build</strong>: 위젯의 UI를 그리는 메서드로, 여러 번 호출될 수 있습니다. 상태 변화가 없기 때문에 항상 같은 UI를 그립니다.</li>
</ol>
<p><strong>예시:</strong></p>
<pre><code class="language-dart">class MyStatelessWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(&#39;Stateless Widget&#39;),
      ),
      body: Center(
        child: Text(&#39;Hello, Stateless Widget!&#39;),
      ),
    );
  }
}
</code></pre>
<h2 id="stateful-widget">Stateful Widget</h2>
<p><code>StatefulWidget</code>은 상태가 변할 수 있는 위젯을 말합니다. 이러한 위젯은 상태가 변경될 때마다 UI를 갱신하며, 복잡한 상호작용을 처리하는 데 사용됩니다.</p>
<h3 id="stateful-widget의-생명주기">Stateful Widget의 생명주기</h3>
<p>Stateful Widget의 생명주기는 여러 단계로 구성됩니다. 이를 통해 상태 변경과 UI 갱신이 효율적으로 관리됩니다.</p>
<ol>
<li><p><strong>createState</strong>:</p>
<ul>
<li><p><strong>설명:</strong> StatefulWidget이 처음 생성될 때 호출됩니다. State 객체를 생성하고 반환합니다.</p>
</li>
<li><p><strong>예시:</strong></p>
<pre><code class="language-dart">@override
_MyWidgetState createState() =&gt; _MyWidgetState();
</code></pre>
</li>
<li><p><strong>사용 예시:</strong> 초기 State 객체를 생성하는 데 사용됩니다.</p>
</li>
</ul>
</li>
<li><p><strong>Constructor</strong>:</p>
<ul>
<li><p><strong>설명:</strong> State 객체의 생성자입니다. 위젯의 초기 상태를 설정합니다.</p>
</li>
<li><p><strong>예시:</strong></p>
<pre><code class="language-dart">class _MyWidgetState extends State&lt;MyWidget&gt; {
  _MyWidgetState() {
      // 초기화 작업
  }
}
</code></pre>
</li>
<li><p><strong>사용 예시:</strong> State 객체가 생성될 때 초기 상태나 변수를 설정하는 데 사용됩니다.</p>
</li>
</ul>
</li>
<li><p><strong>initState</strong>:</p>
<ul>
<li><p><strong>설명:</strong> State 객체가 처음으로 생성될 때 한 번 호출됩니다. 초기화 작업을 수행합니다.</p>
</li>
<li><p><strong>필수:</strong> 반드시 <code>super.initState()</code>를 호출해야 합니다.</p>
</li>
<li><p><strong>예시:</strong></p>
<pre><code class="language-dart">@override
void initState() {
  super.initState();
  // 초기화 작업
}
</code></pre>
</li>
<li><p><strong>사용 예시:</strong> 네트워크 요청, 애니메이션 설정, 이벤트 리스너 등록 등의 초기화 작업을 수행하는 데 사용됩니다. 예를 들어, <code>initState</code>에서 Firebase 초기화, 애니메이션 컨트롤러 초기화 또는 소켓 연결을 설정할 수 있습니다.</p>
</li>
</ul>
</li>
<li><p><strong>didChangeDependencies</strong>:</p>
<ul>
<li><p><strong>설명:</strong> State 객체가 처음 생성된 후 또는 종속성이 변경될 때 호출됩니다.</p>
</li>
<li><p><strong>필수:</strong> 반드시 <code>super.didChangeDependencies()</code>를 호출해야 합니다.</p>
</li>
<li><p><strong>예시:</strong></p>
<pre><code class="language-dart">@override
void didChangeDependencies() {
  super.didChangeDependencies();
  // 종속성 변경 처리
}
</code></pre>
</li>
<li><p><strong>사용 예시:</strong> InheritedWidget과 같은 종속성이 변경되었을 때 반응하는 작업을 수행하는 데 사용됩니다. 예를 들어, Locale이나 Theme 변경 시 이에 맞게 UI를 업데이트할 수 있습니다.</p>
</li>
</ul>
</li>
<li><p><strong>build</strong>:</p>
<ul>
<li><p><strong>설명:</strong> 위젯의 UI를 그리는 메서드로, 여러 번 호출될 수 있습니다. 상태 변경 시마다 호출됩니다.</p>
</li>
<li><p><strong>예시:</strong></p>
<pre><code class="language-dart">@override
Widget build(BuildContext context) {
  return Scaffold(
      appBar: AppBar(
          title: Text(&#39;My Widget&#39;),
      ),
      body: Center(
          child: Text(&#39;Hello, World!&#39;),
      ),
  );
}
</code></pre>
</li>
<li><p><strong>사용 예시:</strong> 위젯의 UI를 생성하고, 상태가 변경될 때마다 UI를 다시 빌드하는 데 사용됩니다. 예를 들어, 카운터 값이 변경될 때마다 화면에 표시되는 숫자를 업데이트할 수 있습니다.</p>
</li>
</ul>
</li>
<li><p><strong>setState</strong>:</p>
<ul>
<li><p><strong>설명:</strong> 상태가 변경되었음을 Flutter 프레임워크에 알리는 메서드입니다. <code>build</code> 메서드를 다시 호출하여 UI를 갱신합니다.</p>
</li>
<li><p><strong>예시:</strong></p>
<pre><code class="language-dart">void _incrementCounter() {
  setState(() {
      _counter++;
  });
}
</code></pre>
</li>
<li><p><strong>사용 예시:</strong> 상태를 변경하고, 이를 반영하여 UI를 갱신하는 데 사용됩니다. 예를 들어, 버튼 클릭 시 카운터 값을 증가시키고 이를 UI에 반영할 수 있습니다.</p>
</li>
</ul>
</li>
<li><p><strong>didUpdateWidget</strong>:</p>
<ul>
<li><p><strong>설명:</strong> 부모 위젯이 새 위젯을 구성할 때 호출됩니다. 위젯 변경 시 필요한 작업을 수행합니다.</p>
</li>
<li><p><strong>필수:</strong> 반드시 <code>super.didUpdateWidget(oldWidget)</code>을 호출해야 합니다.</p>
</li>
<li><p><strong>예시:</strong></p>
<pre><code class="language-dart">@override
void didUpdateWidget(MyWidget oldWidget) {
  super.didUpdateWidget(oldWidget);
  // 위젯 변경 처리
}
</code></pre>
</li>
<li><p><strong>사용 예시:</strong> 부모 위젯이 새 위젯을 구성할 때, 위젯 변경에 필요한 작업을 수행하는 데 사용됩니다. 예를 들어, 부모 위젯의 속성이 변경될 때 이를 반영하여 상태를 업데이트할 수 있습니다.</p>
</li>
</ul>
</li>
<li><p><strong>deactivate</strong>:</p>
<ul>
<li><p><strong>설명:</strong> State 객체가 위젯 트리에서 제거될 때 호출됩니다.</p>
</li>
<li><p><strong>필수:</strong> 반드시 <code>super.deactivate()</code>를 호출해야 합니다.</p>
</li>
<li><p><strong>예시:</strong></p>
<pre><code class="language-dart">@override
void deactivate() {
  super.deactivate();
  // 비활성화 작업
}
</code></pre>
</li>
<li><p><strong>사용 예시:</strong> 위젯이 트리에서 제거될 때, 필요한 정리 작업을 수행하는 데 사용됩니다. 예를 들어, 타이머나 애니메이션을 중지하거나, 리스너를 제거할 수 있습니다.</p>
</li>
</ul>
</li>
<li><p><strong>dispose</strong>:</p>
<ul>
<li><p><strong>설명:</strong> State 객체가 영구적으로 제거될 때 호출됩니다. 리소스를 해제하고 정리하는 데 사용됩니다.</p>
</li>
<li><p><strong>필수:</strong> 반드시 <code>super.dispose()</code>를 호출해야 합니다.</p>
</li>
<li><p><strong>예시:</strong></p>
<pre><code class="language-dart">@override
void dispose() {
  // 정리 작업
  super.dispose();
}
</code></pre>
</li>
<li><p><strong>사용 예시:</strong> 네트워크 요청 취소, 컨트롤러 해제 등 리소스를 정리하는 데 사용됩니다. 예를 들어, 애니메이션 컨트롤러를 해제하거나, 스트림 구독을 취소할 수 있습니다.</p>
</li>
</ul>
</li>
</ol>
<h3 id="생명주기-요약">생명주기 요약</h3>
<ul>
<li><strong>createState</strong>: State 객체 생성</li>
<li><strong>Constructor</strong>: State 객체 초기화</li>
<li><strong>initState</strong>: State 초기화</li>
<li><strong>didChangeDependencies</strong>: 종속성 변경 처리</li>
<li><strong>build</strong>: UI 생성 및 갱신</li>
<li><strong>setState</strong>: 상태 변경 알림 및 UI 갱신</li>
<li><strong>didUpdateWidget</strong>: 부모 위젯에 의해 State가 변경될 때 처리</li>
<li><strong>deactivate</strong>: State 비활성화</li>
<li><strong>dispose</strong>: State 및 리소스 정리</li>
</ul>
<h3 id="생명주기의-활용">생명주기의 활용</h3>
<ul>
<li><strong>효율적인 상태 관리</strong>: 생명주기 메서드를 통해 상태를 적절히 관리하여 성능을 최적화합니다.</li>
<li><strong>리소스 관리</strong>: 네트워크 요청, 데이터베이스 연결 등을 올바른 시점에 초기화하고 해제합니다.</li>
<li><strong>버그 예방</strong>: 위젯 생성 및 소멸 시점을 명확히 하여 의도하지 않은 동작을 방지합니다.</li>
<li><strong>유지보수 용이성</strong>: 생명주기를 이해하면 코드 구조와 흐름을 더 잘 파악할 수 있어 유지보수가 용이합니다.</li>
</ul>
<h2 id="참고자료">참고자료</h2>
<ul>
<li><a href="https://api.flutter.dev/flutter/widgets/StatelessWidget-class.html">Flutter 공식 문서 - StatelessWidget 클래스</a></li>
<li><a href="https://api.flutter.dev/flutter/widgets/StatefulWidget-class.html">Flutter 공식 문서 - StatefulWidget 클래스</a></li>
<li><a href="https://api.flutter.dev/flutter/widgets/State-class.html">Flutter 공식 문서 - State 클래스</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Constraints]]></title>
            <link>https://velog.io/@hayo_dev/Constraints</link>
            <guid>https://velog.io/@hayo_dev/Constraints</guid>
            <pubDate>Sun, 21 Jul 2024 05:12:35 GMT</pubDate>
            <description><![CDATA[<h2 id="flutter에서-레이아웃-제약-이해하기-constraints">Flutter에서 레이아웃 제약 이해하기: Constraints</h2>
<h3 id="제약의-기본-원칙">제약의 기본 원칙</h3>
<p>Flutter 레이아웃의 기본 원칙은 다음과 같습니다:</p>
<ul>
<li><strong>제약은 내려간다:</strong> 부모 위젯이 자식 위젯에게 제약 조건을 전달합니다.</li>
<li><strong>크기는 올라간다:</strong> 자식 위젯이 자신의 크기를 부모 위젯에게 전달합니다.</li>
<li><strong>부모가 위치를 설정한다:</strong> 부모 위젯이 자식 위젯의 위치를 설정합니다.</li>
</ul>
<h3 id="레이아웃-동작-방식">레이아웃 동작 방식</h3>
<p>Flutter의 레이아웃은 다음과 같이 동작합니다:</p>
<ul>
<li><strong>부모 위젯이 자식 위젯이 가질 수 있는 최대 및 최소 크기(=제약 조건)를 정합니다.</strong><ul>
<li>예시: 부모 위젯이 자식 위젯에게 &quot;너는 최소 50픽셀, 최대 200픽셀 너비를 가져야 한다&quot;고 제약 조건을 설정할 수 있습니다.</li>
</ul>
</li>
<li><strong>자식 위젯의 크기는 제약 조건을 만족하지 않는 경우 무시될 수 있습니다.</strong><ul>
<li>예시: 자식 위젯이 300픽셀 너비를 원하더라도 부모 위젯이 설정한 제약 조건(최대 200픽셀)을 넘을 수 없습니다.</li>
</ul>
</li>
<li><strong>자식 위젯의 위치는 부모 위젯이 결정합니다.</strong><ul>
<li>예시: 부모 위젯이 자식 위젯을 화면의 중앙에 배치하거나 특정 위치에 배치할 수 있습니다.</li>
</ul>
</li>
</ul>
<h3 id="제약-조건의-상세">제약 조건의 상세</h3>
<h3 id="제약-조건constraints">제약 조건(Constraints)</h3>
<p>각 위젯은 부모로부터 제약 조건을 받습니다. 제약 조건은 최소 및 최대 너비와 높이를 포함합니다.</p>
<h3 id="제약-조건-전파">제약 조건 전파</h3>
<p>위젯은 자식들에게 제약 조건을 전달하고, 각 자식의 크기를 요청합니다.</p>
<h3 id="위젯-크기-결정">위젯 크기 결정</h3>
<p>각 자식의 크기 요청을 바탕으로 자신의 크기를 결정하고, 이를 부모에게 보고합니다.</p>
<h3 id="예제">예제</h3>
<h3 id="예제-1-기본-컨테이너">예제 1: 기본 컨테이너</h3>
<pre><code class="language-dart">Container(color: red)
</code></pre>
<p>화면은 컨테이너에게 정확히 화면 크기만큼의 크기를 강제합니다. 따라서 컨테이너는 화면 전체를 채우고 빨간색으로 칠합니다.</p>
<h3 id="예제-2-center-위젯-사용">예제 2: Center 위젯 사용</h3>
<pre><code class="language-dart">Center(
  child: Container(width: 100, height: 100, color: red),
)
</code></pre>
<p>화면은 Center에게 화면 크기를 강제하지만, Center는 자식에게 아무 크기나 가질 수 있게 허용합니다. 이 경우, 컨테이너는 100x100 크기를 가질 수 있습니다.</p>
<h3 id="예제-3-align-위젯-사용">예제 3: Align 위젯 사용</h3>
<pre><code class="language-dart">Align(
  alignment: Alignment.bottomRight,
  child: Container(width: 100, height: 100, color: red),
)
</code></pre>
<p>Align은 자식이 화면 내에서 원하는 크기를 가질 수 있도록 하지만, 여유 공간이 있을 경우 오른쪽 하단에 정렬합니다.</p>
<h3 id="예제-4-중첩된-컨테이너">예제 4: 중첩된 컨테이너</h3>
<pre><code class="language-dart">Center(
  child: Container(
    color: red,
    child: Container(color: green, width: 30, height: 30),
  ),
)
</code></pre>
<p>빨간 컨테이너는 자식의 크기에 맞추어 크기를 결정합니다. 따라서 빨간 컨테이너의 크기는 30x30이 되고, 초록색 컨테이너가 이를 덮어씁니다.</p>
<h3 id="제약-유형">제약 유형</h3>
<h3 id="tight-constraints">Tight Constraints</h3>
<ul>
<li><strong>Tight Constraints</strong>: 특정 크기를 강제하는 제약 조건입니다. 최소 및 최대 크기가 동일합니다.</li>
</ul>
<p>여기서, 화면은 컨테이너에게 정확히 화면 크기만큼의 크기를 강제합니다.
    - 예시: 화면이 컨테이너에게 화면 전체 크기를 강제하는 경우.</p>
<pre><code>```dart
Container(color: Colors.red)

```</code></pre><h3 id="loose-constraints">Loose Constraints</h3>
<ul>
<li><strong>Loose Constraints</strong>: 위젯이 0에서 최대 크기까지 가질 수 있는 제약 조건입니다.</li>
</ul>
<p>Center는 자식에게 아무 크기나 가질 수 있게 허용하지만, 화면보다 클 수 없게 합니다.
    - 예시: Center 위젯이 자식에게 크기를 자유롭게 허용하지만 화면보다 클 수 없게 하는 경우.</p>
<pre><code>```dart
Center(
  child: Container(width: 100, height: 100, color: Colors.red),
)

```</code></pre><h3 id="unbounded-constraints">Unbounded Constraints</h3>
<ul>
<li><strong>Unbounded Constraints</strong>: 제약 조건이 무한대인 경우로, 위젯이 원하는 만큼 클 수 있습니다.</li>
</ul>
<p>여기서 내부 ListView는 무한대 너비를 가지게 되어 에러를 발생시킬 수 있습니다.
    - 예시: ListView 내부에 또 다른 ListView가 있을 때, 내부 ListView는 무한대 너비를 가집니다.</p>
<pre><code>```dart
ListView(
  scrollDirection: Axis.horizontal,
  children: &lt;Widget&gt;[
    ListView(
      scrollDirection: Axis.vertical,
      children: &lt;Widget&gt;[
        Container(height: 100, color: Colors.red),
        Container(height: 100, color: Colors.blue),
      ],
    ),
  ],
)

```</code></pre><h3 id="레이아웃-박스-종류">레이아웃 박스 종류</h3>
<ul>
<li><p><strong>크기가 최대한 큰 박스</strong>: Center와 ListView 같은 위젯들이 해당됩니다.</p>
<ul>
<li><p>예시: Center 위젯은 자식이 가질 수 있는 최대 크기를 허용합니다.</p>
<pre><code class="language-dart">Center(
child: Container(color: Colors.red),
)
</code></pre>
</li>
</ul>
</li>
<li><p><strong>자식과 같은 크기를 가지는 박스</strong>: Transform과 Opacity 같은 위젯들이 해당됩니다.</p>
<ul>
<li><p>예시: Opacity 위젯은 자식의 크기를 그대로 따릅니다.</p>
<pre><code class="language-dart">Opacity(
opacity: 0.5,
child: Container(width: 100, height: 100, color: Colors.red),
)
</code></pre>
</li>
</ul>
</li>
<li><p><strong>특정 크기를 가지는 박스</strong>: Image와 Text 같은 위젯들이 해당됩니다.</p>
<ul>
<li><p>예시: Image 위젯은 이미지의 원본 크기를 따릅니다.</p>
<pre><code class="language-dart">Image.network(&#39;&lt;https://example.com/image.png&gt;&#39;)
</code></pre>
</li>
</ul>
</li>
</ul>
<h3 id="flex-위젯">Flex 위젯</h3>
<p>Flex 박스(Row 및 Column)는 주 방향의 제약 조건에 따라 다르게 동작합니다. 주 방향이 제한된 경우 가능한 한 크게 되려고 하며, 무제한인 경우 자식들이 주 방향에 맞게 배치됩니다.</p>
<h3 id="추가-팁">추가 팁</h3>
<ul>
<li><strong>전체 화면 디자인 고려:</strong> 각 위젯이 어떻게 화면 내에서 배치되고 크기를 가지는지 고려해야 합니다.</li>
<li><strong>반응형 디자인:</strong> 다양한 기기와 화면 크기에 대응하기 위해 반응형 디자인을 고려하는 것이 중요합니다.</li>
</ul>
<h3 id="관련-자료">관련 자료</h3>
<ul>
<li><a href="https://medium.com/flutter-community/flutter-layout-cheat-sheet-5363348d037e"><strong>Flutter Layout Cheat Sheet</strong></a></li>
<li><a href="https://flutter.dev/docs/development/ui/widgets/layout"><strong>공식 문서 - Layout Widgets</strong></a></li>
<li><a href="https://docs.flutter.dev/ui/layout/constraints"><strong>공식 문서 - Layout Constraints</strong></a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[flutter_localizations & intl]]></title>
            <link>https://velog.io/@hayo_dev/flutterlocalizations-intl</link>
            <guid>https://velog.io/@hayo_dev/flutterlocalizations-intl</guid>
            <pubDate>Tue, 09 Jul 2024 14:44:02 GMT</pubDate>
            <description><![CDATA[<h2 id="flutter에서-다국어-지원하기-flutter_localizations--intl">Flutter에서 다국어 지원하기: <code>flutter_localizations</code> &amp; <code>intl</code></h2>
<p>Flutter 애플리케이션에서 다국어 지원을 구현하려면 <code>flutter_localizations</code>와 <code>intl</code> 패키지를 사용합니다. <code>flutter_localizations</code>는 Flutter 위젯의 현지화를 지원하는 반면, <code>intl</code> 패키지는 메시지 번역, 날짜 및 숫자 형식 지정 등의 기능을 제공합니다. 또한, <code>Flutter Intl</code> 플러그인을 사용하여 번역 파일 관리를 자동화할 수 있습니다.</p>
<h2 id="주요-특징">주요 특징</h2>
<h3 id="flutter_localizations">flutter_localizations</h3>
<ol>
<li><strong>위젯 현지화</strong>:<ul>
<li><code>flutter_localizations</code> 패키지는 Flutter의 Material 및 Cupertino 위젯의 텍스트를 현지화합니다. 이 패키지를 사용하면 Flutter 기본 위젯의 텍스트가 사용자의 로케일에 맞게 자동으로 번역됩니다.</li>
</ul>
</li>
<li><strong>다양한 로케일 지원</strong>:<ul>
<li>여러 로케일을 쉽게 추가하고 관리할 수 있습니다.</li>
</ul>
</li>
<li><strong>플랫폼 독립적</strong>:<ul>
<li>Android와 iOS 모두에서 동일한 방식으로 동작합니다.</li>
</ul>
</li>
</ol>
<h3 id="intl">intl</h3>
<ol>
<li><strong>메시지 번역</strong>:<ul>
<li><code>intl</code> 패키지는 메시지를 번역하고, 복수형 및 성별 처리 등의 기능을 제공합니다.</li>
</ul>
</li>
<li><strong>날짜 및 숫자 형식 지정</strong>:<ul>
<li>각 로케일에 맞는 날짜와 숫자 형식 지정 및 구문 분석을 지원합니다.</li>
</ul>
</li>
<li><strong>다양한 국제화 기능</strong>:<ul>
<li>다국어 지원을 위한 다양한 기능을 제공합니다.</li>
</ul>
</li>
</ol>
<h2 id="설치">설치</h2>
<p><code>pubspec.yaml</code> 파일에 <code>flutter_localizations</code>와 <code>intl</code> 패키지를 종속성으로 추가합니다.</p>
<pre><code class="language-yaml">dependencies:
  flutter:
    sdk: flutter
  flutter_localizations:
    sdk: flutter
  intl: ^0.17.0
</code></pre>
<h2 id="사용-방법">사용 방법</h2>
<h3 id="flutter-프로젝트-설정">Flutter 프로젝트 설정</h3>
<ol>
<li><p><strong>패키지 추가</strong>:</p>
<ul>
<li><code>flutter_localizations</code>와 <code>intl</code> 패키지를 <code>pubspec.yaml</code> 파일에 추가합니다.</li>
</ul>
</li>
<li><p><strong>로케일 설정</strong>:</p>
<ul>
<li><p><code>main.dart</code> 파일에서 <code>localizationsDelegates</code>와 <code>supportedLocales</code>를 설정합니다.</p>
<pre><code class="language-dart">import &#39;package:flutter/material.dart&#39;;
import &#39;package:flutter_localizations/flutter_localizations.dart&#39;;
import &#39;package:house_of_tomorrow/util/lang/generated/l10n.dart&#39;;

void main() {
runApp(MyApp());
}

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
  return MaterialApp(
    localizationsDelegates: [
      S.delegate,
      GlobalMaterialLocalizations.delegate,
      GlobalWidgetsLocalizations.delegate,
      GlobalCupertinoLocalizations.delegate,
    ],
    supportedLocales: S.delegate.supportedLocales,
    home: HomePage(),
  );
}
}
</code></pre>
</li>
</ul>
</li>
</ol>
<h3 id="번역-파일-작성">번역 파일 작성</h3>
<ol>
<li><p><strong>Android Studio Flutter Intl 플러그인 사용</strong>:</p>
<ul>
<li>Android Studio에서 <code>Flutter Intl</code> 플러그인을 설치하고, <code>Tools</code> 메뉴에서 <code>Flutter Intl</code> 옵션을 사용하여 초기 설정을 진행합니다.</li>
</ul>
</li>
<li><p><strong>번역 파일 작성</strong>:</p>
<ul>
<li><p><code>intl_en.arb</code>:</p>
<pre><code class="language-json">  {
    &quot;@@locale&quot;: &quot;en&quot;,
    &quot;title&quot;: &quot;Hello World&quot;,
    &quot;message&quot;: &quot;This is a localized message.&quot;
  }
</code></pre>
</li>
<li><p><code>intl_ko.arb</code>:</p>
<pre><code class="language-json">  {
    &quot;@@locale&quot;: &quot;ko&quot;,
    &quot;title&quot;: &quot;안녕하세요&quot;,
    &quot;message&quot;: &quot;이것은 현지화된 메시지입니다.&quot;
  }
</code></pre>
</li>
</ul>
</li>
</ol>
<h3 id="번역된-텍스트-사용">번역된 텍스트 사용</h3>
<p>번역된 텍스트를 가져와 UI에서 사용합니다.</p>
<pre><code class="language-dart">import &#39;package:house_of_tomorrow/util/lang/generated/l10n.dart&#39;;

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: Text(S.of(context).title),
    ),
    body: Center(
      child: Text(S.of(context).message),
    ),
  );
}
</code></pre>
<h2 id="주요-활용도">주요 활용도</h2>
<ul>
<li><strong>UI 텍스트 번역</strong>: 애플리케이션의 모든 UI 텍스트를 다양한 언어로 번역하여 다국어 지원을 구현합니다.</li>
<li><strong>날짜 및 숫자 형식 지정</strong>: 사용자의 로케일에 맞는 날짜 및 숫자 형식으로 데이터를 표시합니다.</li>
<li><strong>메시지 현지화</strong>: 사용자에게 표시되는 메시지를 현지화하여 사용자가 이해하기 쉽게 만듭니다.</li>
</ul>
<h2 id="관련-자료">관련 자료</h2>
<ul>
<li><a href="https://api.flutter.dev/flutter/flutter_localizations/flutter_localizations-library.html"><strong>flutter_localizations library - Dart API</strong></a></li>
<li><a href="https://pub.dev/packages/intl"><strong>intl | Dart Package</strong></a></li>
<li><a href="https://marketplace.visualstudio.com/items?itemName=localizely.flutter-intl"><strong>Flutter Intl - Visual Studio Marketplace</strong></a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Design system]]></title>
            <link>https://velog.io/@hayo_dev/Design-system</link>
            <guid>https://velog.io/@hayo_dev/Design-system</guid>
            <pubDate>Tue, 09 Jul 2024 08:34:24 GMT</pubDate>
            <description><![CDATA[<h2 id="flutter에서-ui-일관성-유지하기-design-system">Flutter에서 UI 일관성 유지하기: Design system</h2>
<p>디자인 시스템은 일관된 사용자 경험을 제공하고, UI 요소들의 반복 작업을 줄이며, 유지보수성을 높이는 데 사용되는 방법론입니다. 이를 통해 시각적 일관성을 유지하고, 다양한 디바이스와 해상도에서 일관된 인터페이스를 제공할 수 있습니다.</p>
<h3 id="ui--ux">UI &amp; UX</h3>
<ul>
<li><strong>UI(User Interface)</strong>: 사용자가 시스템과 상호작용하는 인터페이스를 의미합니다. UI는 버튼, 아이콘, 텍스트 필드 등 사용자가 직접적으로 조작할 수 있는 모든 시각적 요소를 포함합니다. UI 디자인은 사용자의 직관적인 사용을 목표로 하며, 심미성과 기능성을 고려합니다.</li>
<li><strong>UX(User Experience)</strong>: 사용자가 UI와 상호작용하면서 느끼는 전체적인 경험을 의미합니다. UX는 사용자가 제품을 사용할 때 느끼는 만족도, 편의성, 접근성 등을 포함합니다. UX 디자인은 사용자의 문제 해결을 목표로 하며, 사용자가 제품을 통해 얼마나 효율적이고 만족스러운 경험을 하는지에 중점을 둡니다.</li>
</ul>
<h2 id="주요-개념">주요 개념</h2>
<ul>
<li><strong>Foundation</strong>: 텍스트, 아이콘, 색상, 여백, 이미지 등 UI의 기본 구성 요소를 정의합니다.</li>
<li><strong>Component</strong>: 버튼, 입력 폼, 카드 등 여러 기초 요소들이 모여 하나의 구성 요소를 이룹니다.</li>
<li><strong>Page</strong>: 구성 요소들이 모여 하나의 페이지를 구성합니다.</li>
<li><strong>Design System</strong>: 반복되는 기초 요소와 구성 요소를 시각적으로 일관되게 만들어 반복 작업을 줄이는 디자인 관리 방법입니다.</li>
</ul>
<h2 id="주요-요소">주요 요소</h2>
<h3 id="foundation">Foundation</h3>
<p>Foundation은 텍스트, 아이콘, 색상, 여백 등 UI의 기본 구성 요소를 포함합니다.</p>
<h3 id="텍스트-text">텍스트 (Text)</h3>
<ul>
<li><strong>타이포그래피(Typography)</strong>: 텍스트의 크기, 굵기, 폰트 종류 등을 정의합니다.</li>
</ul>
<h3 id="아이콘-icon">아이콘 (Icon)</h3>
<ul>
<li><strong>아이콘 사이즈 통일</strong>: 아이콘의 크기를 일관되게 유지하여 UI 요소 배치의 일관성을 유지합니다.</li>
</ul>
<h3 id="색상-color">색상 (Color)</h3>
<ul>
<li><strong>색상 팔레트(Color Palette)</strong>: 앱에서 사용하는 전체 색상 목록을 정의합니다.</li>
<li><strong>시맨틱 컬러(Semantic Color)</strong>: 색상의 역할에 따라 이름을 부여하여 용도를 명확히 합니다.</li>
</ul>
<h3 id="component">Component</h3>
<p>Component는 여러 기초 요소들이 모여 하나의 구성 요소를 이루는 것입니다.</p>
<h3 id="버튼-button">버튼 (Button)</h3>
<ul>
<li><strong>기본 버튼</strong>: Primary, Secondary 버튼 등 다양한 상태와 크기의 버튼을 정의합니다.</li>
</ul>
<h3 id="카드-card">카드 (Card)</h3>
<ul>
<li><strong>정보 카드</strong>: 텍스트와 이미지를 포함한 카드 구성 요소를 정의합니다.</li>
</ul>
<h3 id="page">Page</h3>
<p>Page는 구성 요소들이 모여 하나의 화면 단위를 이루는 것입니다.</p>
<h3 id="쇼핑-페이지-shopping-page">쇼핑 페이지 (Shopping Page)</h3>
<ul>
<li><strong>상품 리스트</strong>: 여러 상품 카드를 포함한 리스트를 구성합니다.</li>
<li><strong>필터</strong>: 다양한 필터 옵션을 포함한 섹션을 정의합니다.</li>
</ul>
<h3 id="상품-상세-페이지-product-page">상품 상세 페이지 (Product Page)</h3>
<ul>
<li><strong>상품 정보</strong>: 상품 이미지, 설명, 가격 등을 포함한 상세 정보 페이지를 정의합니다.</li>
</ul>
<h2 id="코드-예제">코드 예제</h2>
<h3 id="색상-정의">색상 정의</h3>
<pre><code class="language-dart">class AppColors {
  static const Color primary = Color(0xFF6200EE);
  static const Color secondary = Color(0xFF03DAC6);
  static const Color background = Color(0xFFF6F6F6);
  static const Color surface = Color(0xFFFFFFFF);
}
</code></pre>
<h3 id="버튼-구성-요소">버튼 구성 요소</h3>
<pre><code class="language-dart">class PrimaryButton extends StatelessWidget {
  final String text;
  final VoidCallback onPressed;

  PrimaryButton({required this.text, required this.onPressed});

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: onPressed,
      child: Text(text),
      style: ElevatedButton.styleFrom(
        primary: AppColors.primary,
        onPrimary: Colors.white,
        padding: EdgeInsets.symmetric(horizontal: 16, vertical: 12),
        textStyle: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
      ),
    );
  }
}
</code></pre>
<h3 id="페이지-구성">페이지 구성</h3>
<pre><code class="language-dart">class ShoppingPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(&#39;Shopping&#39;)),
      body: ListView(
        children: [
          ProductCard(product: Product(name: &#39;Product 1&#39;, price: 29.99)),
          ProductCard(product: Product(name: &#39;Product 2&#39;, price: 59.99)),
          ProductCard(product: Product(name: &#39;Product 3&#39;, price: 19.99)),
        ],
      ),
    );
  }
}
</code></pre>
<h2 id="디자인-시스템의-특징과-단점">디자인 시스템의 특징과 단점</h2>
<p>디자인 시스템은 다음과 같은 특징과 단점을 가지고 있습니다.</p>
<h3 id="특징">특징</h3>
<ol>
<li><strong>일관성 유지</strong>: 다양한 디바이스와 해상도에서 일관된 사용자 경험을 제공합니다.</li>
<li><strong>생산성 향상</strong>: 반복 작업을 줄여 개발 생산성을 높입니다.</li>
<li><strong>유지보수성 향상</strong>: 기초 요소와 구성 요소의 재사용을 통해 유지보수성을 높입니다.</li>
<li><strong>효율적인 협업</strong>: 디자이너와 개발자 간의 효율적인 협업을 가능하게 합니다.</li>
</ol>
<h3 id="단점">단점</h3>
<ol>
<li><strong>초기 구축의 어려움</strong>: 초기 구축 시 많은 시간과 노력이 필요합니다.</li>
<li><strong>지속적인 업데이트 필요</strong>: 디자인 트렌드와 사용자 요구에 맞춰 지속적인 업데이트가 필요합니다.</li>
</ol>
<h2 id="관련-자료">관련 자료</h2>
<ul>
<li><a href="https://material.io/design"><strong>Material Design</strong></a>: Google의 디자인 시스템 가이드라인</li>
<li><a href="https://developer.apple.com/design/human-interface-guidelines/"><strong>Apple Human Interface Guidelines</strong></a>: Apple의 디자인 시스템 가이드라인</li>
<li><a href="https://www.microsoft.com/design/fluent/"><strong>Fluent Design</strong></a>: Microsoft의 디자인 시스템 가이드라인</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Bloc]]></title>
            <link>https://velog.io/@hayo_dev/Bloc</link>
            <guid>https://velog.io/@hayo_dev/Bloc</guid>
            <pubDate>Tue, 09 Jul 2024 03:05:26 GMT</pubDate>
            <description><![CDATA[<h2 id="flutter에서-이벤트-기반-상태-관리-및-비즈니스-로직-분리하기-bloc">Flutter에서 이벤트 기반 상태 관리 및 비즈니스 로직 분리하기: Bloc</h2>
<p><code>Bloc</code>(Business Logic Component)은 Flutter 애플리케이션에서 상태 관리를 단순화하고, 비즈니스 로직을 UI와 분리하여 유지보수성을 높이는 데 사용되는 디자인 패턴이자 라이브러리입니다. 이를 통해 상태의 예측 가능성과 테스트 가능성을 높일 수 있습니다.</p>
<h2 id="주요-개념">주요 개념</h2>
<ul>
<li><strong>Bloc</strong>: 이벤트를 받아서 상태로 변환하는 역할을 합니다. Bloc 클래스는 이벤트를 처리하고 새로운 상태를 방출합니다.</li>
<li><strong>Event</strong>: Bloc에서 처리해야 할 동작이나 변화입니다. 이벤트는 사용자 입력, 네트워크 요청 등으로 발생합니다.</li>
<li><strong>State</strong>: Bloc이 처리한 이벤트에 따라 변화하는 상태입니다. UI는 이 상태를 기반으로 업데이트됩니다.</li>
<li><strong>BlocProvider</strong>: Bloc 인스턴스를 위젯 트리 내에서 제공하는 역할을 합니다.</li>
<li><strong>BlocBuilder</strong>: Bloc의 상태 변화를 구독하고, 새로운 상태에 따라 UI를 빌드하는 위젯입니다.</li>
</ul>
<h2 id="코드-예제">코드 예제</h2>
<h3 id="counterbloc-구현">CounterBloc 구현</h3>
<h3 id="counter_eventdart">counter_event.dart</h3>
<pre><code class="language-dart">abstract class CounterEvent {}

class Increment extends CounterEvent {}

class Decrement extends CounterEvent {}
</code></pre>
<h3 id="counter_statedart">counter_state.dart</h3>
<pre><code class="language-dart">class CounterState {
  final int counterValue;
  CounterState(this.counterValue);
}
</code></pre>
<h3 id="counter_blocdart">counter_bloc.dart</h3>
<pre><code class="language-dart">import &#39;package:bloc/bloc.dart&#39;;
import &#39;counter_event.dart&#39;;
import &#39;counter_state.dart&#39;;

class CounterBloc extends Bloc&lt;CounterEvent, CounterState&gt; {
  CounterBloc() : super(CounterState(0));

  @override
  Stream&lt;CounterState&gt; mapEventToState(CounterEvent event) async* {
    if (event is Increment) {
      yield CounterState(state.counterValue + 1);
    } else if (event is Decrement) {
      yield CounterState(state.counterValue - 1);
    }
  }
}
</code></pre>
<h3 id="maindart">main.dart</h3>
<pre><code class="language-dart">import &#39;package:flutter/material.dart&#39;;
import &#39;package:flutter_bloc/flutter_bloc.dart&#39;;
import &#39;counter_bloc.dart&#39;;
import &#39;counter_event.dart&#39;;
import &#39;counter_state.dart&#39;;

void main() =&gt; runApp(CounterApp());

class CounterApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: BlocProvider(
        create: (_) =&gt; CounterBloc(),
        child: CounterPage(),
      ),
    );
  }
}

class CounterPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text(&#39;Counter&#39;)),
      body: BlocBuilder&lt;CounterBloc, CounterState&gt;(
        builder: (context, state) {
          return Center(
            child: Text(
              &#39;${state.counterValue}&#39;,
              style: TextStyle(fontSize: 24),
            ),
          );
        },
      ),
      floatingActionButton: Column(
        crossAxisAlignment: CrossAxisAlignment.end,
        mainAxisAlignment: MainAxisAlignment.end,
        children: &lt;Widget&gt;[
          FloatingActionButton(
            child: const Icon(Icons.add),
            onPressed: () =&gt; context.read&lt;CounterBloc&gt;().add(Increment()),
          ),
          const SizedBox(height: 4),
          FloatingActionButton(
            child: const Icon(Icons.remove),
            onPressed: () =&gt; context.read&lt;CounterBloc&gt;().add(Decrement()),
          ),
        ],
      ),
    );
  }
}
</code></pre>
<h2 id="bloc의-특징과-단점">Bloc의 특징과 단점</h2>
<p>Bloc 패턴은 다음과 같은 특징과 단점을 가지고 있습니다:</p>
<h3 id="특징">특징</h3>
<ol>
<li><strong>명확한 구조</strong>: 이벤트와 상태의 흐름이 명확하여 코드의 가독성과 유지보수성이 높습니다.</li>
<li><strong>단일 출처의 진실 (Single Source of Truth)</strong>: 상태가 Bloc 내에서만 관리되므로 상태의 일관성을 유지하기 쉽습니다.</li>
<li><strong>높은 테스트 가능성</strong>: 이벤트와 상태의 변환 과정을 단위 테스트로 검증할 수 있습니다.</li>
<li><strong>비즈니스 로직 분리 (Separation of Concerns)</strong>: 비즈니스 로직을 UI와 분리하여 코드 유지보수와 재사용성을 높입니다.</li>
<li><strong>불변성 (Immutability)</strong>: 상태를 변경할 수 없도록 만들고, 변경 시 새로운 상태 객체를 생성하여 상태 추적과 디버깅이 용이합니다.</li>
</ol>
<h3 id="단점">단점</h3>
<ol>
<li><strong>초기 설정의 복잡성</strong>: 다른 상태 관리 방법에 비해 초기 설정이 다소 복잡할 수 있습니다.</li>
<li><strong>보일러플레이트 코드</strong>: 이벤트, 상태, Bloc 클래스를 정의하는 데 많은 코드를 작성해야 할 수 있습니다.</li>
</ol>
<h2 id="관련-자료">관련 자료</h2>
<ul>
<li><a href="https://bloclibrary.dev/"><strong>Bloc 공식 문서</strong></a>: Bloc의 자세한 사용 방법과 예제를 제공합니다.</li>
<li><a href="https://flutter.dev/docs/development/data-and-backend/state-mgmt"><strong>Flutter 상태 관리 문서</strong></a>: 다양한 상태 관리 도구와 패턴을 설명합니다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Cubit]]></title>
            <link>https://velog.io/@hayo_dev/Cubit</link>
            <guid>https://velog.io/@hayo_dev/Cubit</guid>
            <pubDate>Mon, 08 Jul 2024 08:17:41 GMT</pubDate>
            <description><![CDATA[<h2 id="flutter에서-bloc의-간소화-cubit">Flutter에서 BLoC의 간소화: Cubit</h2>
<p>Cubit은 BLoC 패턴을 간소화한 버전입니다. BLoC에서는 상태(State)와 이벤트(Event)를 각각 정의하고 관리해야 하지만, Cubit은 상태(State) 클래스만 구현하고, 메서드를 통해 이벤트를 처리합니다. 이를 통해 코드의 복잡성을 줄이고 더 간단하게 상태 관리를 할 수 있습니다.</p>
<h3 id="bloc-패턴">BLoC 패턴</h3>
<p>BLoC(Business Logic Component) 패턴은 애플리케이션을 다음과 같은 구성 요소로 나누어 관리합니다:</p>
<ul>
<li><code>View</code>: 사용자 인터페이스(UI)와 관련된 부분.</li>
<li><code>State</code>: 현재 상태를 나타내는 객체.</li>
<li><code>Event</code>: 상태를 변경하는 이벤트.</li>
<li><code>Data</code>: 애플리케이션의 데이터.</li>
</ul>
<p>BLoC 패턴은 <code>Stream</code>을 이용하여 상태와 이벤트를 송수신하며, 이를 통해 <code>View</code>와 비즈니스 로직을 분리하여 구조적으로 관리합니다.</p>
<h2 id="주요-개념">주요 개념</h2>
<ul>
<li><strong><code>Cubit 클래스</code>:</strong> 상태를 관리하는 기본 클래스입니다. <code>Cubit&lt;상태 타입&gt;</code>을 상속받아 커스텀 Cubit을 생성하고, 상태 변경 로직을 정의합니다.</li>
<li><strong><code>상태(States)</code>:</strong> Cubit의 상태는 단순한 Dart 객체입니다. 상태가 변경될 때마다 새로운 객체로 대체되어 UI가 업데이트됩니다.</li>
<li><strong><code>상태 전환(Emit)</code>:</strong> <code>emit</code> 메서드를 통해 새로운 상태로 전환합니다. 상태가 전환되면 이를 구독하고 있는 UI 컴포넌트들이 자동으로 업데이트됩니다.</li>
</ul>
<h2 id="주요-속성-및-메서드">주요 속성 및 메서드</h2>
<ul>
<li><strong><code>state</code>:</strong> 현재 상태를 나타냅니다.</li>
<li><strong><code>emit(newState)</code>:</strong> 새로운 상태로 전환합니다.</li>
<li><strong><code>Cubit</code> 생성자:</strong> 초기 상태를 설정합니다.</li>
</ul>
<h2 id="주요-활용도">주요 활용도</h2>
<ul>
<li><strong>상태 전환 간소화:</strong> 이벤트 클래스를 생성할 필요 없이 메서드를 통해 직접 상태 전환을 관리할 수 있습니다.</li>
<li><strong>UI 업데이트 자동화:</strong> 상태가 전환될 때 UI가 자동으로 업데이트됩니다.</li>
<li><strong>다양한 상태 관리:</strong> 단일 Cubit 클래스에서 여러 상태를 관리할 수 있습니다.</li>
</ul>
<h2 id="코드-예제">코드 예제</h2>
<p>아래 예제는 Cubit을 사용하여 카운터를 증가시키고 감소시키는 방법을 보여줍니다.</p>
<pre><code class="language-dart">import &#39;package:bloc/bloc.dart&#39;;
import &#39;package:flutter/material.dart&#39;;
import &#39;package:flutter_bloc/flutter_bloc.dart&#39;;

// Cubit 클래스 정의
class CounterCubit extends Cubit&lt;int&gt; {
  CounterCubit() : super(0); // 초기 상태는 0

  void increment() =&gt; emit(state + 1); // 상태 증가
  void decrement() =&gt; emit(state - 1); // 상태 감소
}

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: BlocProvider(
        create: (_) =&gt; CounterCubit(),
        child: CounterPage(),
      ),
    );
  }
}

class CounterPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final counterCubit = context.read&lt;CounterCubit&gt;();

    return Scaffold(
      appBar: AppBar(title: Text(&#39;Cubit Counter Example&#39;)),
      body: Center(
        child: BlocBuilder&lt;CounterCubit, int&gt;(
          builder: (context, count) {
            return Text(&#39;$count&#39;, style: TextStyle(fontSize: 24));
          },
        ),
      ),
      floatingActionButton: Column(
        mainAxisAlignment: MainAxisAlignment.end,
        children: &lt;Widget&gt;[
          FloatingActionButton(
            child: Icon(Icons.add),
            onPressed: () =&gt; counterCubit.increment(),
          ),
          SizedBox(height: 8),
          FloatingActionButton(
            child: Icon(Icons.remove),
            onPressed: () =&gt; counterCubit.decrement(),
          ),
        ],
      ),
    );
  }
}
</code></pre>
<h2 id="cubit의-접근-방법">Cubit의 접근 방법</h2>
<ul>
<li><strong><code>context.watch()</code></strong>: 상태가 변경될 때마다 위젯을 갱신합니다.</li>
<li><strong><code>context.read()</code></strong>: 상태가 변경되어도 위젯을 갱신하지 않습니다.</li>
<li><strong><code>BlocBuilder</code></strong>: 특정 위젯만 갱신합니다. <code>buildWhen</code>을 사용하여 갱신 여부를 결정할 수 있습니다.</li>
</ul>
<h2 id="cubit-제공자-종류">Cubit 제공자 종류</h2>
<ul>
<li><strong><code>BlocProvider</code></strong>: 상태 변경 알림 기능이 있는 Cubit을 위젯 트리에 등록할 때 사용합니다.</li>
<li><strong><code>RepositoryProvider</code></strong>: 상태 변경 알림 기능이 없는 클래스를 위젯 트리에 등록할 때 사용합니다.</li>
</ul>
<h2 id="cubit-상호-작용-및-주의사항">Cubit 상호 작용 및 주의사항</h2>
<p>Cubit 간의 상태 변경을 동기화하려면 <code>StreamSubscription</code>을 사용하여 다른 Cubit의 상태 변화를 수신하고, 이를 바탕으로 상태를 업데이트합니다. 이를 통해 여러 Cubit 간의 상호 작용을 구현할 수 있습니다.</p>
<h3 id="주의사항">주의사항</h3>
<p><code>StreamSubscription</code>을 사용한 경우, 반드시 구독을 해제해야 메모리 누수를 방지할 수 있습니다. 이를 위해 <code>close</code> 메서드를 호출하여 <code>Cubit</code>이 더 이상 필요 없을 때 구독을 해제해야 합니다.</p>
<pre><code class="language-dart">class ExampleCubit extends Cubit&lt;ExampleState&gt; {
  final AnotherCubit anotherCubit;
  late StreamSubscription anotherCubitSubscription;

  ExampleCubit(this.anotherCubit) : super(InitialExampleState()) {
    anotherCubitSubscription = anotherCubit.stream.listen((state) {
      // Handle state changes
    });
  }

  @override
  Future&lt;void&gt; close() {
    anotherCubitSubscription.cancel();
    return super.close();
  }
}
</code></pre>
<h2 id="상태-클래스-관리">상태 클래스 관리</h2>
<p>하나의 Cubit 클래스에서 여러 상태를 관리하려면 상태 클래스를 불변 객체로 생성합니다. <code>copyWith</code> 메서드를 사용하여 불변 객체의 특정 속성만 변경하고, 새로운 객체를 생성하여 상태를 전환합니다.</p>
<h2 id="추가-팁">추가 팁</h2>
<ul>
<li><strong>복잡한 상태 관리:</strong> 단순한 상태 관리에는 Cubit이 적합하지만, 보다 복잡한 상태 관리가 필요한 경우에는 BLoC 패턴을 사용하는 것이 더 적합할 수 있습니다.</li>
<li><strong>반응형 디자인:</strong> 다양한 기기와 화면 크기에 대응하기 위해 반응형 디자인을 고려하는 것이 중요합니다.</li>
</ul>
<h2 id="관련-자료">관련 자료</h2>
<ul>
<li><a href="https://bloclibrary.dev/#/"><strong>Bloc Documentation</strong></a>: Cubit과 BLoC 패턴에 대한 공식 문서.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Sealed Class]]></title>
            <link>https://velog.io/@hayo_dev/Sealed-Class-vbxtlfrj</link>
            <guid>https://velog.io/@hayo_dev/Sealed-Class-vbxtlfrj</guid>
            <pubDate>Mon, 08 Jul 2024 07:54:02 GMT</pubDate>
            <description><![CDATA[<h2 id="dart에서-안전하게-데이터-클래스를-관리하기-sealed-class">Dart에서 안전하게 데이터 클래스를 관리하기: Sealed Class</h2>
<p>Dart에서는 <code>SealedClass</code>를 사용하여 여러 타입의 서브클래스를 가질 수 있는 안전한 데이터 클래스를 정의할 수 있습니다. 이는 특히 불변 데이터 모델링과 명시적 타입 검사를 위한 강력한 도구입니다. <code>SealedClass</code>는 Dart의 Null Safety와 결합하여 타입 안정성과 코드의 가독성을 높입니다.</p>
<h2 id="주요-속성">주요 속성</h2>
<ul>
<li><strong><code>base</code>:</strong> 추상 기본 클래스로, 모든 서브클래스가 상속받아야 합니다. 이를 통해 특정 타입 집합의 상속을 강제합니다.</li>
<li><strong><code>subclasses</code>:</strong> <code>SealedClass</code>의 서브클래스를 정의하여 다양한 상태를 나타냅니다. 각 서브클래스는 특정 상태를 명시적으로 표현합니다.</li>
</ul>
<h2 id="주요-특징">주요 특징</h2>
<ol>
<li><strong>제한된 하위 클래스:</strong> Sealed Class는 특정 파일 내에서만 하위 클래스를 가질 수 있습니다. 이를 통해 타입 계층의 예측 가능성을 높이고, 코드의 안전성을 강화할 수 있습니다.</li>
<li><strong>패턴 매칭:</strong> Sealed Class를 사용하면 각 하위 클래스에 대해 명확하게 매칭할 수 있습니다. 이를 통해 코드의 가독성과 유지보수성을 향상시킬 수 있습니다.</li>
</ol>
<h2 id="주요-활용도">주요 활용도</h2>
<ul>
<li><strong>데이터 모델링:</strong> 여러 타입의 상태를 안전하게 표현할 수 있으며, 예측 가능한 상태 전이를 모델링합니다.</li>
<li><strong>코드 가독성 향상:</strong> 명시적인 상태 정의를 통해 코드 가독성과 유지 보수성을 높입니다.</li>
<li><strong>타입 안전성 확보:</strong> 컴파일 시 타입 검사를 통해 런타임 오류를 줄입니다.</li>
</ul>
<h2 id="코드-예제">코드 예제</h2>
<p>아래 예제는 <code>SealedClass</code>를 사용하여 네트워크 요청 상태를 안전하게 관리하는 방법을 보여줍니다.</p>
<pre><code class="language-dart">sealed class NetworkState {}

class Loading extends NetworkState {}

class Success extends NetworkState {
  final String data;
  Success(this.data);
}

class Error extends NetworkState {
  final String message;
  Error(this.message);
}

void handleState(NetworkState state) {
  if (state is Loading) {
    print(&#39;Loading...&#39;);
  } else if (state is Success) {
    print(&#39;Data: ${state.data}&#39;);
  } else if (state is Error) {
    print(&#39;Error: ${state.message}&#39;);
  }
}

void main() {
  var currentState = Loading();
  handleState(currentState);

  currentState = Success(&#39;Data loaded&#39;);
  handleState(currentState);

  currentState = Error(&#39;Failed to load data&#39;);
  handleState(currentState);
}
</code></pre>
<h3 id="예제">예제</h3>
<p>아래는 Dart에서 Sealed Class를 사용하는 예제입니다.</p>
<pre><code class="language-dart">// base.dart 파일

sealed class Shape {
  const Shape();
}

class Circle extends Shape {
  final double radius;
  const Circle(this.radius);
}

class Rectangle extends Shape {
  final double width;
  final double height;
  const Rectangle(this.width, this.height);
}

// main.dart 파일

import &#39;base.dart&#39;;

void printShapeArea(Shape shape) {
  switch (shape) {
    case Circle c:
      print(&#39;Circle area: ${3.14 * c.radius * c.radius}&#39;);
      break;
    case Rectangle r:
      print(&#39;Rectangle area: ${r.width * r.height}&#39;);
      break;
  }
}

void main() {
  Shape shape1 = Circle(10);
  Shape shape2 = Rectangle(5, 10);

  printShapeArea(shape1); // Circle area: 314.0
  printShapeArea(shape2); // Rectangle area: 50.0
}
</code></pre>
<h3 id="장점">장점</h3>
<ol>
<li><strong>안전한 타입 계층 관리:</strong> Sealed Class는 타입 계층을 명확하게 제한하므로, 코드의 의도하지 않은 확장을 방지할 수 있습니다.</li>
<li><strong>패턴 매칭의 용이성:</strong> Sealed Class를 사용하면 switch 문이나 if-else 문을 통해 각 하위 클래스를 쉽게 매칭할 수 있습니다.</li>
<li><strong>가독성과 유지보수성 향상:</strong> 코드의 구조가 명확해지므로 가독성과 유지보수성이 향상됩니다.</li>
</ol>
<h3 id="제한사항">제한사항</h3>
<ol>
<li><strong>확장이 제한적:</strong> Sealed Class는 특정 파일 내에서만 하위 클래스를 가질 수 있으므로, 확장이 제한됩니다.</li>
<li><strong>추상 클래스와의 차이:</strong> 추상 클래스와 다르게, Sealed Class는 하위 클래스를 제한적으로 정의하므로 더 엄격한 타입 계층 관리가 필요합니다.</li>
</ol>
<h2 id="추가-팁">추가 팁</h2>
<ul>
<li><strong>불변성 유지:</strong> <code>SealedClass</code>를 사용할 때 상태 객체를 불변으로 설계하여 상태 관리의 예측 가능성을 높입니다.</li>
<li><strong>명시적 상태 전이:</strong> 상태 전이를 명시적으로 정의하여 상태 관리의 복잡성을 줄입니다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Enum]]></title>
            <link>https://velog.io/@hayo_dev/Enum</link>
            <guid>https://velog.io/@hayo_dev/Enum</guid>
            <pubDate>Mon, 08 Jul 2024 07:02:04 GMT</pubDate>
            <description><![CDATA[<h2 id="dart에서-고정된-상수-값을-효과적으로-관리하는-방법-enum">Dart에서 고정된 상수 값을 효과적으로 관리하는 방법: Enum</h2>
<p>Dart에서 <code>enum</code>(열거형)은 고정된 상수 값의 집합을 나타내기 위해 사용되는 특수한 클래스입니다. <code>enum</code>을 사용하면 코드의 가독성과 유지보수성을 높일 수 있습니다. 모든 <code>enum</code>은 자동으로 <code>Enum</code> 클래스를 상속하며, 하위 클래스화, 구현, 믹스인, 또는 명시적으로 인스턴스화할 수 없습니다.</p>
<h3 id="enum의-도입-배경">Enum의 도입 배경</h3>
<p>프로그래밍에서 상수는 코드의 가독성과 유지보수성을 높이는 중요한 요소입니다. 그러나 기존의 상수 정의 방식에는 가독성 문제, 유효성 검사 문제, 타입 안전성 부족 등의 문제가 있었습니다. 이러한 문제를 해결하기 위해 <code>enum</code>이 도입되었습니다. <code>enum</code>은 상수 값을 그룹화하여 열거형으로 정의하고, 이 값을 타입 안전하게 사용할 수 있도록 합니다.</p>
<h3 id="기본적인-사용법">기본적인 사용법</h3>
<p>다음은 <code>enum</code>을 정의하고 사용하는 기본적인 예제입니다:</p>
<pre><code class="language-dart">enum Color {
  red,
  green,
  blue
}

void main() {
  Color favoriteColor = Color.blue;

  switch (favoriteColor) {
    case Color.red:
      print(&#39;Red!&#39;);
      break;
    case Color.green:
      print(&#39;Green!&#39;);
      break;
    case Color.blue:
      print(&#39;Blue!&#39;);
      break;
  }
}
</code></pre>
<p>위 예제에서 <code>Color</code>라는 <code>enum</code>을 정의하였고, <code>red</code>, <code>green</code>, <code>blue</code> 세 가지 값을 가집니다. <code>main</code> 함수에서는 <code>favoriteColor</code> 변수를 <code>Color.blue</code>로 설정하고, <code>switch</code> 문을 사용하여 해당 값에 따라 다른 출력을 합니다.</p>
<h3 id="주요-특징">주요 특징</h3>
<ol>
<li><p><strong>기본 값</strong>: <code>enum</code>은 0부터 시작하는 인덱스를 기본 값으로 가집니다.</p>
<pre><code class="language-dart"> void main() {
   print(Color.red.index); // 출력: 0
   print(Color.green.index); // 출력: 1
   print(Color.blue.index); // 출력: 2
 }
</code></pre>
</li>
<li><p><strong>values 속성</strong>: <code>enum</code>의 모든 값을 리스트로 가져올 수 있습니다.</p>
<pre><code class="language-dart"> void main() {
   List&lt;Color&gt; colors = Color.values;
   print(colors); // 출력: [Color.red, Color.green, Color.blue]
 }
</code></pre>
</li>
<li><p><strong>메소드 및 필드 추가</strong>: Dart 2.15 버전 이후, <code>enum</code>에 메소드와 필드를 추가할 수 있습니다.</p>
<pre><code class="language-dart"> enum Color {
   red(0xFF0000),
   green(0x00FF00),
   blue(0x0000FF);

   final int value;

   const Color(this.value);

   void printValue() {
     print(&#39;Value: $value&#39;);
   }
 }

 void main() {
   Color.red.printValue(); // 출력: Value: 16711680
   Color.green.printValue(); // 출력: Value: 65280
   Color.blue.printValue(); // 출력: Value: 255
 }
</code></pre>
</li>
</ol>
<h3 id="향상된-enum">향상된 Enum</h3>
<p>Dart에서는 필드, 메서드 및 상수 생성자가 있는 클래스를 포함할 수 있는 향상된 <code>enum</code>을 선언할 수 있습니다. 이를 통해 고정된 상수 인스턴스로 제한된 클래스를 선언할 수 있습니다.</p>
<p>다음은 필드, 게터 및 인터페이스를 구현한 향상된 <code>enum</code>의 예제입니다:</p>
<pre><code class="language-dart">enum Vehicle implements Comparable&lt;Vehicle&gt; {
  car(tires: 4, passengers: 5, carbonPerKilometer: 400),
  bus(tires: 6, passengers: 50, carbonPerKilometer: 800),
  bicycle(tires: 2, passengers: 1, carbonPerKilometer: 0);

  const Vehicle({
    required this.tires,
    required this.passengers,
    required this.carbonPerKilometer,
  });

  final int tires;
  final int passengers;
  final int carbonPerKilometer;

  int get carbonFootprint =&gt; (carbonPerKilometer / passengers).round();

  bool get isTwoWheeled =&gt; this == Vehicle.bicycle;

  @override
  int compareTo(Vehicle other) =&gt; carbonFootprint - other.carbonFootprint;
}
</code></pre>
<h3 id="향상된-enum의-특징">향상된 Enum의 특징</h3>
<ul>
<li><strong>인스턴스 변수는 반드시 <code>final</code>이어야 합니다.</strong></li>
<li><strong>모든 생성자는 상수여야 합니다.</strong></li>
<li><strong>팩토리 생성자는 고정된 열거형 인스턴스 중 하나만 반환할 수 있습니다.</strong></li>
<li><strong><code>Enum</code>은 자동으로 확장되며 다른 클래스를 확장할 수 없습니다.</strong></li>
<li><strong><code>index</code>, <code>hashCode</code>, 동등 연산자 <code>==</code>를 재정의할 수 없습니다.</strong></li>
<li><strong><code>values</code>라는 이름의 멤버를 선언할 수 없습니다.</strong></li>
<li><strong>모든 인스턴스는 선언의 시작 부분에 선언되어야 하며, 최소 하나의 인스턴스가 선언되어야 합니다.</strong></li>
</ul>
<h3 id="관련-자료">관련 자료</h3>
<ul>
<li><a href="https://dart.dev/guides/language/language-tour#enumerated-types"><strong>Dart 공식 문서 - Enum</strong></a>: Dart에서 enum을 사용하는 방법에 대한 공식 가이드입니다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Riverpod]]></title>
            <link>https://velog.io/@hayo_dev/Riverpod</link>
            <guid>https://velog.io/@hayo_dev/Riverpod</guid>
            <pubDate>Sun, 07 Jul 2024 14:08:46 GMT</pubDate>
            <description><![CDATA[<h2 id="flutter에서-provider의-개선-riverpod">Flutter에서 Provider의 개선: Riverpod</h2>
<p><code>Riverpod</code>은 Flutter에서 상태 관리를 보다 안전하고 효율적으로 할 수 있도록 도와주는 패키지로, 기존의 <code>Provider</code> 패키지를 개선하여 다양한 기능과 유연성을 제공합니다. 이를 통해 애플리케이션의 상태를 보다 쉽게 관리하고, 유지보수를 용이하게 합니다.</p>
<h2 id="주요-개념">주요 개념</h2>
<ul>
<li><strong>Riverpod</strong>: <code>Provider</code>의 개선판으로, 상태 관리의 편의성과 안전성을 높여줍니다. 전역 변수로 제공자를 선언하고, <code>ProviderScope</code>로 감싸 사용합니다.</li>
<li><strong>ProviderScope</strong>: Riverpod의 상태를 유지하고, 위젯 트리에서 상태를 공유할 수 있도록 하는 역할을 합니다.</li>
<li><strong>WidgetRef</strong>: Riverpod에서 상태를 읽거나, 상태 변경을 감지할 수 있도록 도와주는 객체입니다.</li>
<li><strong>ConsumerWidget</strong>: <code>StatelessWidget</code>과 유사하지만, Riverpod의 상태를 구독할 수 있는 기능을 제공합니다.</li>
</ul>
<h2 id="주요-속성-및-메서드">주요 속성 및 메서드</h2>
<ul>
<li><strong><code>ref.watch()</code></strong>: 상태를 구독하고, 상태가 변경될 때마다 빌드합니다.</li>
<li><strong><code>ref.read()</code></strong>: 상태를 읽기만 하고, 변경 사항을 구독하지 않습니다.</li>
<li><strong><code>NotifierProvider</code></strong>: 상태 변경을 알리는 <code>Notifier</code> 객체를 제공하는 Provider입니다.</li>
<li><strong><code>StateProvider</code></strong>: 간단한 상태를 관리하기 위한 Provider입니다.</li>
</ul>
<h2 id="주요-활용도">주요 활용도</h2>
<ul>
<li><strong>글로벌 상태 관리</strong>: 앱 전체에서 공유되는 상태를 관리하는 데 유용합니다.</li>
<li><strong>상태의 안전한 변경</strong>: 상태 변경 로직을 중앙 집중화하여 버그를 줄이고 유지보수를 용이하게 합니다.</li>
<li><strong>비동기 작업 관리</strong>: 비동기 작업의 상태를 쉽게 관리할 수 있습니다.</li>
</ul>
<h2 id="코드-예제">코드 예제</h2>
<p>아래 예제는 간단한 카운터 앱을 통해 Riverpod의 사용 방법을 보여줍니다.</p>
<pre><code class="language-dart">import &#39;package:flutter/material.dart&#39;;
import &#39;package:flutter_riverpod/flutter_riverpod.dart&#39;;

// 상태 제공자 선언
final counterProvider = StateProvider&lt;int&gt;((ref) =&gt; 0);

void main() {
  runApp(
    ProviderScope(
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: CounterApp(),
    );
  }
}

class CounterApp extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final counter = ref.watch(counterProvider).state;

    return Scaffold(
      appBar: AppBar(title: Text(&#39;Counter App&#39;)),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: &lt;Widget&gt;[
            Text(&#39;You have pushed the button this many times:&#39;),
            Text(&#39;$counter&#39;, style: Theme.of(context).textTheme.headline4),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          ref.read(counterProvider).state++;
        },
        tooltip: &#39;Increment&#39;,
        child: Icon(Icons.add),
      ),
    );
  }
}
</code></pre>
<h2 id="riverpod의-특징">Riverpod의 특징</h2>
<h3 id="1-제공자-등록-편의성">1. 제공자 등록 편의성</h3>
<ul>
<li><p><strong>Provider</strong>:</p>
<ul>
<li><p>위젯 트리에 직접 명시적으로 등록해야 하며, 의존성이 있는 경우 등록 순서에 주의해야 합니다.</p>
<pre><code class="language-dart">  MultiProvider(
    providers: [
      ChangeNotifierProvider(create: (context) =&gt; A()),
      ChangeNotifierProvider(create: (context) =&gt; B(a: context.read())),
    ],
    child: MyApp(),
  );
</code></pre>
</li>
</ul>
</li>
<li><p><strong>Riverpod</strong>:</p>
<ul>
<li><p>제공자를 전역 변수로 선언하며, <code>ProviderScope</code>로 감싸면 의존성 순서에 상관없이 등록됩니다.</p>
<pre><code class="language-dart">  final a = StateProvider&lt;int&gt;((ref) =&gt; 0);
  final b = StateProvider&lt;int&gt;((ref) =&gt; ref.watch(a) * 2);

  ProviderScope(
    child: MyApp(),
  );
</code></pre>
</li>
</ul>
</li>
</ul>
<h3 id="2-제한-없는-provider">2. 제한 없는 Provider</h3>
<ul>
<li><p><strong>Provider</strong>:</p>
<ul>
<li><p>같은 클래스를 여러 개 등록하는 경우, 가장 가까운 클래스가 호출됩니다.</p>
<pre><code class="language-dart">  MultiProvider(
    providers: [
      ChangeNotifierProvider(create: (context) =&gt; Counter()), // 1
      ChangeNotifierProvider(create: (context) =&gt; Counter()), // 2
    ],
    child: MyApp(),
  );
</code></pre>
<pre><code class="language-dart">  Counter counter = context.read&lt;Counter&gt;(); // 2번만 접근 가능
</code></pre>
</li>
</ul>
</li>
<li><p><strong>Riverpod</strong>:</p>
<ul>
<li><p>같은 클래스도 다른 이름으로 생성하고 접근할 수 있습니다.</p>
<pre><code class="language-dart">  final a = NotifierProvider&lt;Counter, int&gt;(() =&gt; Counter());
  final b = NotifierProvider&lt;Counter, int&gt;(() =&gt; Counter());
</code></pre>
<pre><code class="language-dart">  Counter counter1 = ref.read(a.notifier);
  Counter counter2 = ref.read(b.notifier);
</code></pre>
</li>
</ul>
</li>
</ul>
<h3 id="3-flutter에-의존하지-않음">3. Flutter에 의존하지 않음</h3>
<ul>
<li><p><strong>Provider</strong>:</p>
<ul>
<li><p>Flutter 프레임워크에서 제공하는 <code>BuildContext</code>를 사용합니다.</p>
<pre><code class="language-dart">  class MyWidget extends StatelessWidget {
    @override
    Widget build(BuildContext context) {
      Counter counter = context.watch&lt;Counter&gt;();
      return Text(&quot;${counter.count}&quot;);
    }
  }
</code></pre>
</li>
</ul>
</li>
<li><p><strong>Riverpod</strong>:</p>
<ul>
<li><p>Flutter 프레임워크와 무관한 <code>WidgetRef</code>를 별도로 만들어 사용합니다.</p>
<pre><code class="language-dart">  class MyWidget extends ConsumerWidget {
    @override
    Widget build(BuildContext context, WidgetRef ref) {
      Counter counter = ref.watch(counterProvider);
      return Text(&quot;${counter.count}&quot;);
    }
  }
</code></pre>
</li>
</ul>
</li>
</ul>
<h2 id="riverpod의-단점">Riverpod의 단점</h2>
<h3 id="1-전역-변수의-증가">1. 전역 변수의 증가</h3>
<p>Riverpod에서는 제공자를 전역 변수로 선언합니다. 이는 동일한 클래스를 여러 개 등록하고 사용할 수 있는 유연성을 제공하지만, 전역 변수가 늘어나게 되어 코드 관리가 어려워질 수 있습니다.</p>
<h3 id="2-widgetref-사용의-필요성">2. WidgetRef 사용의 필요성</h3>
<p>Riverpod은 Flutter의 <code>BuildContext</code>를 사용하지 않고 <code>WidgetRef</code>를 사용합니다. 이는 Flutter에 의존하지 않는다는 장점이 있지만, <code>ConsumerWidget</code>과 같은 위젯을 사용하기 위해 추가적인 코드가 필요하게 됩니다.</p>
<pre><code class="language-dart">class MyWidget extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    Counter counter = ref.watch(counterProvider);
    return Text(&quot;${counter.count}&quot;);
  }
}</code></pre>
<h2 id="추가-팁">추가 팁</h2>
<ul>
<li><strong>성능 최적화</strong>: <code>ref.watch</code>는 필요한 경우에만 호출하여 불필요한 위젯 빌드를 최소화합니다.</li>
<li><strong>복잡한 상태 관리</strong>: 앱의 상태가 여러 위젯 간에 공유되거나, 글로벌 상태 관리가 필요한 경우, <code>Riverpod</code>와 같은 상태 관리 도구를 사용하는 것이 좋습니다.</li>
</ul>
<h2 id="관련-자료">관련 자료</h2>
<ul>
<li><a href="https://docs-v2.riverpod.dev/"><strong>Riverpod 공식 문서</strong></a>: Riverpod의 자세한 사용 방법과 예제를 제공합니다.</li>
<li><a href="https://flutter.dev/docs/development/data-and-backend/state-mgmt"><strong>Flutter 상태 관리 문서</strong></a>: 다양한 상태 관리 도구와 패턴을 설명합니다.</li>
<li><a href="https://pub.dev/packages/provider"><strong>Provider 패키지</strong></a>: Flutter 팀에서 권장하는 상태 관리 도구입니다.</li>
<li><a href="https://bloclibrary.dev/#/"><strong>BLoC (Business Logic Component)</strong></a>: 이벤트 기반 상태 관리 패턴입니다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Provider]]></title>
            <link>https://velog.io/@hayo_dev/Provider</link>
            <guid>https://velog.io/@hayo_dev/Provider</guid>
            <pubDate>Sun, 07 Jul 2024 11:47:47 GMT</pubDate>
            <description><![CDATA[<h2 id="flutter에서-inheritedwidget의-개선-provider">Flutter에서 InheritedWidget의 개선: Provider</h2>
<p><code>Provider</code>는 Flutter에서 상태 관리의 문제를 해결하기 위한 패키지로, 특히 Prop Drilling 문제를 효과적으로 해결할 수 있는 도구입니다. <code>InheritedWidget</code>을 보다 쉽게 사용할 수 있도록 래핑하여 상태 관리를 더 간단하고 효율적으로 만들어줍니다.</p>
<h2 id="주요-개념">주요 개념</h2>
<ul>
<li><strong>Provider</strong>: <code>InheritedWidget</code>을 래핑하여 더 쉽게 상태를 관리하고, 필요한 부분에서만 상태를 갱신할 수 있도록 도와줍니다.</li>
<li><strong>ChangeNotifier</strong>: 상태가 변경될 때 이를 알리기 위한 클래스. <code>notifyListeners()</code> 메서드를 호출하여 상태 변경을 알립니다.</li>
<li><strong>ChangeNotifierProvider</strong>: <code>ChangeNotifier</code>를 사용하는 <code>Provider</code>의 한 종류로, 상태 객체를 제공하고 관리합니다.</li>
<li><strong>Consumer</strong>: 특정 <code>Provider</code>의 상태를 구독하여 변경될 때마다 빌드하는 위젯.</li>
</ul>
<h2 id="provider-특징">Provider 특징</h2>
<ul>
<li><strong>Prop Drilling 문제 해결</strong>: 중간 위젯들에게 속성을 계속 전달해야 하는 문제를 해결할 수 있습니다.</li>
<li><strong>Lazy Loading 지원</strong>: 필요할 때만 객체를 생성하여 성능을 최적화합니다.</li>
<li><strong>간단한 보일러플레이트</strong>: 새로운 클래스를 작성할 때 필요한 코드를 줄여줍니다.</li>
<li><strong>Flutter DevTools 친화적</strong>: 상태를 시각화하고 디버깅을 쉽게 할 수 있습니다.</li>
<li><strong>상태를 별도 클래스로 분리</strong>: <code>StatefulWidget</code>보다 유지 관리가 용이합니다.</li>
<li><strong>작성해야 하는 코드 감소</strong>: <code>InheritedWidget</code>보다 코드량이 적습니다.</li>
<li><strong>선택적 갱신 가능</strong>: 원하는 위젯만 선택적으로 갱신할 수 있습니다.</li>
<li><strong>Provider가 부모 위젯으로 등록되지 않은 경우, 자식 위젯에서 접근 시 런타임 에러 발생</strong>: 위젯 트리상에 등록할 때 의존성 순서가 중요합니다.</li>
</ul>
<h2 id="주요-속성-및-메서드">주요 속성 및 메서드</h2>
<ul>
<li><strong><code>ChangeNotifierProvider</code></strong>: <code>ChangeNotifier</code> 객체를 제공하는 Provider입니다.</li>
<li><strong><code>Consumer</code></strong>: <code>Provider</code>에서 제공하는 상태를 구독하고, 상태가 변경될 때마다 빌드합니다.</li>
<li><strong><code>context.watch&lt;T&gt;()</code></strong>: <code>Provider</code>에서 상태를 구독하고 변경 시 위젯을 다시 빌드합니다.</li>
<li><strong><code>context.read&lt;T&gt;()</code></strong>: 상태를 구독하지 않고 읽기만 합니다.</li>
<li><strong><code>context.select&lt;T, R&gt;(R selector(T value))</code></strong>: 특정 속성만 구독하여 변경 시에만 빌드합니다.</li>
</ul>
<h2 id="실제-사용-예">실제 사용 예</h2>
<h3 id="기본-사용법">기본 사용법</h3>
<ol>
<li><p><strong>ChangeNotifier 클래스 작성</strong></p>
<pre><code class="language-dart"> class Counter with ChangeNotifier {
   int _count = 0;

   int get count =&gt; _count;

   void increment() {
     _count++;
     notifyListeners();
   }
 }
</code></pre>
</li>
<li><p><strong>ChangeNotifierProvider로 상태 주입</strong></p>
<pre><code class="language-dart"> void main() {
   runApp(
     ChangeNotifierProvider(
       create: (context) =&gt; Counter(),
       child: MyApp(),
     ),
   );
 }
</code></pre>
</li>
<li><p><strong>Consumer를 사용하여 상태 접근 및 UI 업데이트</strong></p>
<pre><code class="language-dart"> class MyApp extends StatelessWidget {
   @override
   Widget build(BuildContext context) {
     return MaterialApp(
       home: Scaffold(
         appBar: AppBar(
           title: Text(&#39;Provider Example&#39;),
         ),
         body: Center(
           child: Column(
             mainAxisAlignment: MainAxisAlignment.center,
             children: &lt;Widget&gt;[
               Text(&#39;You have pushed the button this many times:&#39;),
               Consumer&lt;Counter&gt;(
                 builder: (context, counter, child) {
                   return Text(
                     &#39;${counter.count}&#39;,
                     style: Theme.of(context).textTheme.headline4,
                   );
                 },
               ),
             ],
           ),
         ),
         floatingActionButton: FloatingActionButton(
           onPressed: () {
             Provider.of&lt;Counter&gt;(context, listen: false).increment();
           },
           tooltip: &#39;Increment&#39;,
           child: Icon(Icons.add),
         ),
       ),
     );
   }
 }
</code></pre>
</li>
</ol>
<h3 id="provider-접근-방법">Provider 접근 방법</h3>
<ol>
<li><p><strong><code>context.watch()</code></strong>: <code>notifyListeners()</code> 호출 시 위젯 갱신</p>
<pre><code class="language-dart"> ProviderCart providerCart = context.watch&lt;ProviderCart&gt;();
 isInCart: providerCart.cartProductList.contains(product),
 onPressed: providerCart.onProductPressed,
</code></pre>
</li>
<li><p><strong><code>context.read()</code></strong>: <code>notifyListeners()</code> 호출 시 갱신하지 않음</p>
<pre><code class="language-dart"> onPressed: context.read&lt;ProviderCart&gt;().onProductPressed,
</code></pre>
</li>
<li><p><strong><code>context.select()</code></strong>: 특정 속성이 변경된 경우에만 갱신</p>
<pre><code class="language-dart"> List&lt;Product&gt; cartProductList = context.select&lt;ProviderCart, List&lt;Product&gt;&gt;(
   (providerCart) =&gt; providerCart.cartProductList,
 );
</code></pre>
</li>
<li><p><strong><code>Consumer</code></strong>: <code>watch</code>와 동일하나 특정 위젯만 갱신</p>
<pre><code class="language-dart"> Consumer&lt;Counter&gt;(
   builder: (context, counter, child) {
     return Text(
       &#39;${counter.count}&#39;,
       style: Theme.of(context).textTheme.headline4,
     );
   },
 );
</code></pre>
</li>
<li><p><strong><code>Selector</code></strong>: <code>select</code>와 동일하나 특정 위젯만 갱신</p>
<pre><code class="language-dart"> Selector&lt;ProviderBadge, int&gt;(
   selector: (context, providerBadge) =&gt; providerBadge.counter,
   builder: (context, counter, child) =&gt; BottomBar(
     currentIndex: currentIndex,
     cartTotal: &quot;$counter&quot;,
     onTap: (index) =&gt; setState(() {
       currentIndex = index;
     }),
   ),
 ),
</code></pre>
</li>
</ol>
<h2 id="provider-제공자-종류">Provider 제공자 종류</h2>
<ol>
<li><p><strong><code>ChangeNotifierProvider</code></strong>: 변경 사항을 알릴 필요가 있는 클래스</p>
<pre><code class="language-dart"> ChangeNotifierProvider(
   create: (context) =&gt; ProviderCart(),
 )
</code></pre>
</li>
<li><p><strong><code>Provider</code></strong>: 변경 사항을 알릴 필요가 없는 클래스</p>
<pre><code class="language-dart"> Provider(
   create: (context) =&gt; MyService(),
 )
</code></pre>
</li>
</ol>
<h3 id="고급-사용법">고급 사용법</h3>
<h3 id="statefulwidget-생애-주기-활용">StatefulWidget 생애 주기 활용</h3>
<ul>
<li><p><code>initState()</code>에서 Provider에 접근하려면 <strong>StatefulWidget</strong>의 속성에서 Provider를 생성해야 합니다.</p>
</li>
<li><p><code>ChangeNotifierProvider</code>로 등록한 Provider는 해당 <strong>StatefulWidget</strong>이 위젯 트리에서 제거될 때 함께 <code>dispose()</code> 됩니다.</p>
</li>
<li><p><strong>예시</strong>:</p>
<pre><code class="language-dart">  @override
  void initState() {
    super.initState();
    Provider.of&lt;MyProvider&gt;(context, listen: false).fetchData();
  }
</code></pre>
</li>
</ul>
<h3 id="provider-상호작용">Provider 상호작용</h3>
<ul>
<li><p>특정 Provider의 상태가 변경될 때 다른 Provider의 상태도 함께 변경되어야 하는 경우</p>
<pre><code class="language-dart">  class MyBadge with ChangeNotifier {
    MyBadge(this.myCart) {
      myCart.addListener(_update);
    }

    final MyCart myCart;
    int _count = 0;

    void _update() {
      _count = myCart.items.length;
      notifyListeners();
    }

    @override
    void dispose() {
      myCart.removeListener(_update);
      super.dispose();
    }
  }
</code></pre>
</li>
</ul>
<h2 id="관련자료">관련자료</h2>
<ul>
<li><a href="https://pub.dev/packages/provider"><strong>Provider 공식 문서</strong></a></li>
<li><a href="https://flutter.dev/docs/development/data-and-backend/state-mgmt"><strong>Flutter 상태 관리 문서</strong></a></li>
<li><a href="https://dartpad.dev/?id=58941d08723e173ecaa46a10fe833ebc"><strong>Provider 예제 및 샘플 코드</strong></a></li>
<li><a href="https://riverpod.dev/"><strong>Riverpod</strong></a>: Provider의 개선된 버전</li>
<li><a href="https://bloclibrary.dev/#/"><strong>BLoC (Business Logic Component)</strong></a>: 이벤트 기반 상태 관리 패턴</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[InheritedWidget]]></title>
            <link>https://velog.io/@hayo_dev/InheritedWidget</link>
            <guid>https://velog.io/@hayo_dev/InheritedWidget</guid>
            <pubDate>Sat, 06 Jul 2024 13:26:50 GMT</pubDate>
            <description><![CDATA[<h2 id="flutter에서-상태관리의-prop-drilling-문제-해결-inheritedwidget">Flutter에서 상태관리의 Prop Drilling 문제 해결: InheritedWidget</h2>
<p><code>InheritedWidget</code>은 Flutter에서 상위 위젯에서 하위 위젯으로 데이터를 전달할 때 사용하는 위젯입니다. <code>InheritedWidget</code>을 사용하면 트리의 중간 위젯들을 거치지 않고도 상태를 하위 위젯으로 전달할 수 있어 상태 관리에 유용합니다.</p>
<h2 id="주요-개념">주요 개념</h2>
<ul>
<li><strong>InheritedWidget</strong>: 상위 위젯에서 하위 위젯으로 데이터를 전달하는 역할을 합니다. 데이터가 변경되면 해당 데이터를 사용하는 모든 하위 위젯들이 다시 빌드됩니다.</li>
<li><strong>of 메서드</strong>: <code>InheritedWidget</code>에서 데이터를 가져올 때 사용합니다. <code>BuildContext</code>를 통해 상위 <code>InheritedWidget</code>에 접근합니다.</li>
</ul>
<h2 id="inheritedwidget-특징">InheritedWidget 특징</h2>
<ul>
<li><strong>Prop Drilling 문제 해결</strong>: 중간 위젯들에게 속성을 계속 전달해야 하는 문제를 해결할 수 있습니다.</li>
<li><strong>상태 변경 및 갱신 별도 구현 필요</strong>: 자식 위젯의 접근만 도와줄 뿐, 상태 변경 및 위젯 갱신은 별도로 구현해야 합니다.</li>
<li><strong>위젯 트리 존재 여부 주의</strong>: 위젯 트리상에 <code>InheritedWidget</code>이 존재하지 않으면 런타임 에러가 발생할 수 있습니다.</li>
</ul>
<p><strong>자식 위젯의 독립성</strong>: 자식 위젯이 공유 상태나 메서드를 갖지 않아도 됩니다. 따라서 <code>const</code> 키워드를 사용할 수 있어 빌드 성능이 최적화됩니다.</p>
<h3 id="실제-사용-예">실제 사용 예</h3>
<ul>
<li><code>MediaQuery</code>, <code>Theme.of</code> 등 Flutter의 기본적인 위젯들도 <code>InheritedWidget</code>을 사용하여 구현되었습니다. 이를 통해 디바이스의 크기나 테마 설정 등에 쉽게 접근할 수 있습니다.</li>
</ul>
<h2 id="주요-속성-및-메서드">주요 속성 및 메서드</h2>
<ul>
<li><strong><code>updateShouldNotify</code></strong>: <code>InheritedWidget</code>이 재빌드되어야 하는지를 결정하는 메서드입니다. 이전 데이터와 새로운 데이터를 비교하여 필요할 때만 하위 위젯들을 다시 빌드합니다.</li>
</ul>
<h2 id="주요-활용도">주요 활용도</h2>
<ul>
<li><strong>전역 상태 관리</strong>: 간단한 전역 상태를 관리할 때 유용합니다. 예를 들어, 테마, 언어 설정 등.</li>
<li><strong>상태 공유</strong>: 여러 위젯에서 동일한 데이터를 필요로 할 때 중간 위젯을 거치지 않고 데이터를 공유할 수 있습니다.</li>
</ul>
<h2 id="코드-예제">코드 예제</h2>
<p>아래 예제는 간단한 카운터 앱을 통해 <code>InheritedWidget</code>의 사용 방법을 보여줍니다.</p>
<pre><code class="language-dart">class Counter extends InheritedWidget {
  final int count;
  final Function() increment;

  Counter({
    Key? key,
    required this.count,
    required this.increment,
    required Widget child,
  }) : super(key: key, child: child);

  static Counter? of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType&lt;Counter&gt;();
  }

  @override
  bool updateShouldNotify(Counter oldWidget) {
    return oldWidget.count != count;
  }
}

class CounterApp extends StatefulWidget {
  @override
  _CounterAppState createState() =&gt; _CounterAppState();
}

class _CounterAppState extends State&lt;CounterApp&gt; {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Counter(
      count: _counter,
      increment: _incrementCounter,
      child: Scaffold(
        appBar: AppBar(title: Text(&#39;Counter App&#39;)),
        body: Center(child: CounterDisplay()),
        floatingActionButton: FloatingActionButton(
          onPressed: _incrementCounter,
          tooltip: &#39;Increment&#39;,
          child: Icon(Icons.add),
        ),
      ),
    );
  }
}

class CounterDisplay extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final counter = Counter.of(context);

    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: &lt;Widget&gt;[
        Text(&#39;You have pushed the button this many times:&#39;),
        Text(&#39;${counter?.count}&#39;, style: Theme.of(context).textTheme.headline4),
      ],
    );
  }
}
</code></pre>
<h2 id="prop-drilling-문제-해결">Prop Drilling 문제 해결</h2>
<p><code>InheritedWidget</code>은 Prop Drilling 문제를 효과적으로 해결할 수 있는 도구입니다. 부모 위젯에서 자식 위젯으로 상태를 전달할 때 중간에 위치한 위젯들이 불필요한 속성을 전달받지 않도록 합니다.</p>
<h3 id="문제점-해결">문제점 해결</h3>
<ul>
<li><strong>중간 위젯의 불필요한 속성 전달 방지</strong>: 데이터가 필요한 위젯만 데이터를 직접 받아 사용합니다.</li>
<li><strong>코드의 가독성 향상</strong>: 위젯의 역할이 명확해지고, 코드가 단순해집니다.</li>
<li><strong>유지보수 용이</strong>: 데이터 구조가 변경되더라도 중간 위젯을 수정할 필요가 없습니다.</li>
</ul>
<h2 id="추가-팁">추가 팁</h2>
<ul>
<li><strong>성능 최적화</strong>: <code>updateShouldNotify</code> 메서드를 적절히 구현하여 불필요한 위젯 빌드를 최소화합니다.</li>
<li><strong>복잡한 상태 관리</strong>: 앱이 커지고 상태가 복잡해질 경우, <code>Provider</code>, <code>Riverpod</code>, <code>BLoC</code> 등 더 강력한 상태 관리 도구를 사용하는 것이 좋습니다.</li>
</ul>
<h2 id="관련-자료">관련 자료</h2>
<ul>
<li><a href="https://velog.io/@hayo_dev/State"><strong>State</strong></a>: 상태 관리의 배경지식.</li>
<li><a href="https://api.flutter.dev/flutter/widgets/InheritedWidget-class.html"><strong>InheritedWidget</strong></a>: 상위 위젯에서 하위 위젯으로 데이터를 전달합니다.</li>
<li><a href="https://pub.dev/packages/provider"><strong>Provider</strong></a>: Flutter 팀에서 권장하는 상태 관리 도구입니다.</li>
<li><a href="https://riverpod.dev/"><strong>Riverpod</strong></a>: Provider의 개선된 버전입니다.</li>
<li><a href="https://bloclibrary.dev/#/"><strong>BLoC (Business Logic Component)</strong></a>: 이벤트 기반 상태 관리 패턴입니다.</li>
</ul>
<h2 id="추가-참고-리소스">추가 참고 리소스</h2>
<ul>
<li><a href="https://flutter.dev/docs/development/data-and-backend/state-mgmt/simple#inheritedwidget"><strong>Inherited Widgets &amp; State Management</strong></a></li>
<li><a href="https://api.flutter.dev/flutter/widgets/InheritedWidget-class.html"><strong>공식 문서 - InheritedWidget</strong></a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[StatefulWidget]]></title>
            <link>https://velog.io/@hayo_dev/StatefulWidget</link>
            <guid>https://velog.io/@hayo_dev/StatefulWidget</guid>
            <pubDate>Sat, 06 Jul 2024 07:15:19 GMT</pubDate>
            <description><![CDATA[<h2 id="flutter에서-간단한-로컬-상태-관리하기-statefulwidget">Flutter에서 간단한 로컬 상태 관리하기: StatefulWidget</h2>
<p><code>StatefulWidget</code>은 Flutter에서 상태를 관리하는 기본적인 방법 중 하나로, 상태가 변할 수 있는 위젯을 만들 때 사용됩니다. <code>StatefulWidget</code>을 통해 동적인 UI 업데이트가 가능하며, 이를 이용해 다양한 상태 기반 인터랙션을 구현할 수 있습니다.</p>
<h2 id="주요-개념">주요 개념</h2>
<ul>
<li><strong>StatefulWidget</strong>: 상태가 변할 수 있는 위젯을 정의합니다. 상태 변화에 따라 UI를 재구성합니다.</li>
<li><strong>State 클래스</strong>: <code>StatefulWidget</code>의 상태를 나타내며, 상태 변화를 관리합니다. <code>State</code> 클래스는 <code>StatefulWidget</code>과 분리되어 상태를 독립적으로 관리할 수 있습니다.</li>
</ul>
<h2 id="주요-속성-및-메서드">주요 속성 및 메서드</h2>
<ul>
<li><strong><code>initState</code></strong>: <code>State</code> 클래스의 초기화 메서드로, 상태 초기화를 수행합니다. <code>State</code> 객체가 처음 생성될 때 한 번 호출됩니다.</li>
<li><strong><code>setState</code></strong>: 상태를 변경하고, UI를 다시 빌드하도록 하는 메서드입니다. 상태가 변경될 때마다 호출합니다.</li>
<li><strong><code>dispose</code></strong>: <code>State</code> 객체가 소멸될 때 호출되는 메서드로, 리소스를 정리하는 데 사용됩니다.</li>
</ul>
<h2 id="주요-활용도">주요 활용도</h2>
<ul>
<li><strong>로컬 상태 관리</strong>: 간단한 상태 관리를 할 때 유용합니다. 예를 들어, 버튼 클릭 수 카운트, 입력 필드 값 등.</li>
<li><strong>동적인 UI 업데이트</strong>: 상태 변경에 따라 UI를 동적으로 업데이트할 수 있습니다.</li>
</ul>
<h2 id="코드-예제">코드 예제</h2>
<p>아래 예제는 간단한 카운터 앱을 통해 <code>StatefulWidget</code>의 사용 방법을 보여줍니다.</p>
<pre><code class="language-dart">class CounterApp extends StatefulWidget {
  @override
  _CounterAppState createState() =&gt; _CounterAppState();
}

class _CounterAppState extends State&lt;CounterApp&gt; {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(&#39;Counter App&#39;)),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: &lt;Widget&gt;[
            Text(&#39;You have pushed the button this many times:&#39;),
            Text(&#39;$_counter&#39;, style: Theme.of(context).textTheme.headline4),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: &#39;Increment&#39;,
        child: Icon(Icons.add),
      ),
    );
  }
}
</code></pre>
<h2 id="prop-drilling-문제">Prop Drilling 문제</h2>
<p><code>StatefulWidget</code>을 사용하여 상태를 관리할 때 발생할 수 있는 문제 중 하나는 <strong>Prop Drilling</strong>입니다. 이는 부모 위젯에서 자식 위젯으로 상태를 전달할 때 중간에 위치한 모든 위젯이 해당 속성을 전달받아야 하는 문제를 말합니다.</p>
<h3 id="문제점">문제점</h3>
<ul>
<li><strong>중간 위젯의 불필요한 속성 전달</strong>: 중간 위젯들이 본래 필요하지 않은 속성을 전달받아야 하며, 코드가 복잡해집니다.</li>
<li><strong>코드의 가독성 저하</strong>: 각 위젯의 역할이 명확하지 않게 되며, 코드가 길어지고 이해하기 어려워집니다.</li>
<li><strong>유지보수의 어려움</strong>: 속성을 전달하는 구조가 변경되면 중간 위젯들의 코드도 함께 수정해야 합니다.</li>
</ul>
<h3 id="예제">예제</h3>
<pre><code class="language-dart">class ParentWidget extends StatefulWidget {
  @override
  _ParentWidgetState createState() =&gt; _ParentWidgetState();
}

class _ParentWidgetState extends State&lt;ParentWidget&gt; {
  String data = &quot;Hello&quot;;

  void updateData(String newData) {
    setState(() {
      data = newData;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(&#39;Prop Drilling Example&#39;)),
      body: MiddleWidget(
        data: data,
        updateData: updateData,
      ),
    );
  }
}

class MiddleWidget extends StatelessWidget {
  final String data;
  final Function(String) updateData;

  MiddleWidget({required this.data, required this.updateData});

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text(&#39;Middle Widget&#39;),
        ChildWidget(
          data: data,
          updateData: updateData,
        ),
      ],
    );
  }
}

class ChildWidget extends StatelessWidget {
  final String data;
  final Function(String) updateData;

  ChildWidget({required this.data, required this.updateData});

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text(&#39;Data: $data&#39;),
        ElevatedButton(
          onPressed: () {
            updateData(&#39;Hello from Child&#39;);
          },
          child: Text(&#39;Update Data&#39;),
        ),
      ],
    );
  }
}
</code></pre>
<h3 id="prop-drilling-해결-방법">Prop Drilling 해결 방법</h3>
<p>Prop Drilling 문제를 해결하기 위해 Flutter에서는 다양한 상태 관리 도구를 제공합니다:</p>
<ul>
<li><strong>InheritedWidget</strong>: 상위 위젯에서 하위 위젯으로 데이터를 전달할 때 중간 위젯을 거치지 않고 데이터를 전달할 수 있습니다.</li>
<li><strong>Provider</strong>: Flutter 팀에서 권장하는 상태 관리 도구로, DI(Dependency Injection)와 반응형 상태 관리를 제공합니다.</li>
<li><strong>Riverpod</strong>: Provider의 개선된 버전으로, 더 안전하고 테스트하기 쉬운 상태 관리를 제공합니다.</li>
<li><strong>BLoC (Business Logic Component)</strong>: 이벤트 기반 상태 관리 패턴으로, 상태의 예측 가능성을 높여줍니다.</li>
</ul>
<h2 id="추가-팁">추가 팁</h2>
<ul>
<li><strong>성능 최적화</strong>: <code>setState</code>는 필요한 경우에만 호출하여 불필요한 위젯 빌드를 최소화해야 합니다.</li>
<li><strong>복잡한 상태 관리</strong>: 앱의 상태가 여러 위젯 간에 공유되거나, 글로벌 상태 관리가 필요한 경우, <code>Provider</code>, <code>BLoC</code>, <code>Riverpod</code>와 같은 상태 관리 도구를 사용하는 것이 좋습니다.</li>
</ul>
<h2 id="관련-자료">관련 자료</h2>
<ul>
<li><a href="https://velog.io/@hayo_dev/State"><strong>State</strong></a>: 상태관리의 배경지식.</li>
<li><a href="https://api.flutter.dev/flutter/widgets/InheritedWidget-class.html"><strong>InheritedWidget</strong></a>: 상위 위젯에서 하위 위젯으로 데이터를 전달합니다.</li>
<li><a href="https://pub.dev/packages/provider"><strong>Provider</strong></a>: Flutter 팀에서 권장하는 상태 관리 도구입니다.</li>
<li><a href="https://riverpod.dev/"><strong>Riverpod</strong></a>: Provider의 개선된 버전입니다.</li>
<li><a href="https://bloclibrary.dev/#/"><strong>BLoC (Business Logic Component)</strong></a>: 이벤트 기반 상태 관리 패턴입니다.</li>
</ul>
<h2 id="추가-참고-리소스">추가 참고 리소스</h2>
<ul>
<li><a href="https://www.youtube.com/watch?v=AqCMFXEmf3w"><strong>How Stateful Widgets Are Used Best - Flutter Widgets</strong></a></li>
<li><a href="https://api.flutter.dev/flutter/widgets/StatefulWidget-class.html"><strong>공식 문서 - StatefulWidget</strong></a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[State]]></title>
            <link>https://velog.io/@hayo_dev/State</link>
            <guid>https://velog.io/@hayo_dev/State</guid>
            <pubDate>Fri, 05 Jul 2024 13:03:08 GMT</pubDate>
            <description><![CDATA[<h2 id="flutter에서-상태state-이해하기">Flutter에서 상태(State) 이해하기</h2>
<p>Flutter 애플리케이션 개발에서 상태 관리는 UI와 애플리케이션 로직을 동기화하는 중요한 개념입니다. 올바른 상태 관리를 통해 데이터 일관성을 유지하고 사용자 경험을 향상시킬 수 있습니다.</p>
<h2 id="주요-개념">주요 개념</h2>
<h3 id="상태란-무엇인가">상태란 무엇인가?</h3>
<ul>
<li><strong>상태(State)</strong>는 변수에 할당된 값입니다. 애플리케이션의 특정 시점에서의 데이터를 나타내며, UI에 직접적인 영향을 미칩니다.</li>
</ul>
<h3 id="statelesswidget과-statefulwidget">StatelessWidget과 StatefulWidget</h3>
<ul>
<li><p><strong>StatelessWidget</strong>: 상태가 없는 위젯이 아니라 상태를 변경할 수 없는 위젯입니다.</p>
<pre><code class="language-dart">class MyStatelessWidget extends StatelessWidget {
  final Color color = Colors.red; // 상태 상수
  @override
  Widget build(BuildContext context) {
    return Container(color: color);
  }
}</code></pre>
</li>
<li><p><strong>StatefulWidget</strong>: 상태를 변경할 수 있는 위젯입니다.</p>
<pre><code class="language-dart">class MyStatefulWidget extends StatefulWidget {
  @override
  _MyStatefulWidgetState createState() =&gt; _MyStatefulWidgetState();
}

class _MyStatefulWidgetState extends State&lt;MyStatefulWidget&gt; {
  Color color = Colors.red; // 상태 변수

  void _changeColor() {
    setState(() {
      color = Colors.blue;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(&#39;Stateful Widget Example&#39;)),
      body: Center(
        child: Container(color: color),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _changeColor,
        tooltip: &#39;Change Color&#39;,
        child: Icon(Icons.color_lens),
      ),
    );
  }
}</code></pre>
</li>
</ul>
<h2 id="상태의-종류">상태의 종류</h2>
<ul>
<li><strong>로컬 상태(Local State)</strong>: 특정 위젯에서만 사용되는 상태로, 다른 위젯과 공유되지 않습니다.<ul>
<li>예: <code>BottomNavigationBar</code>의 현재 선택된 탭.</li>
</ul>
</li>
<li><strong>공유 상태(Shared State)</strong>: 여러 위젯에서 공유되며 동기화가 필요한 상태입니다.<ul>
<li>예: 로그인한 유저 정보, 특정 게시글의 좋아요 표시, 쇼핑 앱의 장바구니.</li>
</ul>
</li>
</ul>
<h2 id="상태-관리state-management란">상태 관리(State Management)란?</h2>
<p>상태 관리(State Management)는 공유 상태가 변경될 때 이를 동기화하는 과정을 의미합니다. 상태 관리가 없으면 데이터 일관성을 잃어 여러 문제를 초래할 수 있습니다.</p>
<h3 id="상태-관리의-필요성">상태 관리의 필요성</h3>
<ul>
<li>동일한 데이터를 여러 곳에서 가지고 있기 때문에 동기화가 필요합니다.</li>
<li><strong>데이터를 한 곳에서 관리</strong>하면 동기화 문제를 해결할 수 있습니다. 모든 상태 관리 방법은 공유 상태를 한 곳에서 관리하도록 중앙 집중식으로 문제를 해결합니다.</li>
</ul>
<h2 id="flutter에서의-상태-관리-방법">Flutter에서의 상태 관리 방법</h2>
<p>Flutter에서는 다양한 상태 관리 도구와 패턴을 제공하여 상태를 효과적으로 관리할 수 있습니다.</p>
<h3 id="statefulwidget">StatefulWidget</h3>
<ul>
<li>가장 기본적인 상태 관리 방식으로, 로컬 상태를 관리할 때 사용됩니다.</li>
</ul>
<h3 id="inheritedwidget">InheritedWidget</h3>
<ul>
<li>위젯 트리에서 데이터를 하위 위젯에 전달하기 위한 방법으로, 주로 로컬 상태를 상위 위젯에서 하위 위젯으로 전달할 때 사용됩니다.</li>
</ul>
<h3 id="provider">Provider</h3>
<ul>
<li>Flutter 팀에서 권장하는 상태 관리 도구로, DI(Dependency Injection)와 반응형 상태 관리를 제공합니다.</li>
</ul>
<h3 id="riverpod">Riverpod</h3>
<ul>
<li>Provider의 개선된 버전으로, 더 안전하고 테스트하기 쉬운 상태 관리를 제공합니다.</li>
</ul>
<h3 id="cubit">Cubit</h3>
<ul>
<li>간단하고 가벼운 상태 관리 솔루션으로, BLoC 패턴의 일부분입니다.</li>
</ul>
<h3 id="bloc-business-logic-component">BLoC (Business Logic Component)</h3>
<ul>
<li>이벤트 기반 상태 관리 패턴으로, 상태의 예측 가능성을 높여줍니다.</li>
</ul>
<h2 id="관련-자료">관련 자료</h2>
<ul>
<li><a href="https://pub.dev/packages/provider"><strong>Provider Package</strong></a>: Flutter의 상태 관리 솔루션.</li>
<li><a href="https://pub.dev/packages/riverpod"><strong>Riverpod Package</strong></a>: 더 안전한 상태 관리.</li>
<li><a href="https://pub.dev/packages/bloc"><strong>Bloc Package</strong></a>: 이벤트 기반 상태 관리.</li>
<li><a href="https://flutter.dev/docs/development/data-and-backend/state-mgmt/intro"><strong>Flutter 상태 관리 개요</strong></a>: Flutter 공식 문서.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Dismissible]]></title>
            <link>https://velog.io/@hayo_dev/Dismissible</link>
            <guid>https://velog.io/@hayo_dev/Dismissible</guid>
            <pubDate>Fri, 05 Jul 2024 06:33:23 GMT</pubDate>
            <description><![CDATA[<h2 id="flutter에서-항목을-스와이프하여-삭제하기-dismissible">Flutter에서 항목을 스와이프하여 삭제하기: Dismissible</h2>
<p><code>Dismissible</code> 위젯은 사용자가 스와이프하여 항목을 삭제하거나, 다른 작업을 수행할 수 있게 해주는 위젯입니다. 이 위젯은 주로 리스트 항목을 스와이프하여 삭제하는 기능을 구현할 때 사용됩니다.</p>
<h2 id="주요-속성">주요 속성</h2>
<ul>
<li><strong><code>key</code></strong>: 각 항목을 고유하게 식별하기 위한 키입니다. <code>Dismissible</code> 위젯은 반드시 고유한 키를 가져야 합니다.</li>
<li><strong><code>child</code></strong>: 스와이프하여 삭제할 항목의 콘텐츠입니다.</li>
<li><strong><code>onDismissed</code></strong>: 항목이 스와이프되어 삭제되었을 때 호출되는 콜백 함수입니다. 이 함수는 스와이프된 방향과 함께 호출됩니다.</li>
<li><strong><code>direction</code></strong>: 항목을 스와이프할 수 있는 방향을 설정합니다. 기본값은 <code>DismissDirection.horizontal</code>이며, <code>DismissDirection.vertical</code>, <code>DismissDirection.endToStart</code>, <code>DismissDirection.startToEnd</code>로 설정할 수 있습니다.</li>
<li><strong><code>background</code></strong>: 항목이 스와이프될 때 배경에 표시될 위젯입니다. 일반적으로 삭제 아이콘이나 색상을 포함합니다.</li>
<li><strong><code>secondaryBackground</code></strong>: 항목이 반대 방향으로 스와이프될 때 배경에 표시될 위젯입니다.</li>
</ul>
<h2 id="주요-활용도">주요 활용도</h2>
<ul>
<li><strong>리스트 항목 삭제</strong>: 사용자가 항목을 스와이프하여 삭제할 수 있는 기능을 구현합니다.</li>
<li><strong>스와이프 제스처를 통한 다른 작업 수행</strong>: 스와이프 제스처를 통해 다른 작업(예: 항목 완료, 즐겨찾기 추가 등)을 수행할 수 있습니다.</li>
</ul>
<h2 id="코드-예제">코드 예제</h2>
<p>아래 예제는 <code>Dismissible</code> 위젯을 사용하여 리스트 항목을 스와이프하여 삭제하는 방법을 보여줍니다.</p>
<pre><code class="language-dart">import &#39;package:flutter/material.dart&#39;;

void main() =&gt; runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: DismissibleExample(),
    );
  }
}

class DismissibleExample extends StatefulWidget {
  @override
  _DismissibleExampleState createState() =&gt; _DismissibleExampleState();
}

class _DismissibleExampleState extends State&lt;DismissibleExample&gt; {
  final List&lt;String&gt; items = List&lt;String&gt;.generate(10, (i) =&gt; &quot;Item ${i + 1}&quot;);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(&#39;Dismissible Example&#39;),
      ),
      body: ListView.builder(
        itemCount: items.length,
        itemBuilder: (context, index) {
          return Dismissible(
            key: Key(items[index]),
            direction: DismissDirection.endToStart,
            onDismissed: (direction) {
              setState(() {
                items.removeAt(index);
              });

              ScaffoldMessenger.of(context).showSnackBar(
                SnackBar(content: Text(&#39;${items[index]} dismissed&#39;)),
              );
            },
            background: Container(
              color: Colors.red,
              alignment: Alignment.centerRight,
              padding: EdgeInsets.symmetric(horizontal: 20),
              child: Icon(
                Icons.delete,
                color: Colors.white,
              ),
            ),
            child: ListTile(
              title: Text(items[index]),
            ),
          );
        },
      ),
    );
  }
}
</code></pre>
<h3 id="설명">설명</h3>
<ul>
<li><strong><code>Dismissible</code> 위젯</strong>: 각 리스트 항목을 <code>Dismissible</code>로 감싸서 스와이프하여 삭제할 수 있게 만듭니다.</li>
<li><strong><code>key</code> 속성</strong>: 각 항목을 고유하게 식별하기 위한 키를 설정합니다.</li>
<li><strong><code>onDismissed</code> 콜백</strong>: 항목이 스와이프되어 삭제될 때 호출되는 함수로, 삭제된 항목을 리스트에서 제거하고 스낵바를 통해 알림을 표시합니다.</li>
<li><strong><code>background</code> 속성</strong>: 항목이 스와이프될 때 표시될 배경으로, 빨간색 배경과 삭제 아이콘을 설정합니다.</li>
<li><strong><code>direction</code> 속성</strong>: 항목을 스와이프할 수 있는 방향을 <code>DismissDirection.endToStart</code>로 설정합니다.</li>
</ul>
<h2 id="추가-팁">추가 팁</h2>
<ul>
<li><strong>스와이프 방향 설정</strong>: 필요에 따라 <code>DismissDirection.horizontal</code>, <code>DismissDirection.vertical</code>, <code>DismissDirection.startToEnd</code> 등 다양한 스와이프 방향을 설정할 수 있습니다.</li>
<li><strong>다양한 작업 수행</strong>: <code>onDismissed</code> 콜백 내에서 삭제 외에도 다양한 작업(예: 항목 완료 처리, 즐겨찾기 추가 등)을 수행할 수 있습니다.</li>
</ul>
<h2 id="관련-자료">관련 자료</h2>
<ul>
<li><a href="https://api.flutter.dev/flutter/widgets/Dismissible-class.html"><strong>공식 문서 - Dismissible</strong></a></li>
<li><a href="https://www.youtube.com/watch?v=iEMgjrfuc58"><strong>Flutter Widget of the Week - Dismissible</strong></a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Drawer]]></title>
            <link>https://velog.io/@hayo_dev/Drawer</link>
            <guid>https://velog.io/@hayo_dev/Drawer</guid>
            <pubDate>Fri, 05 Jul 2024 05:51:09 GMT</pubDate>
            <description><![CDATA[<h2 id="flutter에서-사이드-내비게이션-관리하기-drawer">Flutter에서 사이드 내비게이션 관리하기: Drawer</h2>
<p>애플리케이션의 내비게이션 구조를 사용자에게 제공하는 것은 중요한 디자인 고려사항입니다. <code>Drawer</code> 위젯은 애플리케이션의 주요 목적지 간의 전환을 쉽게 할 수 있는 사이드 내비게이션 메뉴를 제공합니다.</p>
<h2 id="주요-속성">주요 속성</h2>
<ul>
<li><strong><code>child</code>:</strong> 드로어의 내용을 정의하는 위젯입니다. 보통 <code>ListView</code>를 사용하여 여러 개의 <code>ListTile</code>을 배치합니다.</li>
<li><strong><code>elevation</code>:</strong> 드로어의 그림자 높이를 설정합니다. 기본값은 16.0입니다.</li>
</ul>
<h2 id="listview와-drawerheader">ListView와 DrawerHeader</h2>
<p><code>Drawer</code>의 자식은 주로 <code>ListView</code>로 구성되며, 첫 번째 자식으로는 사용자 정보를 표시하는 <code>DrawerHeader</code>가 위치합니다. 나머지 항목들은 주로 <code>ListTile</code>로 구성되며, 마지막에는 <code>AboutListTile</code>이 위치할 수 있습니다.</p>
<h2 id="주요-활용도">주요 활용도</h2>
<ul>
<li><strong>사이드 내비게이션 메뉴 제공:</strong> 사용자가 앱 내의 주요 섹션 간에 쉽게 이동할 수 있도록 도와줍니다.</li>
<li><strong>유저 프로필 및 상태 정보 표시:</strong> <code>DrawerHeader</code>를 사용하여 사용자의 프로필 정보나 현재 상태를 표시할 수 있습니다.</li>
<li><strong>설정 및 정보 항목 추가:</strong> 설정, 정보, 도움말 등의 항목을 쉽게 추가할 수 있습니다.</li>
</ul>
<h2 id="코드-예제">코드 예제</h2>
<p>아래 예제는 <code>Drawer</code>를 사용하여 사이드 내비게이션 메뉴를 구성하는 방법을 보여줍니다. <code>Scaffold</code>의 <code>drawer</code> 속성에 <code>Drawer</code> 위젯을 할당하여 사용합니다.</p>
<pre><code class="language-dart">import &#39;package:flutter/material.dart&#39;;

void main() =&gt; runApp(MyApp());

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() =&gt; _MyAppState();
}

class _MyAppState extends State&lt;MyApp&gt; {
  int _selectedDrawerIndex = 0;  // 현재 선택된 항목의 인덱스를 저장

  final List&lt;Widget&gt; _pages = [
    Center(child: Text(&#39;Home Page&#39;)),
    Center(child: Text(&#39;Settings Page&#39;)),
    Center(child: Text(&#39;Contact Us Page&#39;)),
  ];

  _getDrawerItemWidget(int pos) {
    return _pages[pos];
  }

  _onSelectItem(int index) {
    setState(() {
      _selectedDrawerIndex = index;
    });
    Navigator.of(context).pop();  // 드로어를 닫음
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text(&#39;Drawer Example with State Management&#39;),
        ),
        drawer: Drawer(
          semanticLabel: &#39;Navigation menu&#39;,  // 접근성을 위한 레이블
          child: ListView(
            padding: EdgeInsets.zero,
            children: &lt;Widget&gt;[
              DrawerHeader(
                decoration: BoxDecoration(
                  color: Colors.blue,
                ),
                child: Text(
                  &#39;Drawer Header&#39;,
                  style: TextStyle(
                    color: Colors.white,
                    fontSize: 24,
                  ),
                ),
              ),
              ListTile(
                leading: Icon(Icons.home),
                title: Text(&#39;Home&#39;),
                selected: _selectedDrawerIndex == 0,
                onTap: () =&gt; _onSelectItem(0),
              ),
              ListTile(
                leading: Icon(Icons.settings),
                title: Text(&#39;Settings&#39;),
                selected: _selectedDrawerIndex == 1,
                onTap: () =&gt; _onSelectItem(1),
              ),
              ListTile(
                leading: Icon(Icons.contacts),
                title: Text(&#39;Contact Us&#39;),
                selected: _selectedDrawerIndex == 2,
                onTap: () =&gt; _onSelectItem(2),
              ),
            ],
          ),
        ),
        body: _getDrawerItemWidget(_selectedDrawerIndex),
      ),
    );
  }
}
</code></pre>
<h2 id="추가-팁">추가 팁</h2>
<ul>
<li><strong>NavigationDrawer 사용 고려:</strong> Material 3를 사용하는 경우 <code>NavigationDrawer</code> 위젯을 고려해 보세요. <code>Drawer</code>와 유사하지만 추가 기능과 스타일을 제공합니다.</li>
</ul>
<h2 id="navigationdrawer로의-업데이트">NavigationDrawer로의 업데이트</h2>
<p>Material 3 버전의 컴포넌트인 <code>NavigationDrawer</code>가 있으며, Material 3로 구성된 애플리케이션에서는 <code>NavigationDrawer</code>가 선호됩니다. <code>NavigationDrawer</code>는 시각적으로 다소 차이가 있으며, <code>Drawer</code> 위젯이 하나의 자식만 가질 수 있는 반면, <code>NavigationDrawer</code> 위젯은 여러 위젯 목록을 가질 수 있습니다. 이 목록은 보통 <code>NavigationDrawerDestination</code> 위젯과 맞춤형 위젯들(예: 헤드라인, 구분선)로 구성됩니다.</p>
<h2 id="관련-자료">관련 자료</h2>
<ul>
<li><a href="https://api.flutter.dev/flutter/material/Scaffold/of.html"><strong>Scaffold.of</strong></a>: 현재 <code>ScaffoldState</code>를 얻어 <code>Drawer</code>의 표시와 애니메이션을 관리합니다.</li>
<li><a href="https://material.io/design/components/navigation-drawer.html"><strong>Material Design Navigation Drawer</strong></a>: Material Design 사양에서의 내비게이션 드로어에 대한 정보.</li>
</ul>
<h2 id="추가-참고-리소스">추가 참고 리소스</h2>
<ul>
<li><a href="https://www.youtube.com/watch?v=WRj86iHihgY&amp;list=PLjxrf2q8roU23XGwz3Km7sQZFTdB996iG&amp;index=95"><strong>Drawer (Flutter Widget of the Week)</strong></a></li>
<li><a href="https://api.flutter.dev/flutter/material/Drawer-class.html"><strong>공식 문서 - Drawer</strong></a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Initializer List]]></title>
            <link>https://velog.io/@hayo_dev/Initializer-List</link>
            <guid>https://velog.io/@hayo_dev/Initializer-List</guid>
            <pubDate>Fri, 05 Jul 2024 02:30:24 GMT</pubDate>
            <description><![CDATA[<h2 id="dart에서-final-변수와-상위-클래스-생성자-초기화-initializer-list">Dart에서 final 변수와 상위 클래스 생성자 초기화: Initializer List</h2>
<p>객체 초기화는 Dart의 중요한 부분이며, 초기화 리스트는 생성자 본문이 실행되기 전에 필드를 초기화하는 데 매우 유용한 기능입니다. 이를 통해 <code>final</code> 변수, 상수, 그리고 상위 클래스의 생성자를 호출할 수 있습니다.</p>
<h2 id="주요-활용도">주요 활용도</h2>
<ul>
<li><strong><code>final</code> 변수 초기화:</strong> <code>final</code> 변수는 선언 후 변경할 수 없기 때문에, 생성자 본문이 실행되기 전에 초기화 리스트를 사용하여 초기화합니다. 이를 통해 <code>final</code> 변수를 안전하고 명확하게 설정할 수 있습니다.</li>
<li><strong>상위 클래스 생성자 호출:</strong> 상속 관계에서 초기화 리스트를 사용하여 상위 클래스의 생성자를 명확하게 호출합니다. 이를 통해 상위 클래스의 필드를 올바르게 초기화할 수 있습니다.</li>
<li><strong>복잡한 초기화 논리 수행:</strong> 필드를 초기화할 때 필요한 복잡한 계산이나 변환을 초기화 리스트에서 수행할 수 있습니다. 이는 생성자 본문을 간결하게 유지하면서 초기화 논리를 명확히 할 수 있게 합니다.</li>
</ul>
<h2 id="코드-예제">코드 예제</h2>
<p>아래 예제는 <code>final</code> 변수를 초기화하고, 상위 클래스의 생성자를 호출하며, 초기화 리스트에서 추가적인 초기화 논리를 수행하는 방법을 보여줍니다.</p>
<h3 id="final-변수-초기화"><code>final</code> 변수 초기화</h3>
<pre><code class="language-dart">class Point {
  final int x;
  final int y;

  Point(int x, int y)
      : x = x,
        y = y;

  @override
  String toString() =&gt; &#39;Point($x, $y)&#39;;
}

void main() {
  Point p = Point(2, 3);
  print(p); // 출력: Point(2, 3)
}
</code></pre>
<h3 id="상위-클래스-생성자-호출">상위 클래스 생성자 호출</h3>
<pre><code class="language-dart">class Person {
  final String name;

  Person(this.name);
}

class Employee extends Person {
  final String position;

  Employee(String name, this.position) : super(name);

  @override
  String toString() =&gt; &#39;Employee(name: $name, position: $position)&#39;;
}

void main() {
  Employee e = Employee(&#39;Alice&#39;, &#39;Developer&#39;);
  print(e); // 출력: Employee(name: Alice, position: Developer)
}
</code></pre>
<h3 id="복잡한-초기화-논리-수행">복잡한 초기화 논리 수행</h3>
<pre><code class="language-dart">class Circle {
  final double radius;
  final double area;

  Circle(double radius)
      : radius = radius,
        area = 3.14 * radius * radius;

  @override
  String toString() =&gt; &#39;Circle(radius: $radius, area: $area)&#39;;
}

void main() {
  Circle c = Circle(5);
  print(c); // 출력: Circle(radius: 5.0, area: 78.5)
}
</code></pre>
<h2 id="추가-팁">추가 팁</h2>
<ul>
<li><strong>명확한 초기화 순서 유지:</strong> 초기화 리스트를 사용하면 생성자 본문이 실행되기 전에 모든 필드를 초기화할 수 있어 초기화 순서를 명확하게 유지할 수 있습니다.</li>
<li><strong>상속 관계에서 초기화 주의:</strong> 상속 관계에서 초기화 리스트를 사용하여 상위 클래스의 생성자를 명확하게 호출함으로써 상위 클래스의 필드를 올바르게 초기화합니다.</li>
</ul>
<h2 id="관련-자료">관련 자료</h2>
<ul>
<li><a href="https://dart.dev/guides/language/language-tour#initializer-list"><strong>Initializer List (Dart Language Tour)</strong></a>: 초기화 리스트에 대한 Dart 언어 가이드.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[extends, implements, with]]></title>
            <link>https://velog.io/@hayo_dev/extends-implements-with</link>
            <guid>https://velog.io/@hayo_dev/extends-implements-with</guid>
            <pubDate>Fri, 05 Jul 2024 02:07:55 GMT</pubDate>
            <description><![CDATA[<h2 id="dart의-클래스-상속-인터페이스-구현-기능-확장-extends-implements-with">Dart의 클래스 상속, 인터페이스 구현, 기능 확장: extends, implements, with</h2>
<p>Dart에서는 클래스 상속, 인터페이스 구현, 믹스인을 통해 코드의 재사용성과 확장성을 높일 수 있습니다. 이 중에서 <code>extends</code>, <code>implements</code>, <code>with</code> 키워드는 각각의 용도와 특성이 있으며, 클래스 계층 구조를 구축하고 다양한 기능을 결합하는 데 사용됩니다. 추상 클래스도 포함하여 설명하겠습니다.</p>
<h2 id="주요-키워드-소개">주요 키워드 소개</h2>
<ul>
<li><strong>extends:</strong> 단일 상속을 통해 클래스의 기능을 확장합니다. 일반 클래스와 추상 클래스 상속도 포함됩니다.</li>
<li><strong>implements:</strong> 인터페이스 역할을 하는 클래스의 메서드와 프로퍼티를 구현합니다.</li>
<li><strong>with:</strong> 다중 상속을 흉내내고, 클래스에 믹스인 기능을 혼합합니다.</li>
</ul>
<h2 id="차이점">차이점</h2>
<ul>
<li><strong>extends:</strong><ul>
<li>목적: 단일 상속을 통해 클래스 확장 (추상 클래스 포함)</li>
<li>사용 방법: 한 클래스가 다른 클래스를 상속받을 때 사용</li>
<li>특징:<ul>
<li>상속받은 클래스의 모든 메서드와 프로퍼티를 물려받음</li>
<li>상속받은 메서드를 재정의할 수 있음</li>
<li>단일 상속만 가능 (하나의 부모 클래스만 가질 수 있음)</li>
</ul>
</li>
<li>예:<ul>
<li>일반 클래스: <code>class Dog extends Animal { ... }</code></li>
<li>추상 클래스: <code>class Dog extends Animal { ... }</code></li>
</ul>
</li>
</ul>
</li>
<li><strong>implements:</strong><ul>
<li>목적: 인터페이스 역할을 하는 클래스의 메서드와 프로퍼티를 구현</li>
<li>사용 방법: 클래스가 인터페이스 역할을 하는 클래스를 구현할 때 사용</li>
<li>특징:<ul>
<li>모든 메서드와 프로퍼티를 재정의해야 함</li>
<li>다중 구현 가능 (여러 인터페이스를 동시에 구현할 수 있음)</li>
</ul>
</li>
<li>예: <code>class Bird implements Flyer { ... }</code></li>
</ul>
</li>
<li><strong>with:</strong><ul>
<li>목적: 다중 상속을 흉내내고, 클래스에 믹스인 기능을 혼합</li>
<li>사용 방법: 클래스가 믹스인을 사용할 때 사용</li>
<li>특징:<ul>
<li>이미 구현된 메서드와 프로퍼티를 재사용 가능</li>
<li>다중 믹스인 사용 가능</li>
<li>믹스인의 메서드와 프로퍼티를 재정의할 수 있음</li>
</ul>
</li>
<li>예: <code>class Bird with Flyer, Walker { ... }</code></li>
</ul>
</li>
</ul>
<h2 id="extends의-두-가지-사용-예제">extends의 두 가지 사용 예제</h2>
<h3 id="일반-클래스-상속">일반 클래스 상속</h3>
<p>일반 클래스를 상속받을 때, 자식 클래스는 부모 클래스의 모든 메서드와 프로퍼티를 물려받고, 이를 재정의하거나 확장할 수 있습니다.</p>
<pre><code class="language-dart">class Animal {
  void breathe() {
    print(&#39;Breathing...&#39;);
  }
}

class Dog extends Animal {
  void bark() {
    print(&#39;Woof! Woof!&#39;);
  }
}

void main() {
  Dog dog = Dog();
  dog.breathe(); // 출력: Breathing...
  dog.bark();    // 출력: Woof! Woof!
}
</code></pre>
<h3 id="추상-클래스-상속">추상 클래스 상속</h3>
<p>추상 클래스를 상속받을 때, 자식 클래스는 추상 클래스의 추상 메서드를 반드시 구현해야 합니다. 이는 부모 클래스에서 정의된 특정 메서드의 구현을 자식 클래스에 강제할 수 있게 합니다.</p>
<pre><code class="language-dart">abstract class Animal {
  void breathe() {
    print(&#39;Breathing...&#39;);
  }
  void makeSound(); // 추상 메서드
}

class Dog extends Animal {
  @override
  void makeSound() {
    print(&#39;Woof! Woof!&#39;);
  }
}

void main() {
  Dog dog = Dog();
  dog.breathe(); // 출력: Breathing...
  dog.makeSound(); // 출력: Woof! Woof!
}
</code></pre>
<h2 id="implements-예제">implements 예제</h2>
<p>인터페이스 역할을 하는 클래스를 구현할 때, 클래스는 해당 인터페이스의 모든 메서드와 프로퍼티를 재정의해야 합니다.</p>
<pre><code class="language-dart">class Flyer {
  void fly(){
      print(&#39;fly&#39;);
  };
  String name;
}

class Bird implements Flyer {
  @override
  void fly() {
    print(&#39;Bird is flying&#39;);
  }

  @override
  String name;
}

void main() {
  Bird bird = Bird();
  bird.name = &quot;Sparrow&quot;;
  bird.fly(); // 출력: Bird is flying
  print(bird.name); // 출력: Sparrow
}
</code></pre>
<h2 id="with-예제">with 예제</h2>
<p>믹스인을 사용하여 여러 클래스에서 공통 기능을 재사용할 수 있습니다. 믹스인은 이미 구현된 메서드와 상태를 포함할 수 있으며, 다중 믹스인 사용이 가능합니다.</p>
<pre><code class="language-dart">mixin FlyerMixin {
  void fly() {
    print(&#39;Flying&#39;);
  }
}

mixin WalkerMixin {
  void walk() {
    print(&#39;Walking&#39;);
  }
}

class MixedBird with FlyerMixin, WalkerMixin {
  void chirp() {
    print(&#39;Chirping&#39;);
  }
}

void main() {
  MixedBird mixedBird = MixedBird();
  mixedBird.fly(); // 출력: Flying
  mixedBird.walk(); // 출력: Walking
  mixedBird.chirp(); // 출력: Chirping
}
</code></pre>
<h2 id="추가-팁">추가 팁</h2>
<ul>
<li><strong>효율적인 상속 구조:</strong> 상속을 남용하지 않고 필요한 경우에만 사용하여 클래스를 단순하고 유지보수하기 쉽게 유지합니다.</li>
<li><strong>다형성 활용:</strong> <code>implements</code>를 사용하여 인터페이스를 구현하면 다양한 클래스가 동일한 인터페이스를 구현할 수 있어 다형성을 쉽게 활용할 수 있습니다.</li>
<li><strong>코드 재사용성:</strong> <code>with</code>를 사용하여 공통 기능을 여러 클래스에서 재사용할 수 있습니다.</li>
</ul>
<h2 id="관련-자료">관련 자료</h2>
<ul>
<li><a href="https://dart.dev/guides/language/language-tour#extending-a-class"><strong>extends</strong></a>: 클래스 상속에 대한 Dart 공식 문서</li>
<li><a href="https://dart.dev/guides/language/language-tour#implementing-interfaces"><strong>implements</strong></a>: 인터페이스 구현에 대한 Dart 공식 문서</li>
<li><a href="https://dart.dev/guides/language/language-tour#adding-features-to-a-class-mixins"><strong>mixin</strong></a>: 믹스인 사용에 대한 Dart 공식 문서</li>
<li><a href="https://dart.dev/guides/language/language-tour#abstract-classes"><strong>abstract</strong></a>: 추상 클래스에 대한 Dart 공식 문서</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[url_launcher]]></title>
            <link>https://velog.io/@hayo_dev/urllauncher</link>
            <guid>https://velog.io/@hayo_dev/urllauncher</guid>
            <pubDate>Thu, 04 Jul 2024 15:02:36 GMT</pubDate>
            <description><![CDATA[<h2 id="flutter에서-url-열기-url_launcher-패키지">Flutter에서 URL 열기: url_launcher 패키지</h2>
<p><code>url_launcher</code> 패키지는 Flutter 애플리케이션에서 브라우저를 열거나 이메일, 전화, 문자 메시지를 보내는 등의 기능을 제공합니다. 이 패키지를 사용하면 다양한 URL 스킴을 처리할 수 있습니다.</p>
<h2 id="주요-특징">주요 특징</h2>
<ol>
<li><strong>브라우저에서 URL 열기</strong>:<ul>
<li>주어진 URL을 기본 브라우저에서 엽니다. http, https와 같은 scheme을 처리할 수 있습니다.</li>
</ul>
</li>
<li><strong>전화 걸기</strong>:<ul>
<li>전화 번호로 전화를 겁니다. tel scheme을 사용합니다.</li>
</ul>
</li>
<li><strong>이메일 보내기</strong>:<ul>
<li>이메일 클라이언트를 열어 이메일을 보냅니다. mailto scheme을 사용합니다.</li>
</ul>
</li>
<li><strong>문자 메시지 보내기</strong>:<ul>
<li>문자 메시지 앱을 열어 메시지를 보냅니다. sms scheme을 사용합니다.</li>
</ul>
</li>
</ol>
<h2 id="설치">설치</h2>
<p><code>pubspec.yaml</code> 파일에 <code>url_launcher</code>를 종속성으로 추가합니다.</p>
<pre><code class="language-yaml">dependencies:
  flutter:
    sdk: flutter
  url_launcher: ^6.0.9
</code></pre>
<h2 id="사용-방법">사용 방법</h2>
<h3 id="url-열기">URL 열기</h3>
<pre><code class="language-dart">import &#39;package:flutter/material.dart&#39;;
import &#39;package:url_launcher/url_launcher.dart&#39;;

final Uri _url = Uri.parse(&#39;&lt;https://flutter.dev&gt;&#39;);

void main() =&gt; runApp(
      const MaterialApp(
        home: Material(
          child: Center(
            child: ElevatedButton(
              onPressed: _launchUrl,
              child: Text(&#39;Show Flutter homepage&#39;),
            ),
          ),
        ),
      ),
    );

Future&lt;void&gt; _launchUrl() async {
  if (!await launchUrl(_url)) {
    throw Exception(&#39;Could not launch $_url&#39;);
  }
}
</code></pre>
<h3 id="전화-걸기">전화 걸기</h3>
<pre><code class="language-dart">void _makePhoneCall() async {
  const phoneNumber = &#39;tel:+123456789&#39;;
  if (await canLaunch(phoneNumber)) {
    await launch(phoneNumber);
  } else {
    throw &#39;Could not launch $phoneNumber&#39;;
  }
}
</code></pre>
<h3 id="이메일-보내기">이메일 보내기</h3>
<pre><code class="language-dart">void _sendEmail() async {
  final Uri emailUri = Uri(
    scheme: &#39;mailto&#39;,
    path: &#39;example@example.com&#39;,
    queryParameters: {
      &#39;subject&#39;: &#39;Example Subject &amp; Symbols are allowed!&#39;,
      &#39;body&#39;: &#39;This is an example email body&#39;
    }
  );

  if (await canLaunch(emailUri.toString())) {
    await launch(emailUri.toString());
  } else {
    throw &#39;Could not launch $emailUri&#39;;
  }
}
</code></pre>
<h3 id="문자-메시지-보내기">문자 메시지 보내기</h3>
<pre><code class="language-dart">void _sendSMS() async {
  const smsUri = &#39;sms:+123456789&#39;;
  if (await canLaunch(smsUri)) {
    await launch(smsUri);
  } else {
    throw &#39;Could not launch $smsUri&#39;;
  }
}
</code></pre>
<h2 id="주의사항-및-팁">주의사항 및 팁</h2>
<ul>
<li><p><strong>URL 유효성 검사</strong>: <code>launch</code> 메소드를 호출하기 전에 항상 <code>canLaunch</code>를 사용하여 URL이 유효한지 확인합니다. 유효하지 않은 URL을 열려고 하면 예외가 발생합니다.</p>
<pre><code class="language-dart">  if (await canLaunch(url)) {
    await launch(url);
  } else {
    // URL이 유효하지 않으면 예외 처리
  }
</code></pre>
</li>
<li><p><strong>플랫폼 차이</strong>: 각 플랫폼(Android, iOS)마다 지원하는 스킴이 다를 수 있습니다. 각 스킴이 해당 플랫폼에서 지원되는지 확인해야 합니다.</p>
</li>
<li><p><strong>iOS 권한 설정</strong>: iOS에서는 전화 걸기, SMS 보내기 등의 기능을 사용하려면 Info.plist 파일에 권한 설정이 필요합니다.</p>
<pre><code class="language-xml">  &lt;key&gt;NSAppTransportSecurity&lt;/key&gt;
  &lt;dict&gt;
    &lt;key&gt;NSAllowsArbitraryLoads&lt;/key&gt;
    &lt;true/&gt;
  &lt;/dict&gt;
</code></pre>
</li>
<li><p><strong>Android 권한 설정</strong>: Android에서는 전화 걸기 등의 기능을 사용하려면 AndroidManifest.xml 파일에 권한 설정이 필요합니다.</p>
<pre><code class="language-xml">  &lt;uses-permission android:name=&quot;android.permission.CALL_PHONE&quot;/&gt;
</code></pre>
</li>
<li><p><strong>URL 인코딩</strong>: URL은 특히 공백이나 특수 문자가 포함될 때 올바르게 인코딩되어야 합니다. <code>Uri</code> 클래스를 사용하여 자동으로 처리할 수 있습니다.</p>
</li>
</ul>
<h2 id="주요-활용도">주요 활용도</h2>
<ul>
<li><strong>웹 페이지 열기</strong>: 앱에서 특정 웹 페이지로 이동하는 링크를 제공할 때 사용합니다.</li>
<li><strong>전화 걸기</strong>: 앱 내에서 전화 걸기 기능을 제공할 때 사용합니다.</li>
<li><strong>이메일 보내기</strong>: 고객 지원이나 문의 메일을 보내는 기능을 제공할 때 사용합니다.</li>
<li><strong>문자 메시지 보내기</strong>: 문자 메시지를 통해 사용자와 소통할 때 사용합니다.</li>
</ul>
<h2 id="관련-자료">관련 자료</h2>
<ul>
<li><a href="https://pub.dev/packages/url_launcher"><strong>공식문서 - Flutter url_launcher package</strong></a></li>
<li><a href="https://www.youtube.com/watch?v=lkF0TQJO0bA&amp;list=PLjxrf2q8roU23XGwz3Km7sQZFTdB996iG&amp;index=157"><strong>url_launcher (Flutter Widget of the Week)</strong></a></li>
</ul>
]]></description>
        </item>
    </channel>
</rss>