<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>ho-taek.log</title>
        <link>https://velog.io/</link>
        <description>잘하고싶다</description>
        <lastBuildDate>Sun, 08 Oct 2023 07:30:47 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>ho-taek.log</title>
            <url>https://images.velog.io/images/ho-taek/profile/87244007-8dda-4c8e-ba93-0663fb1a8c75/KakaoTalk_20210707_174606818.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. ho-taek.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/ho-taek" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[프로그래머스] LEVEL 1 - 푸드 파이트 대회 (Pyton && Kotlin)]]></title>
            <link>https://velog.io/@ho-taek/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-LEVEL-1-%ED%91%B8%EB%93%9C-%ED%8C%8C%EC%9D%B4%ED%8A%B8-%EB%8C%80%ED%9A%8C-Pyton-Kotlin</link>
            <guid>https://velog.io/@ho-taek/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-LEVEL-1-%ED%91%B8%EB%93%9C-%ED%8C%8C%EC%9D%B4%ED%8A%B8-%EB%8C%80%ED%9A%8C-Pyton-Kotlin</guid>
            <pubDate>Sun, 08 Oct 2023 07:30:47 GMT</pubDate>
            <description><![CDATA[<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/134240?language=kotlin">문제 링크</a></p>
<p>최근에 코틀린 실력의 부족함을 깨닫고... 파이썬으로 먼저 풀어보고 코틀린으로도 풀어보고 있다!</p>
<h4 id="파이썬">파이썬</h4>
<pre><code class="language-python">def solution(food):
    answer = &quot;&quot;
    for index, i in enumerate(food):
        if(index == 0):
            continue
        else:
            tmp = int(i) // 2
            answer += str(index) * tmp

    return answer + &quot;0&quot; + answer[::-1]</code></pre>
<h4 id="코틀린">코틀린</h4>
<pre><code class="language-kotlin">class Solution {
    fun solution(food: IntArray): String {
        var answer: String = &quot;&quot;
        for(i in 1 .. food.size-1){
            println(food[i]/2)
            answer += i.toString().repeat(food[i]/2)

        }
        return answer + &quot;0&quot; + answer.reversed()
    }
}</code></pre>
<p>문제를 보면 알겠지만
[1, 3, 4, 6] 맨 첫 번째가 물! 그 다음 1칼로리가 3개, 2칼로리가 4개, 3칼로리가 6개이다.</p>
<p>2사람이 공평하게 나눠야 하므로 2로 나눈 몫을 기준으로 나누면 된다.</p>
<p>1칼로리 -&gt; 3 / 2 = 1개
2칼로리 -&gt; 4 / 2 = 2개
3칼로리 -&gt; 6 / 2 = 3개</p>
<p>그러므로 답이 &quot;1223330333221&quot; 나온다.</p>
<p>한 선수를 구하기 위해 repeat()으로 반복한 문자열을 표시해준다.</p>
<p>한 선수만 구하고 나머지는 reversed()메소드로 뒤집어주면 되기 때문에</p>
<pre><code class="language-kotlin">return answer + &quot;0&quot; + answer.reversed()</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[CS] 운영체제와 컴퓨터]]></title>
            <link>https://velog.io/@ho-taek/CS-%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C%EC%99%80-%EC%BB%B4%ED%93%A8%ED%84%B0</link>
            <guid>https://velog.io/@ho-taek/CS-%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C%EC%99%80-%EC%BB%B4%ED%93%A8%ED%84%B0</guid>
            <pubDate>Wed, 28 Dec 2022 11:51:43 GMT</pubDate>
            <description><![CDATA[<p>! 면접을 위한 CS 전공 지식 노트를 통해 공부하고 정리한 글</p>
<h2 id="1-1-운영체제의-역할과-구조">1-1) 운영체제의 역할과 구조</h2>
<blockquote>
<p>운영체제는 사용자가 컴퓨터를 쉽게 다루게 해주는 인터페이스이다. 한정된 메모리나 시스템 자원을 효율적으로 분배하는 일을 한다.</p>
</blockquote>
<ul>
<li>참고로 운영체제와 유사하지만 소프트웨어를  추가로 설치할 수 없는 것을 펌웨어라고 한다.</li>
</ul>
<h3 id="운영체제의-역할">운영체제의 역할</h3>
<ul>
<li>CPU 스케줄링과 프로세스 관리 : CPU 소유권을 어떤 프로세스에 할당할지, 프로세스의 생성과 삭제, 자원 할당 및 반환을 관리한다.</li>
<li>메모리 관리 : 한정된 메모리를 어떤 프로세스에 얼마큼 할당해야 하는지 관리한다.</li>
<li>디스크 파일 관리 : 디스크 파일을 어떠한 방법으로 보관할지 관리합니다.</li>
<li>I/O 디바이스 관리 : I/O 디바이스들인 마우스, 키보드와 컴퓨터 간에 데이터를 주고받는 것을 관리합니다.</li>
</ul>
<h3 id="운영체제의-구조">운영체제의 구조</h3>
<p><img src="https://velog.velcdn.com/images/ho-taek/post/9c0bde71-c926-4a54-b104-4c2cf4770dfe/image.png" alt="">
민트색으로 표시된 부분들(GUI, 시스템콜, 커널, 드라이버)이 운영체제에 속한다.</p>
<ul>
<li>GUI : 사용자 인터페이스의 한 형태로 단순 명령어 창이 아닌 아이콘을 마우스로 클릭하는 단순한 동작으로 컴퓨터와 상호 작용할 수 있도록 해준다.</li>
<li>드라이버 : 하드웨어를 제어하기 위한 소프트웨어</li>
</ul>
<h4 id="시스템-콜">시스템 콜</h4>
<ul>
<li>운영체제가 커널에 접근하기 위한 인터페이스이며 유저 프로그램이 운영체제의 서비스를 받기 위해 커널 함수를 호출할 때 쓴다.</li>
<li>유저 프로그램이 I/O의 요청으로 트랩을 발동하면 올바른 I/O 요청인지 확인한 후 유저 모드가 시스템콜을 통해 커널 모드로 변환되어 실행된다.<ul>
<li>예를 들어 파일 시스템의 파일을 읽는 함수가 발동했을 경우 다음 그림과 같은 과정이 나온다.
<img src="https://velog.velcdn.com/images/ho-taek/post/313b0724-3075-4df0-acf8-b79d8cedd51b/image.png" alt=""></li>
<li>유저 모드에서 파일을 읽지 않고 커널 모드로 들어가 파일을 읽고 다시 유저 모드로 돌아가 그 뒤에 있는 유저 프로그램의 로직을 수행한다.</li>
<li>위의 과정을 통해 컴퓨터 자원에 대한 직접 접근을 차단할 수 있고 프로그램을 다른 프로그램으로부터 보호할 수 있다.
<img src="https://velog.velcdn.com/images/ho-taek/post/858dd0a8-68d8-4346-bf4c-73c56ae2c4dd/image.png" alt=""></li>
</ul>
</li>
<li>위의 그림처럼 프로세스나 스레드에서 운영체제로 어떠한 요청을 할 때 시스템콜이라는 인터페이스와 커널을 거쳐 운영체제에 전달된다.</li>
<li>이 시스템콜은 하나의 추상화 계층이다. 그러므로 이를 통해 네트워크 통신이나 데이터베이스와 같은 낮은 단계의 영역 처리에 대한 부분을 많이 신경 쓰지 않고 프로그램을 구현할 수 있는 장점이 있다.</li>
</ul>
<h4 id="modebit">modebit</h4>
<ul>
<li>시스템콜이 작동될 때 modebit이라는 1 또는 0의 값을 가지는 플래그 변수를 통해 유저 모드와 커널 모드를 구분한다.</li>
<li>키보드, 카메라와 같은 I/O디바이스는 운영체제를 통해서만 작동해야 한다. -&gt; 공격자의 행동들을 막기 위해<ul>
<li>키보드 프로그램을 사용할 때 다음 그림과 같이 modebit을 활용한다.
<img src="https://velog.velcdn.com/images/ho-taek/post/bd4705b7-aeef-42b9-a7cf-84bf8d416dca/image.png" alt=""></li>
</ul>
</li>
<li>정리하자면<ul>
<li>유저모드 : 유저가 접근할 수 있는 영역을 제한적으로 두며 컴퓨터 자원에 함부로 침범하지 못하는 모드</li>
<li>커널모드 : 모든 컴퓨터 자원에 접근할 수 있는 모드</li>
<li>커널 : 운영체제의 핵심 부분이자 시스템콜 인터페이스를 제공하며 보안, 메모리, 프로세스, 파일 시스템, I/O 디바이스, I/O 요청 관리 등 운영체제의 중추적인 역할을 한다.</li>
</ul>
</li>
</ul>
<h2 id="1-2-컴퓨터의-요소">1-2) 컴퓨터의 요소</h2>
<ul>
<li>컴퓨터는 CPU, DMA 컨트롤러, 메모리, 타이머, 디바이스 컨트롤러 등으로 이루어져 있다.</li>
</ul>
<h3 id="cpu">CPU</h3>
<ul>
<li>산술논리연산장치, 제어장치, 레지스터로 구성되어 있는 컴퓨터 장치를 말하며, 인터럽트에 의해 단순히 메모리에 존재하는 명령어를 해석해서 실행한다.</li>
<li>운영체제의 커널이 프로그램을 메모리에 올려 프로세스로 만들면 CPU가 이를 처리한다.</li>
</ul>
<h3 id="제어장치">제어장치</h3>
<ul>
<li>제어장치는 프로세스 조작을 지시하는 CPU의 한 부분이다.</li>
<li>입출력 장치 간 통신을 제어학고 명령어들을 읽고 해석하며 데이터 처리를 위한 순서를 결정한다.</li>
</ul>
<h3 id="레지스터">레지스터</h3>
<ul>
<li>CPU 안에 있는 매우 빠른 임시기억장치이다.</li>
<li>CPU와 직접 연결되어 있으므로 연산 속도가 메모리보다 수십 배에서 수백 배까지 빠르다.</li>
<li>CPU는 자체적으로 데이터를 저장할 방법이 없기 때문에 레지스터를 거쳐 데이터를 전달한다.</li>
</ul>
<h3 id="산술논리연산장치">산술논리연산장치</h3>
<ul>
<li>두 숫자의 산술 연산과 배타적 논리합, 논리곱 같은 논리 연산을 계산하는 디지털 회로이다.<h4 id="cpu의-연산-처리">CPU의 연산 처리</h4>
<img src="https://velog.velcdn.com/images/ho-taek/post/b30de1ac-26b5-4db1-8749-f8713e6dc35c/image.png" alt=""></li>
</ul>
<ol>
<li>제어장치가 메모리에 계산할 값을 로드한다. 또한, 레지스터에도 로드한다.</li>
<li>제어장치가 레지스터에 있는 값을 계산하라고 ALU에 명령한다.</li>
<li>제어장치가 계산된 값을 다시 &#39;레지스터에서 메모리로&#39;계산한 값을 저장한다.</li>
</ol>
<h3 id="인터럽트">인터럽트</h3>
<ul>
<li>어떤 신호가 들어왔을 때 CPU를 잠깐 정지시키는 것을 말한다.</li>
<li>키보드, 마우스 등 IO 디바이스로 인한 인터럽트</li>
<li>0으로 숫자를 나누는 산술 연산에서의 인터럽트, 프로세스 오류 등으로 발생한다.</li>
<li>인터럽트가 발생되면 인트럽트 핸들러 함수가 모여 있는 인터럽트 벡터로 가서 인터럽트 핸들러 함수가 실행된다.<ul>
<li>인터럽트 핸들러 함수 : 인터럽트가 발생했을 때 이를 핸들링하기 위한 함수, 커널 내부의 IRQ를 통해 호출되며 request_irq()를 통해 인터럽트 핸들러 함수를 등록할 수 있다.</li>
</ul>
</li>
<li>인터럽트 간에는 우선순위가 있고 우선순위에 따라 실행되며 인터럽트는 하드웨어 인터럽트, 소프트웨어 인터럽트(트랩)으로 나뉜다.<h3 id="dma-컨트롤러">DMA 컨트롤러</h3>
</li>
<li>I/O 디바이스가 메모리에 직접 접근할 수 있도록 하는 하드웨어 장치를 뜻한다.</li>
<li>CPU에만 너무 많은 인터럽트 요청이 들어오기 때문에 CPU 부하를 막아 주며 CPUㅇ의 일을 부담하는 보조 일꾼이다.</li>
<li>또한, 하나의 작업을 CPU와 DMA 컨트롤러가 동시에 하는 것을 방지한다. </li>
</ul>
<h3 id="메모리">메모리</h3>
<ul>
<li>전자회로에서 데이터나 상태, 명령어 등을 기록하는 장치</li>
<li>보통 RAM을 말한다.</li>
<li>메모리가 크면 클수록 많은 일을 동시에 할 수 있다.</li>
</ul>
<h3 id="타이머">타이머</h3>
<ul>
<li>시간이 많이 걸리는 프로그램이 작동할 때 제한을 걸기 위해 존재한다.</li>
</ul>
<h3 id="디바이스-컨트롤러">디바이스 컨트롤러</h3>
<ul>
<li>컴퓨터와 연결되어 있는 IO 디바이스들의 작은 CPU이다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[CS] IP주소]]></title>
            <link>https://velog.io/@ho-taek/CS-IP%EC%A3%BC%EC%86%8C</link>
            <guid>https://velog.io/@ho-taek/CS-IP%EC%A3%BC%EC%86%8C</guid>
            <pubDate>Sun, 18 Dec 2022 07:30:40 GMT</pubDate>
            <description><![CDATA[<p>! &#39;면접을 위한 CS 전공지식 노트&#39;를 통해 공부한 내용 정리</p>
<h2 id="1-1-arp">1-1) ARP</h2>
<ul>
<li>컴퓨터와 컴퓨터 간의 통신은 IP 주소에서 ARP를 통해 MAC 주소를 찾아 MAC 주소를 기반으로 통신한다.<blockquote>
<p>ARP란 IP 주소로부터 MAC 주소를 구하는 IP와 MAC 주소의 다리 역할을 하는 프로토콜이다.</p>
</blockquote>
</li>
<li>ARP를 통해 가상 주소인 IP 주소를 실제 주소인 MAC 주소로 변환한다.<blockquote>
<p>RARP란 실제 주소인 MAC 주소를 가상 주소인 IP 주소로 변환한다.</p>
</blockquote>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/ho-taek/post/49b1ca70-f222-4b63-9ff0-37b30224c36c/image.png" alt=""></p>
<ul>
<li>아래 그림과 같이 &#39;ARP Request 브로드캐스트&#39;를 보내 찾고자 하는 IP 주소에 해당하는 MAC 주소를 찾는다.
<img src="https://velog.velcdn.com/images/ho-taek/post/2fe0bfcd-987a-427b-b766-9d1288dbfc20/image.png" alt=""></li>
<li>그 뒤 해당 주소에 맞는 장치가 &#39;ARP reply 유니캐스트&#39;를 통해 MAC 주소를 반환하는 과정을 거쳐 IP 주소에 맞는 MAC 주소를 찾는다.<ul>
<li>브로드캐스트 : 송신 호스트가 전송한 데이터가 네트워크에 연결된 모든 호스트에 전송되는 방식</li>
<li>유니캐스트 : 고유 주소로 식별된 하나의 네트워크 목적지에 1:1로 데이터를 전송하는 방식</li>
</ul>
</li>
</ul>
<h2 id="1-2-홉바이홉-통신">1-2) 홉바이홉 통신</h2>
<ul>
<li>IP 주소를 통해 통신하는 과정을 의미.</li>
<li>통신망에서 각 패킷이 여러 개의 라우터를 건너가는 모습을 비유적으로 표현한 것.</li>
<li>각각의 라우터에 있는 라우팅 테이블의 IP를 기반으로 패킷을 전달하고 다시 전달해 나간다.<blockquote>
<p>즉, 통신 장치에 있는 &#39;라우팅 테이블&#39;의 IP를 통해 시작 주소부터 시작해 다음 IP로 계속 해서 이동하는 &#39;라우팅&#39;과정을 거쳐 패킷이 최종 목적지까지 도달하는 통신</p>
</blockquote>
</li>
</ul>
<h3 id="라우팅-테이블">라우팅 테이블</h3>
<ul>
<li>라우터에 들어가 있는 목적지 정보들과 그 목적지로 가기 위한 방법이 들어 있는 리스트</li>
<li>라우팅 테이블에는 게이트웨이와 모든 목적지에 대해 해당 목적지에 도달하기 위해 거쳐야 할 다음 라우터의 정보를 가지고 있다.</li>
</ul>
<h3 id="게이트웨이">게이트웨이</h3>
<ul>
<li>서로 다른 통신망, 프로토콜을 사용하는 네트워크 간의 통신을 가능하게 하는 관문 역할을 하는 컴퓨터나 소프트웨어</li>
<li>게이트웨이는 서로 다른 네트워크 상의 통신 프로토콜을 변환해주는 역할을 하기도 함.</li>
</ul>
<h2 id="1-3-ip-주소-체계">1-3) IP 주소 체계</h2>
<ul>
<li>IPv4 -&gt; 32비트를 8비트 단위로 점을 찍어가며 표시<ul>
<li>123.45.67.89</li>
</ul>
</li>
<li>IPv6 -&gt; 64비트를 16비트 단위로 점을 찍어 표기<ul>
<li>2001:db8:ff00:42:8329</li>
</ul>
</li>
</ul>
<h3 id="클래스-기반-할당-방식">클래스 기반 할당 방식</h3>
<ul>
<li>A,B,C,D,E 다섯 개의 클래스로 구분하는 클래스 기반 할당 방식(CIDER)</li>
<li>앞에 있는 부분을 네트워크 주소, 그 뒤에 있는 부분을 컴퓨터에 부여하는 주소인 호스트 주소로 놓아서 사용한다.
<img src="https://velog.velcdn.com/images/ho-taek/post/d0969d76-71f3-48a9-9a60-d82b25af386d/image.png" alt=""></li>
<li>클래스 A&amp;B&amp;C는 일대일 통신으로 사용</li>
<li>클래스 D는 멀티캐스트 통신</li>
<li>클래스 E는 앞으로 사용할 예비용으로 쓰는 방식임.
<img src="https://velog.velcdn.com/images/ho-taek/post/0299330b-6276-422b-aca1-0bb7bfc4f751/image.png" alt=""></li>
<li>맨 왼쪽에 있는 빨간색으로 표시된 비트를 &#39;구분 비트&#39;라고 한다.<ul>
<li>클래스 A -&gt; 0, 클래스 B -&gt; 10, 클래스 C -&gt; 110</li>
</ul>
</li>
<li>네트워크의 첫 번째 주소는 네트워크 주소로 사용되고 가장 마지막 주소는 브로드캐스트용 주소로 네트워크에 속해 있는 모든 컴퓨터에 데이터를 보낼 때 사용된다.</li>
<li>예를 들어 클래스 A로 15.0.0.0이란 네트워크를 부여받았다고 하면 다음 그림과 같다.
<img src="https://velog.velcdn.com/images/ho-taek/post/cc86f01f-ec14-4cd0-ac49-89f113cc2cb0/image.png" alt=""><ul>
<li>15.0.0.0의 경우 네트워크 구별 주소로 사용하면 안됨!</li>
<li>15.255.255.255의 경우도 브로드캐스트용으로 남겨둬야 함</li>
<li>즉 15.0.0.1 ~ 15.255.255.254를 컴퓨터에 부여할 수 있는 호스트 주소로 사용할 수 있다.</li>
</ul>
</li>
<li>이 방식의 경우 사용하는 주소보다 버리는 주소가 많기 때문에 DHCP와 IPv6, NAT가 나오게 된다!<h3 id="dhcp">DHCP</h3>
</li>
<li>IP 주소 및 기타 통신 매개변수를 자동으로 할당하기 위한 네트워크 관리 프로토콜이다.</li>
<li>이 기술을 통해 네트워크 장치의 IP 주소를 수동으로 설정할 필요 없이 인터넷에 접속할 때마다 자동으로 IP주소를 할당할 수 있다.</li>
<li>많은 라우터와 게이트웨이 장비에 DHCP 기능이 있으며 이를 통해 대부분의 가정용 네트워크에서 IP 주소를 할당한다.<h3 id="nat">NAT</h3>
</li>
<li>패킷이 라우팅 장치를 통해 전송되는 동안 패킷의 IP 주소 정보를 수정해 IP 주소를 다른 주소로 매핑하는 방법.</li>
<li>NAT를 통해 공인 IP와 사설 IP로 나눠서 많은 주소를 처리한다.
<img src="https://velog.velcdn.com/images/ho-taek/post/20e231cb-bc58-4d25-949f-904354d0e74c/image.png" alt=""></li>
<li>A,B,C의 경우 192.152.0.xxx를 기반으로 각각의 다른 사설 IP를 가지고 있다.</li>
<li>다음으로 NAT 장치를 통해 공인 IP로 외부 인터넷에 요청할 수 있다.</li>
<li>인터넷 공유기에 경우 이런 NAT 기능이 탑재되어 있어 내부 네트워크에 대한 어느 정도의 보안이 가능해진다.</li>
<li>하지만 여러 명이 동시에 인터넷을 접속하게 되므로 접속 호스트 숫자에 따라 접속 속도가 느려질 수 있다</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[CS] 네트워크 기기]]></title>
            <link>https://velog.io/@ho-taek/CS-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EA%B8%B0%EA%B8%B0-n1h31wyg</link>
            <guid>https://velog.io/@ho-taek/CS-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EA%B8%B0%EA%B8%B0-n1h31wyg</guid>
            <pubDate>Wed, 14 Dec 2022 06:42:37 GMT</pubDate>
            <description><![CDATA[<p>! &#39;면접을 위한 CS 전공 지식 노트&#39;를 공부하고 정리한 내용</p>
<h2 id="1-1-네트워크-기기의-처리-범위">1-1) 네트워크 기기의 처리 범위</h2>
<ul>
<li>네트워크 기기는 계층별로 처리 범위를 나눌 수 있다.<ul>
<li>물리 계층을 처리할 수 있는 기기</li>
<li>데이터 링크 계층을 처리할 수 있는 기기</li>
</ul>
</li>
<li>상위 계층을 처리하는 기기는 하위 계층을 처리할 수 있지만 그 반대는 불가능하다.</li>
<li>계층에 따른 기기 종류<ul>
<li>애플리케이션 계층 : L7 스위치</li>
<li>인터넷 계층 : 라우터, L3 스위치</li>
<li>데이터 링크 계층 : L2 스위치, 브리지</li>
<li>물리 계층 : NIC, 리피터, AP<h2 id="1-2-애플리케이션-계층을-처리">1-2) 애플리케이션 계층을 처리</h2>
<h3 id="l7-스위치">L7 스위치</h3>
<ul>
<li>스위치는 여러 장비를 연결하고 데이터 통신을 중재하며 목적지가 연결된 포트로만 전기 신호를 보내 데이터를 전송하는 통신 네트워크 </li>
<li>포트</li>
<li>IP 내에서 애플리케이션 상호 구분을 위해 사용하는 번호</li>
<li>포트 숫자는 IP 주소가 가리키는 PC에 접속 할 수 있는 통로</li>
<li>이미 사용 중인 포트는 중복해서 사용할 수 없다.</li>
<li>L7 스위치는 <strong>로드밸런서</strong> 라고도 하며, 서버의 부하를 분산하는 기기</li>
<li>클라이언트로부터 오는 요청들을 뒤쪽의 여러 서버로 나누는 역할을 하며 시스템이 처리할 수 있는 트래픽 증가를 목표로 한다.</li>
<li>URL, 서버, 캐시, 쿠키들을 기반으로 트래픽을 분산하며 바이러스, 불필요한 외부 데이터 등을 걸러내는 필터링 기능 또한 가지고 있으며 응용 프로그램 수준의 트래픽 모니터링도 가능하다.</li>
</ul>
</li>
</ul>
</li>
</ul>
<h4 id="l4스위치와-l7스위치의-차이">L4스위치와 L7스위치의 차이</h4>
<ul>
<li>로드밸런서로는 L4스위치도 있다.</li>
<li>L4 스위치의 경우 인터넷 계층을 처리하는 기기로 스트리밍 관련 서비스에서는 사용할 수 없으며 메시지(<del>어플리케이션 계층 PDU</del>)를 기반으로 인식하지 못하고 IP와 포트를 기반으로 트래픽을 분산한다.</li>
<li>반면 L7 로드밸런서는 IP, 포트 외에도 URL, HTTP 헤더, 쿠키 등을 기반으로 트래픽을 분산한다.</li>
</ul>
<h4 id="로드밸런서를-통한-서버-이중화">로드밸런서를 통한 서버 이중화</h4>
<ul>
<li>로드밸런서의 대표적인 기능 -&gt; <strong>서버 이중화</strong></li>
<li>로드밸런서는 2대 이상의 서버를 기반으로 가상 IP를 제공하고 이를 기반으로 안정적인 서비스를 제공한다.(에러 발생에 대비)
<img src="https://velog.velcdn.com/images/ho-taek/post/ba9d9b57-581e-4aac-9767-321ed90aa9a7/image.png" alt="">
로드밸런서가 제공한 0.0.0.12010이란 가상 IP에 사용자들이 접근하게 되고 사용가능한 서버인 0.0.0.12011과 0.0.0.12010를 기반으로 서빙!
만약 0.0.0.12011 장애가 발생했을 때 0.0.0.12012 서버를 기반으로 서비스의 운용이 가능하다.</li>
</ul>
<h2 id="1-3-인터넷-계층을-처리하는-기기">1-3) 인터넷 계층을 처리하는 기기</h2>
<h3 id="라우터">라우터</h3>
<ul>
<li>여러 개의 네트워크를 연결, 분할, 구분시켜주는 역할을 한다.</li>
<li>다른 네트워크에 존재하는 장치끼리 서로 데이터를 주고받을 때 패킷 소모를 최소화하고 경로를 최적화하여 최소 경로로 패킷을 포워딩하는 <strong>라우팅</strong>을 하는 장비</li>
</ul>
<h3 id="l3-스위치">L3 스위치</h3>
<ul>
<li>L2 스위치의 기능과 라우팅 기능을 갖춘 장비 -&gt; 라우터라 해도 무방</li>
<li>L2 &amp; L3 비교</li>
</ul>
<table>
<thead>
<tr>
<th align="center">구분</th>
<th align="center">L2 스위치</th>
<th align="center">L3 스위치</th>
</tr>
</thead>
<tbody><tr>
<td align="center">참조테이블</td>
<td align="center">MAC 주소 테이블</td>
<td align="center">라우팅 테이블</td>
</tr>
<tr>
<td align="center">참조 PDU</td>
<td align="center">이더넷 프레임</td>
<td align="center">IP패킷</td>
</tr>
<tr>
<td align="center">참조 주소</td>
<td align="center">MAC 주소</td>
<td align="center">IP주소</td>
</tr>
</tbody></table>
<h2 id="1-4-데이터-링크-계층을-처리하는-기기">1-4) 데이터 링크 계층을 처리하는 기기</h2>
<h3 id="l2-스위치">L2 스위치</h3>
<ul>
<li>장치들의 MAC 주소를 MAC 주소 테이블을 통해 관리하며, 연결된 장치로부터 패킷이 왔을 때 패킷 전송을 담당한다.</li>
<li>단순히 패킷의 MAC 주소를 읽어 스위칭하는 역할을 한다.</li>
<li>목적지가 MAC 주소 테이블에 없다면 전체 포트에 전달하고 MAC 주소 테이블의 주소는 일정 시간 이후 삭제하는 기능도 있다.</li>
</ul>
<h3 id="브리지">브리지</h3>
<ul>
<li>두 개의 LAN을 상호 접속할 수 있도록 하는 통신망 연결 장치이다.</li>
<li>포트와 포트 사이의 다리 역할을 하며 장치에서 받아온 MAC 주소를 MAC 주소 테이블로 관리한다.</li>
<li>서로 다른 LAN 등으로 이루어진 &#39;하나의&#39; 통신망을 구축할 때 쓰인다.</li>
</ul>
<h2 id="1-5-물리-계층을-처리하는-기기">1-5) 물리 계층을 처리하는 기기</h2>
<h3 id="nic">NIC</h3>
<ul>
<li>LAN 카드라고 하는 네트워크 인터페이스 카드이다.</li>
<li>2대 이상의 컴퓨터 네트워크를 구성하는데 사용하며, 네트워크와 빠른 속도로 데이터를 송수신 할 수 있도록 컴퓨터 내에 설치하는 확장 카드이다.</li>
<li>각 LAN 카드에는 고유 식별번호인 MAC 주소가 있다.</li>
</ul>
<h3 id="리피터">리피터</h3>
<ul>
<li>들어오는 약해진 신호 정도를 증폭해 다른 쪽으로 전달하는 장치이다.</li>
<li>이 기기를 통해 패킷이 더 멀리 갈 수 있지만 광케이블의 보급으로 현재에는 잘 쓰이지 않고 있다.</li>
</ul>
<h3 id="ap">AP</h3>
<ul>
<li>패킷을 복사하는 기기이다.</li>
<li>AP에 유선 LAN을 연결한 후 다른 장치에서 와이파이를 사용해 무선 네트워크 연결을 할 수 있다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[CS] TCP/IP 4계층 모델]]></title>
            <link>https://velog.io/@ho-taek/CS-TCPIP-4%EA%B3%84%EC%B8%B5-%EB%AA%A8%EB%8D%B8</link>
            <guid>https://velog.io/@ho-taek/CS-TCPIP-4%EA%B3%84%EC%B8%B5-%EB%AA%A8%EB%8D%B8</guid>
            <pubDate>Tue, 13 Dec 2022 08:39:37 GMT</pubDate>
            <description><![CDATA[<p>! &#39;면접을 위한 CS 전공지식 노트&#39;를 계속해서 복습한 내용을 적고 있다.</p>
<h2 id="개요">개요</h2>
<ul>
<li>인터넷 프로토콜 스위트 -&gt; 인터넷에서 컴퓨터들이 서로 정보를 주고받는 데 쓰이는 프로토콜의 집합<ul>
<li>프로토콜 : 어떤 시스템이 다른 시스템과 통신을 원활하게 수용하도록 해주는 통신 규약, 약속</li>
</ul>
</li>
<li>정리된 내용은 TCP/IP 4계층 모델로 -&gt; 네트워크에서 사용되는 통신 프로토콜의 집합으로 계층들은 프로토콜의 네트워킹 범위에 따라 네 개의 추상화 계층으로 구성됨.</li>
</ul>
<h2 id="1-1-계층-구조">1-1) 계층 구조</h2>
<p><img src="https://velog.velcdn.com/images/ho-taek/post/8e911d6d-799f-471f-b9ae-8767bf386352/image.png" alt=""></p>
<p>위에 그림과 같이 OSI 계층은 애플리케이션 계층을 세 개로 쪼개고 링크 계층을 데이터 링크 계층, 물리 계층으로 나눠서 표현하는 것이 다르며, 인터넷 계층을 네트워크 계층으로 부른다는 점이 다르다.</p>
<ul>
<li>이 계층들은 특정 계층이 변경되었을 때 다른 계층이 영향을 받지 않도록 설계되었다.<h3 id="애플리케이션-계층">애플리케이션 계층</h3>
</li>
<li>FTTP, HTTP, SSH, SMTP, DNS 등 응용 프로그램이 사용되는 프로토콜 계층<ul>
<li>웹 서비스, 이메일 등 서비스를 실질적으로 사람들에게 제공하는 층</li>
<li>FTP : 장치와 장치 간의 파일을 전송하는 데 사용되는 표준 통신 프로토콜</li>
<li>SSH : 보안되지 않은 네트워크에서 네트워크 서비스를 안전하게 운영하기 위한 암호화 네트워크 프로토콜</li>
<li>HTTP : 데이터 통신의 기초이자 웹 사이트를 이용하는데 쓰이는 프로토콜</li>
<li>SMTP : 전자 메일 전송을 위한 인터넷 표준 통신 프로토콜</li>
<li>DNS : 도메인 이름과 IP 주소를 매핑해주는 서버<h3 id="전송-계층">전송 계층</h3>
</li>
</ul>
</li>
<li>송신자와 수신자를 연결하는 통신 서비스를 제공하며</li>
<li>연결 지향 데이터 스트림 지원, 신뢰성, 흐름 제어를 제공</li>
<li>애플리케이션과 인터넷 계층 사이의 데이터가 전달될 때의 중계 역할을 함<ul>
<li>TCP,  UDP 등이 여기에 속함</li>
<li>TCP는 패킷 사이의 순서를 보장하고 연결지향 프로토콜을 사용해서 연결을 하여 신뢰성을 구축해 수신 여부를 확인하며 <strong>&#39;가상회선 패킷 교환 방식&#39;</strong>을 사용함.</li>
<li>UDP는 순서를 보장하지 않고 수신 여부를 확인하지 않으며 단순히 데이터만 주는 <strong>&#39;데이터그램 패킷 교환 방식&#39;</strong>을 사용함.<h4 id="가상회선-패킷-교환-방식">가상회선 패킷 교환 방식</h4>
</li>
</ul>
</li>
<li>각 패킷에는 가상회선 식별자가 포함되며 모든 패킷을 전송하면 가상회선이 해제되고 패킷들은 <strong>전송된 순서대로</strong> 도착하는 방식
<img src="https://velog.velcdn.com/images/ho-taek/post/97225911-116e-4b63-b90c-47bd003ce7b1/image.png" alt="">
3,2,1로 이루어진 패킷이 회선을 따라 순서대로 도착함<h4 id="데이터그램-패킷-교환-방식">데이터그램 패킷 교환 방식</h4>
</li>
<li>패킷이 독립적으로 이동하며 최적의 경로를 선택하여 감.</li>
<li>하나의 메시지에서 분활된 여러 패킷은 서로 다른 경로로 전송될 수 있으며 <strong>도착한 순서</strong>가 다를 수 있는 방식
<img src="https://velog.velcdn.com/images/ho-taek/post/499b8b50-b701-4a2e-a721-8ea9751e0ad7/image.png" alt="">
패킷이 순서도 다르고 어떠한 회선을 중심으로 가는 것이 아니라 따로따로 이동하며 순서도 다르게 도착함!</li>
</ul>
<h4 id="tcp-연결-성립-과정">TCP 연결 성립 과정</h4>
<ul>
<li>TCP는 신뢰성을 확보할 때 <strong>&#39;3-웨이 핸드셰이크&#39;</strong>라는 작업을 진행한다.</li>
<li>이때 나오는 단어<ul>
<li>SYN : 연결 요청 플래그</li>
<li>ACK : 응답 플래그</li>
<li>ISN : 초기 네트워크 연결을 할 때 할당된 32비트 고유 시퀀스 번호
<img src="https://velog.velcdn.com/images/ho-taek/post/269a4f7a-7e67-4505-a9cb-1fb1a340a284/image.png" alt=""></li>
</ul>
</li>
<li><ol>
<li>SYN 단계 : 클라이언트는 서버에 클라이언트의 ISN을 담아 SYN을 보낸다.
ISN은 새로운 TCP 연결의 첫 번째 패킷에 할당된 임의의 시퀀스(장치 마다 다를 수 있다)</li>
</ol>
</li>
<li><ol start="2">
<li>SYN + ACK 단계 : 서버는 클라이언트의 SYN을 수신하고 서버의 ISN을 보내며 승인 번호로 클라이언트의 ISN + 1을 보낸다.</li>
</ol>
</li>
<li><ol start="3">
<li>ACK 단계 : 클라이언트는 서버의 ISN + 1 한 값의 승인번호를 담아 ACK를 서버에 보낸다.</li>
</ol>
</li>
<li>위 과정 이후에  신뢰성이 구축되고 데이터 전송을 시작한다.<h4 id="tcp-연결-해제-과정">TCP 연결 해제 과정</h4>
</li>
<li>연결 해제시 <strong>&#39;4-웨이 핸드셰이크&#39;</strong>과정이 발생
<img src="https://velog.velcdn.com/images/ho-taek/post/a35dd8b2-debc-4bcd-9014-1031a139f1b4/image.png" alt=""></li>
<li>1번 : 클라이언트가 연결을 닫으려고 할 때 FIN으로 설정된 세그먼트를 보냄. 그리고 클라이언트는 FIN_WAIT_1 상태로 들어가고 서버의 응답을 기다린다.</li>
<li>2번 : 서버는 클라이언트로 ACK라는 승인 세그먼트를 보냄. 그리고 CLOSE_WAIT 상태에 들어감. 클라이언트가 세그먼트를 받으면 FIN_WAIT_2 상태에 들어감</li>
<li>3번 : 서버는 ACK를 보내고 일정 시간 이후에 클라이언트에 FIN이라는 세그먼트를 보냄.</li>
<li>4번 : 클라이언트는 TIME_WAIT 상태가 되고 다시 서버로 ACK를 보내서 서버는 CLOSED 상태가 됨. 이후 클라이언트는 어느 정도의 시간을 대기한 후 연결이 닫히고 클라이언트와 서버의 모든 자원의 연결이 해지됨.</li>
</ul>
<h4 id="time_wait">TIME_WAIT</h4>
<ul>
<li>지연 패킷이 발생할 경우를 대비하기 위함.<ul>
<li>패킷이 뒤늦게 도달하고 이를 처리하지 못할 경우 데이터 무결성 문제가 발생함.</li>
<li>데이터 무결성 : 데이터의 정확성과 일관성을 유지하고 보증하는 것</li>
</ul>
</li>
<li>두 장치가 연결이 닫혔는지 확인하기 위해서. 만약 LAST_ACK 상태에서 닫히게 되면 다시 새로운 연결을 하려고 할 때 장치는 줄공 LAST_ACK로 되어 있기 때문에 접속 오류가 나타나게 됨.</li>
</ul>
<h3 id="인터넷-계층">인터넷 계층</h3>
<ul>
<li>장치로부터 받은 네트워크 패킷을 IP 주소로 지정된 목적지로 전송하기 위해 사용되는 계층</li>
<li>IP, ARP, ICMP 등이 있음</li>
<li>패킷을 수신해야 할 상대의 주소를 지정해 데이터를 전달함.</li>
<li>상대방이 제대로 받았는지에 대해 보장하지 않는 비연결형적인 특징을 가지고 있다.</li>
</ul>
<h3 id="링크-계층">링크 계층</h3>
<ul>
<li>전선, 광섬유, 무선 등으로 실질적으로 데이터를 전달하며 장치 간에 신호를 주고받는 &#39;규칙&#39;을 정하는 계층</li>
<li>물리 계층 : 무선 LAN, 유선 LAN을 통해 0 과 1로 이루어진 데이터를 보내는 계층</li>
<li>데이터 링크 계층 : &#39;이더넷 프레임&#39;을 통해 에러 확인, 흐름 제어, 접근 제어를 담당하는 계층</li>
</ul>
<h4 id="유선-lan">유선 LAN</h4>
<ul>
<li>유선 LAN을 이루는 이더넷은 IEEE802.3이라는 프로토콜을 따르며 전이중화 통신을 쓴다.</li>
<li>전이중화 통신<ul>
<li>양쪽 장치가 동시에 송수신할 수 있는 방식.</li>
<li>송신로와 수신로로 나눠서 데이터를 주고받으며 현대의 고속 이더넷은 이 방식을 기반으로 통신하고 있다.</li>
</ul>
</li>
<li>CSMA/CD<ul>
<li>이전에는 유선 LAN에 &#39;반이중화 통신&#39; 방식을 썼다.</li>
<li>데이터를 보낸 이후 충돌이 발생한다면 일정 시간 이후 재전송하는 방식을 말함.</li>
<li>수신로와 송신로를 각각 둔 것이 아니고 한 경로를 기반으로 데이터를 보내기 때문에 데이터를 보낼 때 충돌에 대해 대비해야 했기 때문.<h4 id="무선-lan">무선 LAN</h4>
</li>
</ul>
</li>
<li>수신과 송신에 같은 채널을 사용하기 때문에 반이중화 통신을 사용함.</li>
<li>반 이중화 통신<ul>
<li>양쪽 자이는 서로 통신할 수 있지만, 동시에는 통신할 수 없으며 한 번에 한 방향만 통신할 수 있는 방식.</li>
<li>장치가 신호를 수신하기 시작하면 응답하기 전에 전송이 완료될 때까지 기다려야함</li>
<li>둘 이상의 장치가 동시에 전송하면 충돌이 발생해 메시지가 손실되거나 왜곡될 수 있기 때문에 충돌 방지 시스템이 필요</li>
</ul>
</li>
<li>CSMA/CA<ul>
<li>반이중화 통신 중 하나로 장치에서 데이터를 보내기 전에 캐리어 감지 등으로 사전에 가능한 한 충돌을 방지하는 방식을 사용함</li>
<li><ol>
<li>데이터를 송신하기 전에 무선 매체를 살핌</li>
</ol>
</li>
<li><ol start="2">
<li>캐리어 감지: 회선이 비어 있는지를 판단</li>
</ol>
</li>
<li><ol start="3">
<li>IFS : 랜덤 값을 기반으로 정해진 시간만큼 기다리며, 만약 무선 매체가 사용 중이면 점차 그 간격을 늘려가며 기다림.</li>
</ol>
</li>
<li><ol start="4">
<li>이후에 데이터를 송신함.</li>
</ol>
</li>
</ul>
</li>
</ul>
<h4 id="이더넷-프레임">이더넷 프레임</h4>
<ul>
<li>프레임 : 데이터를 담는 컨테이너</li>
<li>데이터 링크 계층은 이더넷 프레임을 통해 전달받은 데이터의 에러를 검출하고 캡슐화함.
<img src="https://velog.velcdn.com/images/ho-taek/post/d8e7f427-875f-4658-b8e3-31cbb11793a5/image.png" alt=""><ul>
<li>Preamble : 이더넷 프레임이 시작임을 알림.</li>
<li>SFD : 다음 바이트부터 MAC 주소 필드가 시작됨을 알림</li>
<li>DMAC, SMAC : 수신, 송식 MAC 주소</li>
<li>EtherType : 데이터 계층 위의 계층인 IP 프로토콜을 정의한다. 예를 들어 IPv4 또는 IPv6가 된다.</li>
<li>Payload : 전달받은 데이터</li>
<li>CRC : 에러 확인 비트</li>
</ul>
</li>
<li>MAC 주소<ul>
<li>컴퓨터나 노트북 등 각 장치에는 네트워크에 연결하기 위한 장치(LAN 카드)가 있는데, 이를 구별하기 위한 식별 번호<h3 id="계층간-데이터-송수신-과정">계층간 데이터 송수신 과정</h3>
<img src="https://velog.velcdn.com/images/ho-taek/post/7bf3bb89-24fe-4330-b877-dbc8d58797d0/image.png" alt=""></li>
</ul>
</li>
<li>애플리케이션 계층에서 전송 계층으로 보내는 요청 값들이 캡슐화 과정을 거쳐 전달되고, 다시 링크 계층을 통해 해당 서버와 통신을 하고, 해당 서버의 링크 계층으로부터 애플리케이션 계층까지 비캡슐화 과정을 거쳐 데이터가 전송된다.</li>
</ul>
<h4 id="캡슐화-과정">캡슐화 과정</h4>
<ul>
<li>상위 계층의 헤더와 데이터를 하위 계층의 데이터 부분에 포함시키고 해당 계층의 헤더를 삽입하는 과정
<img src="https://velog.velcdn.com/images/ho-taek/post/d4e52978-cd29-4404-888c-e5fdbbddf4d9/image.png" alt=""></li>
<li>애플리케이션 계층의 데이터가 전송 계층으로 전달되면서 <strong>&#39;세그먼트&#39;</strong> 또는 <strong>&#39;데이터그램</strong>&#39;화 되며 TCP(L4) 헤더가 붙여지게 됨.</li>
<li>그 이후 인터넷 계층으로 가면서 IP(L3) 헤더가 붙여지게 되며 <strong>&#39;패킷&#39;</strong> 화가 되고, 이후 링크 계층으로 전달되면서 프레임 헤더와 프레임 트레일러가 붙어 <strong>&#39;프레임&#39;</strong>화가 됨.</li>
</ul>
<h4 id="비캡슐화-과정">비캡슐화 과정</h4>
<p><img src="https://velog.velcdn.com/images/ho-taek/post/9a077e55-8397-4446-85c4-8345bcccc554/image.png" alt=""></p>
<ul>
<li>캡슐화된 데이터를 받게 되면 링크 계층에서부터 타고 올라오면서 프레임화된 데이터 -&gt; 패킷화 -&gt; 세그먼트, 데이터그램화 -&gt; 메세지화의 과정</li>
<li>최종적으로 사용자에게 애플리케이션의 PDU인 메시지로 전달됨.<h2 id="1-2-pdu">1-2) PDU</h2>
</li>
<li>네트워크의 어떠한 계층에서 계층으로 데이터가 전달될 때 한 덩어리의 단위를 PDU라고 함.</li>
<li>PDU는 제어 관련 정보들이 포함된 &#39;헤더&#39;, 데이터를 의미하는 &#39;페이로드&#39;로 구성되어 있으며 계층마다 부르는 명칭이 다름.<ul>
<li>애플리케이션 계층 : 메시지</li>
<li>전송 계층 : 세그먼트(TCP), 데이터그램(UDP)</li>
<li>인터넷 계층 : 패킷</li>
<li>링크 계층 : 프레임(데이터 링크 계층), 비트(물리 계층)</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[CS]네트워크의 기초]]></title>
            <link>https://velog.io/@ho-taek/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC%EC%9D%98-%EA%B8%B0%EC%B4%88</link>
            <guid>https://velog.io/@ho-taek/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC%EC%9D%98-%EA%B8%B0%EC%B4%88</guid>
            <pubDate>Sun, 11 Dec 2022 07:39:20 GMT</pubDate>
            <description><![CDATA[<p>여러 면접을 보고 다니면서 CS 질문을 받았을 때 &#39;엥 저게 뭐였지? 아...망했네&#39;의 경험이 항상 있었다. 코테를 보더라도 알고리즘 문제 뿐만 아니라 CS 관련한 객관식도 나오는데 항상 찍었...지
그런 스스로를 반성하고 &#39;나도 선배&#39;라는 프로젝트에서 도서를 구입할 수 있는 기회를 얻어 면접을 위한 CS 전공지식노트를 구매했고, 계속 공부하며 노션에 적고는 있지만 기억력이 짧은 나는 계속 복습을 해줘야 한다.
그래서 지금 쓰고 있는 블로그에 공부한 내용들을 다시 정리하고자 한다!! 아자자</p>
<h1 id="1-네트워크란">1. 네트워크란</h1>
<blockquote>
<p>네트워크란 <strong>노드(node)</strong>와 <strong>링크(link)</strong>가 서로 연결되어 있거나 연결되어 있지 않은 집합체를 의미한다.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/ho-taek/post/09d16609-9c74-405c-ad74-b3d188e31cf7/image.png" alt="노드와 링크">
여기서 노드란 서버, 라우터, 스위치 등 네트워크 장치를 의미하고 링크는 유선 또는 무선을 의미함.</p>
<h2 id="1-1-처리량과-지연-시간">1-1) 처리량과 지연 시간</h2>
<blockquote>
<p>좋은 네트워크란 <strong>많은 처리량</strong>을 처리할 수 있고, <strong>지연 시간이 짧고</strong>, <strong>장애 빈도가 적고</strong>, <strong>좋은 보안</strong>을 갖춘 네트워크</p>
</blockquote>
<h3 id="처리량">처리량</h3>
<ul>
<li>링크를 통해 전달되는 단위 시간당 데이터 양</li>
<li>단위는 bps(bits per second) -&gt; 초당 전송 또는 수신되는 비트 수</li>
<li>처리량은 사용자들이 많이 접속할 때마다 커지는 트래픽, 네트워크 장치 간의 대역폭, 네트워크 중간에 발생하는 에러, 장치의 하드웨어 스펙에 영향을 받음.</li>
<li>대역폭  : 주어진 시간 동안 네트워크 연결을 통해 흐를 수 있는 최대 비트 수.
<img src="https://velog.velcdn.com/images/ho-taek/post/f3370796-a94e-4520-8d7e-eb1abfa41009/image.png" alt=""></li>
</ul>
<h3 id="지연시간">지연시간</h3>
<ul>
<li>요청이 처리되는 시간 -&gt; 어떤 메세지가 두 장치 사이를 왕복하는데 걸린 시간</li>
<li>지연시간은 매체 타입(무선, 유선), 패킷 크기, 라우터의 패킷 처리 시간에 영향을 받음.
<img src="https://velog.velcdn.com/images/ho-taek/post/a8135d13-39d9-4194-898f-57046a72bbf3/image.png" alt=""></li>
</ul>
<h2 id="1-2-네트워크-토폴로지와-병목-현상">1-2) 네트워크 토폴로지와 병목 현상</h2>
<h3 id="네트워크-토폴로지">네트워크 토폴로지</h3>
<blockquote>
<p>노드와 링크가 어떻게 배치되어 있는지에 대한 방식이자 연결 형태를 의미</p>
</blockquote>
<h4 id="트리-토폴로지">트리 토폴로지</h4>
<ul>
<li>계층형 토폴로지라고 하며 트리 형태로 배치한 네트워크 구성</li>
<li>노드의 추가, 삭제가 쉬우며 특정 노드에 트래픽이 집중될 때 하위 노드에 영향을 끼칠 수 있음.
<img src="https://velog.velcdn.com/images/ho-taek/post/ab2a6763-6c85-41bc-8425-a9d3814ee7b3/image.png" alt=""></li>
</ul>
<h4 id="버스-토폴로지">버스 토폴로지</h4>
<ul>
<li>중앙 통신 회선 하나에 여러 개의 노드가 연결되어 공유하는 네트워크 구성</li>
<li>근거리 통신만(LAN)에 사용한다.</li>
<li>설치 비용이 적고 신뢰성이 우수하며 중앙 통신 회선에 노드를 추가하거나 삭제하기 쉬움.</li>
<li>스푸핑이 가능한 문제점이 있다!<ul>
<li>스푸핑은 LAN상에서 송신부의 패킷을 송신과 관련 없는 다른 호스트에 가지 않도록 하는 스위칭 기능을 마비시켜 -&gt; 특정 노드에 해당 패킷이 오도록 처리하는 것.</li>
<li><del>데이터를 빼오는 느낌?</del>
<img src="https://velog.velcdn.com/images/ho-taek/post/a1f9760b-c2ca-488b-a920-febe92b20968/image.png" alt=""></li>
</ul>
</li>
</ul>
<h4 id="스타-토폴로지">스타 토폴로지</h4>
<ul>
<li>중앙에 있는 노드에 모두 연결된 네트워크 구성</li>
<li>노드를 추가하거나 에러를 탐지하기 쉽고 패킷의 충돌 발생 가능석이 적음.</li>
<li>어떠한 노드에 장애가 발생해도 쉽게 에러를 발견할 수 있음.</li>
<li>장애 노드가 중앙 노드가 아닐 경우 다른 노드에 영향을 끼치는 것이 적음 -&gt; 즉 중앙 노드에 장애가 발생하면 전체 네트워크를 사용할 수 없고 설치 비용이 고가
<img src="https://velog.velcdn.com/images/ho-taek/post/0ca4b0c7-de39-4ea0-95ec-884a37d5adf2/image.png" alt=""></li>
</ul>
<h4 id="링형-토폴로지">링형 토폴로지</h4>
<ul>
<li>각각의 노드가 양 옆의 두 노드와 연결해 전체적으로 고리처럼 하나의 연속된 길을 통해 통신을 하는 망 구성 방식</li>
<li>데이터는 노드에서 노드로 이동</li>
<li>노드 수가 증가되어도 네트워크상의 손실이 거의 없고 충돌이 발생되는 가능성이 적고, 노드의 고장 발견을 쉽게 찾을 수 있음</li>
<li>네트워크 구성 변경이 어렵고 회선에 장애가 발생하면 전체 네트워크에 영향을 크게 끼치는 단점이 있음.
<img src="https://velog.velcdn.com/images/ho-taek/post/6f0520e4-b9f5-439a-b18c-9f9d36ba6717/image.png" alt=""></li>
</ul>
<h4 id="메시-토폴로지망형-토폴로지">메시 토폴로지(망형 토폴로지)</h4>
<ul>
<li>그물망처럼 연결되어 있는 구조</li>
<li>한 단말 장치에 장애가 발생해도 여러 개의 경로가 존재하므로 네트워크를 계속 사용할 수 있고 트래픽도 분산 처리가 가능</li>
<li>노드의 추가가 어렵고 구축 비용과 운용 비용이 고가임</li>
</ul>
<h3 id="병목-현상">병목 현상</h3>
<blockquote>
<p>병목현상은 전체 시스템의 성능이나 용량이 하나의 구성 요소로 인해 제한을 받는 현상, 서비스에서 이벤트를 열었을 때 트래픽이 많이 생기고 그 트래픽을 잘 관리하지 못하면 병복 현상이 생겨 사용자가 웹 사이트로 들어갈 수 없다.</p>
</blockquote>
<ul>
<li>토폴로지가 중요한 이유는 병목 현상을 찾을 때 중요한 기준이 되기 때문(회선 추가 및 네트워크 구성 변경을 통해)</li>
<li>네트워크가 어떤 토폴로지를 갖는지, 어떠한 경로로 이루어져 있는지 알아야 병목 현상을 해결할 수 있음.</li>
</ul>
<h2 id="1-3-네트워크-분류">1-3) 네트워크 분류</h2>
<ul>
<li>네트워크는 규모를 기반으로 분류가 가능<ul>
<li>LAN : 사무실과 개인적 소유 가능한 규모</li>
<li>MAN : 시 정도의 규모</li>
<li>WAN : 세계 규모<h3 id="lan">LAN</h3>
</li>
</ul>
</li>
<li>근거리 통신망을 의미</li>
<li>전송 속도가 빠르고 혼잡하지 않음.<h3 id="man">MAN</h3>
</li>
<li>대도시 지역 네트워크를 나타내며 도시 같은 넓은 지역에서 운영</li>
<li>전송 속도는 평균이며 LAN보다는 혼잡<h3 id="wan">WAN</h3>
</li>
<li>광역 네트워크를 의미하며, 국가 또는 대륙 같은 더 넓은 지역에서 운영</li>
<li>전송 속도는 낮으며 MAN보다 더 혼잡</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Android] Kotlin - 손전등]]></title>
            <link>https://velog.io/@ho-taek/Android-%EC%86%90%EC%A0%84%EB%93%B1</link>
            <guid>https://velog.io/@ho-taek/Android-%EC%86%90%EC%A0%84%EB%93%B1</guid>
            <pubDate>Sun, 04 Dec 2022 07:43:40 GMT</pubDate>
            <description><![CDATA[<p>! 혼자서 여러 기능<del>(아무거나 내가 넣어보고 싶은 것들)</del>을 가진 모듬을 만들고 있는데, 그 중 첫 번째가 손전등 기능이다.</p>
<p>일단, 의존성 주입은 Hilt를 사용했고, 손전등이 꺼져 있는지 안꺼져있는지 상태를 관찰하기 위해 ViewModel과 StateFlow를 사용해서 구현했다.</p>
<p>일단 Torch라는 코틀린 파일을 하나 만들어서 코드를 구현했다.</p>
<pre><code class="language-kotlin">package com.assorted.presentation.light

import android.content.Context
import android.hardware.camera2.CameraCharacteristics
import android.hardware.camera2.CameraManager
import dagger.hilt.android.qualifiers.ActivityContext
import javax.inject.Inject


class Torch @Inject constructor(
    @ActivityContext private val context: Context
) {
    private var cameraId: String? = null
    //1
    private val cameraManager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager 

    //2
    init {
        cameraId = getCameraId()
    }

    //MainActivity에서 사용할 예정.
    //3
    fun flashCheck(value: Boolean) {
        cameraManager.setTorchMode(cameraId.toString(), value)
    }

    //2
    private fun getCameraId(): String? {
        val cameraIds = cameraManager.cameraIdList
        for (id in cameraIds) {
            val info = cameraManager.getCameraCharacteristics(id)
            val flashAvailable = info.get(CameraCharacteristics.FLASH_INFO_AVAILABLE)

            val lensFacing = info.get(CameraCharacteristics.LENS_FACING)
            if (flashAvailable != null
                &amp;&amp; flashAvailable
                &amp;&amp; lensFacing != null
                &amp;&amp; lensFacing == CameraCharacteristics.LENS_FACING_BACK
            ) return id
        }
        return null
    }
}</code></pre>
<ol>
<li>손전등을 키기 위해서는 cameraManager객체가 필요하다.<pre><code class="language-kotlin"> private val cameraManager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager</code></pre>
</li>
<li>손전등을 끄거나 킬때 카메라 ID가 필요한데 이는 init 생성자를 통해 클래스 초기화 시에 얻는다.
카메라ID는 기기에 내장된 카메라마다 고유한 ID가 부여된다.<pre><code class="language-kotlin">init {
     cameraId = getCameraId()
 }

</code></pre>
</li>
</ol>
<p> private fun getCameraId(): String? {
        val cameraIds = cameraManager.cameraIdList
        for (id in cameraIds) {
            val info = cameraManager.getCameraCharacteristics(id)
            val flashAvailable = info.get(CameraCharacteristics.FLASH_INFO_AVAILABLE)</p>
<pre><code>        val lensFacing = info.get(CameraCharacteristics.LENS_FACING)
        if (flashAvailable != null
            &amp;&amp; flashAvailable
            &amp;&amp; lensFacing != null
            &amp;&amp; lensFacing == CameraCharacteristics.LENS_FACING_BACK
        ) return id
    }
    return null
}</code></pre><pre><code>이때 플래쉬가 이용가능한지 뒷면에 렌즈가 있는 카메라인지를 체크한다.
![](https://velog.velcdn.com/images/ho-taek/post/a0b4eed4-f1c6-4be6-a21e-2f1f31610d42/image.png)

가능하다면 카메라 ID를 return 한다.

3. setTorchMode를 통해 플래쉬를 끄거나 킨다.
위에서 생성한 cameraId와 킬경우 true를, 끌경우 false를 넣어주면 된다.
![](https://velog.velcdn.com/images/ho-taek/post/34a943db-7de1-4358-82a0-bad66e3186a7/image.png)


```kotlin
fun flashCheck(value: Boolean) {
        cameraManager.setTorchMode(cameraId.toString(), value)</code></pre><p>이렇게 Torch 클래스를 만든 뒤 MainActivity에서 이미지와 이벤트를 연결시켜 주면 끝난다!</p>
<p>```kotlin
@AndroidEntryPoint
class MainActivity : BaseActivity<ActivityMainBinding>(R.layout.activity_main) {
    @Inject
    lateinit var torch: Torch</p>
<p>override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        clickLight()
        setLight()
    }</p>
<p>//손전등 클릭 이벤트
    private fun clickLight() {
        binding.btnLight.setOnClickListener {
            mainViewModel.setLightCheck()
        }
    }</p>
<p>//손전등 관찰
private fun setLight() {
        mainViewModel.lightCheck.flowWithLifecycle(lifecycle)
       .onEach {
           torch.flashCheck(it)
           binding.btnLight.isSelected = it
     }
     .launchIn(lifecycleScope)
    }</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Android] debounce 코루틴 구현]]></title>
            <link>https://velog.io/@ho-taek/Android-debounce-%EC%BD%94%EB%A3%A8%ED%8B%B4-%EA%B5%AC%ED%98%84</link>
            <guid>https://velog.io/@ho-taek/Android-debounce-%EC%BD%94%EB%A3%A8%ED%8B%B4-%EA%B5%AC%ED%98%84</guid>
            <pubDate>Tue, 14 Jun 2022 16:11:51 GMT</pubDate>
            <description><![CDATA[<p>!빵동여지도 앱을 개발하면서 빵집 검색에 있어서 타이핑이 될 때마다 즉시 서버 통신으로 받아오게끔 로직을 짰는데 이 부분에서 서버에 큰 부하를 주게 된다는 점을 알려주시며 debounce를 추천해주셨다.</p>
<h1 id="1-debounce란">1. debounce란</h1>
<blockquote>
<p>여러 이벤트가 발생할 때 이 이벤트를 일정 그룹으로 묶어서 하나로 처리하는 것.</p>
</blockquote>
<p>주로 실시간 검색에서 사용되는데 우리가 네이버와 같은 검색 엔진에서 검색 할때 밑에 관련 검색어가 나타난다!
<img src="https://velog.velcdn.com/images/ho-taek/post/05aa62e1-42fc-4d30-a56e-5236521be05d/image.png" alt=""></p>
<p>이때 하나의 타이핑 입력할 때마다 서버에 요청하게 되면 그만큼 서버에 부하를 주기 때문에 이를 타이핑이 입력되고 0.7초 0.5초 이런식으로 이벤트가 없을 경우 서버에 데이터를 요청하도록 하는 것이다!</p>
<p>만약 설정한 시간안에 새로운 이벤트(타이핑)을 할 경우 전에 입력했던 이벤트는 취소된다!</p>
<h1 id="2-코드">2. 코드</h1>
<p>코루틴을 이용해서 구현했다!</p>
<pre><code>fun &lt;T&gt; debounce(
    timeMillis: Long = 300L,
    coroutineScope: CoroutineScope,
    block: (T) -&gt; Unit
): (T) -&gt; Unit {
    var debounceJob: Job? = null
    return {
        debounceJob?.cancel()
        debounceJob = coroutineScope.launch {
            delay(timeMillis)
            block(it)
        }
    }
}</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[Android] 컴포넌트 - 서비스(Service)]]></title>
            <link>https://velog.io/@ho-taek/Android-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EC%84%9C%EB%B9%84%EC%8A%A4Service</link>
            <guid>https://velog.io/@ho-taek/Android-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EC%84%9C%EB%B9%84%EC%8A%A4Service</guid>
            <pubDate>Mon, 18 Apr 2022 17:04:57 GMT</pubDate>
            <description><![CDATA[<h1 id="1-service란">1. Service란?</h1>
<blockquote>
<p>백그라운드에서 오래 실행되는 작업을 수행할 수 있는 어플리케이션 컴포넌트이다.</p>
</blockquote>
<ul>
<li><p>사용자에게 인터페이스(UI)를 제공하지 않는다</p>
</li>
<li><p>다른 어플리케이션 컴포넌트가 Service를 시작할 수 있고, 다른 어플로 전환하더라도 백그라운드에서 계속 실행된다</p>
</li>
<li><p>어플리케이션 컴포넌트와 Service를 바인딩하여 Service와 상호작용할 수 있고, 프로세스간 통신(IPC)도 실행이 가능하다.</p>
</li>
<li><p>Service는 별개의 프로세스가 아니며, 특별히 지정하지 않았을 경우 어플리케이션이 실행되고 있는 것과 동일한 스레드에서 실행된다</p>
</li>
<li><p>추가로 Service는 스레드가 아니다</p>
</li>
<li><p>Service는 앱에서 오직 1개의 인스턴스만을 생성할 수 있다.</p>
</li>
</ul>
<p>네트워크 트랜잭션을 처리하거나, 음악을 재생하거나, 파일 입출력을 수행하는 등의 작업에 사용된다.</p>
<h1 id="2-service-유형">2. Service 유형</h1>
<h3 id="1-포그라운드-서비스">1) 포그라운드 서비스</h3>
<ul>
<li><p>사용자에게 직접 보이는 작업을 수행한다</p>
<ul>
<li><p>알림창을 통해서 Service가 실행중인 것을 나타낸다. 대신, 시스템에 의해서 강제로 종료되지 않는다</p>
</li>
<li><p>사용자가 앱과 상호작용 하지 않을 때에도 계속 실행된다.</p>
</li>
<li><p>예를 들면, 음악 앱일 경우 우리가 음악 트랙을 재생할 때 사용하는 것이 포그라운드 서비스이다.</p>
</li>
</ul>
</li>
</ul>
<h3 id="2-백그라운드-서비스">2) 백그라운드 서비스</h3>
<ul>
<li><p>사용자에게 보이지 않는 작업을 수행한다.</p>
</li>
<li><p>시스템에서 리소스가 부족할 경우에 강제 종료 될 수 있다.</p>
</li>
<li><p>API 26(오레오) 이상 부터 앱이 포그라운드에 있지 않을 때 백그라운드 서비스를 강제로 종료시킨다!(제한을 적용) 이를 위해, 앱이 scheduled job을 대체로 사용해야 한다</p>
</li>
<li><p>예를 들면, 사용자의 위치 정보를 가지고 올 때 사용된다.</p>
</li>
</ul>
<h3 id="3-바인드-서비스">3) 바인드 서비스</h3>
<ul>
<li><p>서버 - 클라이언트 구조에서 서버에 해당된다.</p>
</li>
<li><p>액티비티와 같은 컴포넌트들이 바인드 한 후 요청을 보내고, 응답을 받고, 프로세스간 통신(IPC)를 할 수 있도록 만들 수 있다.</p>
</li>
<li><p>바인드된 서비스의 경우 보통 다른 앱 컴포넌트들에 바인드 되어 있는 동안 살아있어서 백그라운드에서 계속 실행되는 것은 아니다!</p>
</li>
</ul>
</n>
포그라운드, 백그라운드 서비스는 started Service, 바인드 서비스는 bound Service로 작동이 된다.

