<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>hy2ji_k5.log</title>
        <link>https://velog.io/</link>
        <description>iOS Developer</description>
        <lastBuildDate>Thu, 28 Mar 2024 19:28:14 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. hy2ji_k5.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/hy2ji_k5" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[SwiftUI] 컴포넌트 - TabView]]></title>
            <link>https://velog.io/@hy2ji_k5/SwiftUI-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-TabView</link>
            <guid>https://velog.io/@hy2ji_k5/SwiftUI-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-TabView</guid>
            <pubDate>Thu, 28 Mar 2024 19:28:14 GMT</pubDate>
            <description><![CDATA[<p><strong>TabView: 사용자 인터페이스 요소를 통해 여러 하위 뷰 사이를 전환하는 뷰</strong>
<br></p>
<pre><code class="language-swift">struct ContentView: View {
  var body: some View {
    TabView {
      Rectangle()
        .fill(Color.green)
        .badge(15)
        .tabItem {
          Label(&quot;Green&quot;, systemImage: &quot;music.note&quot;)
        }
      Rectangle()
        .fill(Color.red)
        .tabItem {
          Label(&quot;Red&quot;, systemImage: &quot;video&quot;)
        }
      Rectangle()
        .fill(Color.blue)
        .tabItem {
          Label(&quot;Blue&quot;, systemImage: &quot;person&quot;)
        }
    }
  }
}</code></pre>
<img src=https://velog.velcdn.com/images/hy2ji_k5/post/55a7af0b-a704-4377-b0a2-57d3e653bea3/image.gif width=200>
<br>

<h3 id="✔️-tabview의-selection-이용하기">✔️ TabView의 selection 이용하기</h3>
<pre><code class="language-swift">struct ContentView: View {
  @State private var selectedTab: Int = 0

  var body: some View {
    VStack {
      Button {
        selectedTab = 1
      } label: {
        Text(&quot;Change Red Tab&quot;)
      }

      TabView(selection: $selectedTab) {
        Rectangle()
          .fill(Color.green)
          .tabItem {
            Label(&quot;Green&quot;, systemImage: &quot;music.note&quot;)
          }
          .tag(0)

        Rectangle()
          .fill(Color.red)
          .tabItem {
            Label(&quot;Red&quot;, systemImage: &quot;video&quot;)
          }
          .tag(1)
      }
    }
  }
}</code></pre>
<img src="https://velog.velcdn.com/images/hy2ji_k5/post/87a8ae5c-db54-4ed6-b2de-47671fc301ee/image.gif" width=200>
<br>

<h3 id="✔️-tabviewstyle">✔️ TabViewStyle</h3>
<img src="https://velog.velcdn.com/images/hy2ji_k5/post/3843ff49-02af-48b0-a68e-3bf04c2177a5/image.png" width=500>
<br>

<p><code>.tabViewStyle(.automatic)</code>
<img src="https://velog.velcdn.com/images/hy2ji_k5/post/e55eb74c-0f7d-4a16-9043-da3153f3841b/image.gif" width=200>
<br></p>
<p><code>.tabViewStyle(.page(indexDisplayMode: .always))</code>
<img src="https://velog.velcdn.com/images/hy2ji_k5/post/beb081ca-b34f-4db7-85f6-59f680e5bed1/image.gif" width=200>
<br></p>
<p><code>.tabViewStyle(.page(indexDisplayMode: .never))</code>
<img src="https://velog.velcdn.com/images/hy2ji_k5/post/c688d991-cf8e-4330-b307-462199c40dde/image.gif" width=200></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SwiftUI] 컴포넌트 - Text, Image, Button, HStack, VStack, Spacer]]></title>
            <link>https://velog.io/@hy2ji_k5/SwiftUI-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-Text-Image</link>
            <guid>https://velog.io/@hy2ji_k5/SwiftUI-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-Text-Image</guid>
            <pubDate>Thu, 28 Mar 2024 19:08:25 GMT</pubDate>
            <description><![CDATA[<h2 id="text"><strong>Text</strong></h2>
<p><strong>하나 이상의 줄로 구성된 읽기 전용 텍스트</strong></p>
<pre><code class="language-swift">Text(&quot;Hello world&quot;)</code></pre>
<p>자주 사용되는 Modifier</p>
<ul>
<li>font</li>
<li>bold</li>
<li>lineLimit</li>
<li>foregroundColor</li>
<li>background</li>
<li>strikethrough</li>
<li>monospaced<br>

</li>
</ul>
<h2 id="image">Image</h2>
<p><strong>이미지를 나타내는 뷰</strong></p>
<pre><code class="language-swift">Image(&quot;bell.fill&quot;)</code></pre>
<p>자주 사용되는 Modifier</p>
<ul>
<li>resizable</li>
<li>aspectRatio</li>
<li>renderingMode</li>
<li>scaledToFill</li>
<li>scaledToFit<br>

</li>
</ul>
<h2 id="button">Button</h2>
<p><strong>특정 동작을 시작하는 컨트롤</strong></p>
<pre><code class="language-swift">Button(
    action: signIn
    label: {Label}
)</code></pre>
<p>💡 Label은 모든 종류의 뷰가 들어올 수 있음
<br></p>
<h2 id="hstack">HStack</h2>
<p><strong>하위 뷰를 수평으로 배열하는 뷰</strong>
<img src="https://velog.velcdn.com/images/hy2ji_k5/post/7e062a59-61d3-4ba1-9351-23704023840f/image.png" alt="">
<br></p>
<h2 id="vstack">VStack</h2>
<p><strong>하위 뷰를 수직으로 배열하는 뷰</strong>
<img src="https://velog.velcdn.com/images/hy2ji_k5/post/da7ba4f0-a0e0-4b70-9a8f-b7286706b7e5/image.png" alt="">
<br></p>
<h2 id="spacer">Spacer</h2>
<p><strong>스택 레이아웃의 장축을 따라 확장하거나 스택에 포함되지 않은 경우 양쪽 축에 확장하는 유연한 공간</strong></p>
<pre><code class="language-swift">VStack(spacing: 20) {
    Spacer()
        .frame(height: 50)

    Image(systemName: &quot;globe&quot;)

    Text(&quot;Hello, world!&quot;)

    Image(systemName: &quot;bell.fill&quot;)
}
.background(.red)</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SwiftUI] MVVM]]></title>
            <link>https://velog.io/@hy2ji_k5/SwiftUI-MVVM</link>
            <guid>https://velog.io/@hy2ji_k5/SwiftUI-MVVM</guid>
            <pubDate>Thu, 28 Mar 2024 17:38:47 GMT</pubDate>
            <description><![CDATA[<h3 id="mvvm-아키텍처-">MVVM 아키텍처 :</h3>
<p>애플리케이션의 로직과 UI를 분리하여 관리하며, 데이터 바인딩을 통해 뷰와 뷰모델 사이에 동기화를 자동화하는 소프트웨어 디자인패턴.
<br></p>
<h3 id="swiftui와-mvvm의-관계-">SwiftUi와 MVVM의 관계 :</h3>
<ul>
<li>SwiftUI에서는 데이터 바인딩이 가능한 Property Wrapper들을 제공해주기 때문에 View에서 Property Wrapper를 사용하게 되면 이미 그 자체가 View + ViewModel 이다.</li>
<li>데이터 바인딩을 위해서 ViewModel을 만들고, 데이터 바인딩을 구현해주는 역할로 MVVM을 채택하기보다는 비지니스 로직을 분리하고, 상태 관리를 다뤄주기에 적합한 ViewModel을 만들어야 한다.
(View 내에서 비지니스 로직과 View 상태 관리를 위한 프로퍼티들을 ViewModel로 분리함)</li>
<li>SwiftUI에서 중요한건 데이터 바인딩을 위한 MVVM 구조 사용이 아닌 적절한 상태 관리를 위한 MVVM 구조 사용이 필요하다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SwiftUI] 프로퍼티 래퍼(Property Wrapper)]]></title>
            <link>https://velog.io/@hy2ji_k5/SwiftUI-%ED%94%84%EB%A1%9C%ED%8D%BC%ED%8B%B0-%EB%9E%98%ED%8D%BCProperty-Wrapper</link>
            <guid>https://velog.io/@hy2ji_k5/SwiftUI-%ED%94%84%EB%A1%9C%ED%8D%BC%ED%8B%B0-%EB%9E%98%ED%8D%BCProperty-Wrapper</guid>
            <pubDate>Thu, 28 Mar 2024 17:01:36 GMT</pubDate>
            <description><![CDATA[<h2 id="state">@State</h2>
<ul>
<li>SwiftUI에서 상태를 처리하는 방법</li>
<li>뷰의 상태를 저장하는 프로퍼티로, 해당 뷰의 상태를 관리함</li>
<li>기본적으로 Private 선언이기에 다른 뷰와 값을 소통하려면 Binding을 이용함</li>
<li>값이 변경될 때마다 UI가 업데이트 됨</li>
</ul>
<pre><code class="language-swift">struct ContentView: View {
    @State private var isPlaying: Bool = false

    var body: some View {
        Button(isPlaying ? &quot;Pause&quot; : &quot;Play&quot;) {
            isPlaying.toggle()
        }
    }
}</code></pre>
<br>

<h2 id="binding">@Binding</h2>
<ul>
<li>뷰와 상태를 바인딩 하는 방법</li>
<li>상위 @State 변수를 전달 받아 하위 뷰에서 변화를 감지하고 연결함</li>
<li>Binding은 다른 뷰가 소유한 속성을 연결하기 때문에 소유권 및 저장 공간이 없음</li>
</ul>
<pre><code class="language-swift">struct PlayerView: View {
  var episode: Episode
  @State private var isPlaying: Bool = false

  var body: some View {
    VStack {
      Text(episode.title)
        .foregroundStyle(isPlaying ? .primary : .secondary)
      PlayButton(isPlaying: $isPlaying) // Binding
    }
  }
}

struct PlayButton: View {
  @Binding var isPlaying: Bool

  var body: some View {
    Button(isPlaying ? &quot;Pause&quot; : &quot;Play&quot;) {
      isPlaying.toggle()
    }
  }
}</code></pre>
<blockquote>
</blockquote>
<p><code>PlayButton(isPlaying: $isPlaying)</code>
→ <code>$</code>: State 변수의 참조를 생성하여 해당 변수의 상태를 다른 뷰나 속성과 양방향으로 Binding 할 수 있도록 도와줌
<br></p>
<h2 id="observableobject">ObservableObject</h2>
<p><a href="https://developer.apple.com/documentation/combine/observableobject">ObservableObject | Apple Developer Documentation</a></p>
<blockquote>
<p>💡 PropertyWrapper가 아닌 클래스 프로토콜!</p>
</blockquote>
<ul>
<li>객체가 변경되기 전에 그 변경 사항을 방출하는 publisher를 가지고 있는 객체 유형
ObservableObject는 기본적으로 Published 프로퍼티의 값이 변경되기 전에 변경된 값을 방출하는 <code>objectWillChange</code> publisher를 가지고 있음)</li>
<li>뷰에서 인스턴스의 변화를 감시하기 위해 뷰모델 객체를 생성할 때 주로 사용됨</li>
</ul>
<pre><code class="language-swift">class Contact: ObservableObject {
  @Published var name: String
  @Published var age: Int

  init(name: String, age: Int) {
    self.name = name
    self.age = age
  }

  func haveBirthday() -&gt; Int {
    age += 1
    return age
  }
}

let john = Contact(name: &quot;John Appleseed&quot;, age: 24)
let cancellable = john.objectWillChange
  .sink { _ in
    print(&quot;\(john.age) will change&quot;) // 24 will change
  }
print(john.haveBirthday()) // 25</code></pre>
<br>

<h2 id="published">@Published</h2>
<ul>
<li>ObservableObject를 구현한 클래스 내에서 프로퍼티 선언 시 사용</li>
<li>@Published로 선언된 프로퍼티를 뷰에서 관찰할 수 있음</li>
<li>ObservableObject의 objectWillChange.send() 메서드를 @Published 프로퍼티가 변경되면 자동으로 호출함<br>

</li>
</ul>
<h2 id="observedobject">@ObservedObject</h2>
<ul>
<li>뷰에서 ObservableObject 타입의 인스턴스 선언 시 사용</li>
<li>ObservableObject의 값이 업데이트되면 뷰를 업데이트함</li>
</ul>
<pre><code class="language-swift">class User: ObservableObject {
  @Published var age = 10
}

struct ContentView: View {
  @ObservedObject var user: User

  var body: some View {
    Button(&quot;Plus Age&quot;) {
      user.age += 1
    }
  }
}</code></pre>
<br>

<h2 id="stateobject">@StateObject</h2>
<ul>
<li>뷰에서 ObservableObject 타입의 인스턴스 선언 시 사용</li>
<li>뷰마다 하나의 인스턴스를 생성하며, 뷰가 사라지기 전까지 같은 인스턴스를 유지함</li>
<li>@ObservedObject의 뷰 렌더링 시 인스턴스 초기화 이슈를 해결하기 위한 방법으로 사용됨</li>
<li>매번 인스턴스가 새롭게 생성되는 것처럼 외부에서 주입 받는 경우가 아닌 최초 생성 선언 시에 @StateObject를 사용하는 것이 적절한 방법</li>
</ul>
<blockquote>
</blockquote>
<p><strong>@StateObject vs @ObservedObject</strong><br>
▪︎ 인스턴스를 최초로 생성하는 경우 → @StateObject
▪︎ 하위 뷰에서 주입받는 경우 → @ObservedObject</p>
<br>

<h2 id="environment">@Environment</h2>
<ul>
<li>미리 정의되어 있는 시스템의 공유 데이터</li>
<li>사용하려는 공유 데이터의 이름을 keyPath로 전달하여 사용함</li>
<li>시스템 공유 데이터는 가변하기에 var로 선언해야 함</li>
<li>뷰가 생성되는 시점에 값이 자동으로 초기화됨</li>
</ul>
<pre><code class="language-swift">struct ContentView: View {
  @Environment(\.colorScheme) var colorScheme

  var body: some View {
    Text(&quot;Hello, World!&quot;)
      .foregroundStyle(colorScheme == .dark ? .white : .black)
  }
}</code></pre>
<br>

<h2 id="environmentobject">@EnvironmentObject</h2>
<ul>
<li>ObservableObject를 통해 구현된 타입의 인스턴스를 전역적으로 공유하여 사용함</li>
<li>앱 전역에서 공통으로 사용할 데이터를 주입 및 사용</li>
</ul>
<pre><code class="language-swift">class Info: ObservableObject {
  @Published var age = 10
}

@main
struct MyApp: App {
  var body: some Scene {
    WindowGroup {
      MainView()
        .environmentObject(Info())
    }
  }
}

struct MainView: View {
  @EnvironmentObject var info: Info

  var body: some View {
    Button {
      self.info.age += 1
    } label: {
      Text(&quot;Click Me for plus age&quot;)
    }
    SubView()
  }
}

struct SubView: View {
  @EnvironmentObject var info: Info

  var body: some View {
    Button {
      self.info.age -= 1
    } label: {
      Text(&quot;Click Me for minus age&quot;)
    }
  }
}</code></pre>
<blockquote>
</blockquote>
<p><strong>⚠️ @EnvironmentObject 사용의 문제점</strong><br>
<strong>1. 데이터 의존성 문제 발생</strong>: 해당 객체에서 의존성이 앱 전체로 퍼질 수 있어 코드 가독성과 유지 보수가 어려워지고, 예기치 않은 버그를 유발할 수 있음.<br>
<strong>2. 데이터 관리의 복잡도 증가</strong>: 여러 뷰에서 동일한 EnvironmentObject를 참조하고 수정하면 데이터의 일관성을 유지하기가 힘들어짐.<br>
<strong>3. 테스트의 어려움</strong>: EnvironmentObject에 의존하면 단위 테스트나 UI 테스트를 작성하기 어려워짐. (각 테스트케이스마다 필요한 환경객체들을 설정해줘야 하는데 이는 오버헤드를 초래하게 됨.)<br>
최대한 구제적인 범위 안에서는 @State, @Binding, @ObservedObject를 사용하고 정말 필요할 때, 전역적으로 공유되어야 하는 상태에서만 @EnvironmentObject를 사용하는 것이 바람직함.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Swift] 자료구조 - 스택(Stack), 큐(Queue), 덱(Duque)]]></title>
            <link>https://velog.io/@hy2ji_k5/Swift-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-%EC%8A%A4%ED%83%9DStack-%ED%81%90Queue-%EB%8D%B1Duque</link>
            <guid>https://velog.io/@hy2ji_k5/Swift-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-%EC%8A%A4%ED%83%9DStack-%ED%81%90Queue-%EB%8D%B1Duque</guid>
            <pubDate>Thu, 21 Mar 2024 15:42:21 GMT</pubDate>
            <description><![CDATA[<h2 id="스택stack">스택(Stack)</h2>
<blockquote>
</blockquote>
<ul>
<li>LIFO(Last In, First Out) 원리에 따라 작동하는 선형 자료구조</li>
<li>가장 마지막에 추가된 요소가 가장 먼저 제거됨.</li>
<li>주요 연산
<code>push</code>: 스택의 맨 위에 요소를 추가함
<code>pop</code>: 스택의 맨 위에서 요소를 제거하고 그 요소를 반환함
<code>peek</code>: 스택의 맨 위 요소를 반환하지만 제거하지는 않음
<code>isEmpty</code>: 스택이 비어있는지 확인함</li>
</ul>
<pre><code class="language-swift">  struct Stack&lt;Element&gt; {
      private var storage: [Element] = []

      mutating func push(_ element: Element) {
          storage.append(element)
      }

      mutating func pop() -&gt; Element? {
          return storage.popLast()
      }

      func peek() -&gt; Element? {
          return storage.last
      }

      var isEmpty: Bool {
          return storage.isEmpty
      }
  }

  // 사용 예시
  var stack = Stack&lt;Int&gt;()
  stack.push(1)
  stack.push(2)
  stack.push(3)
  print(stack.peek() ?? &quot;스택이 비어있습니다.&quot;) // 3 출력
  print(stack.pop() ?? &quot;스택에서 꺼낼 요소가 없습니다.&quot;) // 3 출력
  print(stack.pop() ?? &quot;스택에서 꺼낼 요소가 없습니다.&quot;) // 2 출력</code></pre>
<h4 id="스택stack이-사용되는-경우">스택(Stack)이 사용되는 경우</h4>
<ul>
<li><strong>역순 문자열 생성</strong>
문자열의 각 문자를 차례대로 스택에 넣고, 이후에 하나씩 꺼내면 문자열이 역순으로 정렬됨.<br></li>
<li><strong>괄호 검사</strong>
여는 괄호를 만날 때마다 스택에 넣고, 닫는 괄호를 만나면 스택에서 꺼내어 짝이 맞는지 확인함.<br></li>
<li><strong>함수 호출</strong>
프로그램에서 함수를 호출할 때 호출 스택을 사용하여 호출된 함수의 주소를 저장하고, 함수가 종료되면 스택에서 해당 함수의 주소를 꺼내어 제어를 반환함.<br></li>
<li><strong>웹 브라우저 방문 기록 관리</strong>
사용자가 방문한 페이지를 스택에 넣고, 사용자가 뒤로 가기를 할 때 스택에서 꺼내어 이전 페이지로 돌아감.</li>
</ul>
<br>

<h2 id="큐queue">큐(Queue)</h2>
<blockquote>
</blockquote>
<ul>
<li>FIFO(First In, First Out) 원리에 따라 작동하는 선형 자료구조</li>
<li>가장 먼저 추가된 요소가 가장 먼저 제거됨. </li>
<li>주요 연산
<code>enqueue</code>: 큐의 뒤쪽에 요소를 추가함
<code>dequeue</code>: 큐의 앞쪽에서 요소를 제거하고 그 요소를 반환함
<code>peek</code>: 큐의 맨 앞 요소를 반환하지만 제거하지는 않음
<code>isEmpty</code>: 큐가 비어있는지 확인함</li>
<li>대기열 관리, 프린터의 인쇄 작업 스케줄링, 네트워크 요청 처리 등에 사용됨.</li>
</ul>
<pre><code class="language-swift">  struct Queue&lt;Element&gt; {
      private var storage: [Element] = []

      mutating func enqueue(_ element: Element) {
          storage.append(element)
      }

      mutating func dequeue() -&gt; Element? {
          guard !storage.isEmpty else { return nil }
          return storage.removeFirst()
      }

      func peek() -&gt; Element? {
          return storage.first
      }

      var isEmpty: Bool {
          return storage.isEmpty
      }
  }

  // 사용 예시
  var queue = Queue&lt;String&gt;()
  queue.enqueue(&quot;A&quot;)
  queue.enqueue(&quot;B&quot;)
  queue.enqueue(&quot;C&quot;)
  print(queue.peek() ?? &quot;큐가 비어있습니다.&quot;) // &quot;A&quot; 출력
  print(queue.dequeue() ?? &quot;큐에서 꺼낼 요소가 없습니다.&quot;) // &quot;A&quot; 출력
  print(queue.dequeue() ?? &quot;큐에서 꺼낼 요소가 없습니다.&quot;) // &quot;B&quot; 출력</code></pre>
<h4 id="큐queue가-사용되는-경우">큐(Queue)가 사용되는 경우</h4>
<ul>
<li><strong>데이터 처리 순서 유지</strong> 
문서 인쇄, 작업 스케줄링 등 순서대로 처리해야 하는 작업에 큐를 사용함.<br></li>
<li><strong>대기열 관리</strong>
은행, 티켓 카운터, 콜센터 등에서 서비스를 기다리는 대기열을 관리할 때 큐를 사용함.<br></li>
<li><strong>너비 우선 탐색(BFS)</strong>
그래프나 트리에서 너비 우선 탐색을 수행할 때 큐를 사용하여 방문할 노드를 관리함.<br></li>
<li><strong>버퍼(buffer)</strong>
데이터를 전송하거나 받는 동안 일시적으로 데이터를 저장하는 버퍼에 큐를 사용할 수 있음.<br></li>
<li><strong>캐시 구현</strong>
최근에 사용된 항목을 기억하고 오래된 항목부터 제거하는 캐시 알고리즘에 사용됨.</li>
</ul>
<br>

<h2 id="덱duque">덱(Duque)</h2>
<blockquote>
</blockquote>
<ul>
<li>양쪽 끝에서 삽입과 삭제가 가능한 자료구조 </li>
<li>스택과 큐의 일반화된 형태</li>
<li>주요 연산
<code>pushFront</code>: 덱의 앞쪽에 요소를 추가함
<code>pushBack</code>: 덱의 뒤쪽에 요소를 추가함
<code>popFront</code>: 덱의 앞쪽에서 요소를 제거하고 그 요소를 반환함
<code>popBack</code>: 덱의 뒤쪽에서 요소를 제거하고 그 요소를 반환함
<code>peekFront</code>: 덱의 맨 앞 요소를 반환하지만 제거하지는 않음
<code>peekBack</code>: 덱의 맨 뒤 요소를 반환하지만 제거하지는 않음
<code>isEmpty</code>: 덱이 비어있는지 확인함</li>
<li>스크롤, 스테핑 기능이 있는 웹 페이지나 앱 인터페이스, 양방향 대기열 등에 사용됨.</li>
</ul>
<pre><code class="language-swift">  struct Deque&lt;Element&gt; {
      private var storage: [Element] = []

      mutating func pushBack(_ element: Element) {
          storage.append(element)
      }

      mutating func pushFront(_ element: Element) {
          storage.insert(element, at: 0)
      }

      mutating func popBack() -&gt; Element? {
          return storage.popLast()
      }

      mutating func popFront() -&gt; Element? {
          guard !storage.isEmpty else { return nil }
          return storage.removeFirst()
      }

      func peekFront() -&gt; Element? {
          return storage.first
      }

      func peekBack() -&gt; Element? {
          return storage.last
      }

      var isEmpty: Bool {
          return storage.isEmpty
      }
  }

  // 사용 예시
  var deque = Deque&lt;Int&gt;()
  deque.pushBack(1)
  deque.pushFront(2)
  deque.pushBack(3)
  print(deque.peekFront() ?? &quot;덱이 비어있습니다.&quot;) // 2 출력
  print(deque.peekBack() ?? &quot;덱이 비어있습니다.&quot;) // 3 출력
  print(deque.popFront() ?? &quot;덱에서 꺼낼 요소가 없습니다.&quot;) // 2 출력
  print(deque.popBack() ?? &quot;덱에서 꺼낼 요소가 없습니다.&quot;) // 3 출력</code></pre>
<h4 id="덱deque이-사용되는-경우">덱(Deque)이 사용되는 경우</h4>
<ul>
<li><strong>양방향 큐</strong>
데이터가 양쪽 끝에서 추가되거나 제거되어야 할 때 덱을 사용함. 
ex) 스크롤 기능이 있는 사용자 인터페이스에서 최근 항목을 양쪽 끝에 추가할 수 있음.<br></li>
<li><strong>양방향 탐색</strong>
리스트의 양쪽 끝에서 동시에 탐색을 시작해야 할 경우 덱을 사용하여 효율적으로 탐색할 수 있음.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Swift] Combine - Publisher(Just) & Subscriber(Sink, Assign)]]></title>
            <link>https://velog.io/@hy2ji_k5/Swift-Combine-PublisherJust-SubscriberSink-Assign</link>
            <guid>https://velog.io/@hy2ji_k5/Swift-Combine-PublisherJust-SubscriberSink-Assign</guid>
            <pubDate>Thu, 21 Mar 2024 13:32:43 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><code>Just</code>: 단일 값을 내보내고 완료하는 Publisher
