<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>sht-3756.log</title>
        <link>https://velog.io/</link>
        <description>안녕하세요</description>
        <lastBuildDate>Fri, 02 Jun 2023 01:56:03 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>sht-3756.log</title>
            <url>https://velog.velcdn.com/cloudflare/sht-3756/7083a6d4-3f42-4b8f-9f87-fb027790659b/social_profile.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. sht-3756.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/sht-3756" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[Flutter] 클릭을 방지하는 위젯]]></title>
            <link>https://velog.io/@sht-3756/Flutter-%ED%81%B4%EB%A6%AD%EC%9D%84-%EB%B0%A9%EC%A7%80%ED%95%98%EB%8A%94-%EC%9C%84%EC%A0%AF</link>
            <guid>https://velog.io/@sht-3756/Flutter-%ED%81%B4%EB%A6%AD%EC%9D%84-%EB%B0%A9%EC%A7%80%ED%95%98%EB%8A%94-%EC%9C%84%EC%A0%AF</guid>
            <pubDate>Fri, 02 Jun 2023 01:56:03 GMT</pubDate>
            <description><![CDATA[<h1 id="클릭을-방지하는-위젯이-뭐-없을까">클릭을 방지하는 위젯이 뭐 없을까?</h1>
<p>짧은 기간안에 데이터를 전송하는 버튼을 연타하는 경우가 생길 상황을 우려해서 Debounce 와 button display 중 둘 중 하나를 고민을 하다가,</p>
<p>디바운스는 프로젝트에 적응한 다음 버튼 함수에다가 디바운스를 거는것보단 데이터 fetcing 하는 함수들 모두 범용성이 있게 작업을 해보자! 라는 생각을 가졌고,</p>
<p>최종적으론 편리하게 클릭을 방지하는 위젯을 찾아보게 되었다.</p>
<h1 id="flutter-에서-위젯-터치-이벤트-무시하는-방법-뚜둔">Flutter 에서 위젯 터치 이벤트 무시하는 방법!! 뚜둔</h1>
<h2 id="방법-1-">방법 1 )</h2>
<h3 id="ignorepointer">IgnorePointer()</h3>
<p>[코드]</p>
<pre><code class="language-dart">IgnorePointer(
    ignoring: true, // Boolean 
    child: ElevatedButton(
            onPressed: () {print(&#39;클릭!&#39;)}, 
            child: Text(&#39;버튼&#39;),
     ),
)</code></pre>
<p>[설명]
IgnorePointer() 위젯의 속성 ignoring 이 true 라면?
child 의 터치 이벤트를 무시하고,
IgnorePointer() 위젯의 속성 ignoring 이 false 라면?
child 의 터치 이벤트를 허용한다.</p>
<h2 id="방법-2-">방법 2 )</h2>
<h3 id="absorbpointer">AbsorbPointer()</h3>
<p>[코드]</p>
<pre><code class="language-dart">AbsorbPointer(
    absorbing: true, // Boolean 
    child: ElevatedButton(
            onPressed: () {print(&#39;클릭!&#39;)}, 
            child: Text(&#39;버튼&#39;),
     ),
)</code></pre>
<p>[설명]
AbsorbPointer() 위젯의 속성 absorbing 이 true 라면?
child 의 터치 이벤트를 흡수하고,
AbsorbPointer() 위젯의 속성 absorbing 이 false 라면?
child 의 터치 이벤트를 흡수하지 않는다.</p>
<h2 id="그렇다면-둘의-차이점은-">그렇다면 둘의 차이점은 ?</h2>
<p>둘의 사용법과 액션은 매우 비슷하다못해 똑같다. </p>
<p><a href="https://www.woolha.com/tutorials/flutter-using-ignorepointer-absorbpointer-examples">https://www.woolha.com/tutorials/flutter-using-ignorepointer-absorbpointer-examples</a></p>
<p>이 부분은 코드와 할께 잘 생각해봐야한다.</p>
<p>버튼들을 따로 쓰면 당연히 같은 동작 처럼 보이겠지만, Stack 위에서 쓰면 동작이 다른것이 확실하게 보인다.
Ignore 은 무시하고 밑의 레이어를 클릭가능하고 
Absorb 는 흡수하고 밑의 레이어를 클릭 못하게 한다.</p>
<pre><code>//Ignore =&gt; 최상위 alert() 실행되고 맨 아래레이어 alert() 도 실행된다. (최초 클릭시 IgnorePointer 가 true 가 되어  재차 클릭시 맨아래 레이어 버튼을 클릭할 수있다.) 
Stack(
    children: [
        ElevatedButton(onPressed: () {
            alert(&#39;맨아래 레이어 클릭&#39;)
            }, child: Text(&#39;맨아래 레이어&#39;),
        ),
        IgnorePointer(
            ignoring: _ignoring,
            onPressed: () {
                alert(&#39;최상위 레이어 클릭&#39;)
                _ignoring = true;
            }
        ),        
    ]
) </code></pre><pre><code class="language-dart">//Absorb =&gt; 최상위 alert() 만 실행된다. (최초 클릭시 AbsorbPointer 가 true 가 되어 맨아래 레이어 버튼을 클릭 안된다. AbsorbPointer 가 최상위에서 클릭 흡수하기때문!)
Stack(
    children: [
        ElevatedButton(onPressed: () {
            alert(&#39;맨아래 레이어 클릭&#39;)
            }, child: Text(&#39;맨아래 레이어&#39;),
        ),
        AbsorbPointer(
            Absorbing: _absorbing,
            onPressed: () {
                alert(&#39;최상위 레이어 클릭&#39;)
                _absorbing = true;
            }
        ),        
    ]
) </code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring-error] 같은 포트가 실행중일 때]]></title>
            <link>https://velog.io/@sht-3756/Spring-error-%EA%B0%99%EC%9D%80-%ED%8F%AC%ED%8A%B8%EA%B0%80-%EC%8B%A4%ED%96%89%EC%A4%91%EC%9D%BC-%EB%95%8C</link>
            <guid>https://velog.io/@sht-3756/Spring-error-%EA%B0%99%EC%9D%80-%ED%8F%AC%ED%8A%B8%EA%B0%80-%EC%8B%A4%ED%96%89%EC%A4%91%EC%9D%BC-%EB%95%8C</guid>
            <pubDate>Sun, 28 May 2023 12:25:00 GMT</pubDate>
            <description><![CDATA[<pre><code>Web server failed to start. Port 8080 was already in use.</code></pre><p>해당 포트 실행되는 것 확인 </p>
<pre><code>lsof -i tcp:8080</code></pre><p><img src="https://velog.velcdn.com/images/sht-3756/post/f841280f-f544-4c40-9310-f569910ef793/image.png" alt=""></p>
<p>해당 포트 죽이기</p>
<pre><code>sudo kill -9 PID </code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[정렬 알고리즘 (Quick sort)]]></title>
            <link>https://velog.io/@sht-3756/%EC%A0%95%EB%A0%AC-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-quick-sort</link>
            <guid>https://velog.io/@sht-3756/%EC%A0%95%EB%A0%AC-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-quick-sort</guid>
            <pubDate>Sat, 20 May 2023 14:00:41 GMT</pubDate>
            <description><![CDATA[<h1 id="sort">Sort</h1>
<p>퀵 정렬 (Quick Sort 정렬)</p>
<p>정렬하는 방법에는 여러가지가 있다. </p>
<p>선택, 버블, 삽입, 셸, 합병 등~ </p>
<p>그 중 퀵은 다른 알고리즘에 비해 자료들을 서로 비교하고 교환하는 횟수가 적다는 장점이 있다. (이는 수향 시간 단축으로 이어진다.) ⇒ 대용량 데이터베이스 처리 시스템 등 이용!</p>
<h2 id="quick-sort">Quick Sort</h2>
<p>무작위의 수가 있다고 가정하면, 4개의 레이블이 있어야한다.</p>
<p><img src="https://velog.velcdn.com/images/sht-3756/post/1487a090-64f6-49fe-ad08-44a843e87b40/image.png" alt=""></p>
<p>퀵 정렬 알고리즘 개념 요약</p>
<p>퀵 정렬은 불안정 정렬이며, 다른 원소와의 비교만으로 정렬을 수행하는 비교 정렬에 속한다.</p>
<p>분할 정복 알고리즘의 하나로, 평균적으로 매우 빠른 수행 속도를 자랑하는 정렬 방법이다. (Merge sort = 합병 정렬)과 달리 퀵 정렬은 리스트를 비균등하게 분할한다.</p>
<p>분할 정복 방법</p>
<p>문제를 작은 2개의 문제로 분리하고 문제를 작은 2개의 문제로 분리하고 해결한다음, 결과를 모아서 원래의 문제를 해결하는 방식이다.</p>
<p>분할 정복방법은 대개 순환 호출을 이용하여 구현한다.</p>
<p>과정 설명</p>
<ol>
<li>리스트 안에 있는 한 요소 선택한다. (이것을 피벗이라고 한다.)</li>
<li>피벗을 기준으로 작은것은 모두 왼쪽으로, 큰 것은 모두 오른쪽으로 이동시킨다.</li>
<li>피벗을 제외한 왼쪽리스트, 오른쪽 리스트를 다시 정렬한다.<ol>
<li>분할된 부분 리스트에 대해 순환 호출을 이용해 정렬을 반복한다.</li>
<li>부분 리스트에서도 다시 피벗을 정하고 기준으로 2개의 부분 리스트로 나누는 과정을 반복한다.</li>
</ol>
</li>
<li>부분 리스트들이 더이상 분할이 불가능할때까지 반복!<ol>
<li>리스트의 크기가 0 이나 1이 될때까지 반복한다!</li>
</ol>
</li>
</ol>
<h2 id="퀵-정렬-알고리즘-구체적인-개념">퀵 정렬 알고리즘 구체적인 개념!</h2>
<p><img src="https://velog.velcdn.com/images/sht-3756/post/6bcef030-c667-4d27-b087-6e900e9a9b65/image.png" alt=""></p>
<p>하나의 리스트를 피벗 기준으로  </p>
<p>퀵 정렬은 3가지 단계로 이뤄진다.</p>
<ol>
<li>분할 <ul>
<li>입력 배열을 피벗 기준으로 비균등하게 2개의 부분 배열로 분할한다.(피벗기준으로 왼, 오른쪽으로!)</li>
</ul>
</li>
<li>정복<ul>
<li>부분 배열을 정렬한다. 부분 배열의 크기가 충분히 작지 않으면 순환 호출을 이용해 다시 분할 정복 방법을 적용한다. (다시 1번(분할)으로)</li>
</ul>
</li>
<li>결합<ul>
<li>정렬된 부분 배열들을 하나의 배열에 합병한다.</li>
<li>순환 호출이 한번 진행될 때마다 최소한 하나의 피벗은 최종적으로 위치가 정해지므로, 이 알고리즘은 반드시 끝난다는 것을 보장할 수 있다.</li>
</ul>
</li>
</ol>
<h2 id="quick-sort-알고리즘의-특징">quick sort 알고리즘의 특징</h2>
<ul>
<li><p>장점</p>
<ul>
<li>속도가 빠르다. 시간 복잡도 O(nlog2n) 를 가지는 다른 정렬 알고리즘과 비교해도 가장 빠르다.</li>
<li>추가 메모리 공간을 필요로 하지 않는다. 퀵정렬은 O(log n) 만큼의 메모리를 핑요로 한다.</li>
</ul>
</li>
<li><p>단점</p>
<ul>
<li>정렬된 리스트에 대해서는 퀵정렬의 불균형 분할에 의해 오히려 수행 시간이 더 많이 걸린다.</li>
<li>퀵정렬의 불균형 분할을 방지하기 위해 피벗을 선택할때 더욱 리스트를 균등하게 분할할 수 있는 데이터를 선택한다.<ul>
<li>ex ) 리스트 내의 몇 개의 데이터 중에서 크기순으로 중간 값을 피벗으로 선택한다.</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="시간-복잡도">시간 복잡도</h2>
<p>와 지금은 봐도 모르겠다…</p>
<h3 id="최선의-경우">최선의 경우</h3>
<p><strong>T(n) = O(nlog2n)</strong></p>
<ul>
<li>비교횟수</li>
</ul>
<p><img src="https://velog.velcdn.com/images/sht-3756/post/35b78024-ec12-46d2-829d-216535b6c019/image.png" alt=""></p>
<ul>
<li><p>순환 호출의 깊이</p>
<p>  레코드의 개수 n이 2의 거듭제곱이라고 가정(n=2^k)했을 때, n=2^3의 경우, 2^3 -&gt; 2^2 -&gt; 2^1 -&gt; 2^0 순으로 줄어들어 순환 호출의 깊이가 3임을 알 수 있다. 이것을 일반화하면 n=2^k의 경우, k(k=log₂n)임을 알 수 있다.
  k=log₂n</p>
</li>
<li><p>각 순환 호출 단계의 비교 연산</p>
<p>  각 순환 호출에서는 전체 리스트의 대부분의 레코드를 비교해야 하므로 평균 n번 정도의 비교가 이루어진다.
  평균 n번</p>
<p>  순환 호출의 깊이 * 각 순환 호출 단계의 비교 연산 = nlog₂n</p>
</li>
<li><p>이동 횟수</p>
<ul>
<li>비교 횟수보다 적으므로 무시할 수 없다.</li>
</ul>
</li>
</ul>
<h3 id="최악의-경우">최악의 경우</h3>
<p>리스트가 계속 불균형하게 나눠지는 경우 (이미, 정렬된 리스트에 대해 퀵 정렬을 실행하는 경우!)</p>
<ul>
<li>비교 횟수</li>
</ul>
<p><img src="https://velog.velcdn.com/images/sht-3756/post/c0abd53f-0236-43b4-b077-8600af022de0/image.png" alt=""></p>
<ul>
<li><p>순환 호출의 깊이</p>
<ul>
<li>레코드의 개수 n 이 2의 거듭 제곱이라고 가정 했을때, 순환호출의 깊이는 n임을 알 수 있다.</li>
<li>n</li>
</ul>
</li>
<li><p>각 순환 호출  단계의 비교 연산</p>
</li>
<li><p>이동 횟수</p>
</li>
<li><p>평균</p>
<p>  평균 T(n) = O(nlog₂n)
  시간 복잡도가 O(nlog₂n)를 가지는 다른 정렬 알고리즘과 비교했을 때도 가장 빠르다.
  퀵 정렬이 불필요한 데이터의 이동을 줄이고 먼 거리의 데이터를 교환할 뿐만 아니라, 한 번 결정된 피벗들이 추후 연산에서 제외되는 특성 때문이다.</p>
</li>
</ul>
<h2 id="정렬-알고리즘-시간복잡도-비교">정렬 알고리즘 시간복잡도 비교</h2>
<p><img src="https://velog.velcdn.com/images/sht-3756/post/0e6b84ee-3b79-4441-927d-9f57ad1f5a97/image.png" alt=""></p>
<blockquote>
<p>출처 : <a href="https://gmlwjd9405.github.io/2018/05/10/algorithm-quick-sort.html">https://gmlwjd9405.github.io/2018/05/10/algorithm-quick-sort.html</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[과제 2) 정렬을 사용해보자!(Sort 중 quick)]]></title>
            <link>https://velog.io/@sht-3756/%EA%B3%BC%EC%A0%9C-2-%EC%A0%95%EB%A0%AC%EC%9D%84-%EC%82%AC%EC%9A%A9%ED%95%B4%EB%B3%B4%EC%9E%90</link>
            <guid>https://velog.io/@sht-3756/%EA%B3%BC%EC%A0%9C-2-%EC%A0%95%EB%A0%AC%EC%9D%84-%EC%82%AC%EC%9A%A9%ED%95%B4%EB%B3%B4%EC%9E%90</guid>
            <pubDate>Mon, 15 May 2023 13:00:29 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>퀵정렬에 대해 정리한 게시글!</p>
</blockquote>
<p><a href="https://velog.io/@sht-3756/%EC%A0%95%EB%A0%AC-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-quick-sort">퀵 정렬이란? </a></p>
<h1 id="문제">문제</h1>
<p><span style="color : orange">퀵정렬</span>을 사용해서 내가 원하는 값의 인덱스를 출력해내라!</p>
<h2 id="조건">조건</h2>
<p>입력 값을 총 <span style="color : blue">두번</span> 받는다. 
1번 : 내가 찾고자하는 값 입력
2번 : 무작위의 숫자값 입력(배열로 담는다.)</p>
<h2 id="해결-방법-생각">해결 방법 (생각)</h2>
<p>입력 값 두번 받고, 하나의 피벗을 정해서 작은 것은 왼쪽, 큰것은 오른쪽으로 간다. </p>
<p>맘대로 숫자를 입력해서 입력한 숫자를 array 로 입력받는다
내가 찾고자 하는 숫자를 입력한다. 
그 방법을 quick sort 하고 정렬된 값에서 찾기!</p>
<p>정렬하는 그 과정에서 전에 찾고자 하는 숫자의 위치의 인덱스를 먼저 출력하고 정렬하도록 하자!</p>
<p>찾고자 하는 숫자의 위치를 인덱스로 출력해라
숫자 를 맘대로 입력 해서 array로 </p>
<p>for 문과 if 문을 이용해서 작성을 해봐라!</p>
<p>quick sort 로 만들어서 코드를 만들어봐라</p>
<pre><code class="language-js">  // 입력 값 1 : 찾고자하는 값
  var inputA = 3; 
  // 입력 값 2 : 배열을 입력한다.
  var arr = [3, 4, 2, 5, 1];

  // 피벗 변수 선언 (우선 제일 낮은 부분)
  var pivot = arr[0];

  // 피벗 보다 높은 배열
  var arrayOfHigh = [];

  // 피벗 보다 낮은 배열
  var arrayOfLow = [];

  // 새로운 피벗 배열
  var arrayOfPivot = [];


  // 퀵정렬된 배열
  var sorted = [];

  // 퀵정렬
    // 입력한 배열의 크기만큼 반복한다. 5의 크기만큼
  for(let i = 0; i &lt; arr.length; i++){  
    // 만약에 피벗보다 작으면 왼쪽 배열 push
    if(pivot &lt; arr[i + 1]) {
      arrayOfLow.push(arr[i + 1]);
    } else if(pivot &gt; arr[i + 1]){
      // 피벗보다 크면 오른쪽 배열 push
      arrayOfHigh.push(arr[i + 1]);
    } else {
      arrayOfPivot.push(arr[i + 1]);
    }
  }

 // quickSort 저장
sorted = arrayOfLow.concat(arrayOfPivot).concat(arrayOfHigh);

// 퀵 정렬 출력
console.log(sorted);
// 입력한 값의 인덱스 값 출력
console.log(sorted.indexOf(inputA));


</code></pre>
<h1 id="피드백">피드백</h1>
<p>문제의 접근을 조금 더 깊게 생각해야한다.</p>
<p>피벗된 왼쪽, 오른쪽 배열도 다시 퀵 정렬을 해줘야하는데, 그 부분에 대한 코드는 없다.</p>
<p>재귀함수도 물론 들어가야하고, 2중 for문을 사용해야지 완벽한 퀵정렬 코드가 가능하다.</p>
<h2 id="피드백-후-코드-작성">피드백 후 코드 작성</h2>
<p>작성중..</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[과제 1 ) 입력 값에 대한 연속성값 더하기!]]></title>
            <link>https://velog.io/@sht-3756/%EA%B3%BC%EC%A0%9C-1-%EC%9E%85%EB%A0%A5-%EA%B0%92%EC%97%90-%EB%8C%80%ED%95%9C-%EC%97%B0%EC%86%8D%EC%84%B1%EA%B0%92-%EB%8D%94%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@sht-3756/%EA%B3%BC%EC%A0%9C-1-%EC%9E%85%EB%A0%A5-%EA%B0%92%EC%97%90-%EB%8C%80%ED%95%9C-%EC%97%B0%EC%86%8D%EC%84%B1%EA%B0%92-%EB%8D%94%ED%95%98%EA%B8%B0</guid>
            <pubDate>Mon, 15 May 2023 08:20:11 GMT</pubDate>
            <description><![CDATA[<h2 id="과제-1-230515230516">과제 1 (23.05.15~23.05.16)</h2>
<p>과제를 진행하겠다.</p>
<p>개발언어 JAVA  </p>
<hr>
<h3 id="문제-1번">문제 1번</h3>
<p>입력을 두번 진행할 것이다.</p>
<p>입력 1 =&gt; 숫자 </p>
<p>입력 2 =&gt; 연속된 숫자 (1~ 100자리의 숫자)</p>
<p>출력 =&gt; 연속된 숫자를 입력 1 의 숫자 만큼 더한다.</p>
<hr>
<p>예시 </p>
<pre><code>예시 1 )
 입력 1 : 2
 입력 2 : 3456789
 출력 : 3+4 = 7 
예시 2 ) 
 입력 1 : 4
 입력 2 : 891204
 출력 : 8 + 9 +1 + 2 = 20; </code></pre><p>코드
kotlin</p>
<pre><code class="language-kotlin">
import java.util.Scanner

fun main() {
    val scanner = Scanner(System.`in`)
    // 총합 값
    var sum: Int = 0;

    println(&quot;첫번째 숫자를 입력하세요 : &quot;)
    val number = scanner.nextInt()

    println(&quot;두번째 숫자를 입력하세요(첫번째 보다 큰자리 숫자 입력 필수!) :&quot;)    
    val number2 = scanner.next().length

    for(i in 0..(number1 - 1)) {
        sum += number2[i]
    }  

    println(&quot;결과는 : $sum&quot;);
}

</code></pre>
<p>js </p>
<pre><code class="language-js">// 총합
let sum = 0;
// 첫번째 숫자
let num1 = 3;
// 두번째 숫자 (연속된 숫자)
let num2 = 12345;
// String 형변환
let parsedNum2 = String(num2);

for(let i =0; i &lt; num1; i++) {        
  let parsedInt = parseInt(parsedNum2[i]);
  sum += parsedInt;
}

console.log(sum);
</code></pre>
<p>java</p>
<pre><code class="language-java">public static void main() {
    Scanner scanner = new Scanner(System.in);
    int sum = 0;
    int num1 = scanner.nextInt();
    int num2 = scanner.nextString();


    for (int i =0; i &lt; num1 - 1; i++) {
        int converted = num2[i].nextInt();
        sum += converted;
    }

    System.print.out(&quot;결과는 : $sum&quot;);

}
</code></pre>
<h2 id="피드백">피드백</h2>
<p>코드를 해결하는 법을 확인하는 것도 있었지만, 제일 중요한 점은 타입의 중요성과 데이터를 저장하는 단위!에 대한 것을 생각하며 개발을 진행해야한다는 점이다.</p>
<p><img src="https://velog.velcdn.com/images/sht-3756/post/44c409e0-e617-4d42-8f49-a7b550c3a00f/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[코틀린 환경 만들기]]></title>
            <link>https://velog.io/@sht-3756/kotlin-%EA%B0%9C%EB%B0%9C%ED%99%98%EA%B2%BD-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@sht-3756/kotlin-%EA%B0%9C%EB%B0%9C%ED%99%98%EA%B2%BD-%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Sun, 07 May 2023 14:30:36 GMT</pubDate>
            <description><![CDATA[<h1 id="코틀린-개발-세팅하기">코틀린 개발 세팅하기</h1>
<p>PC 에 간단하게 코틀린 코드를 실행할 일이 있다.
개인 PC 에 코틀린 설치 및 실행해보도록 하겠다.</p>
<p>개인적으로 homebrew 를 사용해 설치해주겠다!</p>
<hr>
<h2 id="준비">준비</h2>
<p>JVM 을 위한 jdk 를 설치해줘야한다.</p>
<h3 id="자바-설치">자바 설치</h3>
<p>자바 버전 확인
<code>java --version</code> </p>
<p>만약? 없다면?
jdk 11 버전을 설치해주자!</p>
<pre><code>brew tap AdoptOpenJDK/openjdk
brew install --cask adoptopenjdk11</code></pre><h3 id="코틀린-설치">코틀린 설치</h3>
<p><code>brew install kotlin</code></p>
<p>코틀린 버전 확인
<code>kotlinc --version</code></p>
<h3 id="코틀린-테스트-진행">코틀린 테스트 진행</h3>
<p><code>kotlinc-jvm</code></p>
<p>쉘 에서 빠져나오기</p>
<p><code>:quit</code></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[SSL 과 HTTP/HTTPS 설명]]></title>
            <link>https://velog.io/@sht-3756/ssl-http-https-%EC%84%A4%EB%AA%85</link>
            <guid>https://velog.io/@sht-3756/ssl-http-https-%EC%84%A4%EB%AA%85</guid>
            <pubDate>Mon, 01 May 2023 14:16:44 GMT</pubDate>
            <description><![CDATA[<h2 id="ssl-과-tls-은-무엇인가">SSL 과 TLS 은 무엇인가?</h2>
<p>SSL (Secura Socket Layer)은 간단하게 보여지는 데이터와 보내는 데이터들을 암호화 하는 보안 기능을 갖고있는 인증서! 라고 보면된다.</p>
<p>TSL (Transport Layer Security) 은 SSL 의 업그레이드 버전이다.<br>둘을 따로 구분하지 않고 일반적으로 SSL 이라고 부른다.</p>
<p>우리는 보통 호스팅/도메인 업체에서 SSL 을 산다는 것을 의미한다.</p>
<p>네이버 인증서 확인 
<img src="https://velog.velcdn.com/images/sht-3756/post/4f719cc1-6cfe-4594-8ce4-9203296e8bf7/image.png" alt=""></p>
<p>이렇게 SSL 인증서를 받은 웹페이지는 <span style="color: orange">https</span> 로 표시가 된다.
<img src="https://velog.velcdn.com/images/sht-3756/post/6f30322f-0b61-4065-84fc-aec9f39338b7/image.png" alt=""></p>
<h2 id="https-와-http-의-차이점은-">HTTPS 와 HTTP 의 차이점은 ?</h2>
<blockquote>
<p>HTTP + SSL = HTTPS 
HTTPS 는 <span style="color: orange">H</span>yper<span style="color: orange">t</span>ext <span style="color: orange">T</span>ransfer <span style="color: orange">P</span>rotocol Over <span style="color: orange">S</span>ecure Socket Layer</p>
</blockquote>
<p>데이터 전송 기능의 보안을 강화한 전송 기능이라고 보면 된다. 
=&gt; SSL 인증서를 가진 도메인만이 https:// 로 시작한다. </p>
<h3 id="차이점">차이점</h3>
<ol>
<li>https 적용 되지 않은 도메인은 사용자 브라우저에 사용했던 이미지처럼 &#39;주의 요함&#39; 같은 경고 메세지 표시하고, 개인정보에 취약할 수 있다. </li>
<li>검색엔진에서 도메인 평가 시, 구글에서는 https 적용 유/무는 중요요소중 하나이다.
대부분이 도메인이 https 를 사용하기 때문에 확실하게 SSL 을 적용해주는 것이 중요하다.</li>
</ol>
<h2 id="유료-vs-무료-ssl-인증서">유료 vs 무료 SSL 인증서</h2>
<p>기업이 아닌, 일반적인 경우 는 무료 SSL 사용하면 된다.
SSL 갱신 주기와 고객지원의 유/무라고 보면된다.</p>
<p>당연히 무료는 기간이 짧고 유료는 관리를 해주기 때문에 기간이 길다. 
기업에서 사용하면 당연히 유료 SSL 인증서를 발급받아서 사용하도록 하자! </p>
<blockquote>
<p>너무 깊이 알 필요없다. 우리는 그냥 SSL 이 무엇인지와 그에 따른 HTTP/HTTPS 의 차이만 알면 될뿐!</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[도메인]]></title>
            <link>https://velog.io/@sht-3756/%EB%8F%84%EB%A9%94%EC%9D%B8-%EA%B4%80%EB%A0%A8-%EC%84%A4%EB%AA%85</link>
            <guid>https://velog.io/@sht-3756/%EB%8F%84%EB%A9%94%EC%9D%B8-%EA%B4%80%EB%A0%A8-%EC%84%A4%EB%AA%85</guid>
            <pubDate>Wed, 26 Apr 2023 14:45:08 GMT</pubDate>
            <description><![CDATA[<h2 id="도메인의-이름과-구조">도메인의 이름과 구조</h2>
<blockquote>
<p>https:// <a href="http://www.naver.com">www.naver.com</a></p>
</blockquote>
<p>naver.com =&gt; 도메인 이름</p>
<p>naver =&gt; SLD
com =&gt; TLD</p>
<p>URL 과 Domain 은 혼용되어 사용되고 헷갈리지만, 
도메인은 &#39;https://&#39;, &#39;www.&#39; 을 <span style="color: orange">제외한 나머지</span>를 의미한다.</p>
<h3 id="도메인에서도-level-이-있다">도메인에서도 Level 이 있다?</h3>
<blockquote>
<p>도메인 주소에서 우측 부터 1차, 2차 도메인 숫자를 센다!</p>
</blockquote>
<blockquote>
<p>그렇다면, .com 이 1차 도메인, naver.com 2 차 도메인 이다. </p>
</blockquote>
<p>TLD - Top Level Domain (1 차 도메인)</p>
<p>SLD - Second Level Domain (2 차 도메인)</p>
<p>3차/ 4차 도메인영역도 있지만, 단순하게 콤마를 기준으로 위치를 나타내는 정도이다. 의미는 없다.</p>
<p><img src="https://velog.velcdn.com/images/sht-3756/post/4f26e902-b65e-438a-919f-49d443439e0d/image.png" alt=""></p>
<p>흔히, 도메인을 구매해 도메인주소를 만들어내 유저에게 홈페이지를 만들어주는 페이지 (가비아, 아임웹, 후이즈) 같은 경우, TLD는 <code>.com / .kr</code> 같이 고정 되어있고, SLD 는 원하는 대로 설정을 해주는 것이다.</p>
<h2 id="최상위-도메인의-종류">최상위 도메인의 종류</h2>
<blockquote>
<p>국가 도메인 (ccTLD) vs 일반 도메인 (gTLD)</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/sht-3756/post/652f1f90-1622-4d36-bea0-f3d3e719af17/image.png" alt=""></p>
<p>최상위 도메인도 형태에 따라 국가 와 일반으로 나뉜다.
쉽게 국가 도메인은 국가의 특정 조직이 관리를 하고,
일반 도메인은 일반 회사가 관리하는 최상위 도메인이다.</p>
<p>대표적인 국가 도메인으로는 (KISA가 가 관리하는).kr , 일반 (Verisign 가 관리하는) .com, .net, .org 도메인이 있다.
<img src="https://velog.velcdn.com/images/sht-3756/post/8996c8bd-7dee-40f9-ae5e-cc7a521cf1b7/image.png" alt=""></p>
<h2 id="루트-도메인과-서브-도메인">루트 도메인과 서브 도메인</h2>
<blockquote>
<p>blog.naver.com / news.naver.com</p>
</blockquote>
<p>서브 도메인은 도메인을 목적에 따라 나눈 것이라 보면 된다.</p>
<p>대형회사는 <span style="color:orange">서브 도메인</span>을 나눠서 관리한다. 
대형 웹사이트인 네이버 블로그!! <span style="color:orange">&#39;blog.&#39;</span>
뉴스 과련 서비스 <span style="color:orange">&#39;news.&#39;</span> 이렇게 서브 도메인을 나눠서 관리한다.</p>
<h2 id="주소창에-www-없던데-뭐지">주소창에 WWW. 없던데? 뭐지?</h2>
<p><img src="https://velog.velcdn.com/images/sht-3756/post/7b82f436-37ea-4058-9ba5-7aef0d9a1c74/image.png" alt=""></p>
<p>요즘은 <code>www.naver.com</code> 이렇게 입력하고 들어가거나, 주소창을 보면 이렇게 <code>www.</code> 은 항상 안보이는 것을 볼 수 있다.</p>
<p>www. 은 서브 도메인이다.
대형 사이트가 아니면 www. 없는 도메인이 일반적이다.(브라우저 쿠키 생성 효율 때문이라고 한다.)
예전에는 용도에 따라 도메인을 구분지었는데, 웹은 www, 메인은 mail, ftp는 ftp 로 서브 도메인을 구분 지어 사용했다.</p>
<p>하지만, 시간이 지나면서 인터넷 유저들이 많아지고, 서브도메인들이 웹형태인 www 에 쏠리게 되었다. 
그래서 주류로 서브도메인이 웹 형태가 되었고, 이제는 굳이 서브 도메인을 나눌 필요가 없으니, www 를 쓸필요가 없어져 사용을 안하게 된것이다.</p>
<h2 id="예시">예시</h2>
<blockquote>
<p>www(3차 도메인).test(2차 도메인).com(최상위 도메인)</p>
</blockquote>
<blockquote>
<p>www(3차 도메인).test(2차 도메인).kr(국가 최상위 도메인)</p>
</blockquote>
<blockquote>
<p>www(4차 도메인).test(3차 도메인).co(2차 도메인).kr(국가 최상위 도메인)</p>
</blockquote>
<h2 id="dns-란-">DNS 란 ?</h2>
<blockquote>
<p>D 도메인 N 네임 S 시스템</p>
</blockquote>
<p>설명 : IP 주소 및 기타 데이터를 저장하고 이름별로 쿼리할 수 있게 해주는 계층형 분산 데이터베이스이다.</p>
<p>즉, DNS 는 컴퓨터가 서로 통신하는데 사용되는 IP 주소를 우리가 쉽게 읽을 수 있는 도메인 이름으로 변환시켜주는 것이다.</p>
<p>172.198.xxx.xx  =&gt; test.com 으로 도메인 이름으로 변환시켜주는 것을 말한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[애니메이션 라이브러리 적용]]></title>
            <link>https://velog.io/@sht-3756/animation-library-confeti</link>
            <guid>https://velog.io/@sht-3756/animation-library-confeti</guid>
            <pubDate>Mon, 24 Apr 2023 14:21:55 GMT</pubDate>
            <description><![CDATA[<h2 id="사용할-방법">사용할 방법</h2>
<h3 id="confetti컨페티--색종이-라이브러리-사용"><code>confetti</code>(컨페티 : 색종이) 라이브러리 사용!</h3>
<p><a href="https://pub.dev/packages/confetti">confetti 라이브러리</a>를 사용해서 응모하기 버튼을 누르고 당첨 되었을때의 액션을 만들어보기로 한다. </p>
<h3 id="선택-이유-">선택 이유 ?</h3>
<p>우선은 시간적 여유가 그렇게 많지 않고, 빠르게 결과물을 만들어서 보고 싶은 나의 욕심 !!</p>
<p>라이브러리 설치해서 빠르게 구현해보겠다. </p>
<p>(예상 구현 시간 : 최대 1시간, 너무 신경써서 만들진 말자 경험 위주) </p>
<h3 id="개발환경-준비">개발환경 준비</h3>
<pre><code class="language-dart">// pubspec.yaml

// 라이브러리 추가
get: ^4.6.5
confetti: ^0.7.0
</code></pre>
<h3 id="코드-작성">코드 작성</h3>
<pre><code class="language-dart">void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const GetMaterialApp(
      home: Scaffold(body: TestWidget()),
    );
  }
}

class TestWidget extends StatefulWidget {
  const TestWidget({Key? key}) : super(key: key);

  @override
  State&lt;TestWidget&gt; createState() =&gt; _TestWidgetState();
}

class _TestWidgetState extends State&lt;TestWidget&gt; {
    late ConfettiController _controllerTopCenter;

    @override
      void initState() {
        super.initState();
            _controllerTopCenter = ConfettiController(
                duration: const Duration(milliseconds: 600)
            );
        }

    @override
  void dispose() {
        _controllerTopCenter.dispose();
        super.dispose();
    }
}</code></pre>
<pre><code class="language-dart">Align(
  alignment: Alignment.topCenter,
  child: ConfettiWidget(
    confettiController: _controllerTopCenter,
    // 송풍 방향
    blastDirection: pi / 2,
    // 최대 폭발력
    maxBlastForce: 2,
    // 최소 폭발력
    minBlastForce: 1,
    // 방출 빈도
    emissionFrequency: 0.1,
    // 입자 수
    numberOfParticles: 10,
    // 중력
    gravity: 1,
  ),
),
Align(
  alignment: Alignment.topCenter,
  child: TextButton(
      onPressed: () {
        _controllerTopCenter.play();
      },
      child: const Text(&#39;당첨(아래로)!&#39;)),
),</code></pre>
<pre><code class="language-dart">Align(
    alignment: Alignment.center,
    child: ConfettiWidget(
      confettiController: _controllerCenter,
      // 송풍 방향
      blastDirectionality: BlastDirectionality.explosive,
      // 무한 여부
      shouldLoop: false,
      // 색상
      colors: const [
        Colors.green,
        Colors.blue,
        Colors.pink,
        Colors.orange,
        Colors.purple
      ],
      // 커스텀 위젯을 넣는 부분
      createParticlePath: drawStar,
    ),
  ),
  Align(
    alignment: Alignment.center,
    child: TextButton(
        onPressed: () =&gt; checkResults(), child: const Text(&#39;응모\n확인&#39;)),
  ),</code></pre>
<pre><code class="language-dart">// 별 그리는 커스텀
  Path drawStar(Size size) {
    double degToRad(double deg) =&gt; deg * (pi / 180.0);

    const numberOfPoints = 5;
    final halfWidth = size.width / 2;
    final externalRadius = halfWidth;
    final internalRadius = halfWidth / 2.5;
    final degreesPerStep = degToRad(360 / numberOfPoints);
    final halfDegreesPerStep = degreesPerStep / 2;
    final path = Path();
    final fullAngle = degToRad(360);
    path.moveTo(size.width, halfWidth);

    for (double step = 0; step &lt; fullAngle; step += degreesPerStep) {
      path.lineTo(halfWidth + externalRadius * cos(step),
          halfWidth + externalRadius * sin(step));
      path.lineTo(halfWidth + internalRadius * cos(step + halfDegreesPerStep),
          halfWidth + internalRadius * sin(step + halfDegreesPerStep));
    }

    path.close();
    return path;
  }</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[로드 밸런스 란 ??]]></title>
            <link>https://velog.io/@sht-3756/LB-%EC%84%A4%EB%AA%85</link>
            <guid>https://velog.io/@sht-3756/LB-%EC%84%A4%EB%AA%85</guid>
            <pubDate>Sun, 16 Apr 2023 12:34:19 GMT</pubDate>
            <description><![CDATA[<h1 id="로드-밸런스에-대한-설명">로드 밸런스에 대한 설명</h1>
<p>💡 가비아에 자세하게, 친절하게 정리된 것이 있으니 잘 읽어보고 정리하였다. 
가비아 땡큐~!</p>
<h2 id="로드밸런스란-무엇인가">로드밸런스란 무엇인가?</h2>
<p>현재 대부분의 사람들은 인터넷을 이용해 정보를 얻고 업무를 진행하며 일상생활에서도 많은 도움을 주는 역할로 자리잡았다. 그만큼 없으면 문명의 발달도 없었을 것이다. </p>
<p>아무리 성능 좋은 서버라고 해도 모든 트래픽을 감당할 순 없다. </p>
<p>회사들은 서버를 추가적으로 구비를 하고 여러 대의 서버에 동일한 데이터를 저장해 수많은 트래픽을 효과적으로 분산 시킬 필요가 있다. </p>
<p>그런데  다수의 서버를 운영한다고 해서 모든 클라이언트의 응답에 일관성 있게 응답할 수 있을까? </p>
<p>아니다! 로드밸런싱이 필요한 이유는 트래픽을 다수의 서버에 분산시켜주는 기술이 필요 하고, 한 서버에 트래픽이 몰리는 현상을 막을 수 있다.</p>
<p>💡 트래픽 관련 용어 정리한 글이다.</p>
<p>용어 정의 </p>
<h3 id="의미">의미</h3>
<p>로드 밸런서는 서버에 가해지는 부하를 분산시켜주는 기술을 의미한다. </p>
<p>로드 밸런서의 아키텍쳐를 보면서 이해하면 쉽다.</p>
<p>클라이언트(유저)와 서버풀(ServerPool) 사이에 위치하며, 한 대의 서버로 부하가 집중적으로 걸리지 않게 분산시켜주는 역할을 해 최적의 퍼포먼스를 하게 도움을 주는 녀석이다.</p>
<h3 id="로드-밸런서-아키텍쳐">로드 밸런서 아키텍쳐</h3>
<p><img src="https://velog.velcdn.com/images/sht-3756/post/b5b018d8-14e8-4b00-8dd4-4946c5c0f602/image.png" alt="출처 : 가비아 블로그">
출처 : 가비아 블로그</p>
<h3 id="과거-회고-이전-회사에서-겪은-경험으로-내가-생긴-의문에-대해-적어보겠다">[과거 회고] 이전 회사에서 겪은 경험으로 내가 생긴 의문에 대해 적어보겠다.</h3>
<p>이전 회사는 한 기업의 투자를 받아 웹 개발을 진행해 준 경험이 있는데, 서버를 어느정도의 용량까지 투자해야하는지에 대한 고민을 한 적이 있었다. 이 고민에 대해서 만약, 다수의 서버를 구성해도 예상 외의 상황에 유저 몰림현상이 일어난다면, 어떻게 해야할까? 라는 의문을 품었던 적이 있었다. </p>
<p>그때 당시 백엔드 팀장급한테 가서 물어보니 “우리는 지금 다수의 서버를 구축해놓은 상태이고, 만약 서버가 컨트롤 할 수 있는 유저의 수보다  더 유저가 방문하고 이용하게 된다면 서버는 어쩔 수 없이 터질 것이다. 이거는 어쩔 방법이 없다.” 라고 대답을 들은 적이 있다. </p>
<p>하지만 과연 방법이 없을까? </p>
<p>아닐거다! 만약 나와 회사가 LoadBalencer 의 개념을 알았으면 달랐을 것이고, </p>
<p>지금 생각해보면, 시니어의 부재와 나의 경험 미숙, 기초지식 부족이 이유였을 것이라는 생각이 든다.</p>
<h2 id="그렇다면-모든-상황에-항상-로드밸런스를-사용해야하나">그렇다면 모든 상황에 항상 로드밸런스를 사용해야하나?</h2>
<p>No~!</p>
<p>여러 대의 서버를 두고 해야하는 만큼 비용적인 문제가 크기 때문에 서비스의 초기 상태에는 당연하게 힘들 것이다. </p>
<p>만약 서비스 초기 상태라면, 클라이언트의 수도 적으니 한 대의 서버로 요청-응답을 진행하다가 사업이 확장되거나 클라이언트의 수가 늘어나고 사용량이 많아지면 다음의 2가지 방법 사용을 고려해봐야한다.</p>
<p><img src="https://velog.velcdn.com/images/sht-3756/post/37999ea9-b4d0-4154-8f0c-d91284eb7a75/image.png" alt="출처 : 가비아 블로그">
출처 : 가비아 블로그</p>
<ol>
<li><p>Scale-up</p>
<p> Scale-up 의 경우, 서버 자체의 성능을 확장하는 것이다.</p>
<p> 예 : i3 ⇒ i7 으로 성능 버전 up! 시키기! (고 성능으로 승부!)</p>
</li>
<li><p>Scale-out </p>
<p> 💡 Scale-out 로 선택했다면, 여러 대의 서버로 트래픽이 균등하게 분배되는 <strong>*로드밸런싱</strong>이 꼭 필요!*</p>
</li>
</ol>
<pre><code>Scale-out 의 경우, 기존 서버와 동일 혹은 낮은 버전의 서버를 증대시키 것이다.

예 : i3 를 한 대 추가로 구매해 운영하기! (물량으로 승부!)

단점 관리할 게 많아진다. 마이크로서비스 처럼!</code></pre><h2 id="로드-밸런싱에도-다양한-기법들이-있다고">로드 밸런싱에도 다양한 기법들이 있다고?</h2>
<p>💡 다양한 로드밸런싱의 알고리즘 5 가지를 정리해보겠다.</p>
<ol>
<li><p>라운드로빈 방식 (Round Robin Method)</p>
<ul>
<li>서버에 요청한 순서대로 돌아가며 배정하는 방식이다!</li>
<li>여러 대의 서버가 동일한 스펙, 서버와의 연결이 오래지속이 되지 않는 경우에 활용 적합하다.</li>
</ul>
</li>
<li><p>가중 라운드로빈 방식 (Weighted Round Robin Method)</p>
<ul>
<li>각각 서버마다 가중치를 매기고 높은 서버부터 우선적으로 클라이언트 요청을 배분한다.</li>
<li>주로 서버의 트래픽 처리 능력이 상이한 경우 사용되는 부하 분산 방식이다.</li>
<li>예 : 5 가중치로 설정한 A 서버, 2 가중치를 같는 B 서버가 있다고 가정한다면,</li>
</ul>
</li>
<li><p>IP 해시 방식 (IP Hash Method)</p>
<ul>
<li>클라이언트 IP 주소를 특정주소로 매핑해 요청 처리하는 방식</li>
<li>사용자의 IP 를 해싱해 (임의의 길이를 지닌 데이터를 고정된 길이의 데이터로 매핑하는것, 또는 함수) 로드를 분배하기 떄문에 사용자가 항상 동일한 서버로 연결되는 것을 보장한다.</li>
</ul>
</li>
<li><p>최소 연결 방식 (Least Connection Method)</p>
<ul>
<li>요청이 들어온 시점에 가장 적은 연결상태를 보이는 서버에 우선적으로 트래픽을 배분한다.</li>
<li>세션이 자주 길어지거나 서버에 분배된 트래픽들이 일정하지 않은 경우에 적합한 방식이다.</li>
</ul>
</li>
<li><p>최소 리스폰타임 (Least Response Time Method)</p>
<ul>
<li>서버의 현재 연결 상태와 응답 시간을 모두 고려하여 트래픽을 배분한다. 가장 적은 연결 상태와 가장 짧은 응답시간을 보이는 서버에 우선적으로 로드를 배분하는 방식이다.</li>
</ul>
</li>
</ol>
<h3 id="l4-와-l7--이건-뭐지">L4 와 L7 ?? 이건 뭐지?</h3>
<p>네트워크 통신 시스템은 크게 7 가지 계층으로 나뉜다. (OSI 7 layers)</p>
<p>각각의 계층이 L1, L2, L3, L4, L5, L6, L7 에 해당한다. 상위 계층 에서 사용되는 장비는 하위 계층의 장비가 갖고 있는 기능을 모두 가지고 있으며, 상위 계층으로 갈수록 더욱 정교한 로드밸런싱이 가능한다. </p>
<p><img src="https://velog.velcdn.com/images/sht-3756/post/f67d1528-6ee5-4716-8fde-43ba304f7edc/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/sht-3756/post/bc0e1430-f0c4-4544-bfc8-6dce36e6ca5d/image.png" alt=""></p>
<blockquote>
<p>예를 들어 카카오 데이터 센터 화재 사건이 있다.</p>
</blockquote>
<hr>
<h2 id="레퍼런스">레퍼런스</h2>
<p><a href="https://m.post.naver.com/viewer/postView.naver?volumeNo=27046347&amp;memberNo=2521903">로드밸런서(Load Balancer)의 개념과 특징</a></p>
<p><a href="https://aws.amazon.com/ko/what-is/load-balancing/">로드 밸런싱이란 무엇인가요? - 로드 밸런싱 알고리즘 설명 - AWS</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Flutter Animation 라이브러리 검색]]></title>
            <link>https://velog.io/@sht-3756/flutter-animation-%EA%B2%80%EC%83%89-%EC%9E%A5%EB%8B%A8%EC%A0%90</link>
            <guid>https://velog.io/@sht-3756/flutter-animation-%EA%B2%80%EC%83%89-%EC%9E%A5%EB%8B%A8%EC%A0%90</guid>
            <pubDate>Sat, 15 Apr 2023 14:16:47 GMT</pubDate>
            <description><![CDATA[<h2 id="목적">목적</h2>
<p>응모하기 결과에 대한 애니메이션을 추가해서 생동감을 불어넣기</p>
<ul>
<li>깔끔한 디자인 유행이지만, 애니메이션이 없는 웹/앱은 있을 수 없다. 그만큼 당연하기 때문이다.</li>
<li>유저피드백이 필요하다. 웹 보단 앱인 경우는 화면이 작기 때문에, 유저가 어떤 행동을 하던 그 즉시 유저에게 피드백을 줘야한다고 생각한다. (좋아요 버튼을 누르면 바로 눌렀다는 피드백!)</li>
</ul>
<hr>
<h3 id="예측-결과">예측 결과</h3>
<p>내가 응모한 상품의 결과를 생동감 있는 애니메이션이 출력될 것이다.</p>
<hr>
<h3 id="기대-효과">기대 효과</h3>
<p>유저는 내가 응모한 상품에 당첨되었다는 것을 텍스트로 출력되는 것보단 생동감 있는 애니메이션으로 당첨되었다는 사실의 확실성과 정말 응모상품을 받을 수 있는지에 대한 기대감을 부풀려준다.</p>
<hr>
<h3 id="조건">조건</h3>
<ol>
<li>어느정도 like 수가 있어야 한다. (라이브러리가 얼마나 사용성이 좋은지 여부, 안정성 여부에 대한 판단의 기준)</li>
<li>Publish 가 자주 되는 라이브러리 이여야 한다. (에러가 발생하면 바로 업데이트 해줄것이라는 확신때문이다.)</li>
<li>애니메이션 코드가 적용하기 쉬워야함 (라이브러리 사용하는 이유가 편리하게 내가 원하는 라이브러리를 적용하기 위함이라고 생각하기 때문이다.)</li>
<li>원하는 기능이 들어가 있어야함 (원하는 기능이 무조건 포함되어있어야하고, 추가적인 기능이 들어가 있으면 금상첨화!)</li>
<li>Doc 가 친절해야함 (그래야 러닝 커브 적고 내가 이해하기 편하고 적용하기 편함.)</li>
</ol>
<hr>
<h2 id="후보들-소개-😀">후보들 소개 😀</h2>
<h3 id="후보-1-번-👽">후보 1 번 👽</h3>
<p>💡 Like 1225, Pub points 130, Recent Published 26 (게시글 작성 기준), Version 0.10.4 (게시글 작성 기준)</p>
<p><a href="https://pub.dev/packages/rive#examples">rive | Flutter Package</a></p>
<p>장점</p>
<ul>
<li>사용 방법이 무궁무진 하다. (기본 앱은 물론 게임에 관련된 애니메이션까지 적용가능하다. )</li>
<li>DOC 친절하다.</li>
<li>구현이 쉬워 많은 개발자들이 사용하고, 사용 예제들이 많다.</li>
<li>클라이언트의 디테일한 요구, 디자이너의 욕심을 채울 수 있는 라이브러리이다.</li>
</ul>
<p>단점</p>
<ul>
<li>디테일 요하는 애니메이션은 해당 .riv 파일을  추가해줘야한다. (예 ⇒ 인터렉티브한 움직임.riv)</li>
<li>앱의 용량이 조금 커지지 않을까? 라는 의문 (왜냐, 각 riv 파일이 존재해야하기 때문, 서버에서 내려받는다면? 서버 용량이 그만큼 필요하겠지?)</li>
</ul>
<hr>
<h3 id="후보-2-번-👾">후보 2 번 👾</h3>
<p><a href="https://api.flutter.dev/flutter/animation/animation-library.html">animation library - Dart API</a></p>
<p>기존 내장 animation library 사용하기</p>
<p>애니메이션 라이브러리와 캔버스, 페인팅 라이브러리 둘중 하나를 같이 사용 해야할 듯 싶다.</p>
<p>장점</p>
<ul>
<li>커스텀 하기 용이하다. (기존 내장 라이브러리이기 때문에 접근이 쉽고, 에러가 날 가능성 적고, 컨트롤 쉽다.)</li>
<li>DOC 친절하다.</li>
</ul>
<p>단점 </p>
<ul>
<li>하나 하나 애니메이션을 추가해줘야하는 번거로움(그림을 그리는 painting 도 직접 해야할것 같음)</li>
<li>이미지를 추가해 이미지에 대한 애니메이션을 적용하면 너무 단순함, 과연 인터렉티브 할까?란 의문</li>
<li>구현시 시간 오래걸림 (애니메이션을 추가하는 기능에 대해 명확히 정하고 구현 시작 해야 한다.)</li>
<li>AnimationController 을 사용하기에 상태관리를 해줘야하는 번거로움 (사용시 메모리에서 dispose() 해줘야함)</li>
</ul>
<hr>
<h3 id="후보-3-번-👻">후보 3 번 👻</h3>
<p>💡 Like 3800, Pub points 130, Recent Published 29 (게시글 작성 기준), Version 2.0.5 (게시글 작성 기준)</p>
<p><a href="https://pub.dev/packages/flutter_svg">flutter_svg | Flutter Package</a></p>
<p>SVG 파일을 통한 애니메이션 적용하기</p>
<p>이 라이브러리는 Svg 를 불러오기 위한 라이브러리이다.</p>
<p>그렇기에 후보 3 번이라는 것은 애매하다.. 왜냐 후보 2번의 방법을 또 사용해야하기 때문이다!</p>
<p>장점</p>
<ul>
<li>후보 2 번 과 같다.</li>
</ul>
<p>단점</p>
<ul>
<li>svg 파일 필요하다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Flutter - study] 애니메이션 공부 ]]></title>
            <link>https://velog.io/@sht-3756/flutter-study-animation-with-library</link>
            <guid>https://velog.io/@sht-3756/flutter-study-animation-with-library</guid>
            <pubDate>Wed, 12 Apr 2023 14:47:48 GMT</pubDate>
            <description><![CDATA[<h2 id="애니메이션을-사용하는-이유">애니메이션을 사용하는 이유</h2>
<p>모바일에서 애니메이션을 추가하는 이유</p>
<p>깔끔 멋진 인터페이스는 더이상 사용자의 관심을 이끌지 못한다. 이에 대한 솔루션이다.</p>
<p>사용자가 통제감을 느끼는지 확인해야한다. 그들의 행동이 영향을 끼친다는 것을 알려줘야하고, 앱은 항상 사용자의 행동에 따른 피드백을 바로 보내줘야한다. </p>
<p>이런 방식으로 사용자가 당신의 앱 사용법을 빠르게 배우고, 앞으로 방문할 횟수가 높아질 것이다.</p>
<p>Flutter 에서의 Animation 은 매력이 있다.</p>
<p>Flutter 는 시각적으로 효율적인 애니메이션을 만드는 완벽한 프레임워크이다.</p>
<p>유일한 한계는 나의 상상력 정도랄까..??</p>
<h2 id="flutter-의-animation-종류">Flutter 의 Animation 종류</h2>
<p>💡 Flutter 의 Animation 에는 두가지 종류가 있다. 정의와 차이점 알아보자!</p>
<h3 id="1-암시적-animation">1. 암시적 Animation</h3>
<p>Animation 위젯에서 사용할 수 있는 변수만으로 기반으로 하는것을 의미한다.</p>
<p>즉, Flutter 의 내장 위젯을 사용하는 방법이다.</p>
<p>예 : AnimationContainer, AnimatedOpacity, AnimatedCrossFade, 등등..</p>
<p>특징 : 지정된 값이 변경될때 마다 애니메이션이 생성된다.</p>
<h3 id="2-명시적-animation-주로-이걸-사용한다">2. 명시적 Animation (주로 이걸 사용한다.)</h3>
<p>개발자가 직접 동작하는 방식을 정의하는 것을 의미한다.</p>
<p>즉 , AnimationController 를 사용해 암시적 Animation 보다 더 많은 사용성을 제공한다는 것이다.</p>
<p>💡  ❗AnimationController 는 위젯이 아닌라는 점을 기억해주자! 
그렇기 때문에 사용 시 무조건 꼭 메모리에서 제거 해줘야한다.</p>
<p>특징 : 애니메이션 상태를 관리를 해줘야한다. 그래서 복잡한 앱을 만들때 주로 사용한다.</p>
<h2 id="예제">예제</h2>
<p>StatefulWidget 타입의 BouncingAnimationWidget 을 사용해볼 것이다.</p>
<p>이걸 위해 SingleTickerProviderStateMixin 을 사용해보는 경험을 가져보자!</p>
<p>SingleTickerProviderStateMixin 는 애니메이션을 새로 고치는 것을  컨트롤 하는 혼합물이다.</p>
<p>Flutter 엔진은 애니메이션을 표시할때 1 초당 60 프레임을 유지하도록 하는 Tricker 를 보장한다.</p>
<p>그리고 TickerProviderStateMixin 을 사용해 State 확장해야한다.</p>
<pre><code class="language-dart">class BouncingAnimationWidget extends StatefulWidget {
 const BouncingAnimationWidget({Key? key}) : super(key: key);
 @override
 State&lt;BouncingAnimationWidget&gt; createState() =&gt;
     _BouncingAnimationWidgetState();
}
class _BouncingAnimationWidgetState extends State&lt;BouncingAnimationWidget&gt;with SingleTickerProviderStateMixin {
 late final AnimationController _controller;
 @override
 void initState() {
   super.initState();
   _controller = AnimationController(
     duration: const Duration(milliseconds: 500),
     vsync: this,
   );
 }
@override
 Widget build(BuildContext context) {
   return Scaffold();
 }
 @override
 void dispose() {
   _controller.dispose();
   super.dispose();
 }
}</code></pre>
<h3 id="애니메이션을-입힐-직사각형-코드-작성">애니메이션을 입힐 직사각형 코드 작성</h3>
<pre><code class="language-dart">Stack(
         alignment: Alignment.center,
         children: [
           _boxShadow(context),
           Align(
             alignment: Alignment(0.0, _boxJumpHeight.value),
             child: _animatedBox(context),
           ),
         ],
       ),

Widget _boxShadow(BuildContext context) =&gt; Container(
       width: 180,
       height: 15,
       decoration: BoxDecoration(
         borderRadius:
             BorderRadius.all(Radius.elliptical(180, 15)),
         boxShadow: [
           BoxShadow(
             color: Colors.black.withOpacity(0.15),
             spreadRadius: 5,
             blurRadius: 4,
             offset: const Offset(0, 3),
           ),
         ],
       ),
     );

 Widget _animatedBox(BuildContext context) =&gt; Container(
         width: 160,
         height: 50,
         color: Colors.white,
       );</code></pre>
<h3 id="결과물">결과물</h3>
<p><img src="https://velog.velcdn.com/images/sht-3756/post/bedf3a9b-0c68-42d5-bc1b-3330a25c7a2e/image.png" alt=""></p>
<pre><code class="language-dart">void _initJumpAnimation() =&gt; _boxJumpHeight = Tween&lt;double&gt;(
       begin: -0.07,
       end: -0.5,
     ).animate(
       CurvedAnimation(
         parent: _controller,
         curve: const Interval(
           0.0,
           1.0,
           curve: Curves.easeInOut,
         ),
       ),
     );

 void _initBoxRotationAnimation() =&gt; _boxRotationAngle = Tween&lt;double&gt;(
       begin: 0,
       end: 360,
     ).animate(
       CurvedAnimation(
         parent: _controller,
         curve: const Interval(
           0.25,
           1.0,
           curve: Curves.ease,
         ),
       ),
     );

 void _initBoxWidthAnimation() =&gt; _boxWidth = Tween&lt;double&gt;(
       begin: 160,
       end: 50,
     ).animate(
       CurvedAnimation(
         parent: _controller,
         curve: const Interval(
           0.05,
           0.3,
           curve: Curves.ease,
         ),
       ),
     );

 void _initBoxShadowWidthAnimation() =&gt; _boxShadowWidth = Tween&lt;double&gt;(
       begin: 180,
       end: 50,
     ).animate(
       CurvedAnimation(
         parent: _controller,
         curve: const Interval(
           0.05,
           0.5,
           curve: Curves.ease,
         ),
       ),
     );

 void _initBoxShadowIntensityAnimation() =&gt;
     _boxShadowIntensity = Tween&lt;double&gt;(
       begin: 0.15,
       end: 0.05,
     ).animate(
       CurvedAnimation(
         parent: _controller,
         curve: const Interval(
           0.05,
           1.0,
           curve: Curves.ease,
         ),
       ),
     );</code></pre>
<h3 id="전체-코드">전체 코드</h3>
<pre><code class="language-dart">class BouncingAnimationWidget extends StatefulWidget {
 const BouncingAnimationWidget({Key? key}) : super(key: key);


@override
 State&lt;BouncingAnimationWidget&gt; createState() =&gt;
     _BouncingAnimationWidgetState();
}

class _BouncingAnimationWidgetState extends State&lt;BouncingAnimationWidget&gt;with SingleTickerProviderStateMixin {
 late final AnimationController _controller;
 late final Animation&lt;double&gt; _boxJumpHeight;
 late final Animation&lt;double&gt; _boxWidth;
 late final Animation&lt;double&gt; _boxShadowWidth;
 late final Animation&lt;double&gt; _boxShadowIntensity;
 late final Animation&lt;double&gt; _boxRotationAngle;

 @override
 void initState() {
   super.initState();
   _controller = AnimationController(
     duration: const Duration(milliseconds: 500),
     vsync: this,
   );
   _initJumpAnimation();
   _initBoxWidthAnimation();
   _initBoxShadowWidthAnimation();
   _initBoxShadowIntensityAnimation();
   _initBoxRotationAnimation();
 }
 // Insert init functions from the last paragraph here
 @override
 Widget build(BuildContext context) =&gt; AnimatedBuilder(
       builder: (context, _) =&gt; _buildAnimation(context),
       animation: _controller,
     );

 Widget _buildAnimation(BuildContext context) =&gt; GestureDetector(
       onTap: _playAnimation,
       child: Stack(
         alignment: Alignment.center,
         children: [
           _boxShadow(context),
           Align(
             alignment: Alignment(0.0, _boxJumpHeight.value),
             child: _animatedBox(context),
           ),
         ],
       ),
     );

 Future&lt;void&gt; _playAnimation() async {
   try {
     await _controller.forward().orCancel;
     await _controller.reverse().orCancel;
   } on TickerCanceled {
     // the animation got canceled
   }
 }

 Widget _boxShadow(BuildContext context) =&gt; Container(
       width: _boxShadowWidth.value,
       height: 15,
       decoration: BoxDecoration(
         borderRadius:
             BorderRadius.all(Radius.elliptical(_boxShadowWidth.value, 15)),
         boxShadow: [
           BoxShadow(
             color: Colors.black.withOpacity(_boxShadowIntensity.value),
             spreadRadius: 5,
             blurRadius: 4,
             offset: const Offset(0, 3),
           ),
         ],
       ),
     );

 Widget _animatedBox(BuildContext context) =&gt; Transform(
       alignment: Alignment.center,
       transform: _boxRotation(_controller.status),
       child: Container(
         width: _boxWidth.value,
         height: 50,
         color: Colors.white,
       ),
     );

 Matrix4 _boxRotation(AnimationStatus animationStatus) {
   // This will ensure that rotation will be in the same direction on reverse
   if (animationStatus == AnimationStatus.reverse) {
     return Matrix4.identity()..rotateZ(-_boxRotationAngle.value * pi / 180);
   } else {
     return Matrix4.identity()..rotateZ(_boxRotationAngle.value * pi / 180);
   }
 }

 @override
 void dispose() {
   _controller.dispose();
   super.dispose();
 }
}</code></pre>
<h2 id="조금-더-업그레이드-">조금 더 업그레이드 !</h2>
<h3 id="만약-복잡한-애니메이션이-필요로-한다면">만약 복잡한 애니메이션이 필요로 한다면?</h3>
<p>앞서 작성했듯이 애니메이션은 앱에 한 몸이 되듯이 작동해야하고 적용되어야한다.</p>
<p>만약, 클라이언트가 매우 복잡한 애니메이션을 필요로 한다면 어떻게 해야할까?</p>
<p>2가지 방법을 제시하겠다.</p>
<ol>
<li>코드로 애니메이션 구현한다.</li>
</ol>
<p>위에 작성한 예제를 보면된다. (좀 더 디테일하게 하면 원하는 데로 가능하다.)</p>
<ol>
<li>Rive 라이브러리를 사용한다.</li>
</ol>
<h3 id="rive-란-">Rive 란 ??</h3>
<p>Rive 는 인터렉티브 애니메이션을 만드는 플랫폼이다. </p>
<p>Flutter, Swift, Kotlin 등으로 작성된 앱에 직접 포함시킬 수 있고, 브라우저에서도 사용할 수 있다. </p>
<p>개발자가 asset 을 추가할 수 있고, 인터넷을 통해서 애니메이션을 만들어서 업로드할 수 있다. (Rive Community 를 말하는듯!)</p>
<p>심지어 구현하기도 쉬워서 많은 개발자가 애용하고, 온라인에서 많은 가이드와 예제를 찾아볼 수 있다는 점이 있다.</p>
<h3 id="예제-1">예제</h3>
<p>💡 코드를 작성하기 전, Rive 라이브러리 설치 후! .riv 파일을 준비해야 한다.</p>
<pre><code class="language-dart">class HoldappLogoRiveWidget extends StatefulWidget {
 const HoldappLogoRiveWidget({Key? key}) : super(key: key);

 @override
 State&lt;HoldappLogoRiveWidget&gt; createState() =&gt; _HoldappLogoRiveWidgetState();
}

class _HoldappLogoRiveWidgetState extends State&lt;HoldappLogoRiveWidget&gt;with SingleTickerProviderStateMixin {
 Artboard? _riveArtboard;

 @override
 void initState() {
   super.initState();
   rootBundle.load(&#39;assets/example.riv&#39;).then((data) {
         // binary 타입의 data 로부터 RiveFile 을 로드 한다.
     final file = RiveFile.import(data);

         // artboard 는 애니메이션의 시작점이고, Rive 위젯에 그린다.  
     final artboard = file.mainArtboard;
     var controller =
         StateMachineController.fromArtboard(artboard, &#39;State Machine 1&#39;);
     if (controller != null) {
       artboard.addController(controller);
     }
     setState(() =&gt; _riveArtboard = artboard);
   });
 }

 @override
 Widget build(BuildContext context) =&gt; Scaffold(
       backgroundColor: Colors.white,
       body: _riveArtboard != null
           ? Rive(artboard: _riveArtboard!)
           : const Center(
               child: CircularProgressIndicator(),
             ),
     );
}</code></pre>
<h3 id="rive-의-애니메이션-method">Rive 의 애니메이션 method</h3>
<p>💡 Rive 는 애니메이션이 3가지 방법이 있다. 
One-shot, Ping-pong, Loop</p>
<p>One-Shot </p>
<p>Animation 을 한번만 재생하는 것</p>
<p>Ping pong</p>
<p>Animation 을 재생 후  reverse 로 역 재생 하는 것 무한으로~ </p>
<p>0 → 1 → 0 → 1 → 0 → … 이런 식으로 무한으로 재생</p>
<p>Loop</p>
<p>Animation 을 무한으로 재생한다.</p>
<p>0 → 1 , 0 → 1, 0 → 1, … 이런 식으로  무한으로 재생</p>
<p>예 </p>
<ul>
<li>다크모드의 버튼에 따른 이미지를 변경시킬 수 있음</li>
<li>커서의 움직임에 따른 이미지의 변경 (404 페이지의 눈알을 돌리는 이미지를 본적 이 있음)</li>
</ul>
<p>레퍼런스
<a href="https://www.holdapp.com/blog/flutter-animations-rive">https://www.holdapp.com/blog/flutter-animations-rive</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[GetxController 와 GetxService 는 무엇일까?]]></title>
            <link>https://velog.io/@sht-3756/getx-controller%EC%99%80getx-service-7xo95ng1</link>
            <guid>https://velog.io/@sht-3756/getx-controller%EC%99%80getx-service-7xo95ng1</guid>
            <pubDate>Tue, 11 Apr 2023 14:30:26 GMT</pubDate>
            <description><![CDATA[<h1 id="getxcontroller-와-getxservice-설명-시작">GetxController 와 GetxService 설명 시작!</h1>
<blockquote>
<p>GetxController 는 <span style="color: pink">사랑꾼!</span>
GetxService 는 <span style="color: red">불사신!</span></p>
</blockquote>
<p>Getx 로 상태관리를 진행하면서 GetxController 와 GetxService 를 상속을 하면서, 그 둘의 차이를 알고 싶어 정리를 했다.</p>
<p>둘의 정의와 차이점
GetxController 는 비즈니스 로직들을 모아놓은 뷰 모델의 역할을 하는 녀석이고, 
생명주기가 화면단이 죽으면 같이죽는다.</p>
<p>GetxService 는 백엔드 서버와 통신하는 역할을 하는 녀석이다. 
생명주기가 화면단이 죽어도 죽지 않는다.</p>
<p>GetxController 의 모습</p>
<pre><code class="language-dart">class FeedController extends GetxController with StateMixin&lt;List&lt;FeedModel&gt;&gt; {
  // repository 참조! (repository 에서 선언한 api 통신을 사용하기 위함!)
  FeedProvider feedProvider = FeedProvider();

  // private 변수 선언! (변수의 변경은 오직 FeedController 에서만!)
  final Rx&lt;FeedModel?&gt; _feed = Rx&lt;ReedModel?&gt;(null); 

  // getter 선언! (뷰단에서 뿌려주기 위한 용도!)
  FeedModel? get feed =&gt; _feed;

  // 함수 선언! (뷰단에서 호출할 함수!)
  Future&lt;void&gt; getFeedDataFunction() async {
      _feed = await feedProvider.getFeedData();  
  }

}</code></pre>
<p>GetxService 의 모습 </p>
<pre><code class="language-dart">class FeedProvider extends GetConnect implements GetxService {

  final ip = &#39;https://주소.firebaseio.com&#39;;

  // 피드 리스트 불러오기
  Future getFeedData() async {
    final res = await get(&#39;$ip/feed-list.json&#39;);
    print(res);
    if (res.status.hasError) {
      return Future.error({res.statusText});
    } else {
      return FeedModel.fromJson(res.body);
    }
  }
  ...
}</code></pre>
<p>GetxController 는 화면단이 dispose 되면 같이 사라지고, GetService 는 Get의 인스턴스를 모두 초기화 하지 않는 이상 사라지지 않는다!</p>
<blockquote>
<p>Get.reset() =&gt; 겟의 instance 를 모두 초기화하는 것이므로 등록된 service 도 삭제되는 것이다. </p>
</blockquote>
<h2 id="나의-개발-구조">나의 개발 구조</h2>
<p><code>서버(백엔드) -&gt; 레포지토리(Provider) -&gt; 컨트롤러 -&gt; 뷰</code>
내가 현재 개발하고 있는 개발 흐름 구조이다.</p>
<p>백엔드 =&gt; 서버를 담당하고 있으며, NOSQL 로 간편하게 Firebase 를 선택했다.
뷰 =&gt; 유저가 보는 뷰단
컨트롤러 =&gt; 뷰를 관리하는 뷰의 비즈니스 로직 (=viewModel)
프로바이더(레포지토리) =&gt; 컨트롤러에게 데이터를 wrapping해서 넘겨주는 역할(실질적으로 api 통신하는 코드)</p>
<p>개발자가 화면에서 볼 데이터를 컨트롤러가 관리하고, 프로바이더에서 데이터를 wrapping 해서 넘겨주는 방향이다.</p>
<blockquote>
<p>뷰와 뷰비즈니스 로직을 분리해서 의존성을 줄이는 방향으로 진행하는 중이다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[내가 자주사용하는 깃에 대한 기록 ]]></title>
            <link>https://velog.io/@sht-3756/git%EC%97%90%EB%8C%80%ED%95%9C%EC%A0%95%EB%B3%B4%EB%93%A4</link>
            <guid>https://velog.io/@sht-3756/git%EC%97%90%EB%8C%80%ED%95%9C%EC%A0%95%EB%B3%B4%EB%93%A4</guid>
            <pubDate>Mon, 03 Apr 2023 14:54:01 GMT</pubDate>
            <description><![CDATA[<h1 id="상황">상황</h1>
<p>Git 을 상요하다가 자주 까먹을때가 많은데, 매번 구글 검색하지 말고 적용하자
자주 사용하는것들로 정리해본다. 매번 추가할 예정!</p>
<h2 id="명령어들">명령어들</h2>
<p>깃 초기화</p>
<pre><code>git init </code></pre><p>깃 레포지토리 등록</p>
<pre><code>git remote add origin 깃레포지토리주소</code></pre><p>모든 브랜치 보기</p>
<pre><code>git branch -a </code></pre><p>브랜치 생성 및 접속</p>
<pre><code>git branch checkout 브랜치이름</code></pre><p>깃에 설정파일 보기 gitconfig</p>
<pre><code>git config -l</code></pre><p>git config 삭제</p>
<pre><code>// 삭제할거를 --뒤에 넣어주면 된다.
git config --unset --user.name 
// 글로벌 삭제(전역으로 삭제 된거는 삭제 이렇게!)
git config --unset --global user.name</code></pre><p>기본 브랜치 main 으로 전역적으로 선언하기</p>
<pre><code>git config --global init.defaultBranch main</code></pre><p>깃 현재 상황 보기</p>
<pre><code>git status</code></pre><p>깃 로그 확인</p>
<pre><code>git log</code></pre><p>커밋하기</p>
<pre><code>git commit -m &#39;메세지 입력&#39;</code></pre><p>깃허브에 올리기</p>
<pre><code>git push</code></pre><p>깃 히스토리 삭제! </p>
<pre><code>rm -rf .git</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[info.plist permission]]></title>
            <link>https://velog.io/@sht-3756/%ED%8D%BC%EB%AF%B8%EC%85%98-%EC%A0%95%EB%A6%AC-fx699i35</link>
            <guid>https://velog.io/@sht-3756/%ED%8D%BC%EB%AF%B8%EC%85%98-%EC%A0%95%EB%A6%AC-fx699i35</guid>
            <pubDate>Sun, 02 Apr 2023 14:36:14 GMT</pubDate>
            <description><![CDATA[<p>IOS 의 Permission 을 짧게 정리해보겠다.</p>
<p>애플 뮤직</p>
<pre><code class="language-dart">&lt;key&gt;NSAppleMusicUsageDescription&lt;/key&gt;
&lt;string&gt;My description about why I need this capability&lt;/string&gt;</code></pre>
<p>블루투스</p>
<pre><code class="language-dart">&lt;key&gt;NSBluetoothPeripheralUsageDescription&lt;/key&gt;
&lt;string&gt;My description about why I need this capability&lt;/string&gt;</code></pre>
<p>달력</p>
<pre><code class="language-dart">&lt;key&gt;NSCalendarsUsageDescription&lt;/key&gt;
&lt;string&gt;My description about why I need this capability&lt;/string&gt;</code></pre>
<p>카메라</p>
<pre><code class="language-dart">&lt;key&gt;NSCameraUsageDescription&lt;/key&gt;
&lt;string&gt;My description about why I need this capability&lt;/string&gt;</code></pre>
<p>컨택트 렌즈</p>
<pre><code class="language-dart">&lt;key&gt;NSContactsUsageDescription&lt;/key&gt;
&lt;string&gt;My description about why I need this capability&lt;/string&gt;</code></pre>
<p>FaceID</p>
<pre><code class="language-dart">&lt;key&gt;NSFaceIDUsageDescription&lt;/key&gt;
&lt;string&gt;My description about why I need this capability&lt;/string&gt;</code></pre>
<p>피트니스 건강공유</p>
<pre><code class="language-dart">&lt;key&gt;NSHealthShareUsageDescription&lt;/key&gt;
&lt;string&gt;My description about why I need this capability&lt;/string&gt;</code></pre>
<p>건강 업데이트</p>
<pre><code class="language-dart">&lt;key&gt;NSHealthUpdateUsageDescription&lt;/key&gt;
&lt;string&gt;My description about why I need this capability&lt;/string&gt;</code></pre>
<p>홈키트</p>
<pre><code class="language-dart">&lt;key&gt;NSHomeKitUsageDescription&lt;/key&gt;
&lt;string&gt;My description about why I need this capability&lt;/string&gt;</code></pre>
<p>위치</p>
<pre><code class="language-dart">&lt;key&gt;NSLocationUsageDescription&lt;/key&gt;
&lt;string&gt;My description about why I need this capability&lt;/string&gt;</code></pre>
<p>위치 항상</p>
<pre><code class="language-dart">&lt;key&gt;NSLocationAlwaysUsageDescription&lt;/key&gt;
&lt;string&gt;My description about why I need this capability&lt;/string&gt;</code></pre>
<p>위치 앱 사용중인경우</p>
<pre><code class="language-dart">&lt;key&gt;NSLocationWhenInUseUsageDescription&lt;/key&gt;
&lt;string&gt;My description about why I need this capability&lt;/string&gt;</code></pre>
<p>마이크 권한</p>
<pre><code class="language-dart">&lt;key&gt;NSMicrophoneUsageDescription&lt;/key&gt;
&lt;string&gt;My description about why I need this capability&lt;/string&gt;</code></pre>
<p>동작(가속도계)</p>
<pre><code class="language-dart">&lt;key&gt;NSMotionUsageDescription&lt;/key&gt;
&lt;string&gt;My description about why I need this capability&lt;/string&gt;</code></pre>
<p>NFC (근거리 통신)</p>
<pre><code class="language-dart">&lt;key&gt;NFCReaderUsageDescription&lt;/key&gt;
&lt;string&gt;My description about why I need this capability&lt;/string&gt;</code></pre>
<p>사진 라이브러리</p>
<pre><code class="language-dart">&lt;key&gt;NSPhotoLibraryUsageDescription&lt;/key&gt;
&lt;string&gt;My description about why I need this capability&lt;/string&gt;</code></pre>
<p>사진 라이브러리 (쓰기 전용 액세스) :</p>
<pre><code class="language-dart">&lt;key&gt;NSPhotoLibraryAddUsageDescription&lt;/key&gt;
&lt;string&gt;My description about why I need this capability&lt;/string&gt;</code></pre>
<p>알림</p>
<pre><code class="language-dart">&lt;key&gt;NSRemindersUsageDescription&lt;/key&gt;
&lt;string&gt;My description about why I need this capability&lt;/string&gt;</code></pre>
<p>시리</p>
<pre><code class="language-dart">&lt;key&gt;NSSiriUsageDescription&lt;/key&gt;
&lt;string&gt;My description about why I need this capability&lt;/string&gt;</code></pre>
<p>음성 인식</p>
<pre><code class="language-dart">&lt;key&gt;NSSpeechRecognitionUsageDescription&lt;/key&gt;
&lt;string&gt;My description about why I need this capability&lt;/string&gt;</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Flutter-error] CocoaPods could not find compatible versions for pod "GTMSessionFetcher/Core"]]></title>
            <link>https://velog.io/@sht-3756/poderror</link>
            <guid>https://velog.io/@sht-3756/poderror</guid>
            <pubDate>Thu, 30 Mar 2023 14:59:33 GMT</pubDate>
            <description><![CDATA[<h1 id="상황">상황</h1>
<p>구글 로그인 하려고 google_sign_in 설치하고 ios inpo.plist 에 설정을 완료후 build 시도했지만, 빌드가 실패한 상황이다.</p>
<h1 id="에러내용">에러내용</h1>
<pre><code>...
CocoaPods could not find compatible versions for pod &quot;GTMSessionFetcher/Core&quot;
...
[!] Automatically assigning platform &#39;iOS&#39; with version &#39;8.0&#39; on target &#39;Runner&#39; because no platform was specified. 
Please specify a platform for this target in your Podfile. 
See &quot;https://guides.cocoapods.org/syntax/podfile.html#platform&quot;.</code></pre><p>podfile 에서 IOS build시 타겟 설정을 안해줘서 에러가 난다는 것이다.
그래서 IOS 8.0으로 빌드시 에러발생!</p>
<h1 id="해결방법">해결방법</h1>
<pre><code>cd ios
pop install</code></pre><p>만약 이렇게 해도 진행이 안된다면, </p>
<pre><code>podfile 을 찾아서 주석을 지워주자
# platform :ios, &#39;9.0&#39;  </code></pre><p><a href="https://stackoverflow.com/questions/74304290/cocoapods-could-not-find-compatible-versions-for-pod-gtmsessionfetcher-core">참초 글</a> </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Flutter] 컨테이너 maxHeight, maxWidth 정하기 및 위젯 사이즈 구하기 ]]></title>
            <link>https://velog.io/@sht-3756/%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88-maxHeight-maxWidth-%EA%B5%AC%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@sht-3756/%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88-maxHeight-maxWidth-%EA%B5%AC%ED%95%98%EA%B8%B0</guid>
            <pubDate>Tue, 14 Mar 2023 13:11:11 GMT</pubDate>
            <description><![CDATA[<p>컨테이너 맥스 height, width 정하기</p>
<pre><code class="language-dart">ConstrainedBox(
    constraints: BoxConstraints(
    minHeight: 100,
    minWidth: 100,
    ),
)</code></pre>
<p>위젯 사이즈 구하기</p>
<pre><code>  final GlobalKey _containerKey = GlobalKey();  

Size? _getSize() {
      if (_containerKey.currentContext != null) {
        final RenderBox renderBox =
            _containerKey.currentContext!.findRenderObject() as RenderBox;
        Size size = renderBox.size;
        return size;
      }
      return null;
    }</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[Flutter-error] LateInitializationError: Field '변수명' has not been initialized.]]></title>
            <link>https://velog.io/@sht-3756/Flutter-error-LateInitializationError-Field-%EB%B3%80%EC%88%98%EB%AA%85-has-not-been-initialized</link>
            <guid>https://velog.io/@sht-3756/Flutter-error-LateInitializationError-Field-%EB%B3%80%EC%88%98%EB%AA%85-has-not-been-initialized</guid>
            <pubDate>Mon, 13 Mar 2023 09:35:12 GMT</pubDate>
            <description><![CDATA[<h3 id="에러-내용">에러 내용</h3>
<pre><code class="language-dart">LateInitializationError: Field &#39;변수명&#39; has not been initialized.</code></pre>
<h3 id="오류-원인">오류 원인</h3>
<pre><code class="language-dart">late String loggedInUserId;</code></pre>
<h3 id="수정-완료">수정 완료</h3>
<pre><code class="language-dart">late String loggedInUserId = &quot;&quot;;</code></pre>
<p>late 로 필드를 늦게 선언해주면, view 단에 내가 해주려는 비교문에 순간적으로 에러가 난다.
그러니 초기값을 반드시 선언해주자!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[매 시간마다 함수 호출하기]]></title>
            <link>https://velog.io/@sht-3756/test-f5415of5</link>
            <guid>https://velog.io/@sht-3756/test-f5415of5</guid>
            <pubDate>Sun, 12 Mar 2023 08:55:01 GMT</pubDate>
            <description><![CDATA[<p>javascript 에서의 setInterval() 함수와 같은 기능을 Flutter 에서 구현해 보도록 하겠다.
매 시, 분, 초마다 원하는 함수를 호출하는 방법을 알아보겠다.</p>
<pre><code class="language-dart">Timer.periodic(Duration(seconds: 1), (timer)) {
    // 함수 실행!!
   print(&#39;안녕&#39;);
}

// 1초마다 print문이 계속 찍힐것이다.</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Flutter] 반응형 UI]]></title>
            <link>https://velog.io/@sht-3756/flutter-responsive-qrkql04w</link>
            <guid>https://velog.io/@sht-3756/flutter-responsive-qrkql04w</guid>
            <pubDate>Tue, 07 Mar 2023 14:59:01 GMT</pubDate>
            <description><![CDATA[<p>MediaQuery
MediaQueryData
physicalSize of WidgetsBinding</p>
<p>화면 사이즈 읽는 방법중 3가지를 소개하겠다.</p>
<h2 id="mediaquery">MediaQuery</h2>
<pre><code class="language-dart">MediaQuery.of(context).sized.width;</code></pre>
<p>현재 빌드된 위젯트리에서 가장 가까운 MediaQuery 위젯에서 논리적인 픽셀단위로 디바이스 너비를 가져온다.</p>
<p>인자로 BuildContext 를 넘겨줘야한다. 
현재 화면의 크기를 알기위해선 BuildContext 트리를 타고 올라가야한다. 
반드시 위젯트리에서 접근가능한 build 메소드 안에 작성해야한다!</p>
<p>그래서 위젯트리에 따라 원하지 않는 동작을 일으킬 문제점이 있다.</p>
<h2 id="mediaquerydatafromwindow">MediaQueryData.fromWindow</h2>
<pre><code class="language-dart">MediaQueryData.fromWindow(WidgetsBinding.instance.window).size.width;</code></pre>
<p>현재 화면의 너비를 논리적 픽셀단위로 가져온다.
Mediaquery 와 비슷해보이지만, 다른점은 BuildContext 를 인자로 받지 않아서 build 메소드안에 작성안해도된다.</p>
<p>앱에서는 앱 시작시 로딩화면에서 초기화 작업을 하면서 해당기기의 unitSize를 설정할때 사용한다고 한다.</p>
<p>논리적인 레이아웃 크기를 반환하여 레이아웃 작업에 사용한다.</p>
<p>위젯트리와 관계없이 작동하므로 싱글톤 처럼 어느 한곳에 메모리를 잡아놓고 build 메소드 안에서 값 할당하면 MediaQuery 와 다르게 오작동을 막을 수 있다.</p>
<h2 id="widgetsbindinginstancewindowphysicalsize">WidgetsBinding.instance.window.physicalSize</h2>
<pre><code class="language-dart">MediaQueryData.fromData(WidgetsBinding.instance.windwo).size.width;</code></pre>
<p>현재 디바이스의 너비를 물리적 픽셀 단위를 반환한다.</p>
<p><img src="https://velog.velcdn.com/images/sht-3756/post/094aaea7-ead1-4472-a235-be1e48144501/image.gif" alt=""></p>
<pre><code>1번째 화면 사이즈에 따라  값이 변한다.
2번째 build 메소드 밖에서 초기화 한 MediaQueryData.fromWindow 는 화면 사이즈에 따라 변하지 않는다.
3번째 build 메소드 안에서 초기화한 MediaQueryData.fromWindow 는 화면 크기에 따라 값이 변한다.

화면크기가 변경될때마다 Flutter 는 해당화면을 다시 build한다.
build 함수를 다시 호출하는 위젯을 사용하지 않았는데 말이다!
Stateless 위젯과 별도의 rebuild 함수를 사용하지 않았는데, 다시 호출한다는 것이 증거!

4번째는 최대 넓이 일때 3024 이다. </code></pre><h2 id="mediaquery-잘못-사용한-사용법">MediaQuery 잘못 사용한 사용법</h2>
<p> 첫번째 페이지에서 만든 MediaQuery를 두번째 페이지에 넘겨보았다.
 두번째 페이지에서 재빌드 하지 않아 생기는 오류이다.</p>
<p> 첫번째 페이지에서는 MediaQeury 가 잘 작동해도 두번째는 적용이 되지 않는다.</p>
<p>값을 재 할당 해주면 문제없다.
 <img src="https://velog.velcdn.com/images/sht-3756/post/e14cbfdc-81aa-4328-8067-9534b1ed3faa/image.gif" alt=""></p>
<p> 실시간으로 해상도 대응할 필요있을때는 MediaQuery 사용하면 좋다.
 실시간 해상도 대응 =&gt; 모바일 가로모드로 바꿀때!실시간 변경시를 말한다.</p>
<p> 반응형 UI 는 지원하지만, 실시간대응까지는 필요없을때 MediaQueryData.fromWindow 사용하자. 싱글톤 패턴처럼 어딘가에 선언후 변수를 지속적으로 사용하는게 실수를 줄일수 있는 방법이고, 메모리 관리에도 좋다.</p>
<p> 이미지의 픽셀을 강제할때나 그래픽 관련 작업일때는 WidgetsBinding.instance.window.physicalSize 사용하자.</p>
<h2 id="적용">적용</h2>
<p>MediaQuery에서 받은 해상도값을 바탕으로 하는 방법도 있지만, 웹에서는 주로 기준값을 정해서 대응을 한다.</p>
<p>기준값을 정해서 대응하는 법으로 진행하겠다.
size.dart 에서 pageWidth, mobileWidth 을 전역으로 초기화 해주고, build 메소드 안에서 재할당 해주고 mobileWidth 보다 큰지 아닌지 비교해준다.</p>
<pre><code class="language-dart">// size.dart
import &#39;package:flutter/material.dart&#39;;

final double fixedWidth = MediaQueryData.fromWindow(WidgetsBinding.instance.window).size.width;

final pageWidth = MediaQueryData.fromWindow(WidgetsBinding.instance.window).size.width;
const double mobileWidth = 700;
const double breakPointWidth =1200;
bool isWeb = true;</code></pre>
<pre><code class="language-dart">import &#39;package:flutter/material.dart&#39;;
import &#39;package:portfolio/size.dart&#39;;

class FlutterWebTestPage02 extends StatelessWidget {

  const FlutterWebTestPage02({Key? key})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    double pageWidth = MediaQuery.of(context).size.width;
    isWeb = pageWidth &gt; mobileWidth ? true : false;

    TextStyle h1 = const TextStyle(
      fontSize: 30,
      fontWeight: FontWeight.w600,
    );
    TextStyle h2 = const TextStyle(
      fontSize: 25,
      fontWeight: FontWeight.w600,
    );
    TextStyle h3 = const TextStyle(
      fontSize: 20,
      fontWeight: FontWeight.w600,
    );

    return Scaffold(
      body: Column(
        children: [
          Container(
            width: double.infinity,
            height: 48,
            color: Theme.of(context).colorScheme.primary,
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                SizedBox(
                    width: pageWidth &gt; breakPointWidth
                        ? (pageWidth - breakPointWidth) / 2 + 20
                        : 20),
                Text(&quot;hizzang&quot;, style: isWeb ? h1 : h2),
                const Spacer(),
                Text(&quot;Hello&quot;, style: isWeb ? h2 : h3),
                const SizedBox(width: 24),
                Text(&quot;my&quot;, style: isWeb ? h2 : h3),
                const SizedBox(width: 24),
                Text(&quot;friend&quot;, style: isWeb ? h2 : h3),
                SizedBox(
                    width: pageWidth &gt; breakPointWidth
                        ? (pageWidth - breakPointWidth) / 2 + 20
                        : 20),
              ],
            ),
          ),
          Expanded(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Text(&#39;현재는 ${isWeb ? &#39;웹 사이즈&#39; : &#39;모바일 사이즈&#39;} &#39;, style: const TextStyle(fontSize: 30),),
                Text(&quot;pageWidth: $pageWidth&quot;, style: const TextStyle(fontSize: 30),),
              ],
            ),
          )
        ],
      ),
    );
  }
}
</code></pre>
<p>padding 이 되는 SizedBox 의 width 을 설정
(현재사이즈 - 기준 해상도) / 2 + padding
최소 20은 padding 을 준다는 뜻이다. 
화면이 정해진 1200 픽셀보다 크다면 그 차이만큼 공백을 주라는 거다.</p>
<pre><code class="language-dart">SizedBox(
                    width: pageWidth &gt; breakPointWidth
                        ? (pageWidth - breakPointWidth) / 2 + 20
                        : 20),</code></pre>
<p><img src="https://velog.velcdn.com/images/sht-3756/post/27ba3bf6-d114-4b84-a628-ca3a940d826f/image.gif" alt="">
끝!</p>
<p><a href="https://medium.com/doohyeon-kim/flutter-responsive-web-c2c123c0d5d1">참조글 보러가기!</a> </p>
]]></description>
        </item>
    </channel>
</rss>