<p>이 두가지 방식의 서비스는 같이 실행이 가능한데 이 말인 즉슨 한 서비스에서 bindService()와 startService()의 실행이 동시에 가능하다.</p>
<h1 id="3-service-생명주기">3. Service 생명주기</h1>
<p> <img src="https://velog.velcdn.com/images/ho-taek/post/a1fd6303-0111-4c10-a4a4-6aede3e6da76/image.png" alt=""></p>
<p>Service에서는 안드로이드의 다른 컴포넌트 처럼 생명주기 메서드들이 있다 이를 살펴보자</p>
<h3 id="1-startservice">1) startService()</h3>
<h4 id="1-1-oncreate">1-1) onCreate()</h4>
<ul>
<li>Service가 처음 생성되었을 경우 onStartCommand() 및 onBind()가 호출되기 전에 실행된다.
( 서비스가 이미 실행중인 경우에는 실행되지 않는다)</li>
</ul>
<h4 id="1-2-onstartcommand">1-2) onStartCommand()</h4>
<ul>
<li>다른 컴포넌트(액티비티)가 서비스를 시작하도록 요청하는 경우에 이 메서드를 실행한다.</li>
</ul>
<ul>
<li>startService() 메서드를 통해 호출한다.</li>
</ul>
<ul>
<li>이 메서드가 실행될 시 백그라운드에서 무한히 실행되므로, 반드시 stopSelf() 혹은 stopService()로 서비스를 종료시켜야한다.</li>
</ul>
<ul>
<li><p>바인드 서비스만 이용하는 경우에 이 메서드를 사용하지 않아도 된다.</p>
</li>
<li><p>onStartCommand()의 Return값을 살펴보면 다음이 있다</p>
<ul>
<li><p>START_NOT_STICKY : 시스템이 서비스의 onStartCommand()를 반환 후에 중단시키면 서비스를 재생성하면 안됨</p>
</n>
</li>
<li><p>START_STICKY : 시스템이 onStartCommand()를 반환 후 서비스를 중단하는 경우 서비스를 자동으로 다시 생성하고 마지막 인텐트는 전달하지 않는다. 이때 Intent를 null로 반환한다.</p>
</li>
<li><p>START_REDELIVER_INTENT : 시스템이 onStartCommand()를 반환 후에 서비스를 다시 생성하고 이 서비스에 전달된 마지막 인텐트로 onStartCommand()를 호출시 모든 보류 인텐트가 차례로 전달된다.
즉시 재개되어야 하는 작업을 수행하는데 파일 다운로드에 적합하다.</p>
</li>
</ul>
<p>START_STICKY의 경우 필요에 의해 명시적으로 시작되고 중단되는 서비스에 사용되며</p>
<p>나머지 둘의 경우에는 전송된 명령을 처리하는 동안에만 서비스가 실행되어야 하는 경우에 사용된다.</p>
</li>
</ul>
<h4 id="1-3-ondestroy">1-3) onDestroy()</h4>
<ul>
<li>서비스가 종료될 때 이 메소드가 반한된다. 서비스에 등록된 리소스들을 정리하는 작업들을 여기서 한다.</li>
</ul>
<h4 id="1-4-startservice-stopservice">1-4) startService(), stopService()</h4>
<ul>
<li>서비스 실행 및 종료시에 사용한다.</li>
</ul>
<h3 id="2-bindservice">2) BindService</h3>
<h4 id="2-1-oncreate">2-1) onCreate()</h4>
<h4 id="2-2-onbind">2-2) onBind()</h4>
<ul>
<li><p>안드로이드의 구성요소가 서비스에 바인딩하고자 하는 경우, 이 메소드가 호출된다.</p>
</li>
<li><p>이 메소드를 구현할 때에는 클라이언트가 서비스와 통신을 주고 받기 위해 사용할 인터페이스를 제공해야 하낟.</p>
</li>
<li><p>이를 위해 IBinder를 반환하면 된다.</p>
</li>
<li><p>이 메서드는 항상 구현해야 하지만, 바인딩을 허용하지 않으려면 null을 반환하면 된다.</p>
</li>
</ul>
<h4 id="2-3-onrebind">2-3) onRebind()</h4>
<ul>
<li>unBind()된 후에 서비스가 다시 실행될 경우 호출 된다.</li>
</ul>
<h4 id="2-4-onunbind">2-4) onUnbind()</h4>
<ul>
<li>unBindService() 호출시 true가 호출된다.</li>
</ul>
<h4 id="2-5-bindservice">2-5) bindService()</h4>
<ul>
<li>서비스에 바인딩하고자 할 때 사용한다.</li>
</ul>
<h4 id="2-6-unbindservice">2-6) unBindService()</h4>
<ul>
<li>서비스를 언바인딩하고자 할 때 사용한다.</li>
</ul>
</n>