<code>Sink</code>: 가장 간단한 형태의 Subscriber. 데이터 이벤트와 완료 이벤트를 처리하는 데 사용됨. 두 개의 클로저를 인자로 받음(하나는 데이터를 받았을 때 실행, 다른 하나는 완료 이벤트를 받았을 때 실행됨).
<code>Assign</code>: 특정 객체의 KeyPath에 결과를 할당하는 Subscriber. 주로 UI 요소를 업데이트하는 데 사용. ex) 네트워크 요청의 결과를 텍스트 뷰의 텍스트 속성에 할당하는 작업.</p>
</blockquote>
<pre><code class="language-swift">import Foundation
import Combine

let just = Just(1000)
let subscription1 = just.sink { value in
  print(&quot;Received Value: \(value)&quot;) // Received Value: 1000
}

let arrayPublisher = [1, 3, 5, 7, 9].publisher
let subscription2 = arrayPublisher.sink { value in
  print(&quot;Received Value: \(value)&quot;)
}
/*
Received Value: 1
Received Value: 3
Received Value: 5
Received Value: 7
Received Value: 9
*/

class MyClass {
  var property: Int = 0 {
    didSet {
      print(&quot;Did set property to \(property)&quot;)
    }
  }
}

let object = MyClass()
let subscription3 = arrayPublisher.assign(to: \.property, on: object)
/*
Did set property to 1
Did set property to 3
Did set property to 5
Did set property to 7
Did set property to 9
*/

