<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>youn_22.log</title>
        <link>https://velog.io/</link>
        <description>youn</description>
        <lastBuildDate>Mon, 10 Mar 2025 07:41:57 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>youn_22.log</title>
            <url>https://images.velog.io/images/youn_22/profile/790ba26c-ed38-459a-b1bd-74972b14b760/social.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. youn_22.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/youn_22" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[leetcode] 80. Remove Duplicates from Sorted Array II]]></title>
            <link>https://velog.io/@youn_22/leetcode-80.-Remove-Duplicates-from-Sorted-Array-II-39juzqgv</link>
            <guid>https://velog.io/@youn_22/leetcode-80.-Remove-Duplicates-from-Sorted-Array-II-39juzqgv</guid>
            <pubDate>Mon, 10 Mar 2025 07:41:57 GMT</pubDate>
            <description><![CDATA[<h2 id="문제-설명">문제 설명</h2>
<blockquote>
<p><a href="https://leetcode.com/problems/remove-duplicates-from-sorted-array-ii/">링크</a>
배열에서 중복 요소 제거 (최대2개)</p>
</blockquote>
<h2 id="접근1">접근1</h2>
<h3 id="코드">코드</h3>
<pre><code class="language-swift">class Solution {
    func removeDuplicates(_ nums: inout [Int]) -&gt; Int {
        var resultIndex = 1
        var duplicates = 0

        for (index, num) in nums.enumerated() {
            if index == 0 {
                continue
            }
            if num != nums[resultIndex - 1] {
                nums[resultIndex] = num
                resultIndex += 1
                duplicates = 0
            } else {
                duplicates += 1
                if duplicates &lt; 2 {
                    nums[resultIndex] = num
                    resultIndex += 1
                }
            }
        }
        return resultIndex
    }
}</code></pre>
<ul>
<li>불필요한 메모리 발생 (duplicates)</li>
</ul>
<h2 id="접근2">접근2</h2>
<h3 id="코드-1">코드</h3>
<pre><code class="language-swift">class Solution {
    func removeDuplicates(_ nums: inout [Int]) -&gt; Int {
        // 배열이 비어있거나 요소가 1개 또는 2개만 있는 경우 바로 반환
        if nums.count &lt;= 2 {
            return nums.count
        }

        // 결과 인덱스를 2로 시작 (처음 두 요소는 항상 유효)
        var resultIndex = 2

        // 세 번째 요소부터 순회
        for i in 2..&lt;nums.count {
            // 현재 요소가 결과 배열의 두 칸 전 요소와 다르면 추가
            if nums[i] != nums[resultIndex - 2] {
                nums[resultIndex] = nums[i]
                resultIndex += 1
            }
        }

        return resultIndex
    }
}</code></pre>
<ul>
<li>이전 요소 대신 최대 2개전 요소 비교</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[leetcode] 80. Remove Duplicates from Sorted Array II]]></title>
            <link>https://velog.io/@youn_22/leetcode-80.-Remove-Duplicates-from-Sorted-Array-II</link>
            <guid>https://velog.io/@youn_22/leetcode-80.-Remove-Duplicates-from-Sorted-Array-II</guid>
            <pubDate>Thu, 06 Mar 2025 13:20:05 GMT</pubDate>
            <description><![CDATA[<h2 id="문제-설명">문제 설명</h2>
<blockquote>
<p><a href="https://leetcode.com/problems/remove-duplicates-from-sorted-array-ii/">링크</a>
배열에서 중복 요소 제거 (최대2개)</p>
</blockquote>
<h2 id="접근1">접근1</h2>
<h3 id="코드">코드</h3>
<pre><code class="language-swift">class Solution {
    func removeDuplicates(_ nums: inout [Int]) -&gt; Int {
        var resultIndex = 1
        var duplicates = 0

        for (index, num) in nums.enumerated() {
            if index == 0 {
                continue
            }
            if num != nums[resultIndex - 1] {
                nums[resultIndex] = num
                resultIndex += 1
                duplicates = 0
            } else {
                duplicates += 1
                if duplicates &lt; 2 {
                    nums[resultIndex] = num
                    resultIndex += 1
                }
            }
        }
        return resultIndex
    }
}</code></pre>
<ul>
<li>불필요한 메모리 발생 (duplicates)</li>
</ul>
<h2 id="접근2">접근2</h2>
<h3 id="코드-1">코드</h3>
<pre><code class="language-swift">class Solution {
    func removeDuplicates(_ nums: inout [Int]) -&gt; Int {
        // 배열이 비어있거나 요소가 1개 또는 2개만 있는 경우 바로 반환
        if nums.count &lt;= 2 {
            return nums.count
        }

        // 결과 인덱스를 2로 시작 (처음 두 요소는 항상 유효)
        var resultIndex = 2

        // 세 번째 요소부터 순회
        for i in 2..&lt;nums.count {
            // 현재 요소가 결과 배열의 두 칸 전 요소와 다르면 추가
            if nums[i] != nums[resultIndex - 2] {
                nums[resultIndex] = nums[i]
                resultIndex += 1
            }
        }

        return resultIndex
    }
}</code></pre>
<ul>
<li>이전 요소 대신 최대 2개전 요소 비교</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[leetcode] 27. Remove Element]]></title>
            <link>https://velog.io/@youn_22/leetcode-27.-Remove-Element</link>
            <guid>https://velog.io/@youn_22/leetcode-27.-Remove-Element</guid>
            <pubDate>Thu, 06 Mar 2025 13:00:42 GMT</pubDate>
            <description><![CDATA[<h2 id="문제-설명">문제 설명</h2>
<blockquote>
<p><a href="https://leetcode.com/problems/remove-element/">링크</a>
배열에서 특정 요소 제거</p>
</blockquote>
<h2 id="접근-1---뒤에서부터">접근 1 - 뒤에서부터</h2>
<ul>
<li>뒤에서부터 접근</li>
<li>remove, insert 해야하는 단점</li>
</ul>
<h2 id="코드-1">코드 1</h2>
<pre><code class="language-swift">class Solution {
    func removeElement(_ nums: inout [Int], _ val: Int) -&gt; Int {
        var length = 0
        for (index, num) in nums.reversed().enumerated() {
            if num != val {
                length += 1
                nums.remove(at: index)
                nums.insert(num, at: 0)
            }
        }
        return length
    }
}</code></pre>
<h2 id="접근-2---앞에서부터">접근 2 - 앞에서부터</h2>
<ul>
<li>앞 k 까지만 비교한다고 했으므로 앞에넣어버리기</li>
</ul>
<h2 id="코드-2">코드 2</h2>
<pre><code class="language-swift">class Solution {
    func removeElement(_ nums: inout [Int], _ val: Int) -&gt; Int {
        var k = 0

        for (index, num) in nums.enumerated() {
            if num != val {
                nums[k] = num
                k += 1
            }
        }

        return k
    }
}</code></pre>
<ul>
<li>nums[i] 로 접근보다 nums.enumerated() 접근이 메모리 효율적</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[leetcode] 88. Merge Sorted Array]]></title>
            <link>https://velog.io/@youn_22/leetcode-88.-Merge-Sorted-Array</link>
            <guid>https://velog.io/@youn_22/leetcode-88.-Merge-Sorted-Array</guid>
            <pubDate>Thu, 06 Mar 2025 12:25:32 GMT</pubDate>
            <description><![CDATA[<h2 id="문제-설명">문제 설명</h2>
<blockquote>
<p><a href="https://leetcode.com/problems/merge-sorted-array/">링크</a>
MergeSort</p>
</blockquote>
<h2 id="앞에서부터">앞에서부터</h2>
<ul>
<li>작은 수 부터 넣기</li>
<li>rotation: [1, 3, 0, 0] -&gt; [0, 0, 1, 3]</li>
<li>불필요한 rotation</li>
</ul>
<h2 id="코드-1">코드 1</h2>
<pre><code class="language-swift">  class Solution {
    func merge(_ nums1: inout [Int], _ m: Int, _ nums2: [Int], _ n: Int) {
        if n == .zero { return }

        if m &gt; 0 {
            for _ in 0 ... m - 1 {
                nums1.append(nums1.removeFirst())
            }
        } else {
            nums1 = nums2
        }
        var newNums1Index = 0
        var nums1Index = 0
        var nums2Index = 0

        while nums1Index &lt; m &amp;&amp; nums2Index &lt; n {
            if nums1[nums1Index + n] &lt; nums2[nums2Index] {
                nums1[newNums1Index] = nums1[nums1Index + n]
                nums1Index += 1
            } else {
                nums1[newNums1Index] = nums2[nums2Index]
                nums2Index += 1
            }
            newNums1Index += 1
        }

        while newNums1Index &lt; n + m {
            if nums1Index &lt; m {
                nums1[newNums1Index] = nums1[nums1Index + n]
                nums1Index += 1
            } else if nums2Index &lt; n {
                nums1[newNums1Index] = nums2[nums2Index]
                nums2Index += 1
            }
            newNums1Index += 1
        }
    }
}</code></pre>
<h2 id="뒤에서부터">뒤에서부터</h2>
<ul>
<li>제일 큰 수부터 넣기</li>
<li>남은 요소 넣을 필요 없음</li>
</ul>
<h2 id="코드-2">코드 2</h2>
<pre><code class="language-swift"> class Solution {
     func merge(_ nums1: inout [Int], _ m: Int, _ nums2: [Int], _ n: Int) {
         // 뒤에서부터 시작하는 인덱스들
         var i = m - 1      // nums1의 실제 요소 인덱스
         var j = n - 1      // nums2의 인덱스
         var k = m + n - 1  // 결과를 저장할 위치 인덱스

         // 두 배열의 요소를 뒤에서부터 비교하여 큰 값을 nums1의 뒤에서부터 채움
         while i &gt;= 0 &amp;&amp; j &gt;= 0 {
             if nums1[i] &gt; nums2[j] {
                 nums1[k] = nums1[i]
                 i -= 1
             } else {
                 nums1[k] = nums2[j]
                 j -= 1
             }
             k -= 1
         }

         // nums2에 남은 요소가 있다면 복사
         while j &gt;= 0 {
             nums1[k] = nums2[j]
             j -= 1
             k -= 1
         }

         // nums1에 남은 요소는 이미 올바른 위치에 있으므로 추가 작업 필요 없음
     }
 }</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[didSet]]></title>
            <link>https://velog.io/@youn_22/didSet</link>
            <guid>https://velog.io/@youn_22/didSet</guid>
            <pubDate>Tue, 14 Feb 2023 08:15:51 GMT</pubDate>
            <description><![CDATA[<blockquote>
<pre><code class="language-swift">var test = UITableView() {
    didSet {
    // 내부 코드 안불림     
    }
}
</code></pre>
</blockquote>
<p>@IBOutlet private weak var tableView: UITableView! {
    didSet{
     //불림
    }
}</p>
<pre><code>

## ReferenceType vs Struct Type
### 1. ReferenceType (ex. Class)
``` swift
class Person {
    var name = &quot;youn&quot;
}
var test: Person = Person() {
    didSet {
      print(&quot;didSet called&quot;) 
    }
}
</code></pre><ul>
<li>인스턴스 자체를 변경할 때 불림
  test.name = &quot;hi&quot; // 안불림
  test = Person() // 불림<h3 id="2-value-type-ex-struct">2. Value Type (ex. struct)</h3>
<pre><code class="language-swift">struct Person {
  var name = &quot;youn&quot;
}
var test: Person = Person() {
  didSet {
    print(&quot;didSet called&quot;) 
  }
}
</code></pre>
</li>
</ul>
<pre><code>- test.name = &quot;hi&quot; // 불림
## Outlet 의 didSet
- didSet 은 init 타임에 불리지 않음
- outlet 의 경우 초기화 시점에 nil 로 세팅 됨
- 해당 object를 nib 으로부터 가져올 때 다시 세팅, 값을 가짐
- `viewDidLoad` 바로 전에 호출 













[참고](https://sujinnaljin.medium.com/swift-class와-struct에서-didset의-차이-f784e34ea33f)</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[iOS] Stretchable Headers]]></title>
            <link>https://velog.io/@youn_22/iOS-Stretchable-Headers-1-Table-View</link>
            <guid>https://velog.io/@youn_22/iOS-Stretchable-Headers-1-Table-View</guid>
            <pubDate>Fri, 27 Jan 2023 10:58:16 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><a href="https://johncodeos.com/how-to-make-a-stretchy-header-in-ios-using-swift/">참고</a></p>
</blockquote>
<h1 id="1-table-view">1. Table View</h1>
<h3 id="1-table-header-view-생성">1. Table Header View 생성</h3>
<pre><code class="language-swift">// SHTableHeaderView.swift
final class SHTableHeaderView: UIView {
      /**
        init () 
        setSubViews ()
        setSubViewLayouts() -
      */

    func scrollViewDidScroll(scrollView: UIScrollView) {
        let offsetY = -(scrollView.contentOffset.y + scrollView.contentInset.top)
        imageViewHeight.constant = max(offsetY + scrollView.contentInset.top, scrollView.contentInset.top)
    }
}
</code></pre>
<h4 id="setsubviewlayouts"><code>setSubViewLayouts</code></h4>
<ol>
<li>이미지 뷰 단독<ul>
<li>이미지의 넓이, centerX, bottom 을 superView(headerView) 와 동일하게 설정</li>
<li>이미지의 높이도 superview 와 동일하게 설정, 별도 변수로 저장</li>
</ul>
</li>
<li>컨테이너 뷰 사용<ul>
<li>이미지뷰의 bottom constraint 를 통해 아래로 스크롤 시 작아지는 효과를 더할 수 있음</li>
<li>컨테이너 뷰의 넓이, centerX, 높이를 superView 와 동일하게 설정</li>
<li>이미지뷰의 넓이, 높이, bottom 을 컨테이너 뷰와 동일하게 설정 <pre><code class="language-swift">  func scrollViewDidScroll(scrollView: UIScrollView) {
      let offsetY = -(scrollView.contentOffset.y + scrollView.contentInset.top)
      containerView.clipsToBounds = offsetY &lt;= 0
      imageViewBottom.constant = offsetY &gt;= 0 ? 0 : -offsetY / 2 // 추가
      imageViewHeight.constant = max(offsetY + scrollView.contentInset.top, scrollView.contentInset.top)
  }</code></pre>
</li>
</ul>
</li>
</ol>
<h3 id="2-table-header-view-설정">2. Table Header View 설정</h3>
<pre><code class="language-swift">// ViewController.swift
    private lazy var tableViewHeaderView = SHTableHeaderView(frame: CGRect(x: 0, y: 0, width: view.bounds.width, height: 200))

    @IBOutlet private weak var tableView: UITableView! {
        didSet {
            tableView.tableHeaderView = tableViewHeaderView
        }
    }</code></pre>
<h3 id="3-scrollviewdidscroll-호출">3. scrollViewDidScroll 호출</h3>
<pre><code class="language-swift">// ViewController.swift
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        let headerView = self.tableView.tableHeaderView as! SHTableHeaderView
        headerView.scrollViewDidScroll(scrollView: scrollView)
    }</code></pre>
<h3 id="결과">결과</h3>
<blockquote>
</blockquote>
<p>좌 - 이미지뷰를 컨테이너로 한번 더 감쌌을 때 
우 - 이미지뷰 단독 설정</p>
<img src="https://velog.velcdn.com/images/youn_22/post/6f17c28d-0cc8-45ba-9ac2-42f71cba4b4d/image.mp4" align = left width = 40%/>
<img src="https://velog.velcdn.com/images/youn_22/post/196fe26b-a57e-4b84-82e1-a3876a3da44b/image.mp4" align = right width = 40%/>


<hr>
<p><a href="https://github.com/JeonJiyoun/iOS_Study/tree/main/younTest/younTest/StretchableHeader">Source - (private)</a></p>
<h1 id="2-collection-view">2. Collection View</h1>
<h3 id="1-별개의-view">1. 별개의 View</h3>
<ul>
<li>컬렉션 뷰와 별개로 헤더용 뷰 생성, <code>scrollViewDidScroll</code> 에서 레이아웃 조절</li>
</ul>
<h3 id="2-flowlayout">2. FlowLayout</h3>
<pre><code class="language-swift">class CollectionViewFlowLayout: UICollectionViewFlowLayout {
    override func layoutAttributesForElements(in rect: CGRect) -&gt; [UICollectionViewLayoutAttributes]? {
        let layoutAttributes = super.layoutAttributesForElements(in: rect)

        layoutAttributes?.forEach { attribute in
            if attribute.representedElementKind == UICollectionView.elementKindSectionHeader {
                guard let collectionView = collectionView else { return }
                let contentOffsetY = collectionView.contentOffset.y

                if contentOffsetY &lt; 0 {
                    let width = collectionView.frame.width
                    let height = attribute.frame.height - contentOffsetY
                    attribute.frame = CGRect(x: 0, y: contentOffsetY, width: width, height: height)
                }
            }
        }

        return layoutAttributes
    }

    override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -&gt; Bool {
        return true
    }

    // ...

}`</code></pre>
<h3 id="3-compositional-layout">3. Compositional Layout</h3>
<pre><code class="language-swift">// MARK: - HeaderView 
final class StretchyCollectionHeaderView: UICollectionReusableView {
    // ...
    // MARK: - Init
    override init(frame: CGRect) {
        super.init(frame: frame)
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    /// Create Subviews
    private func createViews() {
    }

    /// Setup View Constraints
    func setViewConstraints() {
    }

    /// Notify View of scroll change from container
    public func scrollviewDidScroll(scrollView: UIScrollView) {
        containerViewHeight.constant = scrollView.contentInset.top
        let offsetY = -(scrollView.contentOffset.y + scrollView.contentInset.top)
        containerView.clipsToBounds = offsetY &lt;= 0
        imageViewBottom.constant = offsetY &gt;= 0 ? 0 : -offsetY / 2
        imageViewHeight.constant = max(offsetY + scrollView.contentInset.top, scrollView.contentInset.top)
    }

}

// MARK: - ViewController
func scrollViewDidScroll(_ scrollView: UIScrollView) {
    if let header = homePageCollectionView.supplementaryView(forElementKind: HomePageViewController.sectionHeaderElementKind, at: IndexPath(item: 0, section: 0)) as? StretchyCollectionHeaderView {
                header.scrollviewDidScroll(scrollView: homePageCollectionView)
     }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Diffable DataSource ]]></title>
            <link>https://velog.io/@youn_22/Diffable-DataSource</link>
            <guid>https://velog.io/@youn_22/Diffable-DataSource</guid>
            <pubDate>Sun, 05 Jun 2022 15:45:55 GMT</pubDate>
            <description><![CDATA[<h4 id="why-">WHY ?</h4>
<p><img src="https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb7nQWc%2Fbtq1U8jqP87%2FcUKgMwru6HlNciGR15WjWk%2Fimg.png" alt=""></p>
<ul>
<li>Datasource 를 관리하는 <code>Controller</code> 에게 웹서비스로부터 응답이 왔을 때 UI에게 변경을 알림</li>
<li>에러 발생 
  <img src="https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFPxgo%2Fbtq1XVwaKmt%2FaKQfmw1ikX9CML9pAimjTk%2Fimg.png" alt="">     </li>
<li><code>reloadData</code> 를 통해 해결 가능하지만 애니메이션적용 X → 사용자 경험을 해침</li>
<li>➡️ <strong>Data Controller 와 UI 모두 그들만의 <code>one version of the truth</code> 를 가지고 있음</strong>  → truth들이 다를경우 문제 발생 </li>
<li>즉, *<em>centralized 된 truth 가 없음 *</em></li>
</ul>
<h2 id="diffable-datasource">Diffable DataSource</h2>
<p><img src="https://velog.velcdn.com/images/youn_22/post/4ef79ab2-0088-4a3a-8e47-aa7f2ee55b0f/image.png" alt=""></p>
<ul>
<li>iOS13+</li>
<li>UI state 에 <strong>선언적 접근</strong></li>
<li><strong>snapshot</strong> = 현재 UI state 의 truth</li>
<li>sections 과 items 에 <code>Unique Identifiers</code>     부여, IndexPath ❌<ul>
<li>빠른 속도 </li>
<li>간결성</li>
<li>잘못된 indexpath 로 crash 날 확률이 줄어듬</li>
<li>자동으로 cell 이 사라지고 생기는 애니메이션이 동작함 </li>
</ul>
</li>
<li><strong>Generic Class</strong> (Hashable 준수하는 타입 넣어서 사용)</li>
</ul>
<h4 id="example">Example</h4>
<p>
<img src="https://velog.velcdn.com/images/youn_22/post/ef07d469-b674-4ba3-ae26-a82df951cacd/image.png" width="70%"/></p>

<p>
<img src="https://velog.velcdn.com/images/youn_22/post/dc94d746-8fb1-4d6a-9599-ea4afd4d858d/image.png" width="25%"/>
</p>

<p><img src="https://velog.velcdn.com/images/youn_22/post/f046c6ee-2077-4286-89b2-a9075097e550/image.png" alt=""></p>
<ol start="0">
<li>데이터의 변경</li>
<li>새로운 snapshot 생성</li>
<li>snapshot 에 section 과 item(변경된 데이터) 추가</li>
<li>datasource 에 해당 snapshot <code>apply</code></li>
</ol>
<h3 id="applyanimatingdifferences">apply(animatingDifferences)</h3>
<blockquote>
<p>Prior to iOS 15, passing true to animatingDifferences would apply the diff and animate updates in the UI, while passing false was equivalent to calling reloadData(). As of iOS 15, applying a snapshot using this API will always perform a diff
<a href="https://www.jessesquires.com/blog/2021/07/08/diffable-data-source-behavior-changes-and-reconfiguring-cells-in-ios-15/">참고</a></p>
</blockquote>
<ul>
<li><p>iOS 15 이전 <code>animationgDifference</code></p>
<ul>
<li>true : diff</li>
<li>false : reload </li>
</ul>
</li>
<li><p>iOS 15 이후 : 둘다 diff</p>
</li>
</ul>
<blockquote>
<p>참고
<a href="https://zeddios.tistory.com/1197">https://zeddios.tistory.com/1197</a>
<a href="https://ios-development.tistory.com/717">https://ios-development.tistory.com/717</a>
<a href="https://developer.apple.com/videos/play/wwdc2019/220/">https://developer.apple.com/videos/play/wwdc2019/220/</a>
<a href="https://brunch.co.kr/@eunjin3786/245">https://brunch.co.kr/@eunjin3786/245</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Async / Await]]></title>
            <link>https://velog.io/@youn_22/Async-Await</link>
            <guid>https://velog.io/@youn_22/Async-Await</guid>
            <pubDate>Fri, 03 Jun 2022 07:51:50 GMT</pubDate>
            <description><![CDATA[<h2 id="async--await">async &amp; await</h2>
<ul>
<li>Swift 5.5</li>
<li><code>Completion Handler</code> 없이도 이를 호출한 곳에 알려줌</li>
<li>동시성이랑 다름, 동시성 제공 X </li>
</ul>
<h3 id="async">async</h3>
<ul>
<li>함수 이름 뒤에 <code>async</code>  = 비동기 함수<pre><code class="language-swift">func getUser() async thorws -&gt; () {}</code></pre>
</li>
<li>동시 컨텍스트에서만 실행 가능<ul>
<li>다른 async 함수 내에서</li>
<li>Task {} // 수동으로 concurrent context 제공</li>
</ul>
</li>
</ul>
<h3 id="await">await</h3>
<ul>
<li>async 함수 호출위해 필요<pre><code class="language-swift">let (data, response) = try awiat URLSession.shared.data(for: request)
// URLSession : iOS 이상에서 나온 async 지원 API</code></pre>
</li>
<li><code>await</code> &gt; potential suspension pont(잠재적 일시 중단 지점)으로 지정 (무조건 suspend가 아님)<ul>
<li><code>Suspend</code> : 해당 스레드가 다른 동작을 수행할 수 있게 제어권 넘김</li>
<li><code>Yielding</code> 스레드 양보 </li>
<li>suspension point 에서 유지되는 모든 정보는 Heap 에 저장됨</li>
<li>await 호출 전 코드를 실행한 스레드가, 멈췄던 작업을 재개하는 동일 스레드라는 보장은 없음</li>
</ul>
</li>
</ul>
<h2 id="스레드-제어권">스레드 제어권</h2>
<h3 id="✅-sync-함수-호출시">✅ sync 함수 호출시</h3>
<p><img src="https://velog.velcdn.com/images/youn_22/post/fb01f1be-aee2-4d77-a25d-d854ff25c69e/image.png" alt=""></p>
<h3 id="✅-async-함수-호출시">✅ async 함수 호출시</h3>
<p><img src="https://velog.velcdn.com/images/youn_22/post/a4abc6ee-0494-4e72-a11b-5f64fb530acd/image.png" alt=""></p>
<ul>
<li><code>Suspend</code> &gt; 헤딩 thread 에 대한 control 포기</li>
<li><code>System</code> : 스레드를 사용하여 다른 작업 수행, suspend 된 비동기 함수를 계속 실행하는 작업이 가장 중요하다고 판단되는 순간 Resume</li>
</ul>
<h2 id="task">Task</h2>
<ul>
<li>Swift 가 코드를 병렬로 실행하는 기본 메커니즘</li>
<li>각 Task 는 다른 Task 와 함께 동시(Concurrent)에 실행할 수 있는 새로운 비동기 컨텍스트 제공</li>
<li>명시적으로 생성해야함</li>
<li>Task 로 생성된 작업은 Background Thread 에서 즉시 실행, await 으로 완료된 값이 돌아올 때까지 기다릴 수 있음</li>
<li>async 에서 또 다른 async 함수 호출 &gt; 동일한 Task 에서 execute call 수행</li>
<li><a href="https://velog.io/@youn_22/Task">Task - 참고</a></li>
</ul>
<blockquote>
<p>출처 
<a href="https://sujinnaljin.medium.com/swift-async-await-concurrency-bd7bcf34e26f">https://sujinnaljin.medium.com/swift-async-await-concurrency-bd7bcf34e26f</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[Task]]></title>
            <link>https://velog.io/@youn_22/Task</link>
            <guid>https://velog.io/@youn_22/Task</guid>
            <pubDate>Fri, 03 Jun 2022 07:50:52 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/youn_22/post/5c1990cf-8d9a-400b-8456-ac2417da943b/image.png" alt=""></p>
<h2 id="task">Task</h2>
<ul>
<li><strong>Task</strong> : 비동기적으로 실행할 수있는 작업 단위 </li>
<li><strong>동시(Concurrent)</strong>에 실행할 수 있는 <strong>새로운 비동기 컨텍스트</strong> 제공
  💡동시성 = 비동기 + 병렬</li>
<li>Task 인스턴스 생성시 해당 Task 가 수행할 작업을 포함하는 클로저 함께 제공</li>
<li>생성과 동시에 실행됨</li>
<li>Task Group 을 만들어서 하위 작업을 추가하는 형식. </li>
</ul>
<pre><code class="language-swift">func getUser() async -&gt; Data {
    /// get user data
}

func process() async {
   let userData = await getUser()
   let contents = await decode(data: userData)
   print(contents)
}


 Task {
     await self.process() // &lt;!doctype html&gt;~~~~
 }
</code></pre>
<ul>
<li>async/ await 을 쓰면 가장 바깥은 Task{} 로 감싸야 함</li>
<li>Task 내 /외 는 별개의 스레드로 동작하며 Task 내에서는 순차적으로 코드가 실행됨</li>
<li>=&gt;sync code block 내에서 async 코드를 실행할 수 있게 함 </li>
</ul>
<blockquote>
<p>출처 
<a href="https://inuplace.tistory.com/1125">https://inuplace.tistory.com/1125</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[iOS) Clean Swift_VIP 패턴]]></title>
            <link>https://velog.io/@youn_22/iOS-Clean-SwiftVIP-%ED%8C%A8%ED%84%B4</link>
            <guid>https://velog.io/@youn_22/iOS-Clean-SwiftVIP-%ED%8C%A8%ED%84%B4</guid>
            <pubDate>Fri, 03 Jun 2022 07:13:36 GMT</pubDate>
            <description><![CDATA[<h2 id="vip">VIP</h2>
<p><img src="https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcS6j0J%2FbtqWVSe23I4%2FKTrXoZZa8MsY73RfmC8Jk1%2Fimg.png" alt=""></p>
<ul>
<li>View Controller, Interactor, Presenter</li>
<li>단방향 제어 흐름
  💡VIPER: 양방향으로 로직이 순환하기 때문에 순환참조에 의한 메모리 누수 발생</li>
<li>VIP cycle &gt; interactor에 있는 클로저 기반 비동기 메소드들이 주기적으로 업데이트 제공
  💡MVVM 의 Reactiveness 문제해결</li>
</ul>
<h3 id="data-flow">Data Flow</h3>
<p><img src="https://velog.velcdn.com/images/youn_22/post/8c86df79-98c8-4e2b-8b42-366e3a17329d/image.png" alt=""></p>
<p>*<em>1. View 이벤트 &gt; Interactor 메소드 실행 &gt; 비즈니스로직 실행
2. Interactor : 비즈니스 로직 처리 &gt; Presenter 에게 결과 전송
3. Presenter : Interactor 에서 받은 결과에 대한 UI 처리 
*</em></p>
<blockquote>
<p>💡VIPER : 액션에 대한 비즈니스로직을 Presenter 를 통해 Interactor 에게 전달
    <img src="https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbl4Hbr%2FbtqW4gZSTfo%2FExFXBmOg75JXFx1MHGNZo1%2Fimg.png" alt=""></p>
</blockquote>
<h2 id="vip-주기">VIP 주기</h2>
<ol>
<li>Use Case 트리거 (ex. viewDidLoad())</li>
<li>VC : Interactor 호출</li>
<li>Interactor : 비즈니스 로직 수행, Presenter 호출</li>
<li>Presenter : VC 호출</li>
<li>VC : 화면에 보여줌</li>
</ol>
<blockquote>
<p>출처
<a href="https://ios-development.tistory.com/340">https://ios-development.tistory.com/340</a>
<a href="https://velog.io/@ssionii/Clean-Swift-a.k.a-VIP-%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%84%EB%9D%BC%EB%B3%B4%EC%9E%90">https://velog.io/@ssionii/Clean-Swift-a.k.a-VIP-에-대해-아라보자</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[iOS] View Life Cycle]]></title>
            <link>https://velog.io/@youn_22/iOS-View-Life-Cycle</link>
            <guid>https://velog.io/@youn_22/iOS-View-Life-Cycle</guid>
            <pubDate>Fri, 01 Apr 2022 07:16:39 GMT</pubDate>
            <description><![CDATA[<h2 id="💡-view-life-cycle">💡 View Life Cycle</h2>
<blockquote>
<p><img src="https://media.vlpt.us/images/youn_22/post/4252ce61-f18f-469b-acb5-e2efd1798dc7/image.png" alt=""></p>
</blockquote>
<h2 id="💡-단계별-특징">💡 단계별 특징</h2>
<blockquote>
<p><img src="https://media.vlpt.us/images/youn_22/post/bc48d882-c02f-41a8-8a60-ac14e56921bd/image.png" alt=""></p>
</blockquote>
<h3 id="1-loadview">1. loadView</h3>
<ul>
<li><code>viewController</code> 의 <code>View</code>를 만드는 역할, 해당 프로퍼티가 nil 일 때 호출됨</li>
<li><code>view</code>를 로드하거나 생성, 해당 <code>view</code>를 <code>viewController</code> 의 <code>view</code> 프로퍼티에 저장
  <code>view.backGroudColor = .clear</code> 의 <code>view</code></li>
<li><code>outlet</code> 과 <code>action</code> 생성, 연결</li>
</ul>
<h3 id="2-viewdidload">2. viewDidLoad</h3>
<ul>
<li><code>viewController</code> 의 <code>view</code>가 메모리에 로드된 지후에 호출</li>
<li><code>viewController</code> 에서 사용할 객체들을 초기화할 때 적합</li>
<li><strong><code>view</code>의 <code>bound</code>가 아직 정의되지 않은 상태</strong></li>
<li>메모리워닝이 실행되는 경우 중복 호출될 가능성</li>
</ul>
<h3 id="3-viewwillappear">3. viewWillAppear</h3>
<ul>
<li><code>view</code>가 화면에 나타나기 직전에 호출
  ( ➡️ <code>viewDidLoad</code>가 호출된다고 화면에 <code>view</code>가 보이는 것이 아님)</li>
<li><code>view</code>가 스크린에 보이기 바로 전</li>
<li><code>view</code>의 <code>bound</code>는 정의됐지만, 오리엔테이션이 설정되진 않은 상태</li>
<li>필드를 숨기거나 보여주기에 적합한 시점</li>
<li><code>view</code>가 스크린에 보여질 때마다 호출됨</li>
</ul>
<blockquote>
<h3 id="viewwilllayoutsubviews"><code>viewWillLayoutSubviews</code></h3>
</blockquote>
<ul>
<li><strong>view<code>의</code>bound`가 최종적으로 결정되는 최초 시점</strong></li>
<li><code>subView</code>의 레이아웃을 업데이트하기 적합한 시점</li>
<li><strong>여러 번 중복으로 호출될 수 있다.</strong><ul>
<li>메인뷰의 서브뷰가 로드되는 경우</li>
<li>LoadView is only called once: when the view needs to be loaded</li>
<li>LayoutSubviews, however, is called once per run loop on any view that has had <code>setNeedsLayout</code> or <code>setNeedsDisplayInRect</code> called on it - this includes whenever a subview has been added to the view, scrolling, resizing, etc. <a href="https://stackoverflow.com/questions/27014360/why-is-viewdidlayoutsubviews-called-multiple-times">참고</a></li>
</ul>
</li>
</ul>
<h3 id="4-viewdidappear">4. viewDidAppear</h3>
<ul>
<li>view`가 스크린에 보여진 후에 호출</li>
<li>애니메이션을 시작하거나, 외부 API를 불러오기에 적합</li>
</ul>
<h3 id="5-viewwilldisappear">5. viewWillDisappear</h3>
<ul>
<li><code>view</code>가 사라지기 직전에 호출 </li>
<li>ex. 키보드 숨기기 </li>
</ul>
<h3 id="6-viewdiddisappear">6. viewDidDisappear</h3>
<ul>
<li><code>view</code>가 사라진 직후에 호출</li>
<li>ex.  구독 해제<h3 id="7-viewdidunload">7. viewDidUnload</h3>
</li>
</ul>
<hr>
]]></description>
        </item>
        <item>
            <title><![CDATA[[iOS] Custom Font 추가]]></title>
            <link>https://velog.io/@youn_22/iOS-Custom-Font-%EC%B6%94%EA%B0%80</link>
            <guid>https://velog.io/@youn_22/iOS-Custom-Font-%EC%B6%94%EA%B0%80</guid>
            <pubDate>Thu, 17 Mar 2022 08:52:39 GMT</pubDate>
            <description><![CDATA[<h2 id="🎃-폰트-추가하기">🎃 폰트 추가하기</h2>
<h3 id="1-폰트-파일-import">1. 폰트 파일 import</h3>
<img src="https://images.velog.io/images/youn_22/post/a167da35-ee2b-4edc-bab5-bc9ea45aab31/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-03-17%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%205.12.41.png" width="40%" height="30">

<ul>
<li>.ttf .otf 지원 </li>
<li>.wotf 파일 인식 ❌</li>
<li><strong>Add to targets</strong> 에서 프로젝트 반드시 체크</li>
<li>디렉토리 상관없이 인식가능, 원하는 경로에 넣어주기</li>
</ul>
<h3 id="2-infoplist-추가">2. <code>info.plist</code> 추가</h3>
<img src="https://images.velog.io/images/youn_22/post/61752377-ddba-4e52-bf1b-fcbbe1a880f4/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-03-17%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%205.16.27.png" height="50">

<ul>
<li><code>Info.plist &gt; Information Property List &gt;</code> <strong><code>Fonts provided by application</code></strong></li>
<li>파일의 확장자를 포함하여 파일명 정의</li>
</ul>
<h2 id="🎃-폰트-사용하기">🎃 폰트 사용하기</h2>
<h3 id="1-코드">1. 코드</h3>
<pre><code class="language-swift">    public enum BalooBhai2Type: String {
        case semibold = &quot;-SemiBold&quot;
        case regular = &quot;Regular&quot;
        case extraBold = &quot;-ExtraBold&quot;
        case bold = &quot;-Bold&quot;
        case medium = &quot;-Medium&quot;
    }

    static func BalooBhai2(_ type: BalooBhai2Type = .regular, size: CGFloat = UIFont.systemFontSize) -&gt; UIFont {
        return UIFont(name: &quot;BalooBhai2\(type.rawValue)&quot;, size: size)!
    }
    static func Jua(size: CGFloat = UIFont.systemFontSize) -&gt; UIFont {

        return UIFont(name: &quot;Jua-Regular&quot;, size: size)!
    }

    numberLabel.font = UIFont.BalooBhai2(.bold, size: 16.0)
</code></pre>
<blockquote>
<p>💡 위 방법으로 적용이 안될 때 <code>SceneDelegate.swift</code>의     <code>willConnectTo</code> 함수에</p>
</blockquote>
<pre><code class="language-Swift">for fontFamily in UIFont.familyNames {
    for fontName in UIFont.fontNames(forFamilyName: fontFamily) {
        print(fontName)
    }
}</code></pre>
<blockquote>
<p>실제 파일명과 다른 폰트명이 적용되어 있을 수 있으므로 확인해서 해당 폰트명으로 코드를 작성해주면 됨 </p>
</blockquote>
<h3 id="2-스토리보드">2. 스토리보드</h3>
<img src = "https://images.velog.io/images/youn_22/post/3ebe51e3-f014-431e-a905-cb439b26210e/%E1%84%89%E1%85%B3%E1%84%8F%E1%85%B3%E1%84%85%E1%85%B5%E1%86%AB%E1%84%89%E1%85%A3%E1%86%BA%202022-03-17%20%E1%84%8B%E1%85%A9%E1%84%92%E1%85%AE%205.50.45.png" width="40%" height="20">]]></description>
        </item>
        <item>
            <title><![CDATA[Transforming Operators]]></title>
            <link>https://velog.io/@youn_22/Transforming-Operators</link>
            <guid>https://velog.io/@youn_22/Transforming-Operators</guid>
            <pubDate>Sun, 05 Dec 2021 09:57:03 GMT</pubDate>
            <description><![CDATA[<h2 id="toarray">toArray</h2>
<blockquote>
<p>옵져버블이 방출하는 모든 요소를 하나의 배열로 방출 (종료전까지 전달 x)</p>
</blockquote>
<pre><code class="language-swift">let subject = PublishSubject&lt;Int&gt;()
&gt;
subject
    .toArray()
    .subscribe { print$(0) }
    .disposed(by: disposeBag)
&gt;
subject.onNext(1)   // 방출 X
subject.onNext(2)   // 방출 X
subject.onCompleted() // 방출 success([1,2])</code></pre>
<h2 id="map">map</h2>
<blockquote>
<p> 옵저버블이 방출하는 요소를 대상으로 함수를 실행하고 결과를 새로운 옵저버블로 리턴</p>
</blockquote>
<pre><code class="language-swift">Observable.from([1, 2, 3])
    .map { &quot;age : \($0)&quot; }
    .subscribe { print($0) }
    .disposed(by: disposeBag)</code></pre>
<ul>
<li>파라미터와 다른 타입을 리턴해도 됨 (문자열 &gt; 정수)</li>
</ul>
<h2 id="flatmap">flatMap</h2>
<blockquote>
<p>원본 옵져버블이 항목을 방출하면 flatmap 이 변환연산 시작. 원본 옵져버블이 방출하는 값을 지속적으로 감시, 최신 값 확인.
모든 옵져버블이 방출하는 항목을 모아 최종적으로 하나의 옵져버블 방출</p>
</blockquote>
<pre><code class="language-swift">let a = BehaviorSubject(value : 1)
let b = BehaviorSubject(value : 2)

let subject = PublishSubject&lt;BehaviorSubject&lt;Int&gt;&gt;()

subject
    .flatMap { $0.asObservable() }  //subject -&gt; observable
    .subscribe { print($0) } 
    .disposed(by: disposeBag)

subject.onNext(a) 
subject.onNext(b)
-- next(1), next(2)</code></pre>
<ul>
<li>네트워크 요청에 주로 사용</li>
<li>최신 값도 다 전달</li>
</ul>
<h2 id="flatmapfirst-flatmaplatest">flatMapFirst, flatMapLatest</h2>
<ul>
<li>하나로 병합 X <h3 id="flatmapfirst">flatMapFirst</h3>
<blockquote>
<p>처음에 변환된 옵져버블이 방출하는 항목만 구독자로 전달, 나머지는 무시</p>
</blockquote>
</li>
</ul>
<h3 id="flatmaplatest">flatMapLatest</h3>
<blockquote>
<p>가장 최근에 항목을 방출한 옵져버블을 제외한 나머지는 무시</p>
</blockquote>
<h2 id="scan">scan</h2>
<blockquote>
<p>accumulator function을 활용, 작업 결과 누적 + 중간결과도 알고 싶을 때 사용</p>
</blockquote>
<pre><code class="language-swift">Observable.range(start: 1, count: 10)
    .scan(0, accmulator: +)
</code></pre>
<h2 id="buffer">buffer</h2>
<blockquote>
<p>특정주기동안 옵져버블이 방출하는 항목 수집, 배열 요소를 하나로 방출 </p>
</blockquote>
<pre><code class="language-swift">Observable&lt;Int&gt;.interval(.seconds(1), scheduler: MainScheduler.instance)
    .buffer(timeSpan: .seconds(2), count: 3, scheduler: MainScheduler.instance)
    .take(5)</code></pre>
<h2 id="window">window</h2>
<blockquote>
<p>옵져버블이 방출하는 항목들을 작은단위의 옵져버블로 분해 &gt; 옵져버블을 방출하는 옵져버블(inner observable) 리턴</p>
</blockquote>
<pre><code class="language-swift">Observable&lt;Int&gt;.interval(.seconds(1), scheduler: MainScheduler.instance)
    .window(timeSpan : .seconds(2), count: 3, scheduler: MainScheduler.instance)
    .take(5)
    .subscribe {
        print($0)
        if let obs = $0.element { 
            obs.subscribe { print (&quot; inner : &quot; , $0) }
     }</code></pre>
<h2 id="groupby">groupBy</h2>
<blockquote>
<p>방출되는 요소를 조건에 따라 그룹핑, groupedObesrvable 방출 </p>
</blockquote>
<pre><code class="language-swift">Observable.from([&quot;hi&quot;,&quot;hello&quot;,&quot;ad&quot;])
    .groupBy ( $0.count }
    .flatMap ( $0.toArray()) }
    .subscribe {print($0)}
   })</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Filtering Operators]]></title>
            <link>https://velog.io/@youn_22/Filtering-Operators</link>
            <guid>https://velog.io/@youn_22/Filtering-Operators</guid>
            <pubDate>Sat, 04 Dec 2021 12:08:47 GMT</pubDate>
            <description><![CDATA[<h2 id="ignoreelements">ignoreElements</h2>
<blockquote>
<p>옵져버블이 방출하는 next 이벤트를 필터링, completed 와 error 이벤트만 구독자로 전달</p>
</blockquote>
<pre><code class="language-swift">Observable.from([1,2,3])
    .ignoreElements()
    .subscribe {print($0)}
    .disposed(by: disposeBag)</code></pre>
<ul>
<li>작업의 성공/실패에만 관심 있을 때 사용 </li>
</ul>
<h2 id="elementat">elementAt</h2>
<blockquote>
<p>특정 인덱스에 위치한 요소를 제한적으로 방출, 구독자에게 하나의 요소만 전달되고 나머지는 무시</p>
</blockquote>
<pre><code class="language-swift">Observable.from([1,2,3])
    .elementAt(1)
    .subscribe {print($0)}
    .disposed(by: disposeBag)

--- 2 요소만 방출</code></pre>
<h2 id="filter">filter</h2>
<blockquote>
<p>옵져버블이 방출하는 요소 필터링</p>
</blockquote>
<pre><code class="language-swift">Observable.from(Array(1...10)
    .filter { $0.isMultiple(of: 2) }
    .subscribe {print($0)}
    .disposed(by: disposeBag)

--- 구독자로 짝수 요소만 방출</code></pre>
<h2 id="skip-skipwhile-skipuntil">skip, skipwhile, skipUntil</h2>
<blockquote>
<p>특정 요소를 무시</p>
</blockquote>
<h3 id="skip">skip</h3>
<pre><code class="language-swift">&lt;!-- 1. Skip --&gt; 
Observable.from([1,2,3])
    .skip(3)
    .subscribe {print($0)}
    .disposed(by: disposeBag)</code></pre>
<ul>
<li>정수를 파라미터로 받음</li>
<li>파라미터의 값만큼 요소를 무시한 뒤 이후 방출되는 요소가 포함되는 옵져버블 전달 </li>
<li>파라미터를 count 로 생각하기</li>
</ul>
<h3 id="skipwhile">skipWhile</h3>
<pre><code class="language-swift">&lt;! -- 2. SkipWhile --&gt;
Observable.from([1,2,3])
    .skipWhile { !$0.isMultiple(of: 2) }
    .subscribe {print($0)}
    .disposed(by: disposeBag)

-- 2, 3  전달</code></pre>
<ul>
<li>파라미터로 받은 클로저가 true 를 리턴하는 동안 방출 무시 </li>
<li>false 리턴 이후에는 더이상 조건 판단 X </li>
</ul>
<h3 id="skipuntil">skipUntil</h3>
<pre><code class="language-swift">&lt;! -- 3. skipUntil --&gt;
let subject = PublishSubject&lt;Int&gt;()
let trigger = PublishSubject&lt;Int&gt;()

subject.skipUntil { trigger }
    .subscribe {print($0)}
    .disposed(by: disposeBag)

// subject 에서 요소 방출
subject.onNext(1)

trigger.onNext(0)

subject.onNext(2)
-- next(2)</code></pre>
<ul>
<li>파라미터로 받은 옵져버블(트리거)가 next 이벤트를 전달하기 전까지 원본 옵져버블 전달 X </li>
</ul>
<h2 id="take-takewhile-takeuntil-takelast">take, takeWhile, takeUntil, takeLast</h2>
<blockquote>
<p>요소 방출 조건 설정</p>
</blockquote>
<h3 id="take">take</h3>
<pre><code class="language-swift">Observable.from([1,2,3])
    .take(2)
    .subscribe {print($0)}
    .disposed(by: disposeBag)
-- 1, 2 방출</code></pre>
<ul>
<li>파라미터로 정수를 받음, 해당 숫자 만큼만 요소 방출 </li>
</ul>
<h3 id="takewhile">takeWhile</h3>
<pre><code class="language-swift">Observable.from([1,2,3])
    .takeWhile{ !$0.isMultiple(of: 2) }
    .subscribe {print($0)}
    .disposed(by: disposeBag)
-- 1</code></pre>
<ul>
<li>파라미터로 받은 클로져가 true 인동안 방출</li>
<li>false 를 리턴하면 더이상 요소 방출 X</li>
</ul>
<h3 id="takeuntil">takeUntil</h3>
<pre><code class="language-swift">let subject = PublishSubject&lt;Int&gt;()
let trigger = PublishSubject&lt;Int&gt;()

subject.takeUntil { trigger }
    .subscribe {print($0)}
    .disposed(by: disposeBag)

// subject 에서 요소 방출
subject.onNext(1)

trigger.onNext(0)

subject.onNext(2)
-- next(1)</code></pre>
<ul>
<li><ul>
<li>파라미터로 받은 옵져버블(트리거)가 next 이벤트를 전달하기 전까지 원본 옵져버블에서 next 이벤트 전달 </li>
</ul>
</li>
</ul>
<h3 id="takelast">takeLast</h3>
<pre><code class="language-swift">let subject = PublishSubject&lt;Int&gt;()

subject.takeLast(2)
    .subscribe {print($0)}
    .disposed(by: disposeBag)

[1,2,3].forEach { subject.onNext($0) }  // 버퍼 2,3

subject.onNext(11) // 버퍼 3, 11

subject.onCompleted() // 요소 방출 
subject.onError(MyError.error) // 버퍼 요소 방출 없이 에러이벤트만 방출</code></pre>
<ul>
<li>정수를 파라미터로 받아 observable 리턴 </li>
<li>리턴되는 observable 에는 원본 옵져버블 마지막 n 개의 요소 포함</li>
<li>구독자로 전달되는 시점이 지연됨</li>
</ul>
<h2 id="single">single</h2>
<blockquote>
<p>원본 옵져버블에서 첫번째 요소만 방출 / 조건과 일치하는 첫번째 요소 방출</p>
</blockquote>
<pre><code class="language-swift">Observable.just(1)
    .single()
    .subscribe {print($0)}
    .disposed(by: disposeBag)

-- 1 전달 , completed

Observable.from([1,2,3])
    .single()
    .subscribe {print($0)}
    .disposed(by: disposeBag)

-- 1 전달 , error</code></pre>
<ul>
<li>원본 옵졉버블에서 completed 전달될때까지 기다림</li>
</ul>
<h2 id="distinctuntilchanged">distinctUntilChanged</h2>
<blockquote>
<p>동일한 항목이 연속적으로 방출되지 않도록 필터링
2개의 요소를 비교하여 이전과 동일하면 방출 X</p>
</blockquote>
<pre><code class="language-swift">Observable.from(Array(1...10))
    .distinctUntilChanged()
    .subscribe {print($0)}
    .disposed(by: disposeBag)</code></pre>
<h2 id="debounce-throttle">debounce, throttle</h2>
<blockquote>
<p>짧은 시간동안 반복적으로 방출되는 이벤트 제어</p>
</blockquote>
<h3 id="debounce">debounce</h3>
<ul>
<li>정해진 시간동안 이벤트가 방출되지 않으면 마지막 이벤트 방출, 이벤트 방출되면 타이머 초기화</li>
<li>검색 기능에 활용<img src="https://images.velog.io/images/youn_22/post/71971539-5ae9-4cf8-8b7a-bc17620352c6/iOS_-_RxSwift%20(1).png" alt=""></li>
</ul>
<h3 id="throttle">throttle</h3>
<ul>
<li>정해진 시간동안 하나의 이벤트만 전달</li>
<li>탭 이벤트 처리에 활용</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Create Operators]]></title>
            <link>https://velog.io/@youn_22/Create-Operators</link>
            <guid>https://velog.io/@youn_22/Create-Operators</guid>
            <pubDate>Fri, 05 Nov 2021 04:40:51 GMT</pubDate>
            <description><![CDATA[<ul>
<li>next 이벤트 방출 이후 completed 이벤트 전달</li>
</ul>
<h2 id="just">just</h2>
<blockquote>
<p>하나의 항목을 방출하는 observable 생성</p>
<pre><code class="language-swift">Observable.just(element)</code></pre>
</blockquote>
<pre><code>
```swift
let disposeBag = DisposeBag()
let element = &quot;hi&quot;
Observable.just(element)  // observable 생성 
/* 구독 */.subscribe{event in print(event)}
.disposed(by: disposeBag)

Observable.just([1, 2, 3])
   .subscribe { event in print(event) }
   .disposed(by: disposeBag)
// &gt;&gt; 1,2,3 방출 

</code></pre><ul>
<li>parameter 로 전달한 요소를 그대로 방출함</li>
<li>1개 방출</li>
</ul>
<h2 id="of">of</h2>
<blockquote>
<p>2개 이상의 요소 방출</p>
</blockquote>
<pre><code class="language-swift">Observable.of(&quot;hi&quot;, &quot;bye)
Observable.of([1, 2], [3, 4], [5, 6])
// &gt;&gt; next 이벤트가 요소 수만큼 전달됨! </code></pre>
<ul>
<li>원하는 수만큼 요소 방출 가능</li>
</ul>
<h2 id="from">from</h2>
<blockquote>
<p>배열로 받은 요소를 하나씩 순서대로 방출</p>
</blockquote>
<pre><code class="language-swift">Observable.from([1,2,3,4,5])
//&gt;&gt; next(1)
//   next(2)
//   next(3)
//   next(4)
//   next(5)</code></pre>
<h2 id="range">range</h2>
<blockquote>
<p>정수를 지정된 수만큼 방출</p>
</blockquote>
<pre><code class="language-swift">Observable.range(start: 1, count: 10) 
// &gt;&gt; next(1), next(2), next(3), next(4), next(5), next(6), next(7), next(8), next(9), next(10)</code></pre>
<ul>
<li>param (시작할정수, 방출할 개수)</li>
<li>정수만 가능</li>
</ul>
<h2 id="generate">generate</h2>
<blockquote>
<p>증가 / 감소 폭을 변경할 수 있는 시퀀스 방출</p>
</blockquote>
<pre><code class="language-swift">Observable.generate(initialState: 0, condition: {$0 &lt;= 10}, iterate: {$0 + 2})</code></pre>
<ul>
<li>param (시작값, condition(true - 요소방출, false - completed), nil, 변경값)</li>
<li>정수로 제한되지 않는 parameter</li>
</ul>
<h2 id="repeatelement">repeatElement</h2>
<blockquote>
<p>동일한 요소를 반복적(무한)으로 방출하는 옵져버블 생성</p>
</blockquote>
<pre><code class="language-swift">Observable.repeatElement(element)</code></pre>
<ul>
<li><p>무한정 생성되기 때문에 요소 개수를 정하는 것이 중요함 (take 연산자 등으로 정해줄 것)</p>
<pre><code class="language-swift">Observable.repeatElement(element)
  .take(7)
  .subscribe {print($0)}
  .disposed(by: disposeBag)
  // &gt;&gt; 7개요소 방출 이후 completed event 방출</code></pre>
<h2 id="deferred">deferred</h2>
<blockquote>
<p>특정 조건에 따라 옵져버블 생성 </p>
</blockquote>
<pre><code class="language-swift">let factory: Observable&lt;String&gt; = Observable.deferred {
  flag.toggle()
&gt;    
  if flag {
      return Observable.from(animals) // 배열에 있는 요소들이 개별적으로 방출
  } else {
      return Observable.from(fruits)
  }
}
factory
  .subscribe {print($0)}
  .disposed(by: disposeBag)
&gt;
factory
  .subscribe {print($0)}
  .disposed(by: disposeBag)
  &gt;
&gt; // &gt;&gt; animals 요소들의 이벤트 방출 이후 fruits 요소들의 이벤트 방출조금</code></pre>
</li>
<li><p>param(옵져버블을 return 하는 closure)</p>
</li>
</ul>
<h2 id="create">create</h2>
<blockquote>
<p>옵져버블이 동작하는 방식을 직접 구현 </p>
</blockquote>
<pre><code class="language-swift">Observable&lt;String&gt;.create { (observer) -&gt; Disposable in
    guard let url = URL(string: &quot;https://www.apple.com&quot;)
    else { // error
        observer.onError(MyError.error)
        return Disposables.create()
    }
    guard let html = try? String(contentsOf: url, encoding: .utf8) else {  // error
        return Disposables.create()
    }
    &gt;
    observer.onNext(html) // 정상적 문자열 방출
    observer.onCompleted()
    &gt;
    return Disposables.create() // 모든 리소스 정리, 옵져버블 정상적으로 종료
}
.subscribe{print($0)}
.disposed(by: disposeBag)</code></pre>
<ul>
<li>param(옵져버블을 파라미터로 받아서 disposable return 하는 클로저)</li>
<li>disposable 을 return 할때는 <code>Disposables.create()</code> 사용</li>
<li>요소를 방출할 때 - <code>onNext(방출할 요소)</code></li>
<li>옵져버블을 종료하기 위한 <code>onError, onCompleted</code> 를 반드시 호출해야 함 </li>
</ul>
<hr>
<h3 id="empty--error----next-이벤트를-전달하지-않음-요소-방출-x">empty &amp; error -&gt;  next 이벤트를 전달하지 않음, 요소 방출 X</h3>
<h2 id="empty">empty</h2>
<blockquote>
<p>completed event 를 전달하고 종료하는 observable 생성 </p>
</blockquote>
<pre><code class="language-swift">Observable&lt;Void&gt;.empty()
// &gt;&gt; completed()</code></pre>
<ul>
<li>param X</li>
<li>옵져버가 아무 동작없이 종료해야 할 때 활용</li>
</ul>
<h2 id="error">error</h2>
<blockquote>
<p>error event 를 전달하고 종료하는 observable 생성</p>
</blockquote>
<pre><code class="language-swift">enum MyError: Error {
   case error
}
&gt;
Observable&lt;Void&gt;.error(MyError.error)
// &gt;&gt; error(error)</code></pre>
<ul>
<li>param (error)</li>
<li>에러 처리활 때 활용</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Subjects]]></title>
            <link>https://velog.io/@youn_22/Subjects</link>
            <guid>https://velog.io/@youn_22/Subjects</guid>
            <pubDate>Thu, 04 Nov 2021 06:08:10 GMT</pubDate>
            <description><![CDATA[<h2 id="subject">Subject</h2>
<blockquote>
<p>observable 인 동시에 observer
subject 로 전달되는 이벤트를 observer 에게 전달</p>
</blockquote>
<h2 id="publish-subject">Publish Subject</h2>
<blockquote>
<p>이벤트가 전달 되는 즉시 구독자에게 전달하는 subject
-&gt; subject 가 최초로 생성되는 시점과 구독이 시작되는 시점 사이에 생성되는 이벤트는 사라짐
-&gt; 이벤트가 사라지지 않게 하려면 다른 observable 사용 필요</p>
</blockquote>
<pre><code class="language-swift">let subject = PublishSubject&lt;String&gt;()  //문자열이 포함된 nextevent 를 받아서 다른 observer 에게
// subject 생성시점에는 내부에 아무 이벤트가 저장되어 있지 않음

/*1. subject 이벤트 전달 이후 구독자 생성*/
subject.onNext(&quot;hello&quot;)

let o1 = subject.subscribe( {print(&quot;&gt;&gt; 1&quot;, $0)})
o1.disposed(by: disposeBag)
// 출력 X
// 구독이후에 전달되는 새로운 이벤트만 구독자로 전달되기 때문에
// 구독자가 구독시작전 전달되었던 next 이벤트는 오저버로 전달 X

/*1-2. 구독자 생성 이후 전달된 이벤트*/
subject.onNext(&quot;RxSwift&quot;)
// 출력됨

/*2. 구독자 추가*/
let o2 = subject.subscribe{print(&quot;&gt;&gt; 2&quot;, $0)}
subject.onNext(&quot;Subject&quot;)
// o1 -&gt; subject, RxSwift 전달
// o2 -&gt; subject 만 전달

/*3. 완료*/
subject.onCompleted()     또는
subject.onError(MyError.error)
// o1, o2 에게 이벤트 전달

/*3-1.*/ 새로운 구독자 추가 (완료된 이후에)
let o3 = subject.subscribe{print(&quot;&gt;&gt; 3&quot;, $0)}
o3.disposed(by: disposeBag)
// o3 에게는 next 없이 완료이벤트만 전달</code></pre>
<h2 id="behavior-subject">Behavior Subject</h2>
<blockquote>
<p>가장 최근 이벤트를 저장하고 새로운 구독자에게 전달</p>
</blockquote>
<h4 id="생성">생성</h4>
<pre><code class="language-swift">// publish
let p = PublishSubject&lt;Int&gt;() // 비어있는 생성자

// behavior
let b = BehaviorSubject&lt;Int&gt;(value: 0) // 값 전달
</code></pre>
<ul>
<li>내부에 next 이벤트가 하나 만들어짐</li>
<li>구독자가 생성되면 저장되어 있던 next 이벤트가 바로 전달됨</li>
<li>새로운 next event 가 전달되면 새로운 이벤트로 교체됨</li>
<li>가장 최근의 next event 전달</li>
<li>최신 이벤트를 제외한 나머지 이벤트는 사라짐! </li>
</ul>
<h2 id="replay-subject">Replay Subject</h2>
<blockquote>
<p>지정된 수만큼 이벤트를 저장</p>
</blockquote>
<ul>
<li>지정된 버퍼크기 만큼 최신 이벤트 저장, 새로운 구독자에게 전달</li>
<li>버퍼 : 메모리에 저장, 메모리 사용량에 유의해야 함</li>
</ul>
<pre><code class="language-swift">let rs = ReplaySubject&lt;Int&gt;.create(bufferSize: 3) // 3개의 next 이벤트전달가능

(1...10).forEach{rs.onNext($0)}

rs.subscribe{print(&quot;observer 1 &gt;&gt; &quot;, $0)}.disposed(by: disposeBag)
rs.onNext(11)</code></pre>
<h2 id="async-subject">Async Subject</h2>
<blockquote>
<p>completed 이벤트가 전달되는 시점에 가장 최근 next 이벤트 1개를 구독자로 전달</p>
</blockquote>
<ul>
<li>이벤트가 전달됐을때, 즉시 구독자로 그 이벤트를 전달하는 다른 subject 들과 달리 completed event 가 전달되기 전까지 구독자로 이벤트를 전달하지 않음</li>
<li>error 이벤트가 전달됐을 경우 next 이벤트 전달없이 error 이벤트만 전달되고 종료됨</li>
</ul>
<pre><code class="language-swift">let sub = AsyncSubject&lt;Int&gt;()

sub
    .subscribe{print($0)}
    .disposed(by: bag)

sub.onNext(1)
sub.onNext(2)

sub.onCompleted()

/**-출력-/
next(2)
completed</code></pre>
<h2 id="relay">Relay</h2>
<blockquote>
<p>subject 를 래핑, 소스로 부터 next 이벤트를 받아서 다른 구독자로 전달</p>
</blockquote>
<ul>
<li><p>publish relay, behavior relay</p>
</li>
<li><p>next 이벤트만 전달받고 전달함 </p>
</li>
<li><p>disposed 전까지 계속 이벤트 전달 ,종료 X </p>
</li>
<li><p>주로 UI 처리에 활용</p>
</li>
<li><p>RxCocoa framework 에 의해 제공</p>
</li>
<li><p>onnext 대신 <code>accept</code> </p>
</li>
</ul>
<h4 id="publish-relay">publish relay</h4>
<ul>
<li>빈생성자로 생성</li>
</ul>
<h4 id="behavior-relay">behavior relay</h4>
<ul>
<li>value 로 이벤트 값 받아올 수 있음</li>
</ul>
<h4 id="code">code</h4>
<pre><code class="language-swift">import RxCocoa

let bag = DisposeBag()
let pr = PublishRelay&lt;Int&gt;()
let br = BehaviorRelay&lt;Int&gt;(value: 1)

pr.subscribe{ print(&quot;1: \($0)&quot;)}.disposed(by: bag)

pr.accept(1)</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Operators]]></title>
            <link>https://velog.io/@youn_22/Operators</link>
            <guid>https://velog.io/@youn_22/Operators</guid>
            <pubDate>Thu, 04 Nov 2021 06:07:52 GMT</pubDate>
            <description><![CDATA[<h2 id="operators">Operators</h2>
<blockquote>
<p>Example</p>
</blockquote>
<p>```swift
let bag = DisposeBag()</p>
<blockquote>
</blockquote>
<p>Observable.from([1, 2, 3, 4, 5, 6, 7, 8, 9])
    .take(5) // 처음 5개의 요소만 전달
    .filter { $0.isMultiple(of: 2) }
    .subscribe { print($0) }
    .disposed(by: bag)
    &gt;
--- 결과 ---
next(2)
next(4)
completed</p>
<ul>
<li>대부분의 연산자는 observable 상에서 동작하고 observable 을 return 
=&gt; 2개 이상의 연산자를 연달아서 호출 가능</li>
<li>subscribe 앞에 추가 -&gt; 구독자로 전달되는 최종데이터가 내가 원하는 데이터가 됨</li>
<li>호출순서에 따라 다른결과를 만들어낼 수 있으므로 호출순서에 유의</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Disposables]]></title>
            <link>https://velog.io/@youn_22/Disposables</link>
            <guid>https://velog.io/@youn_22/Disposables</guid>
            <pubDate>Thu, 04 Nov 2021 06:07:36 GMT</pubDate>
            <description><![CDATA[<h2 id="ondisposed">onDisposed</h2>
<hr>
<ul>
<li>observable 이 전달하는 이벤트가 X </li>
<li>리소스가 해제되는 시점에 자동으로 호출됨</li>
<li>가능하다면 리소스 정리를 직접 해주는게 좋음</li>
</ul>
<pre><code class="language-swift">let sub1 = Observable.from([1,2,3])
    .subscribe(onNext: {elem in
        print(&quot;Next&quot;, elem)
    },onError: {
        error in print(&quot;Error&quot;, error)
    }, onCompleted: {
        print(&quot;Completed&quot;)
    }, onDisposed: {
        print(&quot;Disposed&quot;)
    })</code></pre>
<h2 id="리소스-해제">리소스 해제</h2>
<hr>
<h4 id="1-직접-해제-하기">1. 직접 해제 하기</h4>
<pre><code class="language-swift">sub1.dispose()</code></pre>
<h4 id="2-disposebag-사용">2. DisposeBag 사용</h4>
<pre><code class="language-swift">var bag = DisposeBag()
Observable.from([1, 2, 3])
    .subscribe(
        print($0)
    }.disposed(by: bag)</code></pre>
<ul>
<li>1번 방법보다 더 권장됨</li>
<li>subscribe 가 return 하는 disposable 이 disposeBag 에 추가됨</li>
<li>disposeBag 이 해제되는 시점에 함께 해지됨</li>
</ul>
<h4 id="-임의의-내가-원하는-시점에-해제하려면">* 임의의 내가 원하는 시점에 해제하려면?</h4>
<ol>
<li><code>swift bag = DisposeBag()</code> 호출
  =&gt; 이전에 있던 disposeBag 이 해제됨</li>
<li><code>dispose()</code> 호출<pre><code class="language-swift">/* 1씩 증가하는 정수를 1초마다 방출*/
let sub2 = Observable&lt;Int&gt;.interval(.seconds(1),
 scheduler: MainScheduler.instance)
 .subscribe(onNext: {elem in
     print(&quot;Next&quot;, elem)
 },onError: { error in
     print(&quot;Error&quot;, error)
 }, onCompleted: {
     print(&quot;Completed&quot;)
 }, onDisposed: {
     print(&quot;Disposed&quot;)
 })
/*3초 뒤에 dispose*/
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {sub2.dispose()}</code></pre>
<ul>
<li>next 다음에 completed 메소드가 실행되지 않음</li>
<li>때문에 권장되지 않음
=&gt; takeuntil 과 같은 연산자 사용</li>
</ul>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[Obeservables & Observers]]></title>
            <link>https://velog.io/@youn_22/Obeservables-Observers</link>
            <guid>https://velog.io/@youn_22/Obeservables-Observers</guid>
            <pubDate>Tue, 02 Nov 2021 11:17:34 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><img src="https://images.velog.io/images/youn_22/post/53acebfb-5e91-4fad-9154-3224db51f852/image.png" alt=""></p>
</blockquote>
<ul>
<li>전달하는 이벤트 <ul>
<li><strong>error</strong> (notification)</li>
<li><strong>completed</strong> (notification)</li>
<li><strong>next</strong>  (emmission)</li>
</ul>
</li>
<li>observerbles - 이벤트의 순서 정의 </li>
<li>observer - subscriber</li>
</ul>
<h2 id="observable-생성">observable 생성</h2>
<h4 id="create-연산자-사용">create 연산자 사용</h4>
<pre><code class="language-swift">let o1 = Observable &lt;Int&gt;.create{ (obs) -&gt; Disposable in
    obs.on(next(0)) // 0이 저장되어 있는 이벤트가 구독자로 전달
    obs.onNext(1)
    obs.onCompleted() // observable 종료
    return Disposables.create() // 메모리 정리
 }</code></pre>
<h4 id="from-연산자-사용">from 연산자 사용</h4>
<pre><code class="language-swift"> Observable.from ([0, 1])</code></pre>
<ul>
<li>param인 배열에 있는 요소를 순서대로 방출한 뒤 completed event 전달</li>
</ul>
<h2 id="이벤트-전달">이벤트 전달</h2>
<ul>
<li>전달 시점<ul>
<li>observer가 구독을 하는 시점</li>
<li>observer는 동시에 2개의 event 를 처리하지 않는다</li>
</ul>
</li>
</ul>
<pre><code class="language-swift">/** 1. */
o1.subscribe{
  print($0)
  if let eme = $0.element { // event 에 전달된 값은 optional 임 
     print(eme)
  }
}
/** 2. */
o1.subscribe(onNext: {elem in print(elem)})</code></pre>
<h2 id="정리">정리</h2>
<pre><code class="language-swift">Observable.subscribe // 옵져버블&#39;을&#39; 구독한다
Observer.onNext // 옵져버&#39;에&#39; 이벤트를 전달한다
Observable.create{(observer) in 
    observer.onNext()
    return Disposable.create()
    }
 // 구독되기 시작하면 이벤트를 발생시켜 observer 에 전달하기 시작한다. </code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[RxSwift]]></title>
            <link>https://velog.io/@youn_22/RxSwift</link>
            <guid>https://velog.io/@youn_22/RxSwift</guid>
            <pubDate>Tue, 02 Nov 2021 11:01:55 GMT</pubDate>
            <description><![CDATA[<h2 id="rxswift">RxSwift</h2>
<ul>
<li><a href="http://reactivex.io">ReactiveX</a> 라이브러리를 swift 언어로 구현한 것</li>
<li><a href="https://github.com/ReactiveX/RxSwift">RxSwift Github</a><h3 id="사용-이유">사용 이유</h3>
</li>
<li>단순하고 직관적인 코드 작성</li>
<li>깔끔한 비동기 코드</li>
<li><a href="https://medium.com/@jang.wangsu/ios-swift-rxswift-%EC%99%9C-%EC%82%AC%EC%9A%A9%ED%95%98%EB%A9%B4-%EC%A2%8B%EC%9D%84%EA%B9%8C%EC%9A%94-5c9995f47bab">참고</a></li>
</ul>
]]></description>
        </item>
    </channel>
</rss>