<h3 id="service-connection-콜백-메소드">Service connection 콜백 메소드</h3>
<h4 id="2-7-onserviceconnected">2-7) onServiceConnected()</h4>
<ul>
<li>서비스에 바인딩 되었을 때 호출 된다.</li>
</ul>
<h4 id="2-8-onservicedisconnected">2-8) onServiceDisconnected()</h4>
<ul>
<li><p>서비스와 바인드 된 구성요소가 중단되거나 예기치 않게 서비스와 연결이 끊어졌을 때 호출된다.</p>
</li>
<li><p>unBind()를 통해 호출되었을 경우에는 호출되지 않는다.</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Kotlin] 스코프함수(Scope function)]]></title>
            <link>https://velog.io/@ho-taek/Kotlin-%EC%8A%A4%EC%BD%94%ED%94%84%ED%95%A8%EC%88%98Scope-function</link>
            <guid>https://velog.io/@ho-taek/Kotlin-%EC%8A%A4%EC%BD%94%ED%94%84%ED%95%A8%EC%88%98Scope-function</guid>
            <pubDate>Wed, 30 Mar 2022 13:27:48 GMT</pubDate>
            <description><![CDATA[<p>! 스코프 함수는 매번 쓸 때마다 apply? run? with? 무엇을 써야할지 헷갈린다. 이번 기회에 확실히 공부해서 정리하고자 한다.</p>
<h1 id="1-스코프-함수">1. 스코프 함수</h1>
<p>코틀린의 표준 라이브러리에서  &#39;스코프 함수&#39;라는 것을 제공해준다. 스코프 함수란</p>
<blockquote>
<p>특정 객체의 컨텍스트 안에서 특정 동작(속성 초기화, 활용 등)을 실행하기 위한 목적 만을 가진 함수</p>
</blockquote>
<p>이 스코프 함수를 람다 함수로 사용할시 스코프를 형성하게 되는데 이 스코프 내에서는 객체의 이름을 참조할 필요 없이 객체에 접근하고 핸들링하기 편하게끔 해준다.</p>
<p><strong>apply, run, with, also, let</strong>이 있고 이제 이것들에 대해 자세히 알아보자!</p>
<pre><code>data class Member(val name : String, var age: Int)</code></pre><h3 id="1-apply">1) apply</h3>
<pre><code>inline fun &lt;T&gt; T.apply(block : T.() -&gt; Unit): T {
        block()
        return this
 }</code></pre><ul>
<li><p>객체를 새로 생성하고 특정 변수에 할당하기 전에 초기화 작업을 하는 스코프를 만든다</p>
</li>
<li><p>apply 함수 내에 모든 명령들이 수행되고 나면 명령들이 적용되어 새로 생성된 객체를 반환</p>
</li>
<li><p>반환 결과가 객체 자신!</p>
</li>
<li><p>확장 함수이기 때문에 객체 컨텍스트를 receiver(this)로 이용이 가능하다.</p>
</li>
</ul>
<p><img src="https://images.velog.io/images/ho-taek/post/32e212b1-8961-4a9a-a08c-a14ea038fd54/image.png" alt=""></p>
<p>실행결과 : 이벤트 아메리카노의 500원</p>
<h3 id="2-run">2) run</h3>
<pre><code>inline fun &lt;T,R&gt; T.run(block : T.() -&gt; R) : R {
        return block()
    }</code></pre><ul>
<li><p>apply와 명확하게 다른 점이 반환하는 값이 객체가 아닌 스코프 내에 실행된 값이다</p>
</li>
<li><p>그러므로 특정 객체의 프로퍼티를 출력하거나 계산값으로 활용하는 등의 핸들링을 할 때 사용한다.</p>
</li>
<li><p>확장함수 이기 때문에 apply와 마찬가지로 receiver(this)로 이용이 가능하다.</p>
</li>
<li><p>safe call(.?)을 붙여 non-null일 때만 실행이 가능하다.</p>
</li>
</ul>
<p><img src="https://images.velog.io/images/ho-taek/post/5636da17-dee8-4071-b3df-47530120df17/image.png" alt=""></p>
<p><img src="https://images.velog.io/images/ho-taek/post/62eba3e2-3dba-4b75-aecc-0b67b55b59e7/image.png" alt=""></p>
<p>반환하는 값이 객체가 아니라 스코프내에서 실행된 this.price + 3000의 값이 나온다.</p>
<h3 id="3-with">3) with</h3>
<pre><code>inline fun &lt;T, R&gt; with(receiver : T, block: T.() -&gt; R) : R{
        return receiver.block()
   }
</code></pre><ul>
<li><p>확장 함수가 아니므로 컨텍스트 객체를 argument로 전달하며 람다의 내부에서는 확장함수로 적용되어 receiver(this)로 사용이 가능하다!</p>
</li>
<li><p>특징 및 동작은 위의 run과 동일하다!</p>
</li>
</ul>
<pre><code>val member = Member(&quot;hotaek&quot;, 26)
with(member) {
    println(&quot;$name&quot;)
    println(&quot;$age&quot;)
}
실행 결과 : hotaek, 26</code></pre><h3 id="4-also">4) also</h3>
<pre><code>inline fun &lt;T&gt; T.also(block: (T) -&gt; Unit) : T {
        block(this)
        return this
 }</code></pre><ul>
<li><p>also는 apply와 동일하게 생성된 인스턴스를 반환한다.</p>
</li>
<li><p>it을 사용해 프로퍼티에 접근이 가능하다.</p>
</li>
<li><p>객체의 프로퍼티를 전혀 사용하지 않거나 변경하지 않고 사용하는 경우에 유용하다</p>
</li>
<li><p>예를 들면, 객체의 데이터 유효성 확인, 디버그, 로깅 등의 부가적인 목적으로 사용함</p>
</li>
</ul>
<p><img src="https://images.velog.io/images/ho-taek/post/5aae2bdf-beae-4a0f-9b7c-dffec57e560b/image.png" alt=""></p>
<h3 id="5-let">5) let</h3>
<pre><code>inline fun&lt;T,R&gt; T.let(block : (T) -&gt; R) : R{
        return block(this)
  }</code></pre><ul>