print(&quot;Final Value: \(object.property)&quot;)
// Final Value: 9</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Swift] 자료구조 - 배열(Array), 연결 리스트(Linked List)]]></title>
            <link>https://velog.io/@hy2ji_k5/Swift-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-%EB%B0%B0%EC%97%B4Array-%EC%97%B0%EA%B2%B0-%EB%A6%AC%EC%8A%A4%ED%8A%B8Linked-List</link>
            <guid>https://velog.io/@hy2ji_k5/Swift-%EC%9E%90%EB%A3%8C%EA%B5%AC%EC%A1%B0-%EB%B0%B0%EC%97%B4Array-%EC%97%B0%EA%B2%B0-%EB%A6%AC%EC%8A%A4%ED%8A%B8Linked-List</guid>
            <pubDate>Thu, 21 Mar 2024 09:57:21 GMT</pubDate>
            <description><![CDATA[<h2 id="배열array">배열(Array)</h2>
<blockquote>
</blockquote>
<ul>
<li>동일한 타입의 요소를 <strong>메모리의 연속적인 공간</strong>에 저장</li>
<li><strong>인덱스</strong>를 통해 각 요소에 빠르게 <strong>접근</strong>할 수 있어, 인덱스를 알고 있는 경우 시간 복잡도가 <strong>O(1)</strong>이다.</li>
<li>하지만 <strong>배열의 크기가 고정</strong>되어 있거나 중간에 있는 요소를 <strong>추가하거나 삭제</strong>하는 경우 다른 요소들을 이동해야 하므로, 이러한 작업은 시간 복잡도가 <strong>O(n)</strong>이다.</li>
<li>빠른 인덱스를 통한 접근이 필요하거나, 데이터의 크기가 고정되어 있고 변경될 일이 없는 경우에 적합함.</li>
</ul>
<pre><code class="language-swift">  // 배열 생성 및 초기화
  var fruits = [&quot;Apple&quot;, &quot;Banana&quot;, &quot;Cherry&quot;]

  // 요소 추가
  fruits.append(&quot;Durian&quot;)

  // 요소에 접근
  print(fruits[2])  // 출력: Cherry

  // 요소 수정
  fruits[2] = &quot;Blueberry&quot;

  // 요소 삭제
  fruits.remove(at: 2)

  // 배열을 사용한 반복
  for fruit in fruits {
      print(fruit)
  }</code></pre>
<br>

<h2 id="연결-리스트linked-list">연결 리스트(Linked List)</h2>
<blockquote>
</blockquote>
<ul>
<li><strong>노드</strong>들이 <strong>포인터</strong>를 통해 연결되어 있는 *<em>선형 자료구조 *</em></li>
<li>각 노드는 데이터와 다음 노드에 대한 <strong>참조(또는 포인터)</strong>를 가진다.</li>
<li>요소의 <strong>추가와 삭제</strong>가 <strong>O(1)</strong> 시간에 이루어질 수 있다는 장점이 있지만, 특정 <strong>인덱스</strong>의 요소에 <strong>접근</strong>하기 위해서는 처음부터 해당 노드까지 순회해야 하므로 최악의 경우 <strong>O(n)</strong> 시간이 소요된다.</li>
</ul>
<pre><code class="language-swift">  class ListNode&lt;T&gt; {
      var value: T
      var next: ListNode?

      init(value: T, next: ListNode? = nil) {
          self.value = value
          self.next = next
      }
  }

  class LinkedList&lt;T&gt; {
      var head: ListNode&lt;T&gt;?

      // 마지막 노드에 요소 추가
      func append(value: T) {
          let newNode = ListNode(value: value)
          if let lastNode = self.last() {
              lastNode.next = newNode
          } else {
              head = newNode
          }
      }

      // 마지막 노드 찾기
      func last() -&gt; ListNode&lt;T&gt;? {
          var node = head
          while let nextNode = node?.next {
              node = nextNode
          }
          return node
      }

      // 모든 요소 출력
      func printAllElements() {
          var node = head
          while node != nil {
              print(node!.value)
              node = node?.next
          }
      }
  }

  // 사용 예시
  let list = LinkedList&lt;String&gt;()
  list.append(value: &quot;Apple&quot;)
  list.append(value: &quot;Banana&quot;)
  list.append(value: &quot;Cherry&quot;)
  list.printAllElements()</code></pre>
<br>

<h4 id="배열array의-사용이-적합한-경우">배열(Array)의 사용이 적합한 경우</h4>
<ol>
<li><strong>데이터 접근이 빈번한 경우</strong>
배열은 인덱스를 통해 즉시 접근할 수 있기 때문에, 데이터에 빠르게 접근해야 할 때 유리함.</li>
<li><strong>데이터의 크기가 고정되어 있는 경우</strong>
배열은 고정된 크기를 가지기 때문에, 데이터의 크기가 변하지 않을 것으로 예상되는 경우에 적합함 (ex. 게임 개발에서 화면에 표시되는 픽셀의 배열, 설정 값의 저장 등).</li>
<li><strong>메모리를 효율적으로 사용해야 하는 경우</strong>
배열은 요소마다 추가적인 메모리를 필요로 하지 않으므로, 메모리 사용을 최소화할 수 있음. 메모리 사용량을 예측하기 쉽고 관리하기 편함.</li>
</ol>
<br>

<h4 id="연결-리스트linked-list의-사용이-적합한-경우">연결 리스트(Linked List)의 사용이 적합한 경우</h4>
<ol>
<li><strong>데이터 추가 및 삭제가 빈번한 경우</strong>
연결 리스트는 노드 사이의 연결만 변경하면 되기 때문에, 요소의 추가나 삭제가 매우 간단하고 효율적임.</li>
<li><strong>데이터의 크기가 미리 예측하기 어려운 경우</strong>
연결 리스트는 데이터의 크기가 동적으로 변할 수 있으므로, 데이터의 크기를 미리 알 수 없거나 데이터가 계속 추가될 것으로 예상되는 경우에 유리함.</li>
<li><strong>메모리 할당이 동적으로 이루어져야 하는 경우</strong>
연결 리스트는 필요할 때마다 메모리를 할당하므로, 사용 가능한 메모리 크기가 변동적인 환경에서 유리함 (ex. 사용자 입력에 따라 데이터의 양이 변하는 경우).</li>
</ol>
]]></description>
        </item>
    </channel>
</rss>