<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Zero2Bang</title>
        <link>https://velog.io/</link>
        <description>의지와 행동</description>
        <lastBuildDate>Thu, 06 Jul 2023 09:21:24 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>Zero2Bang</title>
            <url>https://velog.velcdn.com/images/augus-xury/profile/b1b75cde-b9a6-42fd-aaeb-af833ed2bb8f/image.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. Zero2Bang. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/augus-xury" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[iOS 오토 레이아웃]]></title>
            <link>https://velog.io/@augus-xury/%EB%B6%80%EC%8A%A4%ED%8A%B8%EC%BD%94%EC%8A%A4-iOS-%EC%9D%8C%EC%9B%90%EC%9E%AC%EC%83%9D%EA%B8%B0-%EC%95%B12</link>
            <guid>https://velog.io/@augus-xury/%EB%B6%80%EC%8A%A4%ED%8A%B8%EC%BD%94%EC%8A%A4-iOS-%EC%9D%8C%EC%9B%90%EC%9E%AC%EC%83%9D%EA%B8%B0-%EC%95%B12</guid>
            <pubDate>Thu, 06 Jul 2023 09:21:24 GMT</pubDate>
            <description><![CDATA[<h1 id="개념-정리">개념 정리</h1>
<hr>
<h2 id="오토레이아웃">오토레이아웃</h2>
<blockquote>
<p>오토레이아웃은 뷰의 제약 사항을 바탕으로 뷰 체계 내의 모든 뷰의 크기와 위치를 동적으로 계산합니다. 
오토레이아웃은 애플리케이션을 사용할 때 발생하는 외부 변경과 내부 변경에 동적으로 반응하는 사용자 인터페이스를 가능하게 합니다.</p>
</blockquote>
<p>즉, <a href="https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/AutolayoutPG/index.html#//apple_ref/doc/uid/TP40010853-CH7-SW1">오토 레이아웃</a>이란 애플 기기의 다양한 사이즈에 구애받지 않고 시각적으로 동일한 화면을 구성하기 위한 기능으로 뷰의 위치(x,y 앵커)와 크기를 정해주면 자동으로 레이아웃을 그려주는 것이다.</p>
<p>오토 레이아웃이 발생하는 경우는 외부 변경과 내부 변경이 있을 때이다.</p>
<h3 id="외부-변경external-changes">외부 변경(External Changes)</h3>
<p>외부 변경은 슈퍼뷰의 크기나 모양이 변경될 때 발생한다.</p>
<ul>
<li>사용자가 아이패드의 분할뷰(Split View)를 사용하거나 사용하지 않는 경우(iOS).</li>
<li>장치를 회전하는 경우(iOS).
활성화콜(active call)과 오디오 녹음 바가 보여지거나 사라지는 경우(iOS).</li>
<li>다른 크기의 클래스를 지원하기 원하는 경우</li>
<li>다른 크기의 스크린을 지원하기 원하는 경우 </li>
</ul>
<p>즉, 콘텐츠를 담는 틀 자체에 변경이 일어나는 경우를 말한다.</p>
<h3 id="내부-변경internal-changes">내부 변경(Internal Changes)</h3>
<p>내부 변경은 사용자 인터페이스의 뷰의 크기 또는 설정이 변경되었을 때 발생한다.</p>
<ul>
<li>애플리케이션 변경에 의해 콘텐츠가 보여지는 경우</li>
<li>애플리케이션이 국제화를 지원하는 경우</li>
<li>애플리케이션이 동적 타입을 지원하는 경우</li>
</ul>
<p>콘텐츠(이미지, 텍스트 길이) 마다 사이즈는 다를 것이고, 같은 콘텐츠여도 언어마다 텍스트의 길이가 다를것이며, 사용자마다 폰트 사이즈나 이미지 크기 등을 다르게 설정할 수 있으므로 내부 콘텐츠의 사이즈에는 변화가 있게 된다.</p>
<p><img src="https://velog.velcdn.com/images/augus-xury/post/9221f562-b76c-4a61-8d5c-da4a440c328e/image.png" alt=""></p>
<hr>
<h2 id="nslayoutconstraint">NSLayoutConstraint</h2>
<p>기존 스토리보드를 이용하지 않고 코드상에서 오토 레이아웃을 구현하는 방법은 NSLayoutConstraint 인스턴스 생성을 사용하여 제약조건을 지정하는 것이다.</p>
<h3 id="오토-레이아웃-방정식">오토 레이아웃 방정식</h3>
<p>오토 레이아웃은 view의 x,y,width,height만 정해주면 알아서 굴러가는 방식이기 때문에 뷰들의 상대적인 크기나 위치를 정해줘야 한다. 코드상으로는 방정식을 통해 구현해야하고, 이를 오토 레이아웃 방정식이라고 한다.</p>
<p><img src="https://velog.velcdn.com/images/augus-xury/post/c80e79c7-ed77-4179-be5c-8dc9ffb92166/image.png" alt=""></p>
<p>즉,</p>
<pre><code>view1.attr1 = view2.attr2 * multiplier + constant</code></pre><p>의 꼴이 되고, 이를 정리하면 다음과 같이 된다.</p>
<pre><code>item.attribute = toItem.attribute * multiplier + constant
</code></pre><h3 id="구현-예시">구현 예시</h3>
<p><img src="https://velog.velcdn.com/images/augus-xury/post/a9599614-a412-433c-9722-dfa9d82c1f92/image.png" alt=""></p>
<p>이제 코드 상으로 어떻게 구현을 하는지 살펴보자.</p>
<hr>
<h4 id="1-텍스트필드를-버튼-오른쪽-8포인트-떨어져-위치시킴">1. 텍스트필드를 버튼 오른쪽 8포인트 떨어져 위치시킴</h4>
<p><img src="https://velog.velcdn.com/images/augus-xury/post/d69df272-b0d6-4bd1-abd8-1c885362f55b/image.png" alt=""></p>
<pre><code class="language-swift"> NSLayoutConstraint(item: button, 
               attribute: .right,
               relatedBy: .equal,
               toItem: textField,
               attribute: .left,
               multiplier: 1.0,
               constant: 8.0)</code></pre>
<hr>
<h4 id="2-버튼의-너비가-최소-50-이상이-되도록-함">2. 버튼의 너비가 최소 50 이상이 되도록 함</h4>
<p><img src="https://velog.velcdn.com/images/augus-xury/post/e1d722e5-733e-4f62-a36f-8ba7c1cf212e/image.png" alt=""></p>
<pre><code class="language-swift"> NSLayoutConstraint(item: button,
               attribute: .width,
               relatedBy: .greaterThanOrEqual,
               toItem: nil,
               attribute: .notAnAttribute,
               multiplier: 1.0,
               constant: 50.0)</code></pre>
<hr>
<h4 id="3-purplebox가-superview를-기준으로-왼쪽leading-간격은-50포인트-오른쪽trailing-간격은-50포인트로-설정">3. purpleBox가 superView를 기준으로 왼쪽(Leading) 간격은 50포인트, 오른쪽(Trailing) 간격은 50포인트로 설정</h4>
<p><img src="https://velog.velcdn.com/images/augus-xury/post/63fa5ec6-b5ec-4cbe-a37b-9946c03efe5b/image.png" alt=""></p>
<pre><code class="language-swift"> NSLayoutConstraint(item: purpleBox,
               attribute: .left,
               relatedBy: .equal,
               toItem: self.view,
               attribute: .left,
               multiplier: 1.0,
               constant: 50.0)

 NSLayoutConstraint(item: purpleBox,
               attribute: .right,
               relatedBy: .equal,
               toItem: self.view,
               attribute: .right,
               multiplier: 1.0,
               constant: -50.0)</code></pre>
<hr>
<h4 id="4-topfield와-bottomfield의-세로-사이의-간격을-10포인트로-설정">4. topField와 bottomField의 세로 사이의 간격을 10포인트로 설정</h4>
<p><img src="https://velog.velcdn.com/images/augus-xury/post/124e2699-efc0-445a-b251-6502fb727cd8/image.png" alt=""></p>
<pre><code class="language-swift"> NSLayoutConstraint(item: topField,
               attribute: .bottom,
               relatedBy: .equal,
               toItem: bottomField,
               attribute: .top,
               multiplier: 1.0,
               constant: -10.0)</code></pre>
<hr>
<h4 id="5-maroonview와-blueview의-간격이-없음">5. maroonView와 blueView의 간격이 없음</h4>
<p><img src="https://velog.velcdn.com/images/augus-xury/post/d3a5c80c-a36e-4534-93bb-f2a42accc4c7/image.png" alt=""></p>
<pre><code class="language-swift"> NSLayoutConstraint(item: maroonView,
               attribute: .right,
               relatedBy: .equal,
               toItem: blueView,
               attribute: .left,
               multiplier: 1.0,
               constant: 0.0)</code></pre>
<hr>
<h4 id="6-button의-너비는-100포인트이고-우선도는-20으로-설정">6. button의 너비는 100포인트이고 우선도는 20으로 설정</h4>
<p><img src="https://velog.velcdn.com/images/augus-xury/post/28806a50-8234-4744-b52e-ae88a02e46ac/image.png" alt=""></p>
<pre><code class="language-swift"> NSLayoutConstraint(item: button,
               attribute: .width,
               relatedBy: .equal,
               toItem: nil,
               attribute: .notAnAttribute,
               multiplier: 1.0,
               constant: 100.0).priority = UILayoutPriority(rawValue: 20)</code></pre>
<p>오토 레이아웃에서는 우선도 개념이 들어가 있어 NSLayoutConstraint(...).priority = UILayoutPriority(rawValue: 20) 와 같이 우선도(1 ~ 1000)를 정해줄 수 있다. 숫자가 높을수록 우선도가 높다.</p>
<hr>
<h4 id="7-flexiblebutton의-너비-값이-70포인트보다-크거나-같고-100포인트보다-작거나-같도록-제약">7. flexibleButton의 너비 값이 70포인트보다 크거나 같고 100포인트보다 작거나 같도록 제약</h4>
<p><img src="https://velog.velcdn.com/images/augus-xury/post/33d6bbc1-ad0f-471f-8b94-373f2392a2fd/image.png" alt=""></p>
<pre><code class="language-swift"> NSLayoutConstraint(item: flexibleButton,
               attribute: .width,
               relatedBy: .greaterThanOrEqual,
               toItem: nil,
               attribute: .notAnAttribute,
               multiplier: 1.0,
               constant: 70.0)

 NSLayoutConstraint(item: flexibleButton,
               attribute: .width,
               relatedBy: .lessThanOrEqual,
               toItem: nil,
               attribute: .notAnAttribute,
               multiplier: 1.0,
               constant: 100.0)</code></pre>
<h4 id="8-button1-button2-textfield와-superview의-간격은-표준-간격8포인트이며-textfield의-너비-값은-20포인트보다-크거나-같도록-제약">8. button1, button2, textField와 superView의 간격은 표준 간격(8포인트)이며 textField의 너비 값은 20포인트보다 크거나 같도록 제약</h4>
<p><img src="https://velog.velcdn.com/images/augus-xury/post/82cdd5b6-e2ec-4ec5-b063-5f4658c958c1/image.png" alt=""></p>
<pre><code class="language-swift"> // button1
 NSLayoutConstraint(item: button1,
               attribute: .left,
               relatedBy: .equal,
               toItem: self.view,
               attribute: .left,
               multiplier: 1.0,
               constant: 8.0)

 // button2
 NSLayoutConstraint(item: button2,
               attribute: .left,
               relatedBy: .equal,
               toItem: button1,
               attribute: .right,
               multiplier: 1.0,
               constant: 8.0)

 // textField
 NSLayoutConstraint(item: textField,
               attribute: .left,
               relatedBy: .equal,
               toItem: button2,
               attribute: .right,
               multiplier: 1.0,
               constant: 8.0)

 NSLayoutConstraint(item: textField,
               attribute: .width,
               relatedBy: .greaterThanOrEqual,
               toItem: nil,
               attribute: .notAnAttribute,
               multiplier: 1.0,
               constant: 20.0)

 NSLayoutConstraint(item: textField,
               attribute: .right,
               relatedBy: .equal,
               toItem: self.view,
               attribute: .right,
               multiplier: 1.0,
               constant: -8.0)</code></pre>
<hr>
<h2 id="visual-format-language">Visual Format Language</h2>
<p>단순히 NSLayoutConstraint에 인자를 넣어 뷰를 구현하기에는 복잡하므로, 약간의 ASCII art를 통해 시각화하여 인자를 단순화하도록 한 것이다.
NSLayoutConstraint.constraints(...) 또는 NSLayoutConstraints.constraintsWithVisualFormat(...)을 통해 구현한다.</p>
<pre><code class="language-swift">NSLayoutConstraint.constraints(withVisualFormat:options:metrics:views:)</code></pre>
<ul>
<li><p>withVisualFormat: Visual Format Language(VFL)를 넣는다. 수평(H:) 또는 수직(V:) 제약 조건을 지정한다. 아래 1번 ~ 8번 참조.</p>
</li>
<li><p>options: 뷰와 관련된 추가적인 세부 조정을 지정할 수 있는 옵션 배열이다. 제약의 방향, 정렬 등을 조절한다.</p>
</li>
</ul>
<pre><code>.alignAllLeft: 뷰들의 왼쪽 가장자리를 정렬
.alignAllRight: 뷰들의 오른쪽 가장자리를 정렬
.alignAllTop: 뷰들의 상단 가장자리를 정렬
.alignAllBottom: 뷰들의 하단 가장자리를 정렬
.alignAllLeading: 뷰들의 leading(문서의 시작 방향에 따라 왼쪽 또는 오른쪽) 가장자리를 정렬
.alignAllTrailing: 뷰들의 trailing(문서의 시작 방향에 따라 오른쪽 또는 왼쪽) 가장자리를 정렬
.alignAllCenterX: 뷰들의 x축 중심을 정렬
.alignAllCenterY: 뷰들의 y축 중심을 정렬
.alignAllBaseline: 뷰들의 기준선을 정렬
.alignAllFirstBaseline: 뷰들의 첫 번째 텍스트 기준선을 정렬
.alignAllLastBaseline: 뷰들의 마지막 텍스트 기준선을 정렬</code></pre><ul>
<li><p>metrics: VFL 문자열 내에서 수치를 참조하는 데 사용되는 딕셔너리 인자다. 예를 들어, metrics: [&quot;margin&quot;: 15]과 같이 지정하고 VFL에서 margin을 참조하고 조정할 수 있다.</p>
</li>
<li><p>views: VFL 문자열 내에서 뷰 이름을 참조하는 딕셔너리다. 각 키는 VFL 문자열에서 사용되는 뷰 이름이고, 해당하는 값은 그 이름을 가진 뷰 객체를 뜻한다. views: [&quot;myView&quot;: myViewInstance]와 같이 지정하면 VFL에서 myView라는 이름으로 myViewInstance를 참조할 수 있다.</p>
</li>
</ul>
<hr>
<p>1번 
<img src="https://velog.velcdn.com/images/augus-xury/post/d69df272-b0d6-4bd1-abd8-1c885362f55b/image.png" alt=""></p>
<pre><code> H:[button]-8-[textField] 
     또는 
 H:[button]-[textField]</code></pre><hr>
<p>2번
<img src="https://velog.velcdn.com/images/augus-xury/post/e1d722e5-733e-4f62-a36f-8ba7c1cf212e/image.png" alt=""></p>
<pre><code> H:[button(&gt;=50)]</code></pre><hr>
<p>3번
<img src="https://velog.velcdn.com/images/augus-xury/post/63fa5ec6-b5ec-4cbe-a37b-9946c03efe5b/image.png" alt=""></p>
<pre><code> H:|-50-[purpleBox]-50-|</code></pre><hr>
<p>4번
<img src="https://velog.velcdn.com/images/augus-xury/post/124e2699-efc0-445a-b251-6502fb727cd8/image.png" alt=""></p>
<pre><code> V:[topField]-10-[bottomField]</code></pre><hr>
<p>5번
<img src="https://velog.velcdn.com/images/augus-xury/post/d3a5c80c-a36e-4534-93bb-f2a42accc4c7/image.png" alt=""></p>
<pre><code> H:[maroonView][blueView]</code></pre><hr>
<p>6번
<img src="https://velog.velcdn.com/images/augus-xury/post/28806a50-8234-4744-b52e-ae88a02e46ac/image.png" alt=""></p>
<pre><code> H:[button(100@20)]</code></pre><hr>
<p>7번
<img src="https://velog.velcdn.com/images/augus-xury/post/33d6bbc1-ad0f-471f-8b94-373f2392a2fd/image.png" alt=""></p>
<pre><code> H:[flexibleButton(&gt;=70,&lt;=100)]</code></pre><hr>
<p>8번
<img src="https://velog.velcdn.com/images/augus-xury/post/82cdd5b6-e2ec-4ec5-b063-5f4658c958c1/image.png" alt=""></p>
<pre><code> H:|-[find]-[findNext]-[findField(&gt;=20)]-|</code></pre><h2 id="nslayoutanchor">NSLayoutAnchor</h2>
<pre><code>//사이즈
widthAnchor
heightAnchor

//수직
topAnchor
bottomAnchor
centerYAnchor

//수평
leadingAnchor
trailingAnchor
leftAnchor
rightAnchor
centerXAnchor

//래이블 텍스트 줄 기준
firstBaselineAnchor
lastBaselineAnchor</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[iOS UIKit/스토리보드 다루기 기초]]></title>
            <link>https://velog.io/@augus-xury/UIKit-%EC%8A%A4%ED%86%A0%EB%A6%AC%EB%B3%B4%EB%93%9C-%EA%B8%B0%EC%B4%88</link>
            <guid>https://velog.io/@augus-xury/UIKit-%EC%8A%A4%ED%86%A0%EB%A6%AC%EB%B3%B4%EB%93%9C-%EA%B8%B0%EC%B4%88</guid>
            <pubDate>Wed, 05 Jul 2023 06:37:27 GMT</pubDate>
            <description><![CDATA[<h1 id="개념-정리">개념 정리</h1>
<hr>
<h2 id="xcode-사용법">Xcode 사용법</h2>
<ul>
<li>프로젝트 생성 및 코드작성</li>
<li>인터페이스 빌더를 활용한 UI 구성</li>
<li>유용한 단축키</li>
</ul>
<h3 id="발생했던-문제">발생했던 문제</h3>
<p>sigining과 관련해 &quot;Xcode couldn&#39;t find any iOS App Development
provisioning profiles matching ~&quot; 문제가 발생. 이는 프로파일 프로비저닝과 관련한 문제, 즉 app을 만들 때 app의 안정성을 보장하기 위한 애플의 서명절차와 관련한 문제다.</p>
<p>이는 애플 개발자 계정을 구매한 뒤 developer.apple.com에서 &quot;인증서, 식별자 및 프로파일&quot; 항목을 클릭, appID나 device 등을 등록하면 해결이 된다. </p>
<blockquote>
<p>참고</p>
</blockquote>
<ul>
<li><a href="https://developer.apple.com/documentation/xcode">애플 XCode 공식 문서</a></li>
<li><a href="https://medium.com/@abhimuralidharan/what-is-a-provisioning-profile-in-ios-77987a7c54c2">What is a provisioning profile &amp; code signing in iOS?</a></li>
</ul>
<hr>
<h2 id="assets">Assets</h2>
<p>에셋 카탈로그(Asset Catalog)는 애플리케이션에 사용될 다양한 에셋을 관리한다.
에셋 카탈로그는 에셋과 다양한 디바이스의 속성(디바이스의 특징, 사이즈 클래스, 주문형 리소스, 특정 타입의 정보)에 대한 파일의 mapping을 통해 리소스에 접근 할 수 있게 해준다.</p>
<p>에셋 카탈로그의 콘텐츠는 3가지 타입을 갖는다.</p>
<ul>
<li>Folders : 에셋 카탈로그 폴더는 다른 그룹 폴더나 에셋 폴더를 포함할 수 있다.</li>
<li>JSON files : .json 확장자 파일로서 속성에 대한 정보를 포함하고 있다.</li>
<li>Content files : 이미지, 음원 등 리소스 파일을 나타낸다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/augus-xury/post/4edb7314-37d6-4039-89ca-8e501551e2bc/image.png" alt=""></p>
<blockquote>
<p>참고
<a href="https://developer.apple.com/documentation/xcode/managing-assets-with-asset-catalogs">애플 Asset catalog 공식문서</a></p>
</blockquote>
<hr>
<h2 id="앱-시닝app-thinning">앱 시닝(App Thinning)</h2>
<p><img src="https://velog.velcdn.com/images/augus-xury/post/8391ee88-b490-485d-bd4b-f8081bf51947/image.png" alt=""></p>
<p>앱 시닝이란 애플리케이션이 디바이스에 설치될 때 앱 스토어와 운영체제가 그 디바이스의 특성에 맞게 설치하도록 하는 설치 최적화 기술이다. 이를 통해 애플리케이션의 설치용량을 최소화하고 다운로드의 속도를 향상시킬 수 있다. 앱 시닝의 기술 구성요소는 슬라이싱(slicing), 비트코드(bitcode), 주문형 리소스(on-demand resource)가 있다.</p>
<blockquote>
<p><a href="https://developer.apple.com/documentation/xcode/reducing-your-app-s-size">애플 Reducing your app’s size 공식문서</a>
<a href="https://ankur-s20.medium.com/implementing-app-thinning-in-your-project-step-by-step-tutorial-ios-app-b3cfd139896d">App thinning, Bitcode, Slicing: tutorial (iOS app)</a></p>
</blockquote>
<hr>
<h2 id="uikit-스토리보드">UIKit 스토리보드</h2>
<p><img src="https://velog.velcdn.com/images/augus-xury/post/657e6786-4537-406d-9fe1-e5f94115b01c/image.png" alt=""></p>
<p>스토리보드에서 Type을 Custom으로 변경하면 selected 됐을 때 이미지를 변경할 수 있다.
Cmd + shift + L : 라이브러리에서 요소 선택</p>
<ul>
<li><p><a href="https://developer.apple.com/documentation/uikit/uilabel">UILabel</a></p>
<p>일반 텍스트를 말한다.</p>
</li>
<li><p><a href="https://developer.apple.com/documentation/uikit/uibutton">UIButton</a>
<img src="https://velog.velcdn.com/images/augus-xury/post/6cd80d3c-2399-4ecc-be07-96495de026d5/image.png" alt=""></p>
</li>
</ul>
<ul>
<li><a href="https://developer.apple.com/documentation/uikit/uislider">UISlider</a>
<img src="https://velog.velcdn.com/images/augus-xury/post/f1849dc1-fe3d-47d6-bc69-4b0e4c44caaf/image.png" alt=""></li>
</ul>
<p>@IBOutlet 속성으로 StoryBoard에서 버튼이나 레이블같은 컴포넌트와 연결된다.</p>
<p>@는 컴파일러에게 코드의 특정 부분에 대한 메타데이터를 제공한다. 데코레이터, 어노테이션과 유사한 개념이다.</p>
<p>IBAction은 Event가 일어난 경우 호출되는 Action을 정의해둔 것이고, IBOutlet은 값에 접근하기위한 변수
스토리보드와 연결
IB는 Interface Builder의 약어.</p>
<hr>
<h2 id="avfoundation">AVFoundation</h2>
<p>Apple 플랫폼에서 사운드 및 영상 미디어의 처리, 제어, 가져오기 및 내보내기 등 광범위한 기능을 제공하는 프레임워크다. AV는 AudioVideo 다.</p>
<p>주요 기능은 다음과 같다.</p>
<ul>
<li>미디어 재생 및 편집(QuickTime 동영상 및 MPEG-4 파일 재생/생성/편집, HLS 스트림 재생: <a href="https://developer.apple.com/documentation/avfoundation/avfiletype">재생가능 파일 목록</a>)</li>
<li>디바이스 카메라와 마이크를 이용한 영상 녹화 및 사운드 녹음</li>
<li>시스템 사운드 제어</li>
<li>문자의 음성화</li>
</ul>
<blockquote>
<p><a href="https://developer.apple.com/documentation/avfoundation">AVFoundation 공식문서</a></p>
</blockquote>
<hr>
<h2 id="nsdataasset">NSDataAsset</h2>
<p>NSDataAsset는 에셋 카탈로그에서 데이터 애셋을 로드하는 데 사용되는 클래스다. 이 클래스는 주로 애플리케이션의 에셋 카탈로그에 저장된 이미지나 사운드, 비디오 등의 데이터를 로드하고 이를 메모리에 저장하는 데 사용된다.</p>
<pre><code class="language-swift">let soundAsset: NSDataAsset = NSDataAsset(name: &quot;sound&quot;)</code></pre>
<p>NSDataAsset 인스턴스를 생성할 때 &quot;sound&quot;라는 이름을 지정하면, 애플리케이션은 &quot;sound&quot;라는 이름의 에셋을 에셋 카탈로그에서 찾아 로드하려고 시도한다. 그런 다음 이 데이터는 NSDataAsset의 data 속성에 저장되고, 이 속성을 통해 데이터에 접근할 수 있다.</p>
<p>NS 접두어는 <a href="https://en.wikipedia.org/wiki/NeXTSTEP">NeXTSTEP</a>에서 유래됐다. Objective-C와 Cocoa 프레임워크의 많은 클래스 이름에 &#39;NS&#39; 접두어가 붙어 있는데, NS- 로 시작되는 클래스는 Objective-C와의 호환성이 유지된다.</p>
<hr>
<h2 id="cocoa-touch">Cocoa Touch</h2>
<p>Cocoa Touch는 iOS, iPadOS, watchOS 등 애플의 모바일 운영 체제를 위한 UI 프레임워크로, 기존 macOS를 위한 cocoa 프레임 워크의 AppKit대신 UIKit를 사용해 터치 이벤트 및 센서 데이터 처리 등 모바일에서 요구되는 기능을 추가한 것이다.</p>
<p><a href="https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CocoaFundamentals/WhatIsCocoa/WhatIsCocoa.html">코코아 설명 공식문서</a>
<img src="https://velog.velcdn.com/images/augus-xury/post/99c2ab49-6c73-47ac-9b9a-c26a9ea83913/image.jpg" alt="">
<img src="https://velog.velcdn.com/images/augus-xury/post/0459e639-306f-417a-99b7-d06be8dd1b5a/image.png" alt=""></p>
<p><a href="https://developer.apple.com/documentation/foundation">Foundation</a> : 문자열 처리, 날짜 및 시간 처리, 네트워크 통신, 스레드 관리 등과 같은 기본적인 데이터 관리</p>
<p><a href="https://developer.apple.com/documentation/uikit">UIKit</a>: 사용자 인터페이스를 구축하고 관리하는 데 사용되는 클래스를 제공한다. 창, 패널, 버튼, 메뉴, 스크롤 바 등의 GUI 요소를 담당</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[스프링 DB관리 방법]]></title>
            <link>https://velog.io/@augus-xury/%EC%8A%A4%ED%94%84%EB%A7%81-DB%EA%B4%80%EB%A6%AC-%EB%B0%A9%EB%B2%95-%EC%9A%94%EC%95%BD</link>
            <guid>https://velog.io/@augus-xury/%EC%8A%A4%ED%94%84%EB%A7%81-DB%EA%B4%80%EB%A6%AC-%EB%B0%A9%EB%B2%95-%EC%9A%94%EC%95%BD</guid>
            <pubDate>Sat, 17 Jun 2023 07:09:35 GMT</pubDate>
            <description><![CDATA[<p>스프링 프레임워크에서는 DB 관리를 위한 몇가지 방법을 제공한다.
코드 생산성을 향상시키기 위한 기술의 발전에 따라 크게 4단계로 나눌 수 있다.</p>
<pre><code>JDBC -&gt; JDBC Template -&gt; JPA -&gt; 스프링 데이터 JPA</code></pre><h2 id="🌱-jdbc-java-database-connectivity">🌱 JDBC (Java Database Connectivity):</h2>
<p>JDBC는 자바에서 데이터베이스에 접근할 수 있도록 해주는 API. 이를 통해 SQL 질의를 실행하고, 데이터베이스에서 데이터를 읽고 쓸 수 있다.
그러나 JDBC는 드라이버를 등록하고 DB연결, 쿼리문 작성/실행, 결과 반환, DB 연결 종료 등의 과정을 코드로 일일이 작성해야하고, try-catch 예외 처리가 필요하다.
따라서 반복되는 과정을 템플릿화한 것이 JDBC 템플릿이다</p>
<h2 id="🌱-jdbc-template">🌱 JDBC Template:</h2>
<p>JDBC Template은 데이터베이스 연결의 생성과 종료, SQL 질의의 실행, 결과 처리 등을 자동화해준다. 개발자는 비즈니스 로직에 집중할 수 있다.
실제 아래 링크에 가면 JdbcTemplate 코드를 볼 수 있는데 엄청 긴 것을 확인할 수 있다.
<a href="https://github.com/spring-projects/spring-framework/blob/main/spring-jdbc/src/main/java/org/springframework/jdbc/core/JdbcTemplate.java">https://github.com/spring-projects/spring-framework/blob/main/spring-jdbc/src/main/java/org/springframework/jdbc/core/JdbcTemplate.java</a></p>
<h2 id="🌱-jpa-java-persistence-api">🌱 JPA (Java Persistence API):</h2>
<p>JPA는 자바에서 ORM (Object-Relational Mapping) 기능을 제공하는 API다.
ORM은 객체 지향 프로그래밍과 관계형 데이터베이스를 매핑해주는 기술로, JPA를 사용하면 개발자는 SQL 질의를 직접 작성하지 않고 객체지향 코딩 방식으로 DB를 조작할 수 있게된다.
다만 PK가 아닌 키를 대상으로는 JPQL(Java Persistence Query Language)을 작성해야 한다. JPQL은 JPA(Java Persistence API)가 제공하는 쿼리 언어로서, SQL과 유사하지만 객체 지향적인 측면을 가지고 있다.</p>
<blockquote>
<p>JPQL은 SQL과 달리 데이터베이스 테이블이 아닌 자바 엔티티 객체를 대상으로 작동한다. 예를들어 &quot;select m from Member m&quot;라는 JPQL 문장은 &quot;Member&quot;라는 엔티티 객체를 모두 선택하라는 의미다.
JPQL은 연결된 DB에 상관없이 동일한 자바 코드를 작성할 수 있도록 한다. JPA 구현체가 JPQL을 데이터베이스의 쿼리 언어(SQL 등)로 변환한다. DB가 변경되더라도 JPQL은 변경되지 않아 코드의 이식성이 증가한다.</p>
</blockquote>
<h2 id="🌱-spring-data-jpa">🌱 Spring Data JPA:</h2>
<p>스프링 데이터 JPA는 JPA를 좀 더 편리하게 사용할 수 있도록 하는 라이브러리다. 레포지토리 인터페이스를 만들기만 하면 스프링 데이터 JPA가 자동으로 구현체를 생성해준다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Swift란]]></title>
            <link>https://velog.io/@augus-xury/Swift%EB%9E%80</link>
            <guid>https://velog.io/@augus-xury/Swift%EB%9E%80</guid>
            <pubDate>Mon, 12 Jun 2023 06:12:20 GMT</pubDate>
            <description><![CDATA[<h1 id="about-swift">About Swift</h1>
<p>Swift는 애플이 2014년에 발표한 프로그래밍 언어로, C와 Objective-C에 비해 간결하고, 모던하며 안전한 코드를 작성하기 위해 설계되었다.</p>
<ul>
<li>안전성: Swift는 명시적인 변수 선언을 통해 데이터 타입의 일관성을 보장하며, 초기화되지 않은 변수나 널(null) 값 참조와 같은 프로그래밍 오류를 방지하도록 설계.</li>
<li>퍼포먼스: Swift는 최적화된 컴파일러를 사용하여 고성능의 애플리케이션을 제작 가능.</li>
<li>현대적인 언어 구조: Swift는 최신 프로그래밍 언어 디자인 패턴을 채택, 가독성과 유지 보수가 좋음. 함수형 프로그래밍과 객체지향 프로그래밍, 프로토콜 지향 프로그래밍의 요소를 모두 포함.</li>
</ul>
<blockquote>
<p><a href="https://docs.swift.org/swift-book/documentation/the-swift-programming-language/aboutswift">공식문서 welcome swift - About swift</a></p>
</blockquote>
<p>공식 문서에 따르면 스위프트는 다음과 같은 modern programming patterns을 가지고 있다.</p>
<hr>
<ul>
<li>Variables are always initialized before use.<pre><code class="language-swift">var myVar: Int  // 변수 선언
myVar = 10  // 변수 초기화
print(myVar)  // 변수 사용</code></pre>
</li>
</ul>
<hr>
<ul>
<li>Array indices are checked for out-of-bounds errors.<pre><code class="language-swift">let myArr : Array&lt;Int&gt; = [0, 1, 2]
</code></pre>
</li>
</ul>
<p>print(myArr[2])  // 2 출력
print(myArr[3])  // Index out of range</p>
<pre><code>
---

- Integers are checked for overflow.
```swift
var myInt : Int = Int.max
print(myInt)
print(myInt + 1) // 컴파일 에러</code></pre><hr>
<ul>
<li>Optionals ensure that nil values are handled explicitly.<pre><code class="language-swift">var optionalVar: Int? = nil
if let unwrapped = optionalVar {
  print(&quot;Value: \(unwrapped)&quot;)
} else {
  print(&quot;Value is nil&quot;)
}</code></pre>
</li>
</ul>
<hr>
<ul>
<li>Memory is managed automatically.<pre><code class="language-swift">class MyClass {
  var name: String
  init(name: String) {
      self.name = name
  }
}
var ref: MyClass? = MyClass(name: &quot;Swift&quot;)
ref = nil  // ref가 nil로 설정되면 MyClass 인스턴스는 메모리에서 자동으로 제거</code></pre>
</li>
</ul>
<hr>
<ul>
<li>Error handling allows controlled recovery from unexpected failures.<pre><code class="language-swift">enum MyError: Error {
  case runtimeError(String) // 연관값(associated value)
}
do {
  throw MyError.runtimeError(&quot;An error occurred&quot;)
} catch MyError.runtimeError(let errorMessage) {
  print(&quot;Caught an error: \(errorMessage)&quot;)
} catch {
  print(&quot;Unknown error occurred&quot;)
}</code></pre>
에러는 enum으로 선언하여 사용하게 되는데, 함수처럼 사용되는 것은 연관값이다.</li>
</ul>
<p>또 Swift는 강력한 타입 추론과 패턴 매칭 기능이 있다.</p>
<blockquote>
<p>Swift combines powerful type inference and pattern matching with a modern, lightweight syntax, allowing complex ideas to be expressed in a clear and concise manner.</p>
</blockquote>
<hr>
<h1 id="version-compatibility">Version Compatibility</h1>
<blockquote>
<p><a href="https://docs.swift.org/swift-book/documentation/the-swift-programming-language/compatibility">공식문서 welcome swift - Version Compatibility</a></p>
</blockquote>
<p>2023년 6월 기준 Swift 5.9버전에 대해 기술하고 있으며, 다음 기능들은 5.9버전 이후 버전에서만 사용될 수 있다.</p>
<hr>
<ul>
<li>Functions that return an opaque type require the Swift 5.1 runtime.</li>
</ul>
<p>Opaque type은 불필요한 정보를 감춰 코드를 간결하게 만드는 방법이다.</p>
<hr>
<ul>
<li>The try? expression doesn’t introduce an extra level of optionality to expressions that already return optionals.</li>
</ul>
<p>do { try } catch { } 꼴의 문법에서의 try를 말한다. try에는 try? 옵셔널과 try! 옵셔널이 있다.</p>
<hr>
<ul>
<li>Large integer literal initialization expressions are inferred to be of the correct integer type. For example, UInt64(0xffff_ffff_ffff_ffff) evaluates to the correct value rather than overflowing.</li>
</ul>
<p>타입 추론에 따라 아래 선언을</p>
<pre><code class="language-swift">let largeNumber = 0xffff_ffff_ffff_ffff</code></pre>
<p>다음과 같이 해석한다는 것.</p>
<pre><code class="language-swift">let largeNumber: UInt64 = 0xffff_ffff_ffff_ffff</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[스프링 핵심원리 - 기본편2]]></title>
            <link>https://velog.io/@augus-xury/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B82</link>
            <guid>https://velog.io/@augus-xury/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B82</guid>
            <pubDate>Sat, 10 Jun 2023 04:41:29 GMT</pubDate>
            <description><![CDATA[<p>RateDiscountPolicy 개발</p>
<pre><code class="language-java">package basics.core.discount;

import basics.core.member.Grade;
import basics.core.member.Member;

public class RateDiscountPolicy implements DiscountPolicy {

    private int discountPercent = 10;

    @Override
    public int discount(Member member, int price) {
        if (member.getGrade() == Grade.VIP) {
            return price * discountPercent / 100;
        } else {
            return 0;
        }
    }
}
</code></pre>
<p>하지만</p>
<pre><code class="language-java">public class OrderServiceImpl implements OrderService {
    private final MemberRepository memberRepository = new MemoryMemberRepository();
//    private final DiscountPolicy discountPolicy = new FixDiscountPolicy();
    private final DiscountPolicy discountPolicy = new RateDiscountPolicy();

    @Override
    public Order createOrder(Long memberId, String itemName, int itemPrice) {
        Member member = memberRepository.findById(memberId);
        int discountPrice = discountPolicy.discount(member, itemPrice);

        return new Order(memberId, itemName, itemPrice, discountPrice);
    }
}</code></pre>
<p>구체적인 인스턴스에 의존하는 코드를 짜버렸다. 그래서 의존하지 않는 코드를 짜면,</p>
<pre><code class="language-java">public class OrderServiceImpl implements OrderService {
    private final MemberRepository memberRepository = new MemoryMemberRepository();
    private DiscountPolicy discountPolicy;;

    @Override
    public Order createOrder(Long memberId, String itemName, int itemPrice) {
        Member member = memberRepository.findById(memberId);
        int discountPrice = discountPolicy.discount(member, itemPrice);

        return new Order(memberId, itemName, itemPrice, discountPrice);
    }
}</code></pre>
<p>구현체가 없어 실제 실행을 해보면 NPE(null pointer exception)가 발생한다.</p>
<p>=&gt; 누군가 대신 구현 객체를 생성해 주입해줘야 한다 =&gt; appConfig의 등장
appConfig에서 생성자를 통해서 주입이 됨</p>
<p><img src="https://velog.velcdn.com/images/augus-xury/post/ccc8e66a-480e-4eff-8096-c9ed9c6e1399/image.png" alt=""></p>
<p>AppConfig</p>
<pre><code class="language-java">package basics.core;

import basics.core.discount.DiscountPolicy;
import basics.core.discount.FixDiscountPolicy;
import basics.core.discount.RateDiscountPolicy;
import basics.core.member.MemberService;
import basics.core.member.MemberServiceImpl;
import basics.core.member.MemoryMemberRepository;
import basics.core.order.OrderService;
import basics.core.order.OrderServiceImpl;

public class AppConfig {

    public MemberService memberService() {
        return new MemberServiceImpl(memberRepository());
    }

    private MemoryMemberRepository memberRepository() {
        return new MemoryMemberRepository();
    }

    public OrderService orderService() {
        return new OrderServiceImpl(memberRepository(), discountPolicy());
    }

    public DiscountPolicy discountPolicy() {
//        return new FixDiscountPolicy();
        return new RateDiscountPolicy();

    }
}

</code></pre>
<p>MemberServiceImpl</p>
<pre><code class="language-java">package basics.core.member;

public class MemberServiceImpl implements MemberService {
    private final MemberRepository memberRepository;

    public MemberServiceImpl(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

    @Override
    public void join(Member member) {
        memberRepository.save(member);
    }

    @Override
    public Member findMember(Long memberId) {
        return memberRepository.findById(memberId);
    }
}
</code></pre>
<p>OrderServiceImpl</p>
<pre><code class="language-java">package basics.core.order;

import basics.core.discount.DiscountPolicy;
import basics.core.member.Member;
import basics.core.member.MemberRepository;

public class OrderServiceImpl implements OrderService {
    private final MemberRepository memberRepository;
    private final DiscountPolicy discountPolicy;;

    public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
        this.memberRepository = memberRepository;
        this.discountPolicy = discountPolicy;
    }

    @Override
    public Order createOrder(Long memberId, String itemName, int itemPrice) {
        Member member = memberRepository.findById(memberId);
        int discountPrice = discountPolicy.discount(member, itemPrice);

        return new Order(memberId, itemName, itemPrice, discountPrice);
    }
}
</code></pre>
<p>MemberApp</p>
<pre><code class="language-java">package basics.core;
import basics.core.AppConfig;
import basics.core.member.Grade;
import basics.core.member.Member;
import basics.core.member.MemberService;

public class MemberApp {
    public static void main(String[] args) {
        AppConfig appConfig = new AppConfig();
        MemberService memberService = appConfig.memberService();
        Member member = new Member(1L, &quot;memberA&quot;, Grade.VIP);
        memberService.join(member);
        Member findMember = memberService.findMember(1L);
        System.out.println(&quot;new member = &quot; + member.getName());
        System.out.println(&quot;find Member = &quot; + findMember.getName());
    }
}</code></pre>
<p>OrderApp</p>
<pre><code class="language-java">package basics.core;

import basics.core.member.Grade;
import basics.core.member.Member;
import basics.core.member.MemberService;
import basics.core.order.Order;
import basics.core.order.OrderService;

public class OrderApp {
    public static void main(String[] args) {
        AppConfig appConfig = new AppConfig();

        MemberService memberService = appConfig.memberService();
        OrderService orderService = appConfig.orderService();

        Long memberId = 1L;
        Member member = new Member(memberId, &quot;memberA&quot;, Grade.VIP);
        memberService.join(member);

        Order order = orderService.createOrder(memberId, &quot;itemA&quot;, 10000);

        System.out.println(&quot;order = &quot; + order);
    }
}
</code></pre>
<p>제어의 역전
모든 제어권은 AppConfig가 갖고, 나머지 소스코드는 자기 로직만 수행한다.
AppConfig 처럼 객체를 생성하고 관리하면서 의존관계를 연결해 주는 것을 IoC 컨테이너 또는 DI 컨테이너라 한다.</p>
<p>정적의존관계 vs 동적 의존관계</p>
<blockquote>
<p>정적인 클래스 의존관계
클래스가 사용하는 import 코드만 보고 의존관계를 쉽게 판단할 수 있다. 정적인 의존관계는 애플리케이션을 실행하지 않아도 분석할 수 있다. 클래스 다이어그램을 보자
OrderServiceImpl 은 MemberRepository , DiscountPolicy 에 의존한다는 것을 알 수 있다.
그런데 이러한 클래스 의존관계 만으로는 실제 어떤 객체가 OrderServiceImpl 에 주입 될지 알 수 없다.</p>
</blockquote>
<blockquote>
<p>동적인 객체 인스턴스 의존 관계
애플리케이션 실행 시점에 실제 생성된 객체 인스턴스의 참조가 연결된 의존 관계다.</p>
</blockquote>
<h1 id="스프링으로-변경">스프링으로 변경</h1>
<pre><code class="language-java">package basics.core;

import basics.core.discount.DiscountPolicy;
import basics.core.discount.FixDiscountPolicy;
import basics.core.discount.RateDiscountPolicy;
import basics.core.member.MemberService;
import basics.core.member.MemberServiceImpl;
import basics.core.member.MemoryMemberRepository;
import basics.core.order.OrderService;
import basics.core.order.OrderServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

    @Bean
    public MemberService memberService() {
        return new MemberServiceImpl(memberRepository());
    }

    @Bean
    public MemoryMemberRepository memberRepository() {
        return new MemoryMemberRepository();
    }

    @Bean
    public OrderService orderService() {
        return new OrderServiceImpl(memberRepository(), discountPolicy());
    }

    @Bean
    public DiscountPolicy discountPolicy() {
//        return new FixDiscountPolicy();
        return new RateDiscountPolicy();

    }
}
</code></pre>
<p>AppConfig에 @Bean 어노테이션 추가</p>
<pre><code class="language-java">
package basics.core;
import basics.core.AppConfig;
import basics.core.member.Grade;
import basics.core.member.Member;
import basics.core.member.MemberService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MemberApp {
    public static void main(String[] args) {
//        AppConfig appConfig = new AppConfig();
//        MemberService memberService = appConfig.memberService();
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
        MemberService memberService = applicationContext.getBean(&quot;memberService&quot;, MemberService.class);

        Member member = new Member(1L, &quot;memberA&quot;, Grade.VIP);
        memberService.join(member);
        Member findMember = memberService.findMember(1L);
        System.out.println(&quot;new member = &quot; + member.getName());
        System.out.println(&quot;find Member = &quot; + findMember.getName());
    }
}
</code></pre>
<pre><code class="language-java">
package basics.core;

import basics.core.member.Grade;
import basics.core.member.Member;
import basics.core.member.MemberService;
import basics.core.order.Order;
import basics.core.order.OrderService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class OrderApp {
    public static void main(String[] args) {
//        AppConfig appConfig = new AppConfig();

//        MemberService memberService = appConfig.memberService();
//        OrderService orderService = appConfig.orderService();

        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
        MemberService memberService = applicationContext.getBean(&quot;memberService&quot;, MemberService.class);
        OrderService orderService = applicationContext.getBean(&quot;orderService&quot;, OrderService.class);

        Long memberId = 1L;
        Member member = new Member(memberId, &quot;memberA&quot;, Grade.VIP);
        memberService.join(member);

        Order order = orderService.createOrder(memberId, &quot;itemA&quot;, 10000);

        System.out.println(&quot;order = &quot; + order);
    }
}


</code></pre>
<p>ApplicationContext를 통해 @Bean으로 등록된 객체를 가져옴</p>
<blockquote>
<p>기존에는 개발자가 AppConfig 를 사용해서 직접 객체를 생성하고 DI를 했지만, 이제부터는 스프링 컨테이너를 통해서 사용한다.
스프링 컨테이너는 @Configuration 이 붙은 AppConfig 를 설정(구성) 정보로 사용한다. 여기서 @Bean 이라 적힌 메서드를 모두 호출해서 반환된 객체를 스프링 컨테이너에 등록한다. 이렇게 스프링 컨테이너에 등록된 객체를 스프링 빈이라 한다.
스프링 빈은 @Bean 이 붙은 메서드의 명을 스프링 빈의 이름으로 사용한다. ( memberService , orderService )
이전에는 개발자가 필요한 객체를 AppConfig 를 사용해서 직접 조회했지만, 이제부터는 스프링 컨테이너를 통해서 필요한 스프링 빈(객체)를 찾아야 한다. 스프링 빈은 applicationContext.getBean() 메서드를 사용해서 찾을 수 있다.
기존에는 개발자가 직접 자바코드로 모든 것을 했다면 이제부터는 스프링 컨테이너에 객체를 스프링 빈으로 등록하고, 스프링 컨테이너에서 스프링 빈을 찾아서 사용하도록 변경되었다.</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[플러터 stateless/stateful 위젯]]></title>
            <link>https://velog.io/@augus-xury/%ED%94%8C%EB%9F%AC%ED%84%B0-%EC%9C%84%EC%A0%AF</link>
            <guid>https://velog.io/@augus-xury/%ED%94%8C%EB%9F%AC%ED%84%B0-%EC%9C%84%EC%A0%AF</guid>
            <pubDate>Thu, 08 Jun 2023 05:20:18 GMT</pubDate>
            <description><![CDATA[<h1 id="위젯">위젯</h1>
<p>UI를 구성하는 모든 단위로 클래스의 인스턴스다. 그래픽이나 데이터를 처리하는 함수를 가진다. 각 위젯에는 named args를 넣어주게 된다.</p>
<h2 id="stateless-위젯">stateless 위젯</h2>
<p>상태가 없는 정적인 위젯이다. 스크린에 존재하면서 데이터를 저장하지 않고 아무 변화도 없다. 한 번 렌더링되면, 그 상태가 변하지 않는다. 데이터가 변하지 않거나 위젯이 다시 렌더링될 필요가 없는 경우에 사용한다. (로고, 아이콘 등)</p>
<pre><code class="language-dart">class MyStatelessWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Text(&#39;Hello, I am a stateless widget&#39;),
    );
  }
}</code></pre>
<h2 id="stateful-위젯">stateful 위젯</h2>
<p>계속해서 변화가 있는 위젯이다. 사용자의 인터렉션에 따라 변한다. 사용자 입력이나 API 응답과 같이 동적인 데이터를 처리하거나, 사용자와의 상호작용을 통해 상태가 변화하는 경우 사용한다.</p>
<p>플러터 프레임워크는 createState()를 통해 값이 동적으로 변하는 페이지를 렌더링한다.</p>
<pre><code class="language-dart">class MyStatefulWidget extends StatefulWidget {
  @override
  _MyStatefulWidgetState createState() =&gt; _MyStatefulWidgetState();
}

class _MyStatefulWidgetState extends State&lt;MyStatefulWidget&gt; {
  int counter = 0;

  void incrementCounter() {
    setState(() {
      counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Text(&#39;Counter Value: $counter&#39;),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: incrementCounter,
        tooltip: &#39;Increment&#39;,
        child: Icon(Icons.add),
      ),
    );
  }
}
</code></pre>
<pre><code class="language-dart">class MyStatefulWidget extends StatefulWidget {
  final Color color;

  MyStatefulWidget({this.color});

  @override
  _MyStatefulWidgetState createState() =&gt; _MyStatefulWidgetState();
}

class _MyStatefulWidgetState extends State&lt;MyStatefulWidget&gt; {
  @override
  Widget build(BuildContext context) {
    return Container(
      color: widget.color,
    );
  }
}</code></pre>
<h3 id="state">State</h3>
<p>상태(state)란 애플리케이션에서 시간이 지남에 따라 변경될 수 있는 데이터를 의미한다. StatefulWidget은 createState() 메소드를 통해 상태를 생성하고 관리한다.</p>
<p>플러터 프레임워크는 State<MyStatefulWidget>와 같이 제너릭을 통해 반환된 State 인스턴스를 StatefulWidget과 연결한다. 이는 State 객체가 자신을 소유한 StatefulWidget에 대한 정보를 갖고 있어야 하기 때문이다. State는 StatefulWidget의 데이터를 읽고, 변경 사항이 있을 경우 setState()를 호출하여 화면을 다시 빌드한다.
setState() 메서드를 사용하면 변한 상태 값에 대해 리렌더링 해준다.</p>
<h3 id="createstate">createState</h3>
<p>createState() 함수는 StatefulWidget의 인스턴스를 만들 때 호출되는 함수로, State 클래스의 인스턴스를 반환한다. State 인스턴스는 StatefulWidget의 생명주기 동안 지속되는 상태를 갖고 있다.</p>
<p>StatelessWidget은 상태를 유지하지 않기 때문에 createState와 같은 상태 관리 메서드가 필요하지 않다.</p>
<h3 id="widget-객체">widget 객체</h3>
<p>State 객체가 생성될 때는 widget 객체를 자동으로 생성한다. widget은 State 객체 내에서 사용할 수 있고, 현재 State 객체와 연결된 StatefulWidget 인스턴스를 참조한다. 즉, State 객체가 자신의 부모 StatefulWidget의 속성에 접근할 수 있도록 한다.</p>
<h3 id="initstate">initState</h3>
<p>initState() 메서드는 State 객체가 생성될 때 한 번만 호출되며, 위젯이 초기화되는 로직을 넣는 곳이다.</p>
<p>데이터를 불러오거나, 스트림을 설정하거나, 애니메이션을 초기화하는 등의 작업을 수행할 수 있다. 위젯이 트리에 삽입되기 전에 호출되므로 화면이 그려지기 전에 준비해야 하는 모든 것을 설정하는 데 사용된다.</p>
<pre><code class="language-dart">@override
void initState() {
  super.initState();

  // initialize data, start animations, etc.
}</code></pre>
<h3 id="dispose">dispose</h3>
<p>dispose() 메서드는 StatefulWidget이 위젯 트리에서 제거되기 전에 호출된다. 위젯이 더 이상 필요하지 않을 때 그 위젯과 관련된 모든 리소스를 정리하는 데 사용된다.</p>
<p>컨트롤러를 dispose하거나, 스트림을 닫거나, 메모리에 남아있는 객체를 삭제하는 등의 작업을 수행할 수 있다.</p>
<pre><code class="language-dart">@override
void dispose() {
  // dispose resources like controllers, streams, etc.

  super.dispose();
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[스프링 핵심원리 - 기본편1]]></title>
            <link>https://velog.io/@augus-xury/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B81</link>
            <guid>https://velog.io/@augus-xury/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B81</guid>
            <pubDate>Thu, 01 Jun 2023 12:04:37 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>김영한님 강의 기록</p>
</blockquote>
<h2 id="스프링-세팅">스프링 세팅</h2>
<p><img src="https://velog.velcdn.com/images/augus-xury/post/9d995045-49c8-48f1-bb0c-339bff2de79c/image.png" alt=""></p>
<blockquote>
<p>스프링 부트 3.0을 선택하면</p>
</blockquote>
<ol>
<li>Java 17 이상을 사용해야 합니다.</li>
<li>javax 패키지 이름을 jakarta로 변경해야 합니다.
오라클과 자바 라이센스 문제로 모든 javax 패키지를 jakarta로 변경하기로 했습니다.
패키지 이름 변경 예) <pre><code># JPA 애노테이션
javax.persistence.Entity jakarta.persistence.Entity </code></pre></li>
</ol>
<hr>
<h1 id="스프링에서-자주-사용하는-postconstruct-애노테이션">스프링에서 자주 사용하는 @PostConstruct 애노테이션</h1>
<h2 id="javaxannotationpostconstruct-jakartaannotationpostconstruct">javax.annotation.PostConstruct jakarta.annotation.PostConstruct</h2>
<h1 id="스프링에서-자주-사용하는-검증-애노테이션">스프링에서 자주 사용하는 검증 애노테이션</h1>
<p>javax.validation jakarta.validation</p>
<p>```</p>
<h2 id="비즈니스-요구사항">비즈니스 요구사항</h2>
<h3 id="회원">회원</h3>
<p>회원을 가입하고 조회할 수 있다.
회원은 일반과 VIP 두 가지 등급이 있다.
회원 데이터는 자체 DB를 구축할 수 있고, 외부 시스템과 연동할 수 있다. (미확정)</p>
<h3 id="주문과-할인-정책">주문과 할인 정책</h3>
<p>회원은 상품을 주문할 수 있다.
회원 등급에 따라 할인 정책을 적용할 수 있다.
할인 정책은 모든 VIP는 1000원을 할인해주는 고정 금액 할인을 적용해달라. (나중에 변경 될 수 있다.)
할인 정책은 변경 가능성이 높다. 회사의 기본 할인 정책을 아직 정하지 못했고, 오픈 직전까지 고민을 미루고 싶다. 최악의 경우 할인을 적용하지 않을 수 도 있다. (미확정)</p>
<h2 id="회원-도메인-개발">회원 도메인 개발</h2>
<h3 id="회원-도메인-협력관계">회원 도메인 협력관계</h3>
<ul>
<li>기획자와 개발자가 같이 협업하는 단계
<img src="https://velog.velcdn.com/images/augus-xury/post/14857aba-641c-43f4-a122-53a74938e71e/image.png" alt=""></li>
</ul>
<h3 id="회원-클래스-다이어그램">회원 클래스 다이어그램</h3>
<ul>
<li>개발자가 구현 어떻게 할지 정하는 단계
<img src="https://velog.velcdn.com/images/augus-xury/post/9504b254-a05d-497e-9307-ce6cb86d9bd5/image.png" alt=""></li>
</ul>
<h3 id="회원-객체-다이어그램">회원 객체 다이어그램</h3>
<ul>
<li>repository가 동적으로 결정되기 때문에 실제 사용하는 인스턴스 관계를 명시
<img src="https://velog.velcdn.com/images/augus-xury/post/1fd75875-e480-40ba-8c5b-38fa43462171/image.png" alt=""></li>
</ul>
<ol>
<li>Member 클래스를 구현 -&gt; id/name/grade/생성자/getter/setter</li>
<li>MemberRepository 인터페이스 -&gt; 메모리 구현체 Class</li>
<li>MemberService 인터페이스 -&gt; 구현체인 MemberServiceImpl</li>
</ol>
<h2 id="할인-정책-도메인-개발">할인 정책 도메인 개발</h2>
<h3 id="주문-도메인-전체">주문 도메인 전체</h3>
<p><img src="https://velog.velcdn.com/images/augus-xury/post/64cd0ea5-6e1a-4479-9a31-68199a7b8d01/image.png" alt=""></p>
<p>역할과 구현을 구분해야 한다.</p>
<h3 id="주문-도메인-클래스-다이어그램">주문 도메인 클래스 다이어그램</h3>
<p><img src="https://velog.velcdn.com/images/augus-xury/post/d3cced14-dff1-4136-8ea9-5dac6c4617d4/image.png" alt=""></p>
<h3 id="주문-도메인-객체-다이어그램1">주문 도메인 객체 다이어그램1</h3>
<p><img src="https://velog.velcdn.com/images/augus-xury/post/1f343a40-d1a6-447c-8e6c-84a42abd2693/image.png" alt=""></p>
<h3 id="주문-도메인-객체-다이어그램2">주문 도메인 객체 다이어그램2</h3>
<p><img src="https://velog.velcdn.com/images/augus-xury/post/431309e4-bc73-4193-9010-c77b176e8e4e/image.png" alt="">
협력 관계는 그대로 유지된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[스프링 생태계 버전 흐름]]></title>
            <link>https://velog.io/@augus-xury/%EC%8A%A4%ED%94%84%EB%A7%81-%EC%83%9D%ED%83%9C%EA%B3%84</link>
            <guid>https://velog.io/@augus-xury/%EC%8A%A4%ED%94%84%EB%A7%81-%EC%83%9D%ED%83%9C%EA%B3%84</guid>
            <pubDate>Sun, 28 May 2023 00:40:47 GMT</pubDate>
            <description><![CDATA[<p>과거 자바 진영 표준 기줄인 EJB (Enterprise Java Beans)는 너무 어렵고 복잡, 기술 수준도 낮음</p>
<p>=&gt; Spring의 등장</p>
<p>Spring 설정이 복잡 =&gt; Spring Boot 등장</p>
<p>스프링의 핵심 철학? </p>
<h1 id="스프링-릴리스-history">스프링 릴리스 history</h1>
<h2 id="2004년">2004년</h2>
<h3 id="🌱-스프링-프레임워크-10-릴리스">🌱 스프링 프레임워크 1.0 릴리스</h3>
<p>스프링의 주요 특징인 제어의 역전(IoC) 컨테이너, Dependency Injection, Spring MVC, JDBC 추상화 등이 소개, XML 기반의 빈 설정</p>
<h2 id="2006년">2006년</h2>
<h3 id="🌱-스프링-프레임워크-20-릴리스">🌱 스프링 프레임워크 2.0 릴리스</h3>
<p>XML 스키마를 통한 설정 지원, AspectJ를 통한 Aspect-Oriented Programming (AOP) 기능 향상, 스프링 웹 플로우와의 통합 등이 추가. 2.5에서 Annotation 기반의 설정 도입</p>
<h2 id="2009년">2009년</h2>
<h3 id="🌱-스프링-프레임워크-30-릴리스">🌱 스프링 프레임워크 3.0 릴리스</h3>
<p>REST 웹 서비스, 표현언어(EL), 표준 검증 지원 등이 추가, @Configuration 애노테이션을 통한 자바 기반 설정이 처음 도입</p>
<h2 id="2013년">2013년</h2>
<h3 id="🌱-스프링-프레임워크-40-릴리스">🌱 스프링 프레임워크 4.0 릴리스</h3>
<p>Java 8 도입, 람다 표현식과 메서드 참조 지원, 실시간 웹 애플리케이션 개발을 위한 WebSocket 및 STOMP 메시징을 지원</p>
<h2 id="2014년">2014년</h2>
<h3 id="🌱-스프링-부트-10-릴리스">🌱 스프링 부트 1.0 릴리스</h3>
<p>스프링 프레임워크의 설정을 단순화하고 빠른 프로토타이핑이 가능, 기본적인 템플릿과 설정을 제공하는 Spring Boot Starter 도입, Tomcat, Jetty, Undertow 등의 내장 서버 지원</p>
<h2 id="2017년">2017년</h2>
<h3 id="🌱-스프링-프레임워크-50-릴리스">🌱 스프링 프레임워크 5.0 릴리스</h3>
<p>비동기 처리를 위한 spring-webflux 모듈(Reactive Programming 모델) 도입, Kotlin 언어에 대한 일급 지원 도입, Junit 5에 대한 지원, 모듈 단위 개선, 코어 컨테이너 개선</p>
<h2 id="2018년">2018년</h2>
<h3 id="🌱-스프링-부트-20-릴리스">🌱 스프링 부트 2.0 릴리스</h3>
<p>스프링 프레임워크 5.0 및 Reactor Core 3.1에 대한 기본 지원, Kotlin 지원 등</p>
<h2 id="2022년">2022년</h2>
<h3 id="🌱-스프링-프레임워크-60-릴리스">🌱 스프링 프레임워크 6.0 릴리스</h3>
<p>Java 17기반으로 변경, RPC 지원 종료, 새로운 AOT 엔진 도입 등</p>
<h3 id="🌱-스프링-부트-30-릴리스">🌱 스프링 부트 3.0 릴리스</h3>
<p>Java 17 기반, native 지원 확대</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[플러터 배우면서 정리해보는 Dart 문법]]></title>
            <link>https://velog.io/@augus-xury/Dart-%EB%AC%B8%EB%B2%95-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@augus-xury/Dart-%EB%AC%B8%EB%B2%95-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Tue, 23 May 2023 11:02:30 GMT</pubDate>
            <description><![CDATA[<h2 id="var-와-dynamic">var 와 dynamic</h2>
<p>Dart에는 var 타입과 dynamic 타입이 존재
var 타입에는 아무 자료형이나 넣을 수 있지만, 첫 자료형 타입으로 고정시켜 준다.
반면 dynamic 타입은 아무 자료형이나 막 바꿔서 넣어줄 수 있다.</p>
<pre><code class="language-dart">var name = &quot;jinhyeok&quot;;
name = 123;</code></pre>
<p>이렇게 하면 컴파일 에러가 난다.</p>
<pre><code class="language-dart">dynamic name = &quot;jinhyeok&quot;;
name = 123;</code></pre>
<p>이렇게 하면 괜찮다.</p>
<p>이 외 기본 자료형은 
int, String, double, bool 등등이 있다.</p>
<h2 id="list-map-자료형">List, Map 자료형</h2>
<p>List, Map은 그냥 써도 되고, &lt; &gt; 제너릭을 넣어서 선언해도 된다.</p>
<pre><code class="language-dart">List nums = [5, 4, 3, 2, 1];

// 또는

List&lt;int&gt; nums = [5, 4, 3, 2, 1];
</code></pre>
<pre><code class="language-dart">  Map dics = {
    &quot;cat&quot; : &quot;성격이 드러운 애완동물&quot;,
    &quot;dog&quot; : &quot;성격이 온순한 애완동물&quot;,
  };

  // 또는

  Map&lt;String, String&gt; dics = {
    &quot;cat&quot; : &quot;성격이 드러운 애완동물&quot;,
    &quot;dog&quot; : &quot;성격이 온순한 애완동물&quot;,
  };
</code></pre>
<p>List 선언 시 </p>
<pre><code>List myList = [];

List myList = new List();</code></pre><p>두 가지 방식으로 선언이 가능한데, new List()에 특정 수를 입력하면 List의 길이를 제한할 수 있다.</p>
<pre><code>List myList = new List(5);</code></pre><h2 id="fianl-vs-const">fianl vs const</h2>
<p>const는 build time에 값이 정해져 있어햐 한다.
반면 final은 run time에 값이 결정된다</p>
<pre><code class="language-dart">void main() {
  final now1 = new DateTime.now();  // 가능

  const now2 = new DateTime.now();  // 불가능
}</code></pre>
<h2 id="for-loop">for loop</h2>
<pre><code>for (int i = 0; i &lt; 10 ; i++) // 첫번째 방법


List&lt;int&gt; items = [1, 2, 3, 4, 5];
for (item in items) // 두번째 방법</code></pre><h2 id="continuebreak">continue/break</h2>
<pre><code class="language-dart">void main() {
  for (int i = 0; i &lt; 5; i++) {
    if (i == 3) {
      continue;
    }
    print(&#39;hello ${i}&#39;);
  }
}

...

void main() {
  int i = 0;
  while(i &lt; 5) {
    if (i == 3) {
      i++;
      continue;
    }
    print(&#39;hello $i&#39;);
    i++;
  }
}

...
/* 결과
hello 0
hello 1
hello 2
hello 4
*/</code></pre>
<pre><code class="language-dart">void main() {
  for (int i = 0; i &lt; 5; i++) {
    if (i == 3) {
      break;
    }
    print(&#39;hello ${i}&#39;);
  }
}

...

void main() {
  int i = 0;
  while(i &lt; 5) {
    if (i == 3) {
      break;
    }
    print(&#39;hello ${i}&#39;);
    i++;
  }
}

...

/* 결과
hello 0
hello 1
hello 2
*/</code></pre>
<h1 id="collection-if">collection if</h1>
<pre><code class="language-dart">var nav = [&#39;Home&#39;, &#39;Furniture&#39;, &#39;Plants&#39;, if (promoActive) &#39;Outlet&#39;];</code></pre>
<h1 id="collection-for">collection for</h1>
<pre><code class="language-dart">var listOfInts = [1, 2, 3];
var listOfStrings = [&#39;#0&#39;, for (var i in listOfInts) &#39;#$i&#39;];</code></pre>
<h2 id="함수-optional-paramsdefault-인자">함수 Optional Params/default 인자</h2>
<pre><code class="language-dart">void main() {
  double result1 = add(1,2);

  print(result1);

  double result2 = add(1,2,0);

  print(result2); 
}

double add(double x, double y, [double z = 100]) {
  return (x + y + z);
}

//[dobule z]로만 하면 옵셔널</code></pre>
<p>이를 named parameter 방식으로도 바꿀 수 있다.</p>
<pre><code class="language-dart">void main() {
  double result1 = add(1,2);

  print(result1);

  double result2 = add(1,2, z: 0);

  print(result2); 
}

double add(double x, double y, {double z = 100}) {
  return (x + y + z);
}
</code></pre>
<h1 id="typedef">typedef</h1>
<pre><code class="language-dart">void main() {
  int res1 = calculator(2,3,add);
  int res2 = calculator(2,3,sub);

  print(res1); // 5
  print(res2); // -1
}


typedef Operation(int x, int y);

int add(int x, int y) {
  return (x + y);
}

int sub(int x, int y) {
  return (x - y);
}

int calculator(int x, int y, Operation op) {
  return op(x, y);
} </code></pre>
<h2 id="class">Class</h2>
<p>참고로 private 변수를 선언할때는 _(under bar)를 붙여준다. 다만 private 변수는 파일 단위에서 공유되기 때문에 같은 파일에서는 public 변수처럼 사용된다.</p>
<pre><code class="language-dart">class Person {
  final name;
  final age;

  Person(String name, int age)
    : this.name = name,
      this.age = age;

  void introduce() {
    print(&#39;안녕하세요, 제 이름은 $name이고, 나이는 $age살입니다.&#39;);
  }
}

void main() {
  Person person = Person(&#39;홍길동&#39;, 25);
  person.introduce();
}
</code></pre>
<h2 id="frommap을-사용해-초기화">fromMap을 사용해 초기화</h2>
<p>fromMap을 이용해 생성자 초기화 리스트를 정의하는 방법은 데이터베이스에서 읽은 데이터나 네트워크를 통해 받은 데이터를 Dart 객체로 변환할 때 사용하는 방법이다. fromMap 메서드는 Map 타입의 데이터를 클래스의 인스턴스로 변환하는데 사용된다.</p>
<pre><code class="language-dart">class Person {
  String name;
  int age;

  Person(this.name, this.age);

  Person.fromMap(Map&lt;String, dynamic&gt; map) 
    : this.name = map[&#39;name&#39;],
      this.age = map[&#39;age&#39;];

  void introduce() {
    print(&#39;안녕하세요, 제 이름은 $name이고, 나이는 $age살입니다.&#39;);
  }
}

void main() {
  Map&lt;String, dynamic&gt; personMap = {&#39;name&#39;: &#39;홍길동&#39;, &#39;age&#39;: 25};
  Person person = Person.fromMap(personMap);
  person.introduce();
}
</code></pre>
<p>나머지 클래스 내용은 <a href="https://dart.dev/language/classes">공식 문서</a> 를 참고하자</p>
<h2 id="비동기-처리--futureasyncawait">비동기 처리 : Future/async/await</h2>
<p>플러터에서 Future는 자바스크립트에서의 Promise라고 보면 된다.</p>
<pre><code class="language-dart">import &#39;dart:math&#39;;

Future&lt;int&gt; getRandomNumber() async {
  var random = new Random();
  int num = await Future.delayed(Duration(seconds: 3), () =&gt; random.nextInt(100));
  print(&quot;got a number of $num&quot;);
  return num;
}

void main() async {
  print(&#39;Fetching random number...&#39;);
  int randomNumber = await getRandomNumber();
  print(&#39;Random number: $randomNumber&#39;);
}
</code></pre>
<p>함수 리턴에 Future를 적용하면 return값이 Future가 아니어도 자동 적용된다.
Future에 대한 비동기 처리는 async/await 구문을 적용해 처리한다.</p>
<h2 id="stream">stream</h2>
<p>또 다른 비동기 처리 방식으로는 stream이 있다.
Future는 처리가 끝나면 알려주는 방식이고, Stream은 구독 방식이다.</p>
<p>Stream을 생성하고 관리하는 두 가지 방법이 있는데, async<em>/yield 방식과 streamcontroller 방식이다. 
async</em>와 yield는 Stream의 데이터를 자동으로 생성하고 관리하고 싶을 때 사용하고, StreamController는 Stream의 데이터를 수동으로 관리하고 싶을 때 사용한다.</p>
<pre><code class="language-dart">Stream&lt;int&gt; countStream(int to) async* {
  for (int i = 1; i &lt;= to; i++) {
    await Future.delayed(Duration(seconds: 1));
    yield i;  // 다음 값 발생
  }
}

void main() async {
  print(&#39;Start counting...&#39;);

  await for (int number in countStream(5)) {
    print(number);
  }

  print(&#39;Stream finished.&#39;);
}
</code></pre>
<pre><code class="language-dart">import &#39;dart:async&#39;;

void main() {
  final controller = StreamController&lt;int&gt;();

  final streamListener = controller.stream.listen((val) {
    print(&#39;Received: $val&#39;);
  }); //listen하고 있다가 값을 전달 받으면 프린트

  for (int i = 1; i &lt;= 5; i++) {
    controller.sink.add(i); // 값 stream에 전달
  }

  controller.close();
}
</code></pre>
<h2 id="future-vs-stream">Future vs Stream</h2>
<p>Future는 단일 값에 대한 비동기 작업을 나타낸다. Future는 하나의 값에 대한 결과가 준비되면 완료(complete) 상태가 되고, 그 값은 then이나 async/await를 통해 얻을 수 있다.</p>
<p>반면 Stream은 시간이 지남에 따라 여러 값을 생성할 수 있는 비동기 시퀀스다. Stream을 사용하면 시간이 지나면서 발생하는 이벤트를 처리하거나, 데이터를 순차적으로 처리할 수 있다. Stream은 시간에 따른 결과들을 리턴(yield)하고, 각 결과는 개별적인 Future로 처리된다.</p>
<p>Future는 한 번의 작업에 대한 완료를 기다리는 데 적합하며, Stream은 시간이 지남에 따라 발생하는 여러 이벤트를 처리하는 데 적합하다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[IntelliJ 유용한 단축키 (작성중)]]></title>
            <link>https://velog.io/@augus-xury/IntelliJ-%EC%9C%A0%EC%9A%A9%ED%95%9C-%EB%8B%A8%EC%B6%95%ED%82%A4</link>
            <guid>https://velog.io/@augus-xury/IntelliJ-%EC%9C%A0%EC%9A%A9%ED%95%9C-%EB%8B%A8%EC%B6%95%ED%82%A4</guid>
            <pubDate>Sat, 20 May 2023 08:59:03 GMT</pubDate>
            <description><![CDATA[<p>Command + N: 생성자/메서드/필드를 생성하거나 오버라이드하거나 구현 (메뉴 생성 후 게터/세터 등 생성)</p>
<p>Command + O: 클래스를 찾을 때 사용
Command + Shift + O: 파일을 찾을 때 사용
Command + Shift + F: 전체 프로젝트에서 텍스트 검색</p>
<p>Command + Shift + R: 전체 프로젝트에서 텍스트 변경</p>
<p>Command + Option + L: 코드 자동 정렬</p>
<p>Command + Shift + Enter: 현재 줄 완성</p>
<p>Command + P: 메서드나 생성자의 매개변수 정보를 보여줍니다.</p>
<p>Command + Shift + Backspace: 마지막 수정된 위치로 이동
Command + F12: 현재 파일의 구조 보기
Command + B: 선언이나 정의로 이동 (Command + click)</p>
<p>Command + /: 주석 토글
Command + Option + Up/Down: 이전/다음 메서드나 클래스로 이동합니다.</p>
<p>Control + Option + O: 사용되지 않는 import 제거</p>
<p>Command + []: 이전/다음 편집 위치로 이동
Command + Shift + []: 이전/다음 파일로 이동
Command + Shift + +/-: 모든 코드를 접거나 펼치기.</p>
<p>Command + Shift + T : 같은 이름의 테스트코드 작성</p>
<p>Ctrl + R : 최근 실행 다시 실행</p>
<p>Ctrl + space : 변수 이름/클래스 이름 제안</p>
<p>Option + enter : import 선택</p>
<p>Shift + F6 : rename</p>
<p>Ctrl + T : 리팩토링 관련 기능 찾기</p>
<p>Command + option + M : 선택된 코드 영역 묶어서 빼내기/메서드로 만들기</p>
<p>Option + enter : static import</p>
<p>Shift + 화살표 : 코드 선택
Shift + fn + 화살표 : 코드 뭉텅이로 선택
Ctrl + g : 밑에 있는 같은 단어 선택
Ctrl + Cmd + G : 같은 단어 전체 선택</p>
<p>Shift + Option + 화살표 : 코드 줄 이동</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spring Bean]]></title>
            <link>https://velog.io/@augus-xury/%EC%8A%A4%ED%94%84%EB%A7%81%EB%B9%88-%EB%93%B1%EB%A1%9D</link>
            <guid>https://velog.io/@augus-xury/%EC%8A%A4%ED%94%84%EB%A7%81%EB%B9%88-%EB%93%B1%EB%A1%9D</guid>
            <pubDate>Tue, 16 May 2023 11:48:15 GMT</pubDate>
            <description><![CDATA[<h1 id="spring-bean">Spring Bean</h1>
<p>Spring Bean은 Spring IoC(Inversion of Control) 컨테이너에서 관리하는 객체를 의미한다. 
Spring Framework의 핵심 개념 중 하나로, Spring 컨테이너에 의해 인스턴스화, 조립, 관리되는 객체다. 특정 클래스에 종속적이지 않아, 코드의 유연성을 높이고 테스트를 용이하게 한다.</p>
<p>Spring Bean의 주요 특징은 다음과 같다:</p>
<h3 id="🌱-singleton-scope">🌱 Singleton Scope:</h3>
<p>기본적으로 Spring Bean은 Singleton Scope를 가진다. Spring 컨테이너 내에서 각 빈은 하나의 인스턴스만 존재하게 된다.</p>
<h3 id="🌱-life-cycle-callbacks">🌱 Life Cycle Callbacks:</h3>
<p>Spring Bean은 초기화 및 소멸 과정에서 특정 동작을 수행할 수 있다. InitializingBean 및 DisposableBean 인터페이스를 구현하거나, @PostConstruct 및 @PreDestroy 어노테이션을 사용하여 이러한 콜백을 정의할 수 있다.</p>
<h3 id="🌱-dependency-injection">🌱 Dependency Injection:</h3>
<p>Spring Bean은 Dependency Injection(DI)을 통해 다른 Bean에 의존성을 주입할 수 있다. 이는 객체 간의 독립성을 유지시켜 코드의 재사용성 및 유지보수성을 높인다.</p>
<h1 id="스프링빈을-등록하는-두-가지-방법">스프링빈을 등록하는 두 가지 방법</h1>
<p>아래와 같은 컨트롤러가 있을 때,</p>
<pre><code class="language-java">@Controller
public class MemberController {

    private final MemberService memberService;

    @Autowired //-&gt; 주입된 서비스를 자동으로 가져다가 연결
    public MemberController(MemberService memberService) {
        this.memberService = memberService;
    }
}</code></pre>
<h2 id="1-컴포넌트-스캔-방식">1. 컴포넌트 스캔 방식</h2>
<p>@Controller, @Service, @Repository 어노테이션을 써주고,
각 생성자에는 @Autowired 어노테이션을 써서 의존성을 주입시켜야 한다.</p>
<pre><code class="language-java">
@Service
public class MemberService {
    private final MemberRepository memberRepository;
    @Autowired
    public MemberService(MemberRepository memberRepository) {

        this.memberRepository = memberRepository; // 의존성 주입
    }

    ...

 }


@Repository
public class MemoryMemberRepository implements MemberRepository{

    private static Map&lt;Long, Member&gt; store = new HashMap&lt;&gt;();
    private static long sequence = 0L;

    ...

}</code></pre>
<p>각 @Service, @Repository 어노테이션은 @Component 어노테이션의 특수한 경우로 이렇게 컴포넌트 스캔으로 자동의존관계를 설정하면 스프링빈에 등록된다.</p>
<h2 id="2-configuration-작성">2. @Configuration 작성</h2>
<p>스프링빈에 등록하는 다른 방법으로는 @Service/@Repository 어노테이션을 삭제하고 @Configuration 어노테이션이 있는 자바코드를 새로 작성하는 것이다.</p>
<pre><code class="language-java">@Configuration
public class SpringConfig {
    @Bean
    public MemberService memberService() {

        return new MemberService(memberRepository());
    }

    @Bean
    public MemberRepository memberRepository() {

        return new MemoryMemberRepository();
    }
}</code></pre>
<h1 id="장단점">장단점</h1>
<p>컴포넌트 스캔방식은 쉽다는 장점이 있지만, 나중에 MemoryMemberRepository를 DbMemberRepository로 교체하기가 까다롭다. 반면 Bean 등록 방식은 return 부분에 바꿔주기만 하면 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Gradle로 Spring 프로젝트 빌드하기]]></title>
            <link>https://velog.io/@augus-xury/Gradle%EB%A1%9C-Spring-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EB%B9%8C%EB%93%9C%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@augus-xury/Gradle%EB%A1%9C-Spring-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EB%B9%8C%EB%93%9C%ED%95%98%EA%B8%B0</guid>
            <pubDate>Mon, 15 May 2023 08:02:13 GMT</pubDate>
            <description><![CDATA[<p>프로젝트 폴더로 이동하면 gradlew 실행파일이 있는 것을 볼 수 있다.
<img src="https://velog.velcdn.com/images/augus-xury/post/073d70ee-c157-4036-baf4-7fe1c298748a/image.png" alt="">
./gradlew build 하면 build 폴더가 생성된다.</p>
<p><img src="https://velog.velcdn.com/images/augus-xury/post/9cfc4bf9-a872-4b9a-a9f2-478d9d303fcc/image.png" alt=""></p>
<p>cd build/libs</p>
<p><img src="https://velog.velcdn.com/images/augus-xury/post/f45040f7-14e3-4b83-aacf-5e481050141c/image.png" alt=""></p>
<p>이제 java -jar로 SNAPSHOT.jar 파일을 실행한다.</p>
<p>지울때는
./gradlew clean build</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[SPRING 개발환경 구축(Mac)]]></title>
            <link>https://velog.io/@augus-xury/SPRING-%EA%B0%9C%EB%B0%9C%ED%99%98%EA%B2%BD-%EA%B5%AC%EC%B6%95Mac</link>
            <guid>https://velog.io/@augus-xury/SPRING-%EA%B0%9C%EB%B0%9C%ED%99%98%EA%B2%BD-%EA%B5%AC%EC%B6%95Mac</guid>
            <pubDate>Mon, 15 May 2023 06:48:01 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/augus-xury/post/aff78a0b-c413-49f3-a7bb-c10b84b76bad/image.png" alt=""></p>
<h2 id="java-설치">JAVA 설치</h2>
<p><img src="https://velog.velcdn.com/images/augus-xury/post/ca78ed93-b675-4a5c-ab11-08e5e0dd800c/image.png" alt=""></p>
<p>OracleJDK는 유료버전이고, JDK가 필요한 몇몇 개발도구의 경우 무료 버전인 OpenJDK 설치를 강제한다. 따라서 OpenJDK를 설치했다. </p>
<pre><code>brew install openjdk
or
brew install openjdk@17 // @ 뒤에 버전 특정</code></pre><p>zsh에서 사용할 때 아래와 같이 export 하는 과정을 거쳐줘야 한다.
<img src="https://velog.velcdn.com/images/augus-xury/post/722f7ff2-16f9-4561-b38c-322bc741de3f/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/augus-xury/post/1c609228-9e2a-4973-9de4-fd28244dfd06/image.png" alt=""></p>
<p>설치 당시에는 Flutter 설치 시 설치됐던 OpenJDK버전과 인텔리J의 버전 호환이 맞지 않아 인터넷 검색을 통해 복잡한 과정을 거쳐 설치했다. 정리를 해뒀어야 하는데 경황상 그러지 못했다. </p>
<p>java -version으로 결과가 잘 나오면 설치된 것이고, 그렇지 못하면 해당 에러 메시지를 검색을 통해 해결하도록 하자.</p>
<p>차후 Java를 다시 설치할 일이 생기면 정리해보도록 하겠다.</p>
<p>참고로 자바는 회사마다 사용하는 버전이 다르다고 하니 그때그때 맞춰 설치하면 되겠다.</p>
<h2 id="인텔리j-설치">인텔리J 설치</h2>
<p>VSCode도 확장 설치를 통해 자바/스프링을 사용할 수 있다. 하지만 다들 인텔리J를 추천해서 CE 버전을 설치해 사용해보도록 한다. 아래 사이트에 접속해서 무료로 사용 가능한 CE 버전을 다운로드 받는다. 충분히 익숙해지면 유료버전을 써보도록 하자.
<a href="https://www.jetbrains.com/idea/download/#section=mac">https://www.jetbrains.com/idea/download/#section=mac</a></p>
<h2 id="spring-initializr">spring initializr</h2>
<p><a href="https://start.spring.io">https://start.spring.io</a> 에 접속하면 스프링 프레임워크를 사용하기 위한 기본 세팅을 할 수 있다. </p>
<p><img src="https://velog.velcdn.com/images/augus-xury/post/e1bce62e-959c-4a89-a80c-b5aac07bed0f/image.png" alt=""></p>
<ul>
<li>Project
예전에는 라이브러리 관리 툴로 Maven을 사용했는데 최근에는 Gradle로 옮겨오는 추세라고 한다. Groovy가 Java용이라고 한다.</li>
<li>Language
자바를 선택해준다.</li>
<li>Spring Boot
괄호가 없는 게 정식 버전이다.</li>
<li>Java
사용하는 버전에 맞게 선택한다.</li>
<li>Packaging
Jar War는 자바를 빌드하고 배포할 때 사용되는 형식이라 한다.</li>
</ul>
<blockquote>
<p>JAR (Java ARchive): JAR 파일은 자바 클래스 파일(.class), 메타데이터와 리소스 (텍스트, 이미지 등)을 압축한 패키지로, 이는 자바 플랫폼에 내장된 도구인 &#39;jar&#39;를 사용하여 만들 수 있다. JAR 파일은 주로 라이브러리를 공유하거나 간단한 자바 애플리케이션을 배포하는데 사용된다.</p>
</blockquote>
<blockquote>
<p>WAR (Web application ARchive): WAR 파일은 웹 애플리케이션을 패키징하는 데 사용되는 파일 형식이다. 이 형식은 HTML, JSP, JavaScript, CSS 등의 웹 리소스와 서블릿, 자바 클래스, 자바 라이브러리 등을 포함할 수 있다. WAR 파일은 주로 서블릿 컨테이너 (예: Tomcat)에 배포되어 웹 애플리케이션을 실행하는데 사용된다.</p>
</blockquote>
<p>학습 단계에서는 Jar형식을 이용한다.</p>
<p><img src="https://velog.velcdn.com/images/augus-xury/post/f1e7af47-44b5-423c-a530-72f6b6b90158/image.png" alt=""></p>
<p>이제 필요한 라이브러리에 대한 환경을 세팅하는 항목이다.
spring web, thymeleaf 등 필요한 라이브러리를 설치한다.</p>
<p>이후 다운로드 받은 뒤 압축을 풀고 intellij에서 .gradle 파일을 오픈하면 된다.</p>
<p>추가로 cmd + , 세팅에 들어가서 gradle 항목으로 검색 들어가면 Build and Run에 Gradle이 Default로 설정돼 있다. intellij IDEA로 바꾸면 좀더 빠르게 빌드될 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JS에 대한 단편적인 사실들]]></title>
            <link>https://velog.io/@augus-xury/JS%EC%97%90-%EB%8C%80%ED%95%9C-%EB%8B%A8%ED%8E%B8%EC%A0%81%EC%9D%B8-%EC%82%AC%EC%8B%A4%EB%93%A4</link>
            <guid>https://velog.io/@augus-xury/JS%EC%97%90-%EB%8C%80%ED%95%9C-%EB%8B%A8%ED%8E%B8%EC%A0%81%EC%9D%B8-%EC%82%AC%EC%8B%A4%EB%93%A4</guid>
            <pubDate>Mon, 15 May 2023 05:35:50 GMT</pubDate>
            <description><![CDATA[<h2 id="🟡-js는-숫자-데이터를-일률적으로-64비트로-저장한다-c언어에서는-intfloat-등-타입에-따라-메모리-크기가-다르지만-js는-일률적이다">🟡 JS는 숫자 데이터를 일률적으로 64비트로 저장한다. c언어에서는 int/float 등 타입에 따라 메모리 크기가 다르지만 JS는 일률적이다.</h2>
<h2 id="🟡-js에서-값을-대입한-변수는-그-값을-가진-것이-아니라-그-값을-가리키는-메모리-주소를-갖고-있다">🟡 JS에서 값을 대입한 변수는 그 값을 가진 것이 아니라 그 값을 가리키는 메모리 주소를 갖고 있다.</h2>
<h2 id="🟡-js에는-참조-카운트가-있어서-아무도-참조하지-않는-메모리는-수거gc된다">🟡 JS에는 참조 카운트가 있어서 아무도 참조하지 않는 메모리는 수거(GC)된다.</h2>
<h2 id="🟡-js에서-원시형이나-참조형-모두-사실은-특정-데이터에-대한-주소를-참조하고-있는-것이다-참조형은-단지-참조를-중첩해서-한-것에-불과하다">🟡 JS에서 원시형이나 참조형 모두 사실은 특정 데이터에 대한 주소를 참조하고 있는 것이다. 참조형은 단지 참조를 중첩해서 한 것에 불과하다.</h2>
<h2 id="🟡-js에서는-함수-선언식보다는-함수-표현식을-사용하는-것이-더-안전하다">🟡 JS에서는 함수 선언식보다는 함수 표현식을 사용하는 것이 더 안전하다.</h2>
<h2 id="🟡-js에서-this는-활성화된-실행-컨텍스트를-가리킨다-활성화되지-않으면-전역객체를-가리킨다-따라서-함수로서-호출할때는-전역객체를-메서드로서-호출할-때는-객체를-가리킨다">🟡 JS에서 this는 활성화된 실행 컨텍스트를 가리킨다. 활성화되지 않으면 전역객체를 가리킨다. 따라서 함수로서 호출할때는 전역객체를, 메서드로서 호출할 때는 객체를 가리킨다.</h2>
<h2 id="🟡-this는-변수에-저장이-가능하다-변수로-저장해놓으면-해당-객체를-언제든지-불러올-수-있다">🟡 this는 변수에 저장이 가능하다. 변수로 저장해놓으면 해당 객체를 언제든지 불러올 수 있다.</h2>
<h2 id="🟡-화살표-함수는-this-바인딩을-생략하므로-상위-스코프의-this를-활용-가능하다">🟡 화살표 함수는 this 바인딩을 생략하므로 상위 스코프의 this를 활용 가능하다.</h2>
<h2 id="🟡-js에서-클로저는-외부-함수의-변수를-내부-함수가-참조하는-상황에서-내부-함수를-다른-컨텍스트에-전달해서-사용할-때-일어나는-현상이다-이는-gc의-참조-카운트와-연관이-있다">🟡 JS에서 클로저는 외부 함수의 변수를 내부 함수가 참조하는 상황에서 내부 함수를 다른 컨텍스트에 전달해서 사용할 때 일어나는 현상이다. 이는 GC의 참조 카운트와 연관이 있다.</h2>
<h2 id="🟡-참조-카운트를-0으로-만들면-gc가-메모리를-수거한다-카운트를-0으로-만드는-방법은-변수에-null-또는-원시타입을-할당하는-것이다">🟡 참조 카운트를 0으로 만들면 GC가 메모리를 수거한다. 카운트를 0으로 만드는 방법은 변수에 null 또는 원시타입을 할당하는 것이다.</h2>
]]></description>
        </item>
        <item>
            <title><![CDATA[[docker] 멀티 스테이지 빌드]]></title>
            <link>https://velog.io/@augus-xury/docker-%EB%A9%80%ED%8B%B0-%EC%8A%A4%ED%85%8C%EC%9D%B4%EC%A7%80-%EB%B9%8C%EB%93%9C</link>
            <guid>https://velog.io/@augus-xury/docker-%EB%A9%80%ED%8B%B0-%EC%8A%A4%ED%85%8C%EC%9D%B4%EC%A7%80-%EB%B9%8C%EB%93%9C</guid>
            <pubDate>Mon, 15 May 2023 05:32:14 GMT</pubDate>
            <description><![CDATA[<p>도커는 여러 단계에 걸쳐서 이미지를 가져오고 필요한 결과물만 포함시켜 이미지를 빌드할 수 있다. 다음 예시를 보자.</p>
<pre><code># Stage 0
FROM node:18.15.0-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build

# Stage 1
FROM nginx:1.23.4-alpine
COPY --from=0 /app/build /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf

# 컨테이너가 시작될 때 실행할 명령어
CMD [&quot;nginx&quot;, &quot;-g&quot;, &quot;daemon off;&quot;]</code></pre><p>이 중 COPY --from=0 에 주목해보자.
--from=0 옵션 명령어는 멀티 스테이지 빌드(Multi-stage build)에서 사용되는 문법이다. 멀티 스테이지 빌드를 사용하면, 여러 개의 이미지를 한 개의 Dockerfile로 구성하고, 각 스테이지에서 빌드한 결과물을 다음 스테이지로 전달할 수 있다. 이를 통해 최종적으로 생성되는 이미지의 크기를 줄이고 더 효율적인 빌드 과정을 구현할 수 있다.</p>
<p>좀더 자세히 살펴보자.</p>
<p>COPY --from=0 /app/build /usr/share/nginx/html 에서 </p>
<p>--from=0: 이 플래그는 이전 스테이지에서 생성된 파일이나 디렉토리를 현재 스테이지로 복사하는 것을 뜻한다.
여기서 0은 이전 스테이지를 가리키는 인덱스로, Dockerfile의 첫 번째 FROM 문에 해당한다.</p>
<p>따라서 첫 번째 스테이지(Node.js 이미지를 기반으로 하는 스테이지)에서 빌드된 React 앱의 결과물을 두 번째 스테이지(Nginx 이미지를 기반으로 하는 스테이지)로 전달하고, 최종적으로 생성되는 Docker 이미지에 포함시킨다.</p>
<p>이렇게 함으로써 빌드 도구와 관련된 불필요한 파일들은 제외된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[리액트에서 CSS 사용]]></title>
            <link>https://velog.io/@augus-xury/%EB%A6%AC%EC%95%A1%ED%8A%B8%EC%97%90%EC%84%9C-CSS-%EC%82%AC%EC%9A%A9</link>
            <guid>https://velog.io/@augus-xury/%EB%A6%AC%EC%95%A1%ED%8A%B8%EC%97%90%EC%84%9C-CSS-%EC%82%AC%EC%9A%A9</guid>
            <pubDate>Wed, 19 Apr 2023 01:15:34 GMT</pubDate>
            <description><![CDATA[<h1 id="css-reset">CSS Reset</h1>
<p><a href="https://meyerweb.com/eric/tools/css/reset/">https://meyerweb.com/eric/tools/css/reset/</a></p>
<pre><code class="language-js">import React from &quot;react&quot;;
import Router from &quot;./Router&quot;;
import { createGlobalStyle } from &quot;styled-components&quot;;

const CssDefault = createGlobalStyle`
    html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
    margin: 0;
    padding: 0;
    border: 0;
    font-size: 100%;
    font: inherit;
    vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
    display: block;
}
body {
    line-height: 1;
}
ol, ul {
    list-style: none;
}
blockquote, q {
    quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
    content: &#39;&#39;;
    content: none;
}
table {
    border-collapse: collapse;
    border-spacing: 0;
}
`;

function App() {
    return (
        &lt;&gt;
            &lt;CssDefault /&gt;
            &lt;Router /&gt;
        &lt;/&gt;
    );
}

export default App;
</code></pre>
<p>폰트
<a href="https://fonts.google.com">https://fonts.google.com</a>
색 정하기
<a href="https://flatuicolors.com">https://flatuicolors.com</a></p>
<h1 id="css-import하는-방법들">css import하는 방법들</h1>
<h2 id="1-css-파일-import">1. CSS 파일 import</h2>
<p>import style.css 하고 태그 id또는 classname으로 css 설정</p>
<pre><code class="language-css">.container {
  background-color: lightblue;
  padding: 10px;
}</code></pre>
<pre><code class="language-js">import React from &#39;react&#39;;
import &#39;./style.css&#39;;

function Component() {
  return (
    &lt;div className=&quot;container&quot;&gt;
      This is an example using a normal CSS import.
    &lt;/div&gt;
  );
}

export default Component;</code></pre>
<h2 id="2-인라인-방식">2. 인라인 방식</h2>
<p>&lt;tag&gt;에 style={{속성}}</p>
<pre><code class="language-js">import React from &#39;react&#39;;

function Component() {
  const style = {
    backgroundColor: &#39;lightblue&#39;,
    padding: &#39;10px&#39;,
  };

  return (
    &lt;div style={style}&gt;
      This is an example using inline styles.
    &lt;/div&gt;
  );
}

export default Component;</code></pre>
<h2 id="3-css-모듈">3. css 모듈</h2>
<p>import someStyle from style.module.css하고 태그에 className={someStyle.someclassName}</p>
<pre><code class="language-css">.container {
  background-color: lightblue;
  padding: 10px;
}</code></pre>
<pre><code class="language-js">import React from &#39;react&#39;;
import styles from &#39;./style.module.css&#39;;

function Component() {
  return (
    &lt;div className={styles.container}&gt;
      This is an example using CSS Modules.
    &lt;/div&gt;
  );
}

export default Component;</code></pre>
<h2 id="4-style-component">4. style component</h2>
<pre><code>npm i styled-components</code></pre><pre><code class="language-js">import styled from &quot;styled-components&quot;;

const Father = styled.div`
  display: flex;
`;

const BoxOne = styled.div`
  background-color: teal;
  width: 100px;
  height: 100px;
`;

const BoxTwo = styled.div`
  background-color: tomato;
  width: 100px;
  height: 100px;
`;

const Text = styled.span`
  color: while;
`;

function App() {
  return (
    &lt;Father&gt;
      &lt;BoxOne&gt;
        &lt;Text&gt;Hello&lt;/Text&gt;
      &lt;/BoxOne&gt;
      &lt;BoxTwo&gt;&lt;/BoxTwo&gt;
    &lt;/Father&gt;
  );
}

export default App;
</code></pre>
<p>props사용</p>
<pre><code class="language-js">const BoxOne = styled.div`
  background-color: ${(props) =&gt; props.bgColor};
  width: 100px;
  height: 100px;
`;

const BoxTwo = styled.div`
  background-color: ${(props) =&gt; props.bgColor};
  width: 100px;
  height: 100px;
`;

const Text = styled.span`
  color: while;
`;

function App() {
  return (
    &lt;Father&gt;
      &lt;BoxOne bgColor=&quot;teal&quot;&gt;
        &lt;Text&gt;Hello&lt;/Text&gt;
      &lt;/BoxOne&gt;
      &lt;BoxTwo bgColor=&quot;tomato&quot;&gt;&lt;/BoxTwo&gt;
    &lt;/Father&gt;
  );
}</code></pre>
<p>상속</p>
<pre><code class="language-js">const ChildStyle = styled(BoxOne)`
    border-radius: 50px;
`;</code></pre>
<p>as</p>
<pre><code>&lt;Text as=&quot;a&quot;&gt;Hello&lt;/Text&gt;</code></pre><p>&lt;a&gt;태그로 바꿔줌</p>
<p>속성 부여</p>
<pre><code class="language-js">const Input = styled().input.attrs({required:true, maxLength:10})`
    border-radius: 50px;
`;</code></pre>
<h1 id="theme">theme</h1>
<p><ThemeProvider /> 태그로 감싸게 되면 theme={mytheme}이 props 인자로 자동으로 넘거가게 된다.</p>
<pre><code class="language-js">import {ThemeProvider} from &quot;styled-components&quot;;
...

const darkTheme = {
  textColor: &quot;whiitesmoke&quot;,
  bgColor: &quot;#111&quot;,
};

const lightTheme = {
  textColor: &quot;#111&quot;,
  bgColor: &quot;whitesmoke&quot;,
}

ReactDOM.render(
    &lt;ThemeProvider theme={darkTheme}&gt;
        &lt;App /&gt;
    &lt;/ThemeProvider&gt;
  )
</code></pre>
<pre><code class="language-js">const Title = styled.h1`
    color: ${(props) =&gt; props.theme.textColor};
`;</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[리액트 컴포넌트 방식]]></title>
            <link>https://velog.io/@augus-xury/%EB%A6%AC%EC%95%A1%ED%8A%B8-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EB%B0%A9%EC%8B%9D</link>
            <guid>https://velog.io/@augus-xury/%EB%A6%AC%EC%95%A1%ED%8A%B8-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EB%B0%A9%EC%8B%9D</guid>
            <pubDate>Tue, 18 Apr 2023 00:58:50 GMT</pubDate>
            <description><![CDATA[<h1 id="컴포넌트-방식">컴포넌트 방식</h1>
<p>컴포넌트를 만드는 방법에는 function과 class 두가지가 있다. 예전에는 class를 사용했으나 최근에는 function을 많이 사용한다.</p>
<pre><code class="language-js">/* function type */
import React from &quot;react&quot;;

function App() {
    return &lt;div className=&quot;App&quot;&gt;&lt;/div&gt;;
}

export default App;</code></pre>
<pre><code class="language-js">/* class type */
import React, { Component } from &quot;react&quot;;
class App extends Component {
  render() {
    return (
      &lt;div className=&quot;App&quot;&gt;&lt;/div&gt;
    )
  }
}</code></pre>
<p>함수형을 사용하는 이유는</p>
<p>⭐️ 간결함: 함수형 컴포넌트는 클래스 컴포넌트보다 코드가 간결하고 가독성이 높습니다. 이는 코드를 작성하고 유지 관리하기가 더 쉽다.</p>
<p>⭐️ 훅(Hooks)의 도입: React 16.8부터 훅이 도입되어 함수형 컴포넌트에서도 상태 관리와 생명주기 메서드를 사용할 수 있게 되었다. 이로 인해 함수형 컴포넌트의 기능이 크게 향상되었다.</p>
<p>⭐️ 성능: 함수형 컴포넌트는 클래스 컴포넌트보다 메모리 사용량이 적고, 성능상의 이점이 있다.</p>
<p>⭐️ 테스트 용이성: 함수형 컴포넌트는 순수 함수로 작성되므로 테스트하기가 더 쉽다. 클래스 컴포넌트의 경우 테스트하기 어려운 부분이 있을 수 있다.</p>
<p>⭐️ 커뮤니티 및 라이브러리 지원: React 커뮤니티와 라이브러리는 점점 함수형 컴포넌트에 더 많은 지원을 제공하고 있습니다. 앞으로의 발전 방향을 고려할 때 함수형 컴포넌트를 사용하는 것이 좋다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[리액트 프로젝트 init]]></title>
            <link>https://velog.io/@augus-xury/%EB%A6%AC%EC%95%A1%ED%8A%B8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-init</link>
            <guid>https://velog.io/@augus-xury/%EB%A6%AC%EC%95%A1%ED%8A%B8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-init</guid>
            <pubDate>Tue, 18 Apr 2023 00:58:27 GMT</pubDate>
            <description><![CDATA[<p>npm, npx 설치 후 </p>
<h1 id="프로젝트-생성">프로젝트 생성</h1>
<pre><code>npx create-react-app [폴더] --template typescript

npm i react-router-dom
npm i react-query
npm i styled-components</code></pre><p>--template typescript를 깜빡했다면 앱에서 아래 명령어를 실행</p>
<pre><code>
npm install --save typescript @types/node @types/react @types/react-dom @types/jest</code></pre><p>타입스크립트를 사용하므로 타입 정의를 제공해야 한다.
<a href="https://github.com/DefinitelyTyped/DefinitelyTyped">https://github.com/DefinitelyTyped/DefinitelyTyped</a></p>
<pre><code>npm i --save-dev @types/styled-components
npm i --save-dev @types/react-router-dom
npm i --save-dev @types/react-query
</code></pre><ul>
<li><p>defaul로 설치된 것들 다 지우고 앱개발</p>
</li>
<li><p>npx 실행 후 npm start하면 앱 다시 실행</p>
</li>
<li><p>css는 name.module.css로 import하여 사용</p>
</li>
</ul>
<p>타입스크립트를 사용할 때는 </p>
<h1 id="간단하게-배포">간단하게 배포</h1>
<pre><code>npm run build
npx serve -s build
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[리액트]react-router v6에서의 라우팅 방법]]></title>
            <link>https://velog.io/@augus-xury/%EB%A6%AC%EC%95%A1%ED%8A%B8react-router-v6%EC%97%90%EC%84%9C%EC%9D%98-%EB%9D%BC%EC%9A%B0%ED%8C%85-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@augus-xury/%EB%A6%AC%EC%95%A1%ED%8A%B8react-router-v6%EC%97%90%EC%84%9C%EC%9D%98-%EB%9D%BC%EC%9A%B0%ED%8C%85-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Sun, 09 Apr 2023 11:49:27 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/augus-xury/post/f03793a2-aa10-45f6-94cc-12b808906ad8/image.png" alt=""></p>
<h1 id="browser-router-방식">Browser Router 방식</h1>
<h2 id="indextsx">index.tsx</h2>
<pre><code class="language-js">import React from &#39;react&#39;;
import ReactDOM from &#39;react-dom/client&#39;;
import App from &#39;./App&#39;;

const root = ReactDOM.createRoot(
  document.getElementById(&#39;root&#39;) as HTMLElement
);
root.render(
  &lt;React.StrictMode&gt;
    &lt;App /&gt;
  &lt;/React.StrictMode&gt;
);

</code></pre>
<h2 id="apptsx">App.tsx</h2>
<p> &lt;Router /&gt;를 삽입한다.</p>
<pre><code class="language-js">import Router from &quot;./Router&quot;;

function App() {
  return (
    &lt;div&gt;
      &lt;Router /&gt;
    &lt;/div&gt;
  );
}

export default App;</code></pre>
<h2 id="routertsx">Router.tsx</h2>
<p>path를 통해 라우트를 설정한다. element로 각각 Home과 Login 모듈을 가져온다. Header 모듈은 중복을 피하기 위함이다.</p>
<pre><code class="language-js">import { BrowserRouter, Route, Routes } from &quot;react-router-dom&quot;;
import Header from &quot;./screens/components/Header&quot;;
import Home from &quot;./screens/Home&quot;;
import Login from &quot;./screens/Login&quot;;

function Router() {
    return &lt;BrowserRouter&gt;
        &lt;Header&gt;&lt;/Header&gt;
        &lt;Routes&gt;
            &lt;Route path=&quot;/&quot; element={&lt;Home /&gt;} /&gt;
            &lt;Route path=&quot;/login&quot; element={&lt;Login /&gt;} /&gt;
        &lt;/Routes&gt;
    &lt;/BrowserRouter&gt;
}

export default Router;
</code></pre>
<h2 id="screenshometsx">screens/Home.tsx</h2>
<pre><code class="language-js">function Home() {
    return &lt;h1&gt;Home&lt;/h1&gt;
}
export default Home;
</code></pre>
<h2 id="screenslogintsx">screens/Login.tsx</h2>
<pre><code class="language-js">function Login() {
    return &lt;h1&gt;Login&lt;/h1&gt;
}
export default Login;
</code></pre>
<h2 id="screenscomponentsheadertsx">screens/components/Header.tsx</h2>
<pre><code class="language-js">import { Link } from &quot;react-router-dom&quot;

function Header() {
    return (
        &lt;h1&gt;
            &lt;ul&gt;
                &lt;li&gt;
                    &lt;Link to={&quot;/&quot;}&gt;Home&lt;/Link&gt;
                &lt;/li&gt;
                &lt;li&gt;
                    &lt;Link to={&quot;/login&quot;}&gt;Login&lt;/Link&gt;
                &lt;/li&gt;
            &lt;/ul&gt;
        &lt;/h1&gt;
    );
}

export default Header;</code></pre>
<h1 id="createbrowserrouter-방식">createBrowserRouter 방식</h1>
<p>index.tsx에  &lt;App /&gt; 대신 RouterProvider를 삽입. router를 가져온다.</p>
<pre><code class="language-js">import React from &#39;react&#39;;
import ReactDOM from &#39;react-dom/client&#39;;
import App from &#39;./App&#39;;
import { RouterProvider } from &#39;react-router-dom&#39;;
import router from &#39;./Router&#39;;

const root = ReactDOM.createRoot(
  document.getElementById(&#39;root&#39;) as HTMLElement
);
root.render(
  &lt;React.StrictMode&gt;
    &lt;RouterProvider router={router} /&gt;
  &lt;/React.StrictMode&gt;
);
</code></pre>
<h2 id="routertsx-1">Router.tsx</h2>
<p>Routes 컴포넌트를 하나하나 설정하는 대신 createBrowserRouter로 배열 형식으로 삽입.</p>
<pre><code class="language-js">import { Route, Routes, createBrowserRouter } from &quot;react-router-dom&quot;;
import Header from &quot;./screens/components/Header&quot;;
import Home from &quot;./screens/Home&quot;;
import Login from &quot;./screens/Login&quot;;
import App from &quot;./App&quot;;

const router = createBrowserRouter([
    {
        path: &quot;/&quot;,
        element: &lt;App /&gt;,
        children: [
            {
                path: &quot;&quot;,
                element: &lt;Home /&gt;,
            },
            {
                path: &quot;login&quot;,
                element: &lt;Login /&gt;,
            },
        ],
    },
]);

export default router;</code></pre>
<h2 id="apptsx-1">App.tsx</h2>
<p>Router 컴포넌트 대신 Header 컴포넌트와 Outlet 컴포넌트를 삽입. Outlet컴포넌트는 하위 라우트가 설정돼 있으면 해당 컴포넌트를 갖고와 주는 역할.</p>
<pre><code class="language-js">import { Outlet } from &quot;react-router-dom&quot;;
import Header from &quot;./screens/components/Header&quot;;

function App() {
  return (
    &lt;div&gt;
      &lt;Header /&gt;
      &lt;Outlet /&gt;
    &lt;/div&gt;
  );
}

export default App;
</code></pre>
<h1 id="헤더-링크를-버튼으로-변경">헤더 링크를 버튼으로 변경</h1>
<h2 id="headertsx">Header.tsx</h2>
<p>useNavigate 훅을 사용.</p>
<pre><code>import { Link, useNavigate } from &quot;react-router-dom&quot;

function Header() {
    const nav = useNavigate();
    const onLoginClick = () =&gt; {
        nav(&quot;/login&quot;);
    };
    return (
        &lt;h1&gt;
            &lt;ul&gt;
                &lt;li&gt;
                    &lt;Link to={&quot;/&quot;}&gt;Home&lt;/Link&gt;
                &lt;/li&gt;
                &lt;li&gt;
                    &lt;button onClick={onLoginClick}&gt;Login&lt;/button&gt;
                &lt;/li&gt;
            &lt;/ul&gt;
        &lt;/h1&gt;
    );
}</code></pre><p>export default Header;</p>
<h1 id="에러-메시지로-크래시-방지">에러 메시지로 크래시 방지</h1>
<p>errorElement를 추가해준다.</p>
<pre><code class="language-js">const router = createBrowserRouter([
    {
        path: &quot;/&quot;,
        element: &lt;App /&gt;,
        children: [
            {
                path: &quot;&quot;,
                element: &lt;Home /&gt;,
                errorElement: &lt;CrashError /&gt;,
            },
            {
                path: &quot;login&quot;,
                element: &lt;Login /&gt;,
                errorElement: &lt;CrashError /&gt;,
            },
        ],
        errorElement: &lt;NotFound /&gt;,
    },
]);

export default router;</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[인공신경망(feat.퍼셉트론)]]></title>
            <link>https://velog.io/@augus-xury/%EC%9D%B8%EA%B3%B5%EC%8B%A0%EA%B2%BD%EB%A7%9Dfeat.%ED%8D%BC%EC%85%89%ED%8A%B8%EB%A1%A0</link>
            <guid>https://velog.io/@augus-xury/%EC%9D%B8%EA%B3%B5%EC%8B%A0%EA%B2%BD%EB%A7%9Dfeat.%ED%8D%BC%EC%85%89%ED%8A%B8%EB%A1%A0</guid>
            <pubDate>Sun, 09 Apr 2023 01:44:22 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/augus-xury/post/05d422f4-7b97-4099-bc0e-5a46d25f40e3/image.gif" alt="">
퍼셉트론은 뉴런을 모방해서 만든 알고리즘.</p>
<p>퍼셉트론은 X = [x1, x2, ...] 가 인풋일 때 y를 아웃풋으로 가짐</p>
<p><img src="https://velog.velcdn.com/images/augus-xury/post/2eca16de-1f23-4c09-9ae6-f1ff7e914b23/image.png" alt=""></p>
<pre><code>y = 0 (WX &lt;= ⍬) or 1 (WX &gt; ⍬), where ⍬ = threshold</code></pre><p>위 식을 재정립 하면, </p>
<pre><code>y = 0 (WX + b &lt;= 0) or 1 (WX + b &gt; 0), where b = bias</code></pre><pre><code class="language-py">#AND Perceptron
import numpy as np

def AND(x1, x2):
  X = np.array([x1, x2])
  W = np.array([0.5, 0.5])
  b = -0.5
  theta = 0.5
  y = np.sum(X * W) + b
  if y &lt;= 0:
    return 0
  elif y &gt; 0:
    return 1

print(AND(1,1)) #1
print(AND(1,0)) #0
print(AND(0,1)) #0
print(AND(0,0)) #0

#OR Perceptron
import numpy as np

def OR(x1, x2):
  X = np.array([x1, x2])
  W = np.array([0.5, 0.5])
  b = -0.4
  y = np.sum(X * W) + b
  if y &lt;= 0:
    return 0
  elif y &gt; 0:
    return 1

print(OR(1,1)) #1
print(OR(1,0)) #1
print(OR(0,1)) #1
print(OR(0,0)) #0

#NAND Perceptron
import numpy as np

def NAND(x1, x2):
  X = np.array([x1, x2])
  W = np.array([-0.5, -0.5])
  b = 0.6
  y = np.sum(X * W) + b
  if y &lt;= 0:
    return 0
  elif y &gt; 0:
    return 1

print(NAND(1,1)) #0
print(NAND(1,0)) #1
print(NAND(0,1)) #1
print(NAND(0,0)) #1</code></pre>
<p>그러나 single layer perceptron은 XOR을 분류 할 수 없다는 치명적인 단점이 있다.
<img src="https://velog.velcdn.com/images/augus-xury/post/d76fbe55-aa41-4103-a966-f4a4864d355f/image.png" alt=""></p>
<p>이를 개선한 것이 multi layer perceptron이다.</p>
<pre><code class="language-py">import numpy as np

def NOR(x1, x2):
  s1 = NAND(x1, x2)
  s2 = OR(x1, x2)
  y = AND(s1, s2)
  return y

print(NOR(1,1)) #0
print(NOR(1,0)) #1
print(NOR(0,1)) #1
print(NOR(0,0)) #0</code></pre>
<p>...사실 NAND 게이트로 모든 논리 표현이 가능. 즉, 컴퓨터 설계도 가능. 이론적으로 1개의 히든레이어를 가진 퍼셉트론으로도 비선형 시그모이드 함수를 활성화 함수로 사용하면 컴퓨터를 만들 수 있음.</p>
<p>복잡한 계산을 하기 위해선 W의 가중치를 실험적으로 적절히 배합해 줘야 함.</p>
<p>퍼셉트론은 활성화 함수로 step function 사용.
신경망은 활성화 함수로 시그모이드 함수, ReLU 등 사용.</p>
]]></description>
        </item>
    </channel>
</rss>