<li><p>let은 run과 동일하게 최종 실행 결과를 반환한다.</p>
</li>
<li><p>it을 사용해 프로퍼티에 접근이 가능하다.</p>
</li>
<li><p>지정된 값이 null이 아닌 경우에 코드를 실행해야 하는 경우 및 nullable 객체를 다른 nullable 객체로 변환하는 경우 사용한다.</p>
</li>
</ul>
<p><img src="https://images.velog.io/images/ho-taek/post/d5b6f1d0-fe4d-4d3b-a636-154ce4abc45b/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Kotlin] Object 싱글톤]]></title>
            <link>https://velog.io/@ho-taek/Kotlin-Object-%EC%8B%B1%EA%B8%80%ED%86%A4</link>
            <guid>https://velog.io/@ho-taek/Kotlin-Object-%EC%8B%B1%EA%B8%80%ED%86%A4</guid>
            <pubDate>Thu, 17 Mar 2022 06:37:00 GMT</pubDate>
            <description><![CDATA[<p>! 이번 나도선배에서도 Object를 활용해 싱글톤 패턴을 활용해 후기를 작성한 사람인지 아닌지 구분하는 변수를 호출했었다.</p>
<h1 id="1-싱글톤패턴">1. 싱글톤패턴</h1>
<blockquote>
<p>해당 클래스에 한 개의 인스턴스만을 갖게하고 전역 범위내에서 인스턴스에 접근할 수 있도록 사용하는 패턴</p>
</blockquote>
<p>싱글톤 패턴의 경우 디자인 패턴에 속하고 많이 사용하고 있는 패턴이다!</p>
<p>디자인 패턴이란 반복적으로 일어나는 문제에 대해서 어떻게 해결할 것인지에 대한 해결책이라고 생각하면 된다. </p>
<p><del>나중에 한번 GoF의 디자인 패턴 읽어 보면서 추가로 공부해봐야지!</del></p>
<h3 id="1-사용-이유">1) 사용 이유</h3>
<p>싱글톤 패턴을 사용하는 이유는 프로그램 개발을 하면서 객체를 하나만 써야하는 경우가 존재한다.</p>
<ul>
<li>어플리케이션 사용자 설정, 로그 기록, 대화 상자 및 리소스 관리 객체 등</li>
</ul>
<p>또한 메모리 측면이나 데이터 공유에 있어서 좋기 때문이다.</p>
<p>액티비티나 프래그먼트 딴에서 인텐트 하거나 객체 생성시 번거롭기도 하고 비용이 발생하게 된다. 이를 해결해줄 수 있는 방식이 바로 싱글톤이다.</p>
<h3 id="2-장점">2) 장점</h3>
<ul>
<li><p>고정된 메모리 영역을 할당 받기 때문에 핞번의 생성자 호출로 인스턴스를 생성하며 그 외에는 메모리 안에 있는 인스턴스만을 호출하기 때문에 메모리 낭비를 막고 컨텍스트 스위칭 비용을 아낄 수 있다.</p>
</li>
<li><p>전역 인스턴스이기 때문에 이유에 말했 듯 데이터 공유가 쉽다.</p>
</li>
</ul>
</n>

<h3 id="3-단점">3) 단점</h3>
<ul>
<li>여러 클래스들이 공유하게 될 경우 결합도가 높아지게 되고, 객체지향 원칙인 개방-폐쇄 원칙을 위배하기 때문에 <strong>객체지향적인 싱글톤 설계</strong>가 필요하다</li>
</ul>
<ul>
<li><p>멀티 쓰레드를 사용할 경우 동기화 문제도 잘 설계할 필요성이 있다.</p>
</li>
<li><p>코틀린의 경우 프로세스 시작시 바로 메모리에 올라가기 때문에 만약 클래스를 사용하지 않더라도 메모리 비용이 낭비된다.</p>
</li>
</ul>
<h3 id="4-해결책">4) 해결책</h3>
<ul>
<li>이를 해결하기 위해 by lazy를 통해 내부 변수들의 초기화 시점을 조정한다. 호출될 때 메모리에 올라갈 수 있도록!!</li>
</ul>
<h3 id="5-예시">5) 예시</h3>
<ul>
<li><p>코틀린에서 사용할 때는 Object 키워드를 이용한다.</p>
<pre><code>object{

  val isReviewed by lazy { &quot;후기 작성 안함&quot; }

}</code></pre></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Kotlin] Sealed Class란]]></title>
            <link>https://velog.io/@ho-taek/Kotlin-Sealed-Class%EB%9E%80</link>
            <guid>https://velog.io/@ho-taek/Kotlin-Sealed-Class%EB%9E%80</guid>
            <pubDate>Fri, 11 Feb 2022 08:50:35 GMT</pubDate>
            <description><![CDATA[<p>! 프로젝트 진행하면서 코드를 좀더 간결하게 짜고 싶은 마음에 다시 코틀린 공부를 시작하고 있다.<del>(미리미리좀 해놓을걸...)</del> 앱잼도 끝났고 릴리즈 및 버전 업에도 쓰일만한 것들을 위주로 공부하고 있는데 그 중 하나가 Sealed Class이다.</p>
<h1 id="1-sealed-class란">1. Sealed Class란</h1>
<blockquote>
<p> 값이 제한된 집합의 유형 중 하나를 가질 수 있지만 다른 유형을 가질 수 없는 제한된 클래스 계층 구조를 나타내는데 사용하는 클래스이다.</p>
</blockquote>
<p>클래스를 상속받는 하위 클래스들이 여러 파일에 있을 경우 컴파일러가 클래스에 대해 얼마나 많은 하위 클래스들이 있는지 알지 못한다.</p>
<p>하지만 Sealed Class의 경우 동일한 파일에서 선언해야 하기 때문에 </p>
<p>&quot;이 파일에서 쓰인게 아닌 다른 파일에서 쓰이는 하위 클래스는 없어!!&quot;라는 것을 컴파일러에게 알려줄 수 있다.</p>
<p>예를 들면, Shape라는 상위 클래스를 만들고, 같은 파일에 이 클래스를 상속하는 Rectangle, Circle의 클래스를 만들었다고 생각해보면,</p>
<p>Sealed Class는 이 두가지의 클래스 외에 상속을 받는 하위 클래스가 없다는 것을 컴파일러에게 알려주는 것이다!</p>
<p>그럼 이것이 왜 중요하냐?!! 바로 <strong>when 문 사용시 else부분이 필요가 없다.</strong></p>
<p><img src="https://images.velog.io/images/ho-taek/post/2fa222e0-9ed9-410c-9883-a70f44935cb3/image.png" alt=""></p>
<p>추상 클래스로 작성한 코드에 경우 맨 밑에 else를 반드시 넣어줘야 한다. 넣어주지 않을 경우</p>
<p><img src="https://images.velog.io/images/ho-taek/post/025873eb-4ddd-4dac-91ce-70afdbc6945a/image.png" alt="">
다음과 같이 오류가 발생한다. 즉 컴파일러가 Shape를 상속 받는 하위 클래스들을 정확하게 모르기 때문이다.</p>
<p>하지만 이를 Sealed Class로 변환하면 컴파일러가 하위 클래스들을 정확하게 알 수 있기 때문에 else를 쓰지 않아도 되고, </p>
<p><img src="https://images.velog.io/images/ho-taek/post/64c1f190-9c6d-4cf9-8c9c-fa7c721d9027/image.png" alt=""></p>
<p>빠진 부분에 대해서도 체크가 가능하다.
<img src="https://images.velog.io/images/ho-taek/post/e90bd173-42e1-483f-8685-2650a588d247/image.png" alt=""></p>
<ul>
<li>Sealed 클래스의 생성자는 기본적으로 Private이고 다른 접근 제한자를 가질 수 없다.</li>
</ul>
<h1 id="2-정의-방법">2. 정의 방법</h1>
<ul>
<li><p>Sealed class 키워드를 사용</p>
</li>
<li><p>하위 클래스가 상속 받도록 한다.</p>
</li>
</ul>
<p>위의 사진과 같이 정의가 가능하고</p>
<ul>
<li><p>중첩  클래스로 적용이 가능하다.
<img src="https://images.velog.io/images/ho-taek/post/8450c01e-28e4-4647-a828-10664ad09a55/image.png" alt=""></p>
</li>
<li><p>class, data class, object class로도 정의가 가능하다!</p>
</li>
</ul>
<h3 id="enum-class와의-비교">enum Class와의 비교</h3>
<ul>
<li><p>enum class의 이점과 동일하지만, enum class의 경우에는 1개의 객체만 생성 가능하고 복수의 객체를 생성하는 것이 불가능하다.</p>
</li>
<li><p>하지만 sealed class의 경우 복수의 객체를 생성하는 것이 가능하다!</p>
</li>
</ul>
</n>

<p>참고 : <a href="https://codechacha.com/ko/kotlin-sealed-classes/">codechacha</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Android] Gradle]]></title>
            <link>https://velog.io/@ho-taek/Android-Gradle</link>
            <guid>https://velog.io/@ho-taek/Android-Gradle</guid>
            <pubDate>Tue, 25 Jan 2022 08:55:46 GMT</pubDate>
            <description><![CDATA[<p>! cleanArchitecture 사용을 위해 기존에 single module로 사용했었는데, 이번에는 multimodule를 적용하려고 하다보니 gradle에 대해 알 필요가 있어서 공부한 내용들을 여기에 적어본다.</p>
<h1 id="1-gradle">1. gradle</h1>
<p><img src="https://images.velog.io/images/ho-taek/post/e24543cc-34b8-4ffd-bad8-b3887a703cea/image.png" alt=""></p>
<blockquote>
<p>Gradle이란 Maven Ant와 같은 빌드 배포 도구이다. </p>
</blockquote>
<p>여기서 gradle은 유연함과 성능에 초점을 둔 <strong>오픈소스 빌드 도구</strong>이다. </p>
<p>즉 코드들을 모바일에서 실행하도록 변환해주는 시스템이라고 생각하면 된다!!</p>
<p>안드로이드 스튜디오(IDE)와 빌드 시스템은 서로 독립적인데 <strong>안드로이드 스튜디오는 코드의 편집만을 담당하고 빌드는 이 gradle를 통해서 수행된다.</strong></p>
<p>이런 방식으로 분리되어 있기 때문에 프로젝트 관리가 더 깔끔해질 수 있다.
</n>
<img src="https://images.velog.io/images/ho-taek/post/3e5981ac-e62b-4fc8-8122-26cc7bc00093/image.png" alt=""></p>
<p>안드로이드 스튜디오에서 코끼리가 있는 것이 바로 Gradle Script</p>
<h1 id="2-dsl">2. DSL</h1>
<h2 id="1-dsl이란">1) DSL이란?</h2>
<p>gradle에서는 Groovy DSL 언어와 Kotlin DSL을 사용하는데  이 둘에 대해 간략히 정리하자면 다음과 같다. 먼저 DSL에 대해 알아보자</p>
<ul>
<li><p>DSL</p>
<ul>
<li><p>DSL은 특정 분야에 최적화된 프로그래밍 언어를 뜻한다.</p>
</li>
<li><p>java와 kotlin의 경우는 서버도 만들 수 있고 앱도 만들 수 있기 때문에 DSL에 해당하지 않는다.</p>
</li>
</ul>
</li>
</ul>
<p>즉 <strong>어떤 목적이 있고 그 목적만 달성할 수 있도록 만들어진 언어이다.</strong>
</n></p>
<p>그러면, 안드로이드 스튜디오에서 사용하는 Groovy DSL과 Kotlin DSL은 무엇이고 그 차이는 무엇일까?!</p>
<ul>
<li><p>Groovy DSL</p>
<ul>
<li><p>JVM에서 실행되는 스크립트 언어로 문법이 java와 가깝다.</p>
</li>
<li><p>java와 호환이 되고 java 클래스 파일을 그대로 Groovy 클래스로 사용할 수 있다.</p>
</li>
</ul>
</li>
</ul>
<ul>
<li><p>Kotlin DSL</p>
<ul>
<li>코틀린 언어의 특징으로 가독성이 좋고 간략하나 코드를 사양해 Gradle 스크립팅을 하는 것을 목적으로 하는 DSL이다.</li>
</ul>
</li>
</ul>
<h2 id="2-kotlin-dsl-사용-이유">2) Kotlin DSL 사용 이유?</h2>
<ul>
<li><p>Kotlin DSL 장점</p>
<ul>
<li><p>컴파일 타임에 에러 확인</p>
</li>
<li><p>코드  탐색</p>
</li>
<li><p>자동 완성</p>
</li>
<li><p>구문 강조</p>
</li>
<li><p>IDE의 지원으로 향상된 편집환경</p>
</li>
<li><p>소스코드와 동일한 언어의 사용(일관성)</p>
</li>
</ul>
</li>
<li><p>Kotlin DSL 단점</p>
<ul>
<li><p>클린 빌드시 Groovy보다 느리다.</p>
</li>
<li><p>새로운 라이브러리 버전 inspection 기능 미지원</p>
</li>
</ul>
</li>
</ul>
<p>내가 사용한 언어는 Kotlin DSL로 groovy에서 kts로 변경하는 방법은 <a href="https://developer.android.com/studio/build/migrate-to-kts">구글 공식문서</a>에 나와있다.</p>
<h1 id="3-buildgradle">3. build.gradle</h1>
<p><img src="https://images.velog.io/images/ho-taek/post/3e5981ac-e62b-4fc8-8122-26cc7bc00093/image.png" alt="">
build.gradle을 잘 살펴보면 Project와 Module로 나뉘어져 있다.</p>
<p>Project수준의 경우 전체 프로젝트를 위한 설정이다. Project 수준이 있는 이유는 안드로이드 스튜디오의 앱이 모듈 단위이고, 여러 모듈을 묶어서 관리하기 위해서이다.</p>
<p>Module 수준의 경우 빌드에 사용될 SDK 버전, 애플리케이션 버전, 라이브러리 등의 항목들을 설정하는 것이 가능하다.</p>
<p>Module 하나당 하나의 gradle 파일이 만들어진다.</p>
<p><img src="https://images.velog.io/images/ho-taek/post/75ebd117-9349-48a8-862e-e959b5846674/image.png" alt=""></p>
<p>CleanArchitecture 멀티 모듈로 만들어졌을때, Module에 따라 gradle 파일이 여러개 만들어지는 모습을 볼 수 있다.</p>
<p>추가로 buildsrc 모듈이 있는데 Gradle 문서에서 다음과 같이 buildSrc에 대한 내용이 나와있다.</p>
<blockquote>
<p>gradle이 수행되면 buildSrc 디렉터리가 존재하는지 체크한다. 이 경우에 gradle이 자동적으로 코드를 컴파일하고 테스트한 뒤에 빌드 스크립트의 classpath에 넣는다.</p>
</blockquote>
<p>이 방법의 경우 유지 보수 및 코드 테스트가 더 쉽다.</p>
<p>즉, buildSrc를 통해 전체 프로젝트에서 version이나 App 설정등에 대한 공유가 가능해진다.</p>
<p><img src="https://images.velog.io/images/ho-taek/post/2d6e12c9-721d-4824-b48c-f1cc4d23259c/image.png" alt=""></p>
<h1 id="4-module">4. Module</h1>
<p><img src="https://images.velog.io/images/ho-taek/post/376def52-6cb1-4235-9520-2d8afed11d48/image.png" alt=""></p>
<ol>
<li>plugin </li>
</ol>
<ul>
<li>안드로이드 플러그인 사용을 gradle에 적용하는 것.</li>
</ul>
<ol start="2">
<li>android</li>
</ol>
<ul>
<li>안드로이드와 관련된 빌드 설정들</li>
</ul>
<p><img src="https://images.velog.io/images/ho-taek/post/8af1eecc-2345-4900-b8c3-fb69334c73cb/image.png" alt=""></p>
<ol start="3">
<li>dependencies{}</li>
</ol>
<ul>
<li>라이브러리와 같이 의존성 추가를 위한 곳</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Algorithm] 최단 경로 알고리즘 -  플로이드 워셜 알고리즘]]></title>
            <link>https://velog.io/@ho-taek/Algorithm-%EC%B5%9C%EB%8B%A8-%EA%B2%BD%EB%A1%9C-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%ED%94%8C%EB%A1%9C%EC%9D%B4%EB%93%9C-%EC%9B%8C%EC%85%9C-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</link>
            <guid>https://velog.io/@ho-taek/Algorithm-%EC%B5%9C%EB%8B%A8-%EA%B2%BD%EB%A1%9C-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%ED%94%8C%EB%A1%9C%EC%9D%B4%EB%93%9C-%EC%9B%8C%EC%85%9C-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</guid>
            <pubDate>Mon, 20 Dec 2021 05:17:36 GMT</pubDate>
            <description><![CDATA[<p>!&quot;이것이 코딩 테스트다 with 파이썬&quot; 책을 통해 공부한 내용을 정리하는 중이다. 저번 시간에는 다익스트라 알고리즘에 대해 공부했었는데 우선순위 큐를 통해서 구현하는 과정을 배웠다. 오늘은 그에 이어서 플로이드 워셜 알고리즘에 대해 공부하고 구현하는 것을 정리할 계획이다.</p>
<h1 id="1-플로이드-워셜-알고리즘">1. 플로이드 워셜 알고리즘</h1>
<blockquote>
<p>모든 지점에서 다른 모든 지점까지의 최단 경로를 모두 구해야 하는 경우에 사용</p>
</blockquote>
<p>단계마다 &#39;거쳐 가는 노드&#39;를 기준으로 알고리즘을 수행!</p>
<p>노드의 개수가 N개일 때 N번의 단계를 수행하고, 단계마다 O(N^2)의 연사을 통해 &#39;현재 노드를 거쳐 가는&#39; 모든 경로를 고려한다.</p>
<p>즉 O(N^3)의 시간 복잡도를 가진다.</p>
<p><strong>* 다익스트라 알고리즘이 1차원 리스트를 이용했다면, 플로이드 워셜 알고리즘은 2차원 리스트를 이용한다. *</strong></p>
<p>플로이드 워셜 알고리즘은 앞서 배웠던 다이나믹 프로그래밍인데 이는 노드의 개수가 N개일 때, N번 만큼의 단계를 반복하고 다음의 &#39;점화식에 맞게&#39; 2차원 리스트를 갱신하기 때문이다.</p>
<blockquote>
<p>Dab = min(Dab, Dak + Dkb)</p>
</blockquote>
<p>a에서 b로 가는 최소 비용과 a에서 k를 거쳐 B로 가는 비용을 비교해서 더 작은 값으로 갱신하겠다는 의미이다.</p>
<h2 id="1-과정">1) 과정</h2>
<p><img src="https://images.velog.io/images/ho-taek/post/c46cf02e-e020-440a-ae35-66f6aa73f82a/image.png" alt=""></p>
<p>다음과 같은 그래프가 있을 때, &#39;연결된 간선&#39;의 경우 값을 채워 넣고, 연결되지 않은 간선은 무한의 값을 넣는다.</p>
<p>여기서 무한은 우리가 보통 사용해왔던 int(1e9)를 사용하면 된다.</p>
<p>그리고 자기 자신으로 가는 비용은 0으로 적는다.</p>
<p>표로 살펴보면</p>
<table>
<thead>
<tr>
<th align="center">출발/도착</th>
<th align="center">1번</th>
<th align="center">2번</th>
<th align="center">3번</th>
<th align="center">4번</th>
</tr>
</thead>
<tbody><tr>
<td align="center">1번</td>
<td align="center">0</td>
<td align="center">4</td>
<td align="center">무한</td>
<td align="center">6</td>
</tr>
<tr>
<td align="center">2번</td>
<td align="center">3</td>
<td align="center">0</td>
<td align="center">7</td>
<td align="center">무한</td>
</tr>
<tr>
<td align="center">3번</td>
<td align="center">5</td>
<td align="center">무한</td>
<td align="center">0</td>
<td align="center">4</td>
</tr>
<tr>
<td align="center">4번</td>
<td align="center">무한</td>
<td align="center">무한</td>
<td align="center">2</td>
<td align="center">0</td>
</tr>
</tbody></table>
<h3 id="--단계-1">- 단계 1</h3>
<p>처음 1번 노드를 거쳐 가는 경우를 고려한다. 이때 점화식을 활용해서 모든 경우의 수를 넣으면 된다.</p>
<p>D23 = min(D23,D21+13)
D24 = min(D24,D21+14)
D32 = min(D32,D31+12)
D34 = min(D34,D31+14)
D42 = min(D42,D41+14)
D43 = min(D43,D41+13)</p>
<p>계산한 뒤 값을 갱신해주면 된다.</p>
<table>
<thead>
<tr>
<th align="center">출발/도착</th>
<th align="center">1번</th>
<th align="center">2번</th>
<th align="center">3번</th>
<th align="center">4번</th>
</tr>
</thead>
<tbody><tr>
<td align="center">1번</td>
<td align="center">0</td>
<td align="center">4</td>
<td align="center">무한</td>
<td align="center">6</td>
</tr>
<tr>
<td align="center">2번</td>
<td align="center">3</td>
<td align="center">0</td>
<td align="center">7</td>
<td align="center">9</td>
</tr>
<tr>
<td align="center">3번</td>
<td align="center">5</td>
<td align="center">9</td>
<td align="center">0</td>
<td align="center">4</td>
</tr>
<tr>
<td align="center">4번</td>
<td align="center">무한</td>
<td align="center">무한</td>
<td align="center">2</td>
<td align="center">0</td>
</tr>
</tbody></table>
<h3 id="--단계-2">- 단계 2</h3>
<p>마찬 가지로 2번 노드를 거쳐 가는 경우를 계산한다.</p>
<table>
<thead>
<tr>
<th align="center">출발/도착</th>
<th align="center">1번</th>
<th align="center">2번</th>
<th align="center">3번</th>
<th align="center">4번</th>
</tr>
</thead>
<tbody><tr>
<td align="center">1번</td>
<td align="center">0</td>
<td align="center">4</td>
<td align="center">11</td>
<td align="center">6</td>
</tr>
<tr>
<td align="center">2번</td>
<td align="center">3</td>
<td align="center">0</td>
<td align="center">7</td>
<td align="center">9</td>
</tr>
<tr>
<td align="center">3번</td>
<td align="center">5</td>
<td align="center">9</td>
<td align="center">0</td>
<td align="center">4</td>
</tr>
<tr>
<td align="center">4번</td>
<td align="center">무한</td>
<td align="center">무한</td>
<td align="center">2</td>
<td align="center">0</td>
</tr>
</tbody></table>
<p>그 뒤 쭉쭉쭉쭉 남은 노드들을 계산해주면 다음과 같다.</p>
<table>
<thead>
<tr>
<th align="center">출발/도착</th>
<th align="center">1번</th>
<th align="center">2번</th>
<th align="center">3번</th>
<th align="center">4번</th>
</tr>
</thead>
<tbody><tr>
<td align="center">1번</td>
<td align="center">0</td>
<td align="center">4</td>
<td align="center">8</td>
<td align="center">6</td>
</tr>
<tr>
<td align="center">2번</td>
<td align="center">3</td>
<td align="center">0</td>
<td align="center">7</td>
<td align="center">9</td>
</tr>
<tr>
<td align="center">3번</td>
<td align="center">5</td>
<td align="center">9</td>
<td align="center">0</td>
<td align="center">4</td>
</tr>
<tr>
<td align="center">4번</td>
<td align="center">7</td>
<td align="center">11</td>
<td align="center">2</td>
<td align="center">0</td>
</tr>
</tbody></table>
</br>

<h3 id="2-구현">2) 구현</h3>
<pre><code>INF = int(1e9)

#노드의 개수 및 간선의 개수 입력받기

n = int(input())
m = int(input())

#2차원 리스트를 만들고, 모든 값을 무한으로 초기화

graph = [[INF] * (n+1) for _ in range(n+1)]

#자기 자신으로 가는 비용은 0으로 초기화

for a in range(1, n+1):
    for b in range(1, n+1):
        if a == b:
            graph[a][b] = 0

#각 간선에 대한 정보를 입력받고, 초기화

for _ in range(m):

    #a에서 b로 가는 비용 c
    a,b,c = map(int, input().split())

for k in range(1, n+1):
    for a in range(1, n+1):
        for b in range(1, n+1):
            graph[a][b] = min(graph[a][b], graph[a][k] + graph[k][b])

# 결과 출력
for a in range(1, n+1):
    for b in range(1, n+1):
        if graph[a][b] = INF:
            print(&quot;INF&quot;, end=&quot; &quot;)
        else:
            print(graph[a][b], end=&quot; &quot;)
print()</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[Algorithm] 최단 경로 알고리즘 - 다익스트라 최단 경로 알고리즘]]></title>
            <link>https://velog.io/@ho-taek/Algorithm-%EC%B5%9C%EB%8B%A8-%EA%B2%BD%EB%A1%9C-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</link>
            <guid>https://velog.io/@ho-taek/Algorithm-%EC%B5%9C%EB%8B%A8-%EA%B2%BD%EB%A1%9C-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</guid>
            <pubDate>Thu, 16 Dec 2021 04:12:47 GMT</pubDate>
            <description><![CDATA[<p>! 오랜만에 돌아온 알고리즘 공부... 빡세게 해야지</p>
<h1 id="1-최단-경로-알고리즘">1. 최단 경로 알고리즘</h1>
<blockquote>
<p>가장 짧은 경로를 찾는 알고리즘</p>
</blockquote>
<p>보통 &#39;길 찾기&#39;에 많이 사용하는 알고리즘 이다.</p>
<p>최단 경로 알고리즘의 경우 보통 그래프로 표현하는데 각 지점은 그래프에서 <strong>노드</strong>로 표현되고, 지점 간 연결된 도로는 그래프에서 <strong>간선</strong>으로 표현된다.</p>
<p>주로 많이 사용 되는 최단 경로 알고리즘에는 밑에 3개가 있다.</p>
<ul>
<li>다익스트라 최단 경로 알고리즘</li>
<li>플로이드 워셜</li>
<li>벨만 포드 </li>
</ul>
<h1 id="2-다익스트라-최단-경로-알고리즘">2. 다익스트라 최단 경로 알고리즘</h1>
<blockquote>
<p>그래프에서 여러 개의 노드가 있을 때, 특정한 노드에서 출발하여 다른 노드로 가는 각각의 최단 경로를 구해주는 알고리즘</p>
</blockquote>
<p>중요한 점은 <strong>음의 간선</strong>이 없을 때 정상적으로 동작한다.</p>
<ul>
<li>음의 간선 : 0보다 작은 값을 가지는 간선</li>
</ul>
<p>현실 세계에서의 길은 음의 간선으로 표현되지 않기 때문에 다익스트라 알고리즘은 실제로 GPS 소프트웨어의 기본 알고리즘은 채택 되곤 한다.</p>
<h3 id="1-원리-및-과정">1) 원리 및 과정</h3>
<ul>
<li>출발 노드를 설정</li>
<li>최단 거리 테이블을 초기화</li>
<li>방문하지 않은 노드 중에서 최단 거리가 가장 짧은 노드를 선택</li>
<li>해당 노드를 거쳐 다른 노드로 가는 비용을 계산하여 최단 거리 테이블을 갱신</li>
<li>3번과 4번을 반복!!</li>
</ul>
<p>중요한 점은 &#39;각 노드에 대한 현재까지의 최단 거리&#39;정보를 항상 1차원 리스트에 저장하며 리스트를 계속 갱신한다!!</p>
<p><img src="https://images.velog.io/images/ho-taek/post/f302c203-ec45-4ff9-a6c1-c122a934ad7f/image.png" alt=""></p>
<p>다음과 같은 예시에서 출발 노드는 1이다.</p>
<p>초기 상태에서 다른 모든 노드로 가는 최단 거리를 &#39;무한&#39;으로 초기화 한다.</p>
<p>이때 1e9라는 실수 자료형으로 처리한다.</p>
<ul>
<li><p>방문하지 않은 노드 중에서 최단 거리가 짧은 노드를 선택하는데,  출발 노드에서 출발 노드로의 거리는 0으로 본다.</p>
</br>

<table>
<thead>
<tr>
<th>노드번호</th>
<th align="center">1</th>
<th align="center">2</th>
<th align="center">3</th>
<th align="center">4</th>
<th align="center">5</th>
<th align="center">6</th>
</tr>
</thead>
<tbody><tr>
<td>거리</td>
<td align="center">0</td>
<td align="center">무한</td>
<td align="center">무한</td>
<td align="center">무한</td>
<td align="center">무한</td>
<td align="center">무한</td>
</tr>
</tbody></table>
</li>
</ul>
<ul>
<li><p>다음으로 1번 노드에서 다른 노드로 가는 비용을 계산한다. 즉 1번 노드와 연결된 모든 간선을 하나씩 확인한뒤 테이블을 갱신한다.</p>
<table>
<thead>
<tr>
<th>노드번호</th>
<th align="center">1</th>
<th align="center">2</th>
<th align="center">3</th>
<th align="center">4</th>
<th align="center">5</th>
<th align="center">6</th>
</tr>
</thead>
<tbody><tr>
<td>거리</td>
<td align="center">0</td>
<td align="center">2</td>
<td align="center">5</td>
<td align="center">1</td>
<td align="center">무한</td>
<td align="center">무한</td>
</tr>
</tbody></table>
</li>
</ul>
<ul>
<li><p>다음 단계에서 최단 거리가 가장 짧은 노드를 선택하는데 여기서는</p>
</li>
<li><p><em>4*</em> 가 당첨!! 4에서 갈 수 있는 노드인 3번과 5번 까지의 거리를 구하고 표를 다시 갱신한다.</p>
<table>
<thead>
<tr>
<th>노드번호</th>
<th align="center">1</th>
<th align="center">2</th>
<th align="center">3</th>
<th align="center">4</th>
<th align="center">5</th>
<th align="center">6</th>
</tr>
</thead>
<tbody><tr>
<td>거리</td>
<td align="center">0</td>
<td align="center">2</td>
<td align="center">4</td>
<td align="center">1</td>
<td align="center">2</td>
<td align="center">무한</td>
</tr>
</tbody></table>
</li>
</ul>
<ul>
<li><p>다음 에서는 2번 노드가 선택된다.(거리가 같을 경우 일반적으로 번호가 작은 노드를 선택) 이전 단계와 동일한 방법을 반복한다.</p>
<table>
<thead>
<tr>
<th>노드번호</th>
<th align="center">1</th>
<th align="center">2</th>
<th align="center">3</th>
<th align="center">4</th>
<th align="center">5</th>
<th align="center">6</th>
</tr>
</thead>
<tbody><tr>
<td>거리</td>
<td align="center">0</td>
<td align="center">2</td>
<td align="center">4</td>
<td align="center">1</td>
<td align="center">2</td>
<td align="center">무한</td>
</tr>
<tr>
<td></br></td>
<td align="center"></td>
<td align="center"></td>
<td align="center"></td>
<td align="center"></td>
<td align="center"></td>
<td align="center"></td>
</tr>
</tbody></table>
</li>
<li><p>결국 마지막의 테이블의 최종 갱신본은 다음과 같다.</p>
<table>
<thead>
<tr>
<th>노드번호</th>
<th align="center">1</th>
<th align="center">2</th>
<th align="center">3</th>
<th align="center">4</th>
<th align="center">5</th>
<th align="center">6</th>
</tr>
</thead>
<tbody><tr>
<td>거리</td>
<td align="center">0</td>
<td align="center">2</td>
<td align="center">3</td>
<td align="center">1</td>
<td align="center">2</td>
<td align="center">4</td>
</tr>
</tbody></table>
</li>
</ul>
<p>이 테이블이 의미하는 바는 1번 노드로 출발했을 때 2번, 3번, 4번, 5번, 6번 노드까지 가기 위한 최단 경로가 각각 2,3,1,2,4라는 의미다.</p>
<h3 id="2-코드-구현">2) 코드 구현</h3>
<p>코드 구현을 위해서는 힙 자료구조를 사용한다.</p>
<p><strong>힙</strong> 자료구조는 <strong>우선순위 큐</strong>를 구현하기 위하여 사용하는 자료구조중 하나인데 우선순위 큐는 우선순위가 가장 높은 데이터를 가장 먼저 삭제한다는 점이 특징이다.</p>
<p>이 우선순위 큐를 사용하기 위해서 파이썬에는 heapq 라이브러리를 사용한다.</p>
<p>우선 순위 큐에서는 (가치, 값)으로 구성되며 가치가 낮은 데이터가 먼저 삭제되는 최소 힙, 가치가 높은 데이터가 먼저 삭제되는 최대 힙을 이용할 수 있다.</p>
<p>다익스트라 알고리즘을 구현할 때에도 이 우선순위 큐를 활용한다. 원리는 위의 설명과 동일하고 거리와 노드를 넣을 때 (거리, 노드)의 튜플을 활용한다.</p>
<pre><code class="language-python">import heapq
import sys
input = sys.stdin.readline
INF = int(1e9) #무한을 의미하는 값

#노드의 개수, 간선 개수 입력받기
n,m = map(int, input().split())

#시작 노드 번호 입력
start = int(input())

# 각 노드에 연결되어 있는 노드에 대한 정보를 담는 리스트 만들기

graph = [[] for i in range(n+1)]

#최단 거리 테이블 모두 무한으로 초기화

distance = [INF] * (n+1)

#모든 간선 정보 입력받기

for _ in range(m):
    a, b, c = map(int, input().split())

    #a번 노드에서 b번 노드로 가는 비용이 c라는 의미

    graph[a].append((b,c))

def djkstra(start):
    q = []
    heapq.heappush(q,(0, start))
    distance[start] = 0
    while q:
        #가장 최단 거리가 짧은 노드에 대한 정보 꺼내기
        dist, now = heapq.heappop(q)

        # 현재 노드가 이미 처리된 적이 있는 노드라면 무시
        if distance[now] &lt; dist:
            continue
        #현재 노드와 연결된 다른 인접한 노드들을 확인
        for i in graph[now]:
            cost = dist + i[1]
            #현재 노드를 거쳐서, 다른 노드로 이동하는 거리가 더 짧은 경우
            if cost &lt; distance[i[0]]:
                distance[i[0]] = cost
                heapq.heappush(q, (cost, i[0]))

dikstra(start)

for i in range(1, n+1):
    if distance[i] == INF:
        print(&quot;infinite&quot;)
    else:
        print(distance[i])</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Android] 코루틴]]></title>
            <link>https://velog.io/@ho-taek/Android-%EC%BD%94%EB%A3%A8%ED%8B%B4</link>
            <guid>https://velog.io/@ho-taek/Android-%EC%BD%94%EB%A3%A8%ED%8B%B4</guid>
            <pubDate>Thu, 18 Nov 2021 11:50:10 GMT</pubDate>
            <description><![CDATA[<p>! <a href="https://velog.io/@ho-taek/Android-%EC%8A%A4%EB%A0%88%EB%93%9C%EB%9E%80">스레드</a> 저번에 스레드 공부를 한 이유가 코루틴을 공부하기 위해서인데 혹시 스레드에 대해 모르신다면 저기 링크나 다른 블로그에서 찾아보시는 것을 추천드려요(모르고 공부하니까 진짜 모르겠음...)</p>
<h1 id="1-코루틴">1. 코루틴?</h1>
<p>코루틴이 나오기 이전에 앱이나 웹에서 비동기 처리를 위해 rx programming을 많이 사용해왔다. 하지만 구글이 안드로이드 공식 언어를 코틀린으로 변경한 이후에 코루틴에 대한 중요도도 상당히 높아졌다고 생각된다.</p>
<p><a href="https://wooooooak.github.io/kotlin/2019/08/25/%EC%BD%94%ED%8B%80%EB%A6%B0-%EC%BD%94%EB%A3%A8%ED%8B%B4-%EA%B0%9C%EB%85%90-%EC%9D%B5%ED%9E%88%EA%B8%B0/">쾌락코딩</a>, <a href="https://seunghyun.in/android/7/">Kotlin Coroutine 번역</a> 이 두 블로그를 보면서 공부를 했다.</p>
<blockquote>
<p>코루틴은 스레드 안에서 실행되는 일시 중단 가능한 작업의 단위로 하나의 스레드에 여러 코루틴이 존재할 수 있다.</p>
</blockquote>
<p>코루틴은 resume 될 때 마다 다른 스레드에서 실행될 수 있고, 특정 스레드에서만 국한될 수 있다.</p>
<p>코루틴의 특징 중 중요한 부분이 이 두가지 라고 한다.</p>
<ul>
<li>협력형 멀티 태스킹</li>
<li>동시성 프로그래밍 지원</li>
</ul>
<h2 id="1-협력형-멀티태스킹">1) 협력형 멀티태스킹</h2>
<p>코루틴(Co + Routine)에서 Co는 &quot;협력&quot;이라는 의미를 지니고 있고, Routine은 하나의 함수라고 생각하면 된다. 직역하자면 &quot;협력하는 함수&quot;이다.</p>
<p>Routine에 대해 간단히 알아보자면 main routine과 sub routine이 존재한다.</p>
<pre><code class="language-kotlin">fun main(){
    ...
    val beerCount = drinkBeer(value)
    ...
}

fun drinkBeer(value : Int){
    val one = 1
    val beerCount = vlaue + one

    return beerCount
}</code></pre>
<p>다음과 같은 코틀린 코드에서 main 함수는 메인이 되는 함수! </p>
<p>여기서 drinkBeer라는 서브 함수를 호출한다.</p>
<p>메인 함수는 메인 루틴, 서브 함수는 서브 루틴이 된다.</p>
<p>이 서브 루틴의 경우 루틴에 진입하는 곳과 빠져나오는 곳이 명확하게 보인다. </p>
<p>메인 루틴이 서브 루틴을 호출했을 때, 서브루틴의 맨 처음에 진입하여 return을 호출하거나 닫는 괄호를 만날 때 이 서브 루틴을 빠져나오게 된다.</p>
<p>위의 코드를 예시로 들자면, drinkBeer 함수에 진입하고 return을 통해 빠져나오게 된다.(명확해!)</p>
<p>그러나 코루틴은 다르다.</p>
<p>일단 코루틴도 routine이므로 하나의 함수로 여기자.</p>
<p>위의 서브 루틴과 다르게 코루틴은 진입할 수 있는 곳도 여러 개이고, 함수를 빠져나갈 수 있는 곳도 여러개다.</p>
<p>즉 중간에 나갈 수 있고, 다시 나갔던 그 지점으로 들어올 수도 있다.</p>
</br>

<p>이때 나갈 수 있도록 하는 코드가 <strong>suspend</strong> 코드이다.</p>
<p>추가로 이 suspend를 붙이는 것은 코틀린 컴파일러에게 이 함수가 코루틴 안에서 실행되어야 한다고 알려주는 역할!!</p>
<p>코드로 보자</p>
<pre><code class="language-Kotlin">val scope = CoroutineScope(Dispatchers.Main)

fun homeWork(){
    scope.launch{
        writeCode()
        writeReadMe()
        gitCommit()
        gitPush()
    }
}</code></pre>
<pre><code class="language-Kotlin">suspend fun writeCode(){
    delay(2000)
}

suspend fun wrtieReadMe(){
    delay(3000)
}

suspend fun gitCommit(){
    delay(5000)
}

suspend fun gitPush(){
    delay(1500)
}</code></pre>
<p>homeWork라는 함수가 있다. 쓰레드의 main 함수가 이 homeWork라는 함수를 호출하면 우리가 만든 코루틴 스코프가 launch라는 코루틴 빌더를 만나서 코루틴을 만들어줍니다.(나중에 따로 설명)</p>
<p>위에서 말했다시피 이 homeWork()는 언제든지 진입할 수 있고 탈출할 수 있게 된다.</p>
<p>코루틴이 실행되고, <strong>suspend</strong> 키워드의 함수를 만나게 되면, (여기서는 writeCode에 해당) 더 이상 그 아래의 코드를 실행하지 않고 homeWork() 라는 코루틴 함수를 탈출한다!</p>
<p>탈출했더라도 메인 쓰레드는 가만히 있지 않고, 다른 코드들을 실행하거나 UI 작업을 진행할 수도 있다. 그렇지만 어디선가 writeCode는 계속 실행되고 있다.(다른 쓰레드에서 실행될 수도 있고, 동시성 프로그래밍으로 작동될 수도 있음)</p>
<p>메인쓰레드가 다른 코드를 실행하고 있다가도, wirteCode() 가 다 실행되었을 때 다시 탈출했던 homeWork() 코루틴으로 돌아오고, 그 아래인 writeReadMe()부터 다시 resume 된다.</p>
<p><img src="https://images.velog.io/images/ho-taek/post/86348f65-fdfb-4f4d-b585-9133a53e94e2/image.png" alt=""></p>
<p>정리하면 위의 그림과 같다.</p>
<h2 id="2-동시성-프로그래밍">2) 동시성 프로그래밍</h2>
<ul>
<li><p>동시성 프로그래밍 : 여러가지 작업이 동시에 처리되는 것</p>
</li>
<li><p>병렬 프로그래밍 : 정말로 동시에 같이 일어나는 것</p>
</li>
</ul>
</br>
동시성 프로그래밍과 병력 프로그래밍은 보기에는 같은 개념인 것 같은데 알고 보면 정말 다르다.

<p>위의 코드에 썼던 과제의 예시를 들어보자!</p>
<p>먼저 동시성 프로그래밍의 경우
<img src="https://images.velog.io/images/ho-taek/post/73c165e5-7387-4d38-96d3-1fb7f355efd2/image.png" alt=""></p>
<p>그림과 같이 노트북 한개에 모니터 두개를 연결한 모습이다!</p>
<p>이때 왼쪽 모니터에는 안드로이드 스튜디오가, 오른쪽 모니터에는 ReadMe가 켜져 있다.</p>
<p>안드로이드 스튜디오에서 코드를 작성하다가, 재빠르게 오른쪽 모니터로 눈을 옮겨 ReadMe를 작성한다. 그리고 이러한 행동을 엄청 아주 빠르게 반복한다!!</p>
<p>반면, 병렬성 프로그래밍은</p>
<p><img src="https://images.velog.io/images/ho-taek/post/40e5402b-d51c-4b58-8e40-ab226d2c2e4b/image.png" alt=""></p>
<p>노트북 두개를 왼손으로는 코드 작성, 오른 손으로 ReadMe를 작성하는 것이다.</p>
<pre><code class="language-Kotlin">A
val scope = CoroutineScope(Dispatchers.Main)

fun homeWork(){
    scope.launch{
        writeCode()
        writeReadMe()
        gitCommit()
        gitPush()
    }
}
suspend fun writeCode(){
    delay(2000)
}

suspend fun wrtieReadMe(){
    delay(3000)
}</code></pre>
<pre><code class="language-Kotlin">B
val scope = CoroutineScope(Dispatchers.Main)

fun homeWork(){
    scope.launch{
        writeCode()
        writeReadMe()
        gitCommit()
        gitPush()
    }
}
suspend fun writeCode(){
    delay(2000)
}

suspend fun wrtieReadMe(){
    delay(3000)
}</code></pre>
<p>코루틴도 루틴이기 때문에 하나의 쓰레드에 여러개가 존재 가능하다.</p>
<p>위의 코드에서 메인 쓰레드 안에 코루틴이 두개가 있다. 하나는 왼쪽 모니터, 또 하나는 오른쪽 모니터라고 생각하면 편하다.</p>
<p>왼쪽 코루틴에서 suspend 키워드의 함수를 만나 빠져 나와 다른 코루틴안의 suspend 함수를 만나게 되면, 이때 쓰레드 하나에서 동시성 프로그래밍이 가능해진다!</p>
<h1 id="2-코루틴-사용">2. 코루틴 사용</h1>
<p>코루틴에서 주로 사용하는 키워드들만 간단히 보자면 다음과 같다!</p>
<ul>
<li><p>CoroutineScope</p>
</li>
<li><p>CoroutineContext</p>
</li>
<li><p>Dispatcher</p>
</li>
<li><p>launch &amp; async</p>
</li>
</ul>
<p>하나하나씩 살펴보자</p>
<h3 id="1-coroutinescope">1) CoroutineScope</h3>
<blockquote>
<p>말 그대로 코루틴의 범위로 코루틴 블록을 묶음으로 제어할 수 있는 단위</p>
</blockquote>
<p>이 스코프에서 생성된 코루틴을 계속해서 주시하면서 실행을 취소하거나, 실패할 시에 예외를 처리할 수 있게 해준다.</p>
<p>단, GlobalScope도 쓸 수 있지만 코루틴의 생명주기를 제어하기를 원한다면 권장하지 않는다!</p>
<pre><code class="language-Kotlin">
val scope = CoroutineScope(Dispatchers.Main)

fun homeWork(){
    scope.launch{
    }</code></pre>
<p>코루틴의 실행을 멈추기 위해서 cancel()메소드를 활용한다.</p>
<pre><code class="language-Kotlin">scope.cancel()</code></pre>
<h3 id="2-coroutinecontext">2) CoroutineContext</h3>
<blockquote>
<p>코루틴을 어떻게 처리할 것 인지에 대한 여러가지 정보의 집합</p>
</blockquote>
<p>CoroutineContext의 주요 요소로 Job과 Dispathcer가 있다.</p>
<p>Job에 대한 내용은 이 분의 블로그를 참고 <a href="https://thdev.tech/kotlin/2019/04/08/Init-Coroutines-Job/">Taehwan</a>
하여 공부할 예정</p>
<h3 id="3-dispathcer">3) Dispathcer</h3>
<blockquote>
<p>어떤 스레드를 이용해서 어떻게 동작할 것인지를 정의</p>
</blockquote>
<ul>
<li><p>IO : 네트워크나 디스크 작업 할 때 사용</p>
</li>
<li><p>Defalut : CPU 사용량이 많은 작업, 주 스레드에서 작업하기에 너무 긴 작업 들</p>
</li>
<li><p>Main : UI 작업이나, 쓰레드를 블락하지 않고 빨리 실행되는 작업에 사용</p>
</li>
</ul>
<pre><code class="language-Kotlin">val scope = CoroutineScope(Dispathcer.IO)</code></pre>
<h3 id="4-launch--async">4) launch &amp; async</h3>
<blockquote>
<p>생성된 스코프에서 launch와 async를 사용하여 코루틴을 생성할 수 있다.</p>
</blockquote>
<ul>
<li><p>launch의 경우에는 반환값이 없으며(job), 단순히 그 자리에서 실행시키고 끝남!</p>
</li>
<li><p>async는 반환값이 존재한다.(Deffered)</p>
</li>
</ul>
<p>이 둘의 공통점은</p>
<ul>
<li><p>새로운 코루틴을 만든다.</p>
</li>
<li><p>하나의 Dispatcher를 가진다.</p>
</li>
<li><p>스코프 안에서 실행된다.</p>
</li>
<li><p>suspend 함수가 아니다.</p>
</li>
</ul>
<h1 id="3-코루틴-사용법">3. 코루틴 사용법</h1>
<p>코루틴 사용 단계는 다음과 같다.</p>
<ol>
<li><p>사용할 Dispatcher를 결정</p>
</li>
<li><p>Dispatcher를 이용해서 CoroutineScope를 만들고</p>
</li>
<li><p>CoroutineScope의 launch 또는 async에 수행할 코드 블록을 넘겨준다.</p>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Android] ViewPager2 중첩 스크롤 문제 ]]></title>
            <link>https://velog.io/@ho-taek/Android-ViewPager2-%EC%A4%91%EC%B2%A9-%EC%8A%A4%ED%81%AC%EB%A1%A4-%EB%AC%B8%EC%A0%9C</link>
            <guid>https://velog.io/@ho-taek/Android-ViewPager2-%EC%A4%91%EC%B2%A9-%EC%8A%A4%ED%81%AC%EB%A1%A4-%EB%AC%B8%EC%A0%9C</guid>
            <pubDate>Thu, 04 Nov 2021 04:45:19 GMT</pubDate>
            <description><![CDATA[<p>! 안드로이드 심화 스터디 2번째 시간. 이번에 내가 맡은 부분은 ViewPager2가 중첩 돼있을때의 스크롤이 되지 않는 문제를 해결하는 것이다.</p>
<h1 id="1-문제">1. 문제</h1>
<p><a href="https://developer.android.com/training/animation/vp2-migration#nested-scrollables">안드로이드 공식 문서</a></p>
<p>위의 공식 문서 하단에 다음과 같이 나와있다. </p>
<blockquote>
<p>스크롤 뷰와 이 스크롤 뷰를 포함하는 ViewPager2 객체의 방향이 같은 경우 ViewPager2는 기본적으로 중첩된 스크롤 뷰를 지원하지 않습니다. </p>
</blockquote>
<p>그래서 이번 과제를 하며 BottomNavigation을 위해 VIewPager2를 사용했고, </p>
<p>TabLayout에서 화면이 스와이프 되도록 ViewPager2를 연동했는데, </p>
<p>BottomNavigation의 화면만 스와이프 되고 내부 TabLayout의 </p>
<p>ViewPager2가 스와이프 되지 않는 문제가 생겼다.</p>
<h2 id="2-문제-해결방안">2. 문제 해결방안</h2>
<p>이를 해결하기 위해서 구글 공식 문서에 다음과 같이 나와있다.</p>
<blockquote>
<p>방향이 동일한 ViewPager2 객체 내의 스크롤 뷰를 지원하려면 ViewPager2 객체의 requestDisallowInterceptTouchEvent()를 호출해야 한다.</p>
</blockquote>
<p>코드는 <a href="https://github.com/android/views-widgets-samples/blob/master/ViewPager2/app/src/main/java/androidx/viewpager2/integration/testapp/NestedScrollableHost.kt">다목적 맞춤 레이아웃</a> 여기에 나와있다.</p>
<p><img src="https://images.velog.io/images/ho-taek/post/ae627fc5-1eaf-4e80-bc57-e05572e0f8ae/image.png" alt=""></p>
<p>아래와 같이 NestedScrollableHost.kt 파일을 만든 뒤 그 안에 위의 링크 걸어 놓은 github 코드를 집어넣으면 된다.</p>
<p>그 뒤에 내가 원하는 자식 ViewPager2에다가 </p>
<pre><code class="language-Kotlin"> &lt;org.sopt.myapplication.util.NestedScrollableHost
            android:layout_width=&quot;match_parent&quot;
            android:layout_height=&quot;0dp&quot;
            app:layout_constraintBottom_toBottomOf=&quot;parent&quot;
            app:layout_constraintEnd_toEndOf=&quot;parent&quot;
            app:layout_constraintStart_toStartOf=&quot;parent&quot;
            app:layout_constraintTop_toBottomOf=&quot;@+id/tl_home&quot;&gt;

            &lt;androidx.viewpager2.widget.ViewPager2
                android:id=&quot;@+id/vp_home_tab&quot;
                android:layout_width=&quot;match_parent&quot;
                android:layout_height=&quot;match_parent&quot; /&gt;

        &lt;/org.sopt.myapplication.util.NestedScrollableHost&gt;</code></pre>
<p>다음과 같이 넣어주면 된다.</p>
<h1 id="3-requestdisallowintercepttouchevent란">3. requestDisallowInterceptTouchEvent()란?</h1>
<p>부모와 자식이 ScrollView가 되는 상황이라면 (여기서는 부모 ViewPager2와 자식 ViewPager2가 존재)</p>
<p>부모.requestDisallowInterceptTouchEvent(true)로 주어서 부모에게 TouchEvent를 빼앗기지 않도록 하는 메소드이다.</p>
<p><img src="https://images.velog.io/images/ho-taek/post/36547149-9791-4ab5-86a5-1565cc904085/Android-Emulator-Pixel_3_XL_API_28_5554-2021-11-04-13-41-48.gif" alt=""></p>
<h1 id="4-주의">4. 주의</h1>
<ul>
<li>NestedScrolableHost 레이아웃은 스크롤이 가능한 자식을 하나만 가져야 한다!!</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Android] 스레드란?]]></title>
            <link>https://velog.io/@ho-taek/Android-%EC%8A%A4%EB%A0%88%EB%93%9C%EB%9E%80</link>
            <guid>https://velog.io/@ho-taek/Android-%EC%8A%A4%EB%A0%88%EB%93%9C%EB%9E%80</guid>
            <pubDate>Mon, 01 Nov 2021 13:57:43 GMT</pubDate>
            <description><![CDATA[<h1 id="1-프로세스와-스레드">1. 프로세스와 스레드</h1>
<h3 id="프로세스란">프로세스란?</h3>
<blockquote>
<p>운영체제에 의해 메모리에 올라가 실행 중인 프로그램</p>
</blockquote>
<p>프로세스가 실행될 경우, 프로세스는 자신의 코드 시작점부터 시작하여 종료지점까지 순차적인 실행 흐름을 가진다.</p>
<p>일반적으로 하나의 프로세스는 하나의 스레드를 가지고 작업을 수행한다.</p>
<h3 id="스레드란">스레드란?</h3>
<blockquote>
<p>동시 작업을 위한 하나의 작업 단위이자 프로세스 내에서 순차적으로 실행되는 실행흐름의 최소 단위</p>
</blockquote>
<p>Tip) 하나의 프로세스 내에서 두 개 이상의 스레드가 동작하도록 프로그래밍하는 것을 멀티스레드 프로그래밍이라한다.</p>
<p>Android는 앱 구성하는 여러 컴포넌트들이 각자의 프로세스를 생성할 수 있고, <strong>어느 프로세스에서나 메인 스레드 외의 추가 스레드를 생성할 수 있다!</strong></p>
<h1 id="2-메인-스레드main-thread">2. 메인 스레드(Main Thread)</h1>
<blockquote>
<p>프로세스의 시작과 동시에 무조건 실행되는, 앱의 기본 실행을 담당하는 스레드. 즉 프로세스의 최초 스레드라고 이해하면 된다.</p>
</blockquote>
<p>UI 위젯들을 그리는 역할을 수행하기 때문에 UI스레드 라고도 불린다. 또한 UI와 상호작용할 때 사용된다.(편의를 위해 메인스레드라고 언급하겠다)</p>
<p>예를 들면, 앱 사용자가 화면 버튼 클릭시, 클릭 이벤트를 발생시키는 작업이 메인 스레드에서 실행 된다고 생각하면 된다.</p>
<p><strong>가장 중요한점은 UI작업은 오직 메인스레드에서만 이루어져야 한다는 것이다.</strong></p>
<p>그렇다면 왜 메인스레드에서만 UI 작업이 이루어져야 하냐!!</p>
<p>만약 우리가 뷰를 그릴 때</p>
<p>이미지를 그리는 스레드 A</p>
<p>버튼을 그리는 스레드 B</p>
<p>텍스트를 그리는 스레드 C</p>
<p>가 있을때, A-B-C의 스레드가 순차적으로 실행된다면 우리가 원하는 뷰를 그릴 수 있을 것이다. </p>
<p>하지만 상대적으로 작은 크기인 C가 먼저 실행되고, 큰 데이터인 A가 가장 나중에 실행될 경우 원하지 않는 뷰가 나타날 수 있다.</p>
<p>그러므로 UI작업은 메인스레드 단 하나에서만 진행되어야 한다!</p>
<p>추가로 동일한 프로세스 내에서 실행되는 모든 컴포넌트들은 메인스레드에서 인스턴스화 되며, 각 컴포넌트들에 대한 호출은 메인스레드에서 실행된다. </p>
<p>즉, 시스템 콜백에 응답하는 메소드들은 항상 프로세스의 메인스레드에서 실행된다.</p>
<h1 id="3작업자스레드worker-thread">3.작업자스레드(Worker Thread)</h1>
<p>우리가 작업을 하면서 주의할점은 서버 통신이나 데이터베이스 쿼리 등의 긴 작업을 메인스레드에서 실행할 경우 전체 UI가 차단된다. </p>
<p>스레드가 차단되면 UI를 그리는 이벤트를 포함하여 모든 이벤트가 발송되지 않기 때문에 사용자에게 애플리케이션이 중단된 것처럼 보인다. </p>
<p>메인스레드가 5초 이상 차단되면 사용자에게 &quot;애플리케이션이 응답하지 않습니다(ANR)&quot;라는 다이얼로그가 나타나는 오류가 발생하게 된다.</p>
<p>위와 같은 오류를 발생시키지 않기 위해서 개발자는 UI작업이 차단되지 않도록 하는데 용을 써야한다! 그럼 도대체 어떻게?</p>
<p>위에서 말했다시피 <strong>하나의 프로세스 안에 추가 스레드를 생성하고 조작할 수 있다고 했다.</strong></p>
<p>이 추가된 스레드를 <strong>작업자 스레드(Worker Thread)</strong>라고 한다.</p>
<p>이 작업자 스레드에서 우리는 ANR을 발생시킬 수 있는 네트워크, DB 쿼리 등의 작업을 하도록 조작해야 한다.</p>
<p>새로운 스레드를 생성하고 실행하는 방법은 Thread 클래스를 상속한 서브 클래스를 만든 뒤 Thread()클래스의 run()메서드를 오버라이드 하는 것과, Runnable 인터페이스를 구현한 클래스를 선언한 다음, run() 메서드를 작성하는 것이다.</p>
<p>그리고 Thread 클래스의 start() 메서드를 통해 위에서 생성한 클래스 객체의 run()메서드를 실행해주면 스레드의 생성 및 실행 과정이 완료된다!</p>
<p><del>-&gt; 예시 작성 필요!</del></p>
<p>이렇게 하면 UI 작업이 블록되지 않고 네트워크, 데이터 쿼리 작업 스레드를 따로 생성해줄 수 있다.</p>
<p>하지만 우리는 워커스레드에서의 작업한 결과를 통해 UI를 업데이트 시켜줘야 하는 경우가 존재한다. 이때 UI 업데이트 작업은 위에서 계속 언급했듯 UI스레드에서 실행이 된다.</p>
<p>결과적으로 Worker 스레드에서 UI 스레드를 접근할 필요가 있다. 안드로이드 공식 문서에서 나온 방법은 post() 메소드를 이용하는 것이다.</p>
<pre><code class="language-Kotlin">fun onClick(v: View) {
    Thread(Runnable {
        // a potentially time consuming task
        val bitmap = processBitMap(&quot;image.png&quot;)
        imageView.post {
            imageView.setImageBitmap(bitmap)
        }
    }).start()
}</code></pre>
<p>Thread클래스를 통한 Worker 스레드에서 네트워크 작업을 진행하면, View.post를 통해 여기서는 imageView의 경우 UI스레드에서 조작이 이루어진다.</p>
<p>그러나 더 복잡한 상호작용을 Worker 스레드로 처리하려면, 작업자 스레드에서 <a href="https://developer.android.com/reference/android/os/Handler?hl=ko">Handler</a>라는 것을 이용해야하며, 최선의 해결책은 <a href="https://developer.android.com/reference/android/os/AsyncTask?hl=ko">AsyncTask</a> 클래스를 확장해야 하는 것이다.</p>
<p>이 부분에 경우는 추후에 따로 포스팅할 예정이다.</p>
<p>지금까지 스레드를 배운 이유는 코루틴을 제대로 활용하기 위함인데 코루틴에 대한 내용도 공부한 뒤 정리가 끝나고 포스팅할 예정이다.</p>
</br>
</br>
</br>

<h4 id="참고블로그">참고블로그</h4>
<p><a href="https://recipes4dev.tistory.com/143">https://recipes4dev.tistory.com/143</a>
<a href="https://choheeis.github.io/newblog//articles/2020-12/android-process-thread">https://choheeis.github.io/newblog//articles/2020-12/android-process-thread</a>
<a href="https://developer.android.com/guide/components/processes-and-threads?hl=ko">https://developer.android.com/guide/components/processes-and-threads?hl=ko</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Android] RecyclerView swipe 아이템 삭제]]></title>
            <link>https://velog.io/@ho-taek/Android-RecyclerView-swipe-%EC%95%84%EC%9D%B4%ED%85%9C-%EC%82%AD%EC%A0%9C</link>
            <guid>https://velog.io/@ho-taek/Android-RecyclerView-swipe-%EC%95%84%EC%9D%B4%ED%85%9C-%EC%82%AD%EC%A0%9C</guid>
            <pubDate>Thu, 28 Oct 2021 05:03:30 GMT</pubDate>
            <description><![CDATA[<p>! 안드로이드 심화 스터디에서 각 과제에 대해 파트별로 나눠서 자료를 만들어서 공부하기로 진행했다. 내가 이번에 맡은 부분은 리사이클러뷰 아이템을 스와이프해서 지우거나, 위치를 바꾸는 것이다.</p>
<h1 id="1-recyclerview-adapter-만들기">1. RecyclerView Adapter 만들기</h1>
<h3 id="fragment_followerxml">fragment_follower.xml</h3>
<pre><code class="language-Kotlin">&lt;layout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    xmlns:tools=&quot;http://schemas.android.com/tools&quot;
    xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;&gt;

    &lt;data&gt;

    &lt;/data&gt;

    &lt;androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;
        tools:context=&quot;.ui.profile.FollowerFragment&quot;&gt;

        &lt;androidx.recyclerview.widget.RecyclerView
            android:id=&quot;@+id/recycler_follow&quot;
            android:layout_width=&quot;match_parent&quot;
            android:layout_height=&quot;match_parent&quot;
            app:layoutManager=&quot;androidx.recyclerview.widget.LinearLayoutManager&quot;
            app:layout_constraintTop_toTopOf=&quot;parent&quot;
            app:layout_constraintStart_toStartOf=&quot;parent&quot;
            app:layout_constraintEnd_toEndOf=&quot;parent&quot;
            android:layout_marginStart=&quot;10dp&quot;
            android:layout_marginTop=&quot;20dp&quot;/&gt;

    &lt;/androidx.constraintlayout.widget.ConstraintLayout&gt;
&lt;/layout&gt;
</code></pre>
<h3 id="follwadapterkt">FollwAdapter.kt</h3>
<pre><code class="language-Kotlin">class FollowAdapter : RecyclerView.Adapter&lt;FollowAdapter.FollowViewHolder&gt;() {

    private var followData = mutableListOf&lt;FollowData&gt;()


    override fun onCreateViewHolder(
        parent: ViewGroup,
        viewType: Int
    ): FollowAdapter.FollowViewHolder {
        val binding = ItemFollowerBinding.inflate(
            LayoutInflater.from(parent.context),
            parent,
            false
        )

        return FollowViewHolder(binding)
    }

    override fun onBindViewHolder(holder: FollowAdapter.FollowViewHolder, position: Int) {
        holder.onBind(followData[position])
        holder.binding.root.setOnClickListener {
            val intent = Intent(holder.itemView?.context, DetailActivity::class.java)
            intent.putExtra(&quot;userImage&quot;, followData[position].image)
            intent.putExtra(&quot;userName&quot;, followData[position].name)
            intent.putExtra(&quot;userIntroduce&quot;, followData[position].introduce)
            startActivity(holder.itemView.context, intent, null)

        }
    }

    override fun getItemCount(): Int {
        return followData.size
    }

    class FollowViewHolder(
        val binding: ItemFollowerBinding
    ) : RecyclerView.ViewHolder(binding.root){
        fun onBind(followData: FollowData){
            binding.apply{
                follow = followData
                binding.executePendingBindings()


            }

        }
    }

    // 데이터 전체 값 갱신
    fun setFollowData(followData: MutableList&lt;FollowData&gt;){
        this.followData = followData
        notifyDataSetChanged()
    }

    fun removeData(position: Int){
        followData.removeAt(position)
        notifyItemRemoved(position)
    }

    fun swapData(fromPos: Int, toPos: Int){
        Collections.swap(followData, fromPos, toPos)
        notifyItemMoved(fromPos, toPos)
    }
}
</code></pre>
<p>기존에 RecyclerView 만드는 것과 동일하게 Adapter를 만들었지만 추가 된 부분이 removeData와 swapData함수이다.</p>
<p>removeData는 말 그대로 데이터를 삭제하는 부분!</p>
<p>swapData는 아이템의 위치를 서로 바꿔주는 부분이다.</p>
<h2 id="1-2-removedata">1-2 removeData()</h2>
<h3 id="removeat">removeAt()</h3>
<p>removeAt()은 가변형 Collection에서 사용되는 것으로 해당 인덱스의 인자를 삭제한다.</p>
<p>추가 적으로</p>
<ul>
<li><p>add(E) : 인자 추가 후 true 반환/ 요소가 있거나 중복 불허인 경우 false</p>
</li>
<li><p>addAll, removeAll : 컬렉션 인자를 모두 추가/ 삭제</p>
</li>
<li><p>retainAll: 컬렉션 인자를 받아 해당 요소만 보유</p>
</li>
<li><p>clear() : 컬렉션 모든 요소를 삭제</p>
</li>
</ul>
<h3 id="notifyitemremoved">notifyItemRemoved()</h3>
<p>나는 recyclerView의 리스트를 업데이트 할때 사용하는 함수로 notifyDataSetChanged()를 사용해왔다.</p>
<p>하지만 notifyDataSetChanged()는 리스트의 크기와 아이템이 둘 다 변경되는 경우에 사용해야 한다. LayoutManager가 모든 자료를 다시 바인딩 하고, 모든 View를 다시 레이아웃하게 된다. 즉 아이템 전체를 다시 업데이트 하기 때문에 굉장히 비효율적이다. 그러므로 때에 따라 다른 메소드를 사용해야 할 필요가 있다.</p>
<ul>
<li><p>notifyItemChanged(position) : 어느 특정 위치의 아이템만 변경할 경우에 사용.</p>
</li>
<li><p>notifyItemRangeChanged(positionStart, itemCount)</p>
</li>
<li><ul>
<li>positionStart : 변경된 첫 번째 아이템의 위치</li>
</ul>
</li>
<li><ul>
<li>itemCount: 변경된 아이템의 개수</li>
</ul>
</li>
<li><ul>
<li>변경된 아이템이 연속된 여러 개의 아이템일 때 이 함수를 사용한다.</li>
</ul>
</li>
<li><p>notifyItemInserted(position)</p>
</li>
<li><ul>
<li>특정 위치에 아이템이 새로 삽입했을 때 사용한다.</li>
</ul>
</li>
<li><p>notifyItemRagneInserted(positionStart, itemCount)</p>
</li>
<li><ul>
<li>notifyItemRangeChanged와 비슷하게 연속된 여러 개의 아이템이 삽입될 때 사용한다.</li>
</ul>
</li>
<li><p>notifyItemRemoved(position) : 특정한 아이템 1개를 삭제할 때 사용.</p>
</li>
<li><p>notifyItemRangeRemoved(position, itemCount)</p>
</li>
<li><ul>
<li>연속된 여러 개의 아이템이 삭제될 때 사용</li>
</ul>
</li>
<li><p>notifyItemMoved(fromPosition, toPosition)
-- fromPosition : 아이템의 이전 위치
-- toPosition : 아이템의 새로운 위치
-- 아이템이 이동했을 때 사용하는 함수</p>
</li>
</ul>
<h2 id="1-3-swapdata">1-3 swapData()</h2>
<p>아이템의 위치를 바꿔주는 함수이다</p>
<p>java에서 제공하는 Collections.swap()를 사용해서 followData의 fromPos 위치에 있는 아이템과 toPos 위치에 있는 아이템을 바꾸는 것이다.</p>
<p>그 뒤 위에서 본 notifyItemMoved()를 통해서 recyclerView를 갱신해준다.</p>
<h1 id="2-itemtouchhelper-클래스-구현">2. ItemTouchHelper 클래스 구현</h1>
<p>FollowerFragment.kt</p>
<pre><code class="language-Kotlin">class FollowerFragment : BaseFragment&lt;FragmentFollowerBinding&gt;(R.layout.fragment_follower) {
    private lateinit var followAdapter: FollowAdapter
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        initFollow()
        itemTouch()
    }


    private fun initFollow(){
        followAdapter = FollowAdapter()
        binding.recyclerFollow.adapter = followAdapter
        binding.recyclerFollow.addItemDecoration(MyDecoration(50, Color.BLUE))
        followAdapter.setFollowData(
            mutableListOf(
                FollowData(R.drawable.hotaek, &quot;곽호택&quot;, &quot;안드로이드 OB&quot;),
                FollowData(R.drawable.hotaeks, &quot;곽호택&quot;, &quot;차로 갓갓갓갓&quot;),
                FollowData(R.drawable.hotaekes, &quot;곽호택&quot;, &quot;솝트 갓갓갓갓&quot;)
            )
        )
    }</code></pre>
<p>  기존에 RecyclerVIew 작성할때와 동일하게 작성했다.
  addItemDecoration은 구분선을 넣기 위해서 작성했다.</p>
<pre><code class="language-Kotlin">  private fun itemTouch(){
        val itemTouchCallback = object : ItemTouchHelper.SimpleCallback(
            ItemTouchHelper.UP or ItemTouchHelper.DOWN, ItemTouchHelper.LEFT
        ){
            override fun onMove(
                recyclerView: RecyclerView,
                viewHolder: RecyclerView.ViewHolder,
                target: RecyclerView.ViewHolder
            ): Boolean {
                val fromPos: Int = viewHolder.adapterPosition
                val toPos: Int = target.adapterPosition
                followAdapter.swapData(fromPos, toPos)
                return true
            }

            override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
                followAdapter.removeData(viewHolder.layoutPosition)
            }
        }

        ItemTouchHelper(itemTouchCallback).attachToRecyclerView(binding.recyclerFollow)
    }</code></pre>
<p>아이템 삭제와 스왑을 위한 함수이다.</p>
<p>Object Expression(객체 표현식)을 사용하였는데 객체 표현식은 특정 타입으로 상속되는 익명 클래스의 객체를 생성하기 위해 사용한다.</p>
<p>이와 같은 방식은 일회용으로 사용하기에 유용하다.</p>
<p>그래서 위의 코드에서 ItemTouchHelper.SimpleCallback을 상속 받은 itemTouchCallback 객체를 만들었다.</p>
<ul>
<li>ItemTouchHelper의 경우 공식 문서에 따르면 다음과 같다.<blockquote>
<p>이것은 RecyclerView에 해제 및 드래그 앤 드롭 지원을 위해 스와이프를 추가하는 유틸리티 클래스입니다.</br>
사용할 상호 작용 유형을 구성하고 사용자가 이러한 작업을 수행할 때 이벤트를 수신하는 RecyclerView 및 Callback 클래스와 함께 작동합니다.</p>
</blockquote>
</li>
</ul>
<p>위의 문서 내용과 같이 ItemTouchHelper.SimpleCallback 추상 클래스를 구현해줘야 하고,</p>
<p>여기서 사용한 onMove, onSwiped를 구현해줘야한다.</p>
<p>onMove, onSwiped는 각각 Drag, Swipe 될 때 호출되고 이때 RecyclerViewAdpater에 만들어 놓은 remomveData와 swipedData 함수를 사용했다.</p>
<pre><code class="language-Kotlin"> public ItemTouchHelper(@NonNull Callback callback) {
        mCallback = callback;
    }</code></pre>
<pre><code class="language-kotlin">public void attachToRecyclerView(@Nullable RecyclerView recyclerView)</code></pre>
<p>그 뒤에 
ItemTouchHelper(itemTouchCallback).attachToRecyclerView(binding.recyclerFollow)를 통해 recyclerView에 ItemTouchHelper를 적용시켜줬다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Flutter] 이미지 및 폰트 사용하기]]></title>
            <link>https://velog.io/@ho-taek/Flutter-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EB%B0%8F-%ED%8F%B0%ED%8A%B8-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@ho-taek/Flutter-%EC%9D%B4%EB%AF%B8%EC%A7%80-%EB%B0%8F-%ED%8F%B0%ED%8A%B8-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sun, 17 Oct 2021 10:32:48 GMT</pubDate>
            <description><![CDATA[<p>! 이미지와 폰트를 넣고 사용하는 방법을 공부했다</p>
<h1 id="1-이미지-사용하기">1. 이미지 사용하기</h1>
<h3 id="1-이미지-넣기">1) 이미지 넣기</h3>
<p><img src="https://images.velog.io/images/ho-taek/post/d33c01d6-f158-480d-adc0-01b0e466f512/KakaoTalk_20211017_190936364.png" alt=""></p>
<p>프로젝트가 있는 부분을 우클린 한 뒤 [New -&gt; Directory]를 클릭하고 image라는 폴더를 생성했다.</p>
<p>그리고 원하는 이미지를 image 폴더 안에 넣고 pubspec.yaml 파일에 이미지 정보를 넣어주면 된다.</p>
<pre><code class="language-dart">flutter:
  uses-material-design: true
  assets:
    - image/flutter.png</code></pre>
<p>이미지를 추가했으니 이제 위젯에서 이미지를 호출하면 되는데 방법이 총 3가지가 있다.</p>
<ul>
<li>file: 외부의 폴더나 갤러리에 있는 파일을 사용하는 경우</li>
<li>asset: 앱을 만들 때 미리 넣어놓은 파일을 사용하는 경우</li>
<li>memory: 배열이나 문자열 형태의 이미지 데이터를 사용하는 경우</li>
</ul>
<p>우리는 여기서 파일을 넣어 놓고 pubspec.yaml 파일에 asset으로 선언해줬기 때문에 </p>
<blockquote>
<p>Image.asset(이미지_경로) 형태로 호출하면 된다.</p>
</blockquote>
<p>코드로 작성하면 다음과 같다.</p>
<pre><code class="language-dart">class ImageWidgetApp extends StatefulWidget {
  @override
  State&lt;StatefulWidget&gt; createState(){
    return _ImageWidgetApp();
  }
}

class _ImageWidgetApp extends State&lt;ImageWidgetApp&gt;{
  @override
  Widget build(BuildContext context){
    return Scaffold(
        appBar: AppBar(title: Text(&#39;Imagae Widget&#39;),),
        body: Container(
            child: Center(
                child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: &lt;Widget&gt;[
                      Image.asset(&#39;image/flutter.png&#39;),
                    ]
                )
            )
        )
    );
  }
}</code></pre>
<p>이제 저번 시간에 머터리얼 공부할때 작성했었던 main.dart의 home 부분에 ImageWidgetApp을 넣어주고 실행하면 된다.</p>
<pre><code class="language-dart">class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context){
    return MaterialApp(
      title: &#39;Material Flutter App&#39;,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: ImageWidgetApp(),
    );
  }
}</code></pre>
<p><img src="https://images.velog.io/images/ho-taek/post/fb387c8e-8bd7-4804-8e8e-c3bb0d6c4e85/Android%20Emulator%20-%20Pixel_3_XL_API_28_5554%202021-10-17%20%EC%98%A4%ED%9B%84%207_16_42.png" alt=""></p>
<p>이와 같이 코드 작성을 마쳤을 때 다음과 같이 화면에 이미지가 나오는 것을 볼 수 있따!!!!😁</p>
<h3 id="2-이미지-크기-조정">2) 이미지 크기 조정</h3>
<pre><code class="language-dart">Image.asset(&#39;image/flutter.png&#39;, width: 200, height: 100),</code></pre>
<p>Image.asset의 이미지 경로 뒤에 width, height를 설정해 주면 이미지의 크기를 조정해줄 수 있다.</p>
<p>그리고 width, height 뒤에 Boxfit을 활용하면 이미지 크기를 조절할 수 있다.</p>
<ul>
<li><p>BoxFit.fill : width, height를 가득 채워서 그림</p>
</li>
<li><p>BoxFit.contain : 이미지가 잘리지 않고 비율이 변하지 않는 범위에서 가능한 한 크게 그린다.</p>
</li>
<li><p>BoxFit.cover : 비율을 유지한 채 지정한 범위를 모두 덮도록 그린다. 단 이미지가 잘릴 수 있음</p>
</li>
<li><p>BoxFit.fitWidth : width를 꽉 채워서 그린다. 단 이미지가 잘릴 수 있음</p>
</li>
<li><p>BoxFit.fitheight</p>
</li>
<li><p>BoxFit.none : 원본 이미지를 표시</p>
</li>
<li><p>BoxFit.scaleDown : 전체 이미지가 나올 수 있게 이미지 크기를 조절해서 표시</p>
</li>
</ul>
<h1 id="2-폰트-변경하기">2. 폰트 변경하기</h1>
<p><img src="https://images.velog.io/images/ho-taek/post/35e92206-dee8-4518-b0b6-cf22f35dabde/KakaoTalk_20211017_192834079.png" alt=""></p>
<p>이미지와 동일하게 font 폴더를 만들어주고 안에 차로에서 사용했었던 폰트 하나를 복사해서 넣어 줬다.</p>
<p>그 뒤 pubspec.yaml 파일에 폰트를 넣어 줬다. 이미지와 동일하게!!</p>
<pre><code class="language-dart"> fonts:
    - family: notosanscjkkr
      fonts:
        - asset: font/noto_sans_cjkkr_bold.otf
          weight: 400</code></pre>
<p>그 뒤에 imagewidget.dart 파일에 이미지 아래에 Text를 추가해 주고 style에 TextStyle() 함수를 이용해 텍스트 모양을 설정해 준다. 그리고 fontFamily에 아까 지정한 이름을 넣어주면 끝!!</p>
<pre><code class="language-dart">class _ImageWidgetApp extends State&lt;ImageWidgetApp&gt;{
  @override
  Widget build(BuildContext context){
    return Scaffold(
        appBar: AppBar(title: Text(&#39;Imagae Widget&#39;),),
        body: Container(
            child: Center(
                child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: &lt;Widget&gt;[
                      Image.asset(&#39;image/flutter.png&#39;),
                      const Text(&#39;Hello Flutter&#39;,
                          style: TextStyle(fontFamily: &#39;notosanscjkkr&#39;,
                          fontSize: 30, color: Colors.blue),
                      )
                    ]
                )
            )
        )
    );
  }
}</code></pre>
<p><img src="https://images.velog.io/images/ho-taek/post/76b54d8b-b897-422d-8854-8ccf5ea326ce/Android%20Emulator%20-%20Pixel_3_XL_API_28_5554%202021-10-17%20%EC%98%A4%ED%9B%84%207_31_40.png" alt=""></p>
<p>다음과 같이 이미지 밑에 내가 적용한 Font Style의 Text가 나타나게 된다</p>
]]></description>
        </item>
    </channel>
</rss>