<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>AppleMango </title>
    <link>https://island-developer.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Sat, 1 Aug 2026 19:51:16 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor> Mango</managingEditor>
    <image>
      <title>AppleMango </title>
      <url>https://tistory1.daumcdn.net/tistory/3733035/attach/bb1d73d918e4425d858dd371ef64f73f</url>
      <link>https://island-developer.tistory.com</link>
    </image>
    <item>
      <title>[iOS/Swift] UISearchBar를 활용한 검색 기능 개발</title>
      <link>https://island-developer.tistory.com/177</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;RxSwift의 사본의 사본-21.png&quot; data-origin-width=&quot;1500&quot; data-origin-height=&quot;600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PhxIk/btsLEg3A0hb/mmxHkskDUkLRFBhvokUmeK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PhxIk/btsLEg3A0hb/mmxHkskDUkLRFBhvokUmeK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PhxIk/btsLEg3A0hb/mmxHkskDUkLRFBhvokUmeK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPhxIk%2FbtsLEg3A0hb%2FmmxHkskDUkLRFBhvokUmeK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1500&quot; height=&quot;600&quot; data-filename=&quot;RxSwift의 사본의 사본-21.png&quot; data-origin-width=&quot;1500&quot; data-origin-height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요. 애플망고입니다 &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅은 UISearchBar에 대해 정리해보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;UISearchBar&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UISearchBar는 사용자로부터 검색 정보를 받기 위한 특수화 된 뷰인데요. 이 뷰는 iOS에서 기본적으로 제공되는 UI 요소로, 검색 인터페이스를 간단하게 구현할 수 있도록 도와줍니다. 저는 &lt;b&gt;UICollectionView&lt;/b&gt;와 함께 사용했고, 특정 데이터를 필터링하는데 사용하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;UISearchBar 추가하기&lt;/h2&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;private let searchBar = UISearchBar()

...

private func setupSearchBar() {
    searchBar.delegate = self
    searchBar.placeholder = &quot;그룹 이름을 입력해주세요.&quot;
    searchBar.backgroundImage = UIImage() // border line 제거
    view.addSubview(searchBar)
}

// Auto Layout 설정&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;navigationItem.titleView = searchBar&lt;/code&gt; 를 사용하면 따로 레이아웃 잡아 줄 필요없이 네비게이션 바의 중앙에 UISearchBar가 표시됩니다. 저는 원하는 위치에 넣고 싶어서 저 방식을 선택했습니다. 그리고 몇가지 설정을 해주었는데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;border line 제거&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;searchBar.png&quot; data-origin-width=&quot;618&quot; data-origin-height=&quot;126&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bMgLga/btsLEIFxSoT/LEdmoPecuMmxWri9gjAFxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bMgLga/btsLEIFxSoT/LEdmoPecuMmxWri9gjAFxK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bMgLga/btsLEIFxSoT/LEdmoPecuMmxWri9gjAFxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbMgLga%2FbtsLEIFxSoT%2FLEdmoPecuMmxWri9gjAFxK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;618&quot; height=&quot;126&quot; data-filename=&quot;searchBar.png&quot; data-origin-width=&quot;618&quot; data-origin-height=&quot;126&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 UISearchBar에는 상단과 하단에 경계선(border line)이 포함되어 있습니다. 이를 제거하기 위해 backgroundImage를 빈 이미지(UIImage())로 설정했습니다. 이 코드를 추가해주면 border line이 제거가 됩니다.&lt;/p&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;searchBar.backgroundImage = UIImage()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;UISearchBarDelegate&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자가 입력한 Text를 감지해 Cell을 표시하고 싶어서 UISearchBarDelegate도 사용해주었습니다.&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;메서드&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;func searchBar(UISearchBar, textDidChange: String)&lt;/td&gt;
&lt;td&gt;텍스트가 변경될 때마다 호출&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;func searchBarSearchButtonClicked(UISearchBar)&lt;/td&gt;
&lt;td&gt;검색 버튼을 눌렀을 때 호출&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;func searchBarCancelButtonClicked(UISearchBar)&lt;/td&gt;
&lt;td&gt;취소 버튼을 눌렀을 때 호출&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;func searchBarTextDidBeginEditing(UISearchBar)&lt;/td&gt;
&lt;td&gt;검색창 편집이 시작될 때 호출&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;func searchBarTextDidEndEditing(UISearchBar)&lt;/td&gt;
&lt;td&gt;검색창 편집이 끝날 때 호출&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;textDidChange&lt;/h3&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
    guard let text = searchBar.text else { return }
    viewModel.searchWords(text: text)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;textDidChange&lt;/code&gt;메서드를 통해 사용자가 검색창에 텍스트를 입력할 때마다 단어를 검색하는 함수를 호출해주었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;searchBarSearchButtonClicked&lt;/h3&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
    guard let text = searchBar.text else { return }
    viewModel.searchWords(text: text)
    searchBar.resignFirstResponder()
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;searchBarSearchButtonClicked&lt;/code&gt; 메서드를 통해 검색 버튼을 클릭했을때도 똑같이 단어를 검색하는 함수를 호출했습니다. 검색이 끝난 상태이기 때문에 &lt;code&gt;searchBar.resignFirstResponder()&lt;/code&gt;를 통해 키보드도 내려주었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;searchBarCancelButtonClicked&lt;/h3&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
    searchBar.text = &quot;&quot;
    viewModel.fetchWords()
    searchBar.resignFirstResponder()
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;searchBarCancelButtonClicked&lt;/code&gt; 메서드를 통해 취소 버튼을 클릭했을때는 다시 모든 Cell을 불러왔습니다. 마찬가지로 키보드도 내려주었습니다. 이때 취소버튼은 searchBarTextDidBeginEditing과 searchBarTextDidEndEditing을 통해 검색이 시작됐을때 생기고, 끝났을때 없애주었는데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;private func customizeCancelButton(_ searchBar: UISearchBar) {
    if let cancelButton = searchBar.value(forKey: &quot;cancelButton&quot;) as? UIButton {
        cancelButton.setTitle(&quot;취소&quot;, for: .normal)
        cancelButton.setTitleColor(.gray, for: .normal)
        cancelButton.titleLabel?.font = UIFont.systemFont(ofSize: 16)
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-01-06 오후 10.35.25.png&quot; data-origin-width=&quot;584&quot; data-origin-height=&quot;76&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eD8psy/btsLGifrhqK/AuPWmikKvbxeD5ALMccC30/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eD8psy/btsLGifrhqK/AuPWmikKvbxeD5ALMccC30/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eD8psy/btsLGifrhqK/AuPWmikKvbxeD5ALMccC30/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeD8psy%2FbtsLGifrhqK%2FAuPWmikKvbxeD5ALMccC30%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;300&quot; height=&quot;76&quot; data-filename=&quot;스크린샷 2025-01-06 오후 10.35.25.png&quot; data-origin-width=&quot;584&quot; data-origin-height=&quot;76&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 기본으로 제공되는 cancel버튼이 마음에 들지 않아서 커스텀해주었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;searchBarTextDidBeginEditing&lt;/h3&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
    searchBar.showsCancelButton = true
    customizeCancelButton(searchBar)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;searchBarTextDidBeginEditing&lt;/code&gt; 메서드를 통해 입력이 시작될때 showsCancelButton을 true로 바꿔주었고 cancel버튼도 바꿔주었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;searchBarTextDidEndEditing&lt;/h3&gt;
&lt;pre class=&quot;swift&quot;&gt;&lt;code&gt;func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
    searchBar.showsCancelButton = false
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;searchBarTextDidBeginEditing&lt;/code&gt; 메서드를 통해 입력이 끝났을때 다시 showsCancelButton을 false로 변경해주었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;공식 문서 링크&lt;/h2&gt;
&lt;figure id=&quot;og_1736171500344&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;UISearchBar | Apple Developer Documentation&quot; data-og-description=&quot;A specialized view for receiving search-related information from the user.&quot; data-og-host=&quot;developer.apple.com&quot; data-og-source-url=&quot;https://developer.apple.com/documentation/uikit/uisearchbar&quot; data-og-url=&quot;https://docs.developer.apple.com/documentation/uikit/uisearchbar&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/BOJp2/hyXWp12KXU/APzHfwwKexCpcgwKj9Ghk0/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/cmgNgd/hyXWrrZBp3/44omMwgzvr1FARqZDshk90/img.jpg?width=1024&amp;amp;height=512&amp;amp;face=0_0_1024_512&quot;&gt;&lt;a href=&quot;https://developer.apple.com/documentation/uikit/uisearchbar&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.apple.com/documentation/uikit/uisearchbar&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/BOJp2/hyXWp12KXU/APzHfwwKexCpcgwKj9Ghk0/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/cmgNgd/hyXWrrZBp3/44omMwgzvr1FARqZDshk90/img.jpg?width=1024&amp;amp;height=512&amp;amp;face=0_0_1024_512');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;UISearchBar | Apple Developer Documentation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;A specialized view for receiving search-related information from the user.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developer.apple.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1736171511392&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;UISearchBarDelegate | Apple Developer Documentation&quot; data-og-description=&quot;A collection of optional methods that you implement to make a search bar control functional.&quot; data-og-host=&quot;developer.apple.com&quot; data-og-source-url=&quot;https://developer.apple.com/documentation/uikit/uisearchbardelegate&quot; data-og-url=&quot;https://docs.developer.apple.com/documentation/uikit/uisearchbardelegate&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ssFDi/hyXWrFzxya/yhUkiYLNNYNyucn34KDY5k/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/ceXlHn/hyXWtQUAbk/tBmbiQHBAKS13uuk2wIujK/img.jpg?width=1024&amp;amp;height=512&amp;amp;face=0_0_1024_512&quot;&gt;&lt;a href=&quot;https://developer.apple.com/documentation/uikit/uisearchbardelegate&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.apple.com/documentation/uikit/uisearchbardelegate&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ssFDi/hyXWrFzxya/yhUkiYLNNYNyucn34KDY5k/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/ceXlHn/hyXWtQUAbk/tBmbiQHBAKS13uuk2wIujK/img.jpg?width=1024&amp;amp;height=512&amp;amp;face=0_0_1024_512');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;UISearchBarDelegate | Apple Developer Documentation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;A collection of optional methods that you implement to make a search bar control functional.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developer.apple.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>iOS/Swift</category>
      <author> Mango</author>
      <guid isPermaLink="true">https://island-developer.tistory.com/177</guid>
      <comments>https://island-developer.tistory.com/177#entry177comment</comments>
      <pubDate>Mon, 6 Jan 2025 21:23:43 +0900</pubDate>
    </item>
    <item>
      <title>UIKit에서 Swift Charts Framework 사용하기</title>
      <link>https://island-developer.tistory.com/175</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;RxSwift의 사본-11.png&quot; data-origin-width=&quot;1500&quot; data-origin-height=&quot;600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l51ja/btsKBcVcylc/KTE8GivwYUFkWnKHYD8oS1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l51ja/btsKBcVcylc/KTE8GivwYUFkWnKHYD8oS1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l51ja/btsKBcVcylc/KTE8GivwYUFkWnKHYD8oS1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl51ja%2FbtsKBcVcylc%2FKTE8GivwYUFkWnKHYD8oS1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1500&quot; height=&quot;600&quot; data-filename=&quot;RxSwift의 사본-11.png&quot; data-origin-width=&quot;1500&quot; data-origin-height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; text-align: center;&quot;&gt;안녕하세요 :D 애플망고입니다 &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;&lt;span style=&quot;caret-color: #555555;&quot;&gt;이번에 &lt;span style=&quot;color: #555555; text-align: center;&quot;&gt;새로운 앱을 개발하면서&lt;span&gt; 그래프를 그릴 일이 있었는데요.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #555555;&quot;&gt;&lt;span style=&quot;caret-color: #555555;&quot;&gt;DGCharts라이브러리를 사용하려고 했는데 &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;&lt;span style=&quot;caret-color: #555555;&quot;&gt;제가 원하는 모양의 그래프가 없더라고요.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #555555;&quot;&gt;&lt;span style=&quot;caret-color: #555555;&quot;&gt;그래서 Swift Charts Framework를 사용하게 되었습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;&lt;span style=&quot;caret-color: #555555;&quot;&gt;Swift Charts&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1730977034448&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import SwiftUI
import Charts

struct ChartView: View {
    var dailyPriceData: [DailyPriceData]
    
    var body: some View {
        Chart {
            ForEach(dailyPriceData) { data in
                BarMark(
                    xStart: .value(&quot;Price&quot;, data.minPrice),
                    xEnd: .value(&quot;Price&quot;, data.maxPrice + 1),
                    y: .value(&quot;Day&quot;, &quot;\(data.day)&quot;)
                )
                .foregroundStyle(data.day.contains(&quot;☀️&quot;) ? Color.Chart.dayColor : Color.Chart.nightColor)
                .annotation(position: .trailing) {
                    Text(data.minPrice == data.maxPrice
                        ? &quot;\(Int(data.minPrice))&quot;
                        : &quot;\(Int(data.minPrice)) - \(Int(data.maxPrice))&quot;)
                        .font(.caption)
                        .foregroundColor(.black)
                }
            }
        }
        .padding()
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; text-align: center;&quot;&gt;Swift Charts를 쓰기 위해서는 먼저 SwiftUI와, Charts를 import 해주어야합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;저는 BarMark 형식을 이용해 가로 막대 그래프를 만들었습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;xStart : x의 시작점이고, 저는 최소값을 넣었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;xEnd : x의 끝점이고, 저는 최대값을 넣었는데 , &lt;/span&gt;&lt;/span&gt;데이터값에 +1을 해준 이유는 Start값과 End값이 같으면 아예 표시가 안되더라고요.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;여기에 annotation을 추가해 최소, 최대 값을 표시해주었습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;UIKit에서 SwiftUI 사용하기&lt;/h3&gt;
&lt;pre id=&quot;code_1730978240190&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// UIHostingController를 사용하여 SwiftUI View(ChartView)를 포함
let hostingController = UIHostingController(rootView: ChartView(dailyPriceData: dailyPriceData))

// UIHostingController를 현재 VC의 자식 VC로 추가
addChild(hostingController)

view.addSubview(hostingController.view)

hostingController.view.frame = view.frame

// UIHostingController가 부모 뷰 컨트롤러에 추가됨을 알림
hostingController.didMove(toParent: self)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;UIHostingController를 사용해 UIKit에 SwiftUI View를 통합할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;caret-color: #000000;&quot;&gt;먼저 UIHostingController(rootView:)&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;를 사용하여 &lt;/span&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;SwiftUI 뷰인&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;ChartView&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;를 &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;UIKit에서 사용할 수 있게 만들었습니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;addChild&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;와&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;didMove(toParent:)를 사용해 UIHostingController&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;의 생명주기가 부모와 동기화되도록 만들었습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;caret-color: #000000;&quot;&gt;결과&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_IMG_0660.PNG&quot; data-origin-width=&quot;1179&quot; data-origin-height=&quot;2055&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bMA72Q/btsKAEEJidR/O5vzvHBAEVJtmYvJA4VdRk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bMA72Q/btsKAEEJidR/O5vzvHBAEVJtmYvJA4VdRk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bMA72Q/btsKAEEJidR/O5vzvHBAEVJtmYvJA4VdRk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbMA72Q%2FbtsKAEEJidR%2FO5vzvHBAEVJtmYvJA4VdRk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;1084&quot; data-filename=&quot;edited_IMG_0660.PNG&quot; data-origin-width=&quot;1179&quot; data-origin-height=&quot;2055&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>iOS/SwiftUI</category>
      <author> Mango</author>
      <guid isPermaLink="true">https://island-developer.tistory.com/175</guid>
      <comments>https://island-developer.tistory.com/175#entry175comment</comments>
      <pubDate>Thu, 7 Nov 2024 20:53:03 +0900</pubDate>
    </item>
    <item>
      <title>NotificationCenter를 활용한 뷰 컨트롤러 간 데이터 전달 방법</title>
      <link>https://island-developer.tistory.com/174</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;RxSwift의 사본의 사본-20.png&quot; data-origin-width=&quot;1500&quot; data-origin-height=&quot;600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ckN090/btsKyDe5UDV/ZBqeUIQsk6MIIO88QKepxK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ckN090/btsKyDe5UDV/ZBqeUIQsk6MIIO88QKepxK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ckN090/btsKyDe5UDV/ZBqeUIQsk6MIIO88QKepxK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FckN090%2FbtsKyDe5UDV%2FZBqeUIQsk6MIIO88QKepxK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1500&quot; height=&quot;600&quot; data-filename=&quot;RxSwift의 사본의 사본-20.png&quot; data-origin-width=&quot;1500&quot; data-origin-height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; text-align: center;&quot;&gt;안녕하세요 :D 애플망고입니다 &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;&lt;span style=&quot;caret-color: #555555;&quot;&gt;이번에 새로운 앱을 개발하면서 첫 번째 VC에서 두 번째, 세번째 VC로 동일한 데이터를 전달해야 했습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;&lt;span style=&quot;caret-color: #555555;&quot;&gt;이를 위해 NotificationCenter를 활용해 데이터 전달을 하기로 했습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555;&quot;&gt;&lt;span style=&quot;caret-color: #555555;&quot;&gt;그럼 &lt;span style=&quot;color: #555555; text-align: center;&quot;&gt;NotificationCenter를 활용해 데이터 전달하는 방법에 대해 알아볼까요?&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_edited_스크린샷 2024-11-06 오후 7.43.31.png&quot; data-origin-width=&quot;1066&quot; data-origin-height=&quot;1050&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkA2lo/btsKyqN8XPA/Mda3BqzTm1uqtoeRKptBu1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkA2lo/btsKyqN8XPA/Mda3BqzTm1uqtoeRKptBu1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkA2lo/btsKyqN8XPA/Mda3BqzTm1uqtoeRKptBu1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkA2lo%2FbtsKyqN8XPA%2FMda3BqzTm1uqtoeRKptBu1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;492&quot; data-filename=&quot;edited_edited_스크린샷 2024-11-06 오후 7.43.31.png&quot; data-origin-width=&quot;1066&quot; data-origin-height=&quot;1050&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;저는 1번 VC에서 2, 3번 VC로 데이터 전달이 필요했습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;1. NotificationCenter post&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1번 VC&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1730894722045&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;NotificationCenter.default.post(name: Notification.Name(&quot;notiName&quot;), object: nil, userInfo: [&quot;data&quot;: data])&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;name&lt;/b&gt;: NotificationCenter의 이름입니다. 특정 알림을 구분하는 용도로 사용합니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;b&gt;object&lt;/b&gt; : 특정 객체에 대해서만 알림을 받고 싶을 때 사용하면 됩니다. &lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;기본값은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;nil&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;로, 모든 객체에서 발생한 알림을 받습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;caret-color: #000000;&quot;&gt;&lt;b&gt;userInfo&lt;/b&gt;: &amp;nbsp;전달하고 싶은 데이터를 여기에 저장해서 전달합니다. 딕셔너리의 형태로 사용합니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1730895538537&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;NotificationCenter.default.post(name: .notiName, object: nil, userInfo: [&quot;data&quot;: data])

extension Notification.Name {
    static let notiName = Notification.Name(&quot;notiName&quot;)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: center;&quot;&gt;이름은 extension을 통해 따로 정의해서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;쓸 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. NotificationCenter Observer&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2, 3번 VC&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1730896003937&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;NotificationCenter.default.addObserver(self, 
                                        selector: #selector(self.receiveData), 
                                        name: .notiName, 
                                        object: nil)&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;self&lt;/b&gt;는 알림을 수신할 객체를 뜻합니다. 보통은 자기 자신이기 때문에 self를 씁니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;b&gt;selector&lt;/b&gt; : 알림을 받았을 때 호출될&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&amp;nbsp;메서드입니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;b&gt;name&lt;/b&gt; : NotificationCenter의 이름입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;object&lt;/b&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;: 알림을 발송한 객체이며,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;nil&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;은 모든 객체에서 발생한 알림을 수신합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1730896562627&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    @objc private func receiveData(_ noti: Notification) {
        print(#function)
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 함수를 만들어서 &lt;b&gt;selector&lt;/b&gt;에 넣어주면 됩니다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;3. Observer 제거해주기&lt;/h3&gt;
&lt;pre id=&quot;code_1730896652541&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    deinit {
        NotificationCenter.default.removeObserver(self)
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;메모리 누수를 방지하기 위해 꼭 옵저버를 제거해줍니다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>iOS/Swift</category>
      <author> Mango</author>
      <guid isPermaLink="true">https://island-developer.tistory.com/174</guid>
      <comments>https://island-developer.tistory.com/174#entry174comment</comments>
      <pubDate>Wed, 6 Nov 2024 21:44:02 +0900</pubDate>
    </item>
    <item>
      <title>[Swift] 구름 - 1차원 뿌요뿌요</title>
      <link>https://island-developer.tistory.com/173</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;AppleMango 의 사본.png&quot; data-origin-width=&quot;1500&quot; data-origin-height=&quot;600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HjjeX/btsImfAxgBH/fkeFBR9QEIIkRxOOZN42ik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HjjeX/btsImfAxgBH/fkeFBR9QEIIkRxOOZN42ik/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HjjeX/btsImfAxgBH/fkeFBR9QEIIkRxOOZN42ik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHjjeX%2FbtsImfAxgBH%2FfkeFBR9QEIIkRxOOZN42ik%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1500&quot; height=&quot;600&quot; data-filename=&quot;AppleMango 의 사본.png&quot; data-origin-width=&quot;1500&quot; data-origin-height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;문제 해결 과정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는 앞, 뒤를 비교해서 같은 값이 나올때 start, 다른 값이 나올때 end를 저장해 해당 부분을 빼주는 식으로 구현했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 하니깐 테스트 케이스는 통과했는데 제출에서 몇 개 통과가 안됐다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고보니 스택과 관련된 문제였고, 스택을 통해 구현해보기로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 스택을 하나 생성하고, block을 하나씩 집어넣으면서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;stack의 마지막 block과 현재 block이 같지 않을 때 마지막 block의 count가 m보다 크다면 마지막&amp;nbsp;block&amp;nbsp;삭제&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;stack의 마지막 block과 현재 block이 같다면 stack의 마지막 block의 Count += 1, 같지 않으면 새로 append 해주는 방식으로 구현했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중간에 이걸 반대로 생각한건 아닌데 아무튼 반대로 해도 될 줄 알아서 좀 막혔었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;나의 풀이&lt;/h3&gt;
&lt;pre id=&quot;code_1720013951539&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;func puyoPuyo(_ blocks: [String]) -&amp;gt; String {
	var stack = [(String, Int)]()
	for block in blocks {
		// stack의 마지막 block과 현재 block이 같지 않을 때
		if let last = stack.last, last.0 != block {
			// 마지막 block의 count가 m보다 크다면
			if let last = stack.last, last.1 &amp;gt;= m {
				// 마지막 block 삭제
				stack.removeLast()
			}
		}
		// stack의 마지막 block과 현재 block이 같다면
		if let last = stack.last, last.0 == block {
			// stack의 마지막 block의 Count += 1
			stack[stack.count - 1].1 += 1
		} else {
			// 같지 않으면 새로 append
			stack.append((block, 1))		
		}
	}
	
	// 마지막 남은 값이 m 이상이라면 삭제
	for (_, count) in stack {
		if count &amp;gt;= m {
			stack.removeLast()
		}
	}
	
	return stack.map { String(repeating: $0.0, count: $0.1) }.joined()
}

let input = readLine()!.split(separator: &quot; &quot;).map { Int(String($0))! }
let (n, m) = (input[0], input[1])
let blocks = readLine()!.map { String($0) }
let result = puyoPuyo(blocks)
print(result.count == 0 ? &quot;CLEAR!&quot; : result)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;blocks을 다 돌고 나왔을때 남아있는 값이 m 이상이면 삭제해줬다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;return 할때 block을 count만큼 반복해서 배열로 만들어서 joined해줬다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막 print할때 빈 배열이라면 CLEAR! 아니라면 result값을 그대로 출력해줬다.&lt;/p&gt;</description>
      <category>Algorithm/Swift</category>
      <category>1차원 뿌요뿌요</category>
      <category>구름</category>
      <category>스택</category>
      <author> Mango</author>
      <guid isPermaLink="true">https://island-developer.tistory.com/173</guid>
      <comments>https://island-developer.tistory.com/173#entry173comment</comments>
      <pubDate>Wed, 3 Jul 2024 22:45:25 +0900</pubDate>
    </item>
    <item>
      <title>[Swift] 백준 12933 - 오리</title>
      <link>https://island-developer.tistory.com/172</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;AppleMango .png&quot; data-origin-width=&quot;1500&quot; data-origin-height=&quot;600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PnPzA/btsH5ZytcBf/qbdrFAO9y9LcNIMIuQ0Pt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PnPzA/btsH5ZytcBf/qbdrFAO9y9LcNIMIuQ0Pt1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PnPzA/btsH5ZytcBf/qbdrFAO9y9LcNIMIuQ0Pt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPnPzA%2FbtsH5ZytcBf%2FqbdrFAO9y9LcNIMIuQ0Pt1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1500&quot; height=&quot;600&quot; data-filename=&quot;AppleMango .png&quot; data-origin-width=&quot;1500&quot; data-origin-height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;문제 해결 과정&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는 아래 예시처럼 quack / quack이라 두마리인줄 알았는데 알고보니 연속된 quack은 한마리였던거임!!&lt;br /&gt;그리고&amp;nbsp;울음소리를&amp;nbsp;전부&amp;nbsp;사용해야&amp;nbsp;한다는&amp;nbsp;부분이&amp;nbsp;좀&amp;nbsp;헷갈렸다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;514&quot; data-origin-height=&quot;246&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oDVSI/btsH7CaKviM/jFvxHDMuY4bhx6Syaa6tHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oDVSI/btsH7CaKviM/jFvxHDMuY4bhx6Syaa6tHK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oDVSI/btsH7CaKviM/jFvxHDMuY4bhx6Syaa6tHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoDVSI%2FbtsH7CaKviM%2FjFvxHDMuY4bhx6Syaa6tHK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;514&quot; height=&quot;246&quot; data-origin-width=&quot;514&quot; data-origin-height=&quot;246&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;그래서 정상적인 울음소리가 아닌 경우&lt;br /&gt;&lt;b&gt;-&amp;nbsp;q로&amp;nbsp;시작하지&amp;nbsp;않거나&lt;/b&gt;&lt;br /&gt;&lt;b&gt;-&amp;nbsp;k로&amp;nbsp;끝나지&amp;nbsp;않거나&lt;/b&gt;&lt;br /&gt;&lt;b&gt;- 울음소리 전체가 5로 나누어떨어지지 않으면 -1을 출력해주었다.&lt;/b&gt;&lt;/blockquote&gt;
&lt;pre id=&quot;code_1718888625161&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;duckSound[0] != &quot;q&quot; || duckSound[soundCnt-1] != &quot;k&quot; || soundCnt % 5 != 0&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 울음 소리의 수는 맞지만 윗 예시처럼 이상한 울음소리를 거르기 위해 아래와 같은 조건 추가했다.&lt;/p&gt;
&lt;pre id=&quot;code_1718888665660&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if duckSound[i] == &quot;q&quot; &amp;amp;&amp;amp; visited[i] == 0 {
      getDuckCnt(i)
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;getDuckCnt&lt;/h4&gt;
&lt;pre id=&quot;code_1718888807426&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;func getDuckCnt(_ start: Int) {
    var idx = 0 //quack용 index
    var isNewDuck = true //새로운 오리인지 아닌지
    for i in start..&amp;lt;soundCnt {
        if duckSound[i] == quack[idx] &amp;amp;&amp;amp; visited[i] == 0 {
            idx += 1
            visited[i] = 1
            if duckSound[i] == &quot;k&quot; {
                idx = 0
                if isNewDuck {
                    duckCnt += 1
                    isNewDuck = false
                }
            }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서는&amp;nbsp;quack&amp;nbsp;배열을&amp;nbsp;만들고,&amp;nbsp;quack&amp;nbsp;전용&amp;nbsp;idx를&amp;nbsp;만들어서&amp;nbsp;울음소리와&amp;nbsp;quack을&amp;nbsp;하나씩&amp;nbsp;비교하고&amp;nbsp;방문&amp;nbsp;처리&lt;br /&gt;새로운&amp;nbsp;오리인지&amp;nbsp;아닌지&amp;nbsp;확인해주는&amp;nbsp;변수를&amp;nbsp;추가&lt;br /&gt;만약에&amp;nbsp;새로운&amp;nbsp;오리라면&amp;nbsp;duckCnt&amp;nbsp;+=&amp;nbsp;1해주고&amp;nbsp;&lt;br /&gt;isNewDuck&amp;nbsp;=&amp;nbsp;false&amp;nbsp;바꿔주면서&amp;nbsp;&lt;br /&gt;k&amp;nbsp;다음&amp;nbsp;q가&amp;nbsp;오는&amp;nbsp;한마리의&amp;nbsp;오리가&amp;nbsp;우는&amp;nbsp;상황을&amp;nbsp;대비&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1718888864676&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if duckCnt == 0 || visited.contains(0) {
        print(-1)
    } else {
        print(duckCnt)
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오리의&amp;nbsp;수가&amp;nbsp;0이거나&amp;nbsp;방문하지&amp;nbsp;않은&amp;nbsp;울음소리가&amp;nbsp;있다면&lt;br /&gt;이&amp;nbsp;또한&amp;nbsp;정상적인&amp;nbsp;울음소리가&amp;nbsp;아니기&amp;nbsp;때문에&amp;nbsp;-1&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;나의 풀이&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1718888724194&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;func getDuckCnt(_ start: Int) {
    var idx = 0 //quack용 index
    var isNewDuck = true //새로운 오리인지 아닌지
    for i in start..&amp;lt;soundCnt {
        if duckSound[i] == quack[idx] &amp;amp;&amp;amp; visited[i] == 0 {
            idx += 1
            visited[i] = 1
            if duckSound[i] == &quot;k&quot; {
                idx = 0
                if isNewDuck {
                    duckCnt += 1
                    isNewDuck = false
                }
            }
        }
    }
}

let duckSound = readLine()!.map { String($0) }
let soundCnt = duckSound.count
var visited = Array(repeating: 0, count: soundCnt)
let quack = [&quot;q&quot;, &quot;u&quot;, &quot;a&quot;, &quot;c&quot;, &quot;k&quot;]
var duckCnt = 0 // 출력해야 할 오리 수

if duckSound[0] != &quot;q&quot; || duckSound[soundCnt-1] != &quot;k&quot; || soundCnt % 5 != 0 {
    print(-1)
} else {
    for i in 0..&amp;lt;soundCnt {
        if duckSound[i] == &quot;q&quot; &amp;amp;&amp;amp; visited[i] == 0 {
            getDuckCnt(i)
        }
    }
    if duckCnt == 0 || visited.contains(0) {
        print(-1)
    } else {
        print(duckCnt)
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Algorithm/Swift</category>
      <author> Mango</author>
      <guid isPermaLink="true">https://island-developer.tistory.com/172</guid>
      <comments>https://island-developer.tistory.com/172#entry172comment</comments>
      <pubDate>Thu, 20 Jun 2024 22:09:06 +0900</pubDate>
    </item>
    <item>
      <title>[Swift] 프로그래머스 - 특정 문자열로 끝나는 가장 긴 부분 문자열 찾기</title>
      <link>https://island-developer.tistory.com/171</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;RxSwift의 사본의 사본-19.png&quot; data-origin-width=&quot;1500&quot; data-origin-height=&quot;600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dwoDdd/btsH4gUWXu3/njLJBL5QzgfzzIIOO9KKb1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dwoDdd/btsH4gUWXu3/njLJBL5QzgfzzIIOO9KKb1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dwoDdd/btsH4gUWXu3/njLJBL5QzgfzzIIOO9KKb1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdwoDdd%2FbtsH4gUWXu3%2FnjLJBL5QzgfzzIIOO9KKb1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1500&quot; height=&quot;600&quot; data-filename=&quot;RxSwift의 사본의 사본-19.png&quot; data-origin-width=&quot;1500&quot; data-origin-height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;문제 해결 과정&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot;&gt;이 문제에 대한 내 계획은&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot;&gt;pat의 마지막 원소의 위치를 찾아서, 처음부터 pat의 마지막 원소까지 출력하기였다.&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #212529;&quot;&gt;&lt;span style=&quot;caret-color: #212529; background-color: #ffffff;&quot;&gt;그래서 suffix로 마지막 원소를 찾았고, 처음부터 pat까지 출력하면 되는데...&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #212529;&quot;&gt;&lt;span style=&quot;caret-color: #212529; background-color: #ffffff;&quot;&gt;이거 풀때는 Swift 문자열 다루는 방법을 전혀 모르는 상태라 아래와 같은 코드로 도전해봤다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;s&gt;&lt;span style=&quot;color: #212529;&quot;&gt;&lt;span style=&quot;caret-color: #212529; background-color: #ffffff;&quot;&gt;참고로 블로그 옮기는 중이다..&lt;/span&gt;&lt;/span&gt;&lt;/s&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1718796005393&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    let end = pat.suffix(1)
    let lastIndex = myString.lastIndex(of: end)
    return myString[0...lastIndex]&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;error: cannot convert value of type 'String.SubSequence' (aka 'Substring') to expected argument type 'String.Element' (aka 'Character')&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;나의 풀이&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1718796132443&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;func solution(_ myString:String, _ pat:String) -&amp;gt; String {
    let end = Character(String(pat.suffix(1)))
    if let lastIndex = myString.lastIndex(of: end) {
        let idx = myString.distance(from: myString.startIndex, to: lastIndex)
        let res = myString.prefix(idx+1)
        return String(res)
    }
    return &quot;&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot;&gt;우선 lastIndex(of:)를 사용하기 위해&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot;&gt;String.SubSequence인 end값을 Character로 변환해주었다.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot;&gt;그리고 distance(from:to:)는 from과 to의 거리를 리턴해주는데&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot;&gt;이걸 사용해서 거리를 구하고 &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot;&gt;prefix + 1을 통해 결과를 도출해냈다.&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot;&gt;prefix + 1을 한 이유는 prefix는 문자열의 길이만큼만 가져오기 때문이다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Algorithm/Swift</category>
      <author> Mango</author>
      <guid isPermaLink="true">https://island-developer.tistory.com/171</guid>
      <comments>https://island-developer.tistory.com/171#entry171comment</comments>
      <pubDate>Wed, 19 Jun 2024 20:26:13 +0900</pubDate>
    </item>
    <item>
      <title>SwiftUI - Sticky Header</title>
      <link>https://island-developer.tistory.com/163</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;RxSwift의 사본-13.png&quot; data-origin-width=&quot;1500&quot; data-origin-height=&quot;600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b8ZdM2/btsd6tN6Xvm/iUmLdFKvqVfknsxpWQmiq0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b8ZdM2/btsd6tN6Xvm/iUmLdFKvqVfknsxpWQmiq0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b8ZdM2/btsd6tN6Xvm/iUmLdFKvqVfknsxpWQmiq0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb8ZdM2%2Fbtsd6tN6Xvm%2FiUmLdFKvqVfknsxpWQmiq0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1500&quot; height=&quot;600&quot; data-filename=&quot;RxSwift의 사본-13.png&quot; data-origin-width=&quot;1500&quot; data-origin-height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;안녕하세요 :D 망고입니다 &lt;/span&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;SwiftUI로 Sticky Header 만드는 방법에 대해 알아보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #555555; text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Sticky Header란?&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;사용자가 화면을 아래로 스크롤 할 때 화면 상단에 고정되는 뷰를 말합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;s&gt;&lt;span style=&quot;color: #000000;&quot;&gt;처음엔 Sticky Header라는 용어를 몰라서 한참 찾아봄 ㅠㅠ&lt;/span&gt;&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Header.gif&quot; data-origin-width=&quot;3584&quot; data-origin-height=&quot;2240&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cumkje/btsdZMhpSjm/CgOByU1prjrxtHTzb4BZc1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cumkje/btsdZMhpSjm/CgOByU1prjrxtHTzb4BZc1/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cumkje/btsdZMhpSjm/CgOByU1prjrxtHTzb4BZc1/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/cumkje/btsdZMhpSjm/CgOByU1prjrxtHTzb4BZc1/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3584&quot; height=&quot;2240&quot; data-filename=&quot;Header.gif&quot; data-origin-width=&quot;3584&quot; data-origin-height=&quot;2240&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;LazyVStack의 pinnedViews라는 옵션을 통해 설정할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;[.sectionHeaders]를 통해 상단에 고정시키도록 설정했고,&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;post, liked 부분을 filterBar로 구현 한 다음&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;Section(header: filterBar)에 넣어주었다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1683296368790&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    private var StickyHeader: some View {
        LazyVStack(pinnedViews: [.sectionHeaders]) {
            Section(header: filterBar) {
                코드
            }
        }
    }&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1683296653590&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    private var filterBar: some View {
        HStack {
		코드
        }
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>iOS/SwiftUI</category>
      <category>sticky header</category>
      <category>SwiftUI</category>
      <author> Mango</author>
      <guid isPermaLink="true">https://island-developer.tistory.com/163</guid>
      <comments>https://island-developer.tistory.com/163#entry163comment</comments>
      <pubDate>Tue, 21 Mar 2023 22:27:38 +0900</pubDate>
    </item>
    <item>
      <title>SwiftUI - TabView</title>
      <link>https://island-developer.tistory.com/159</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;RxSwift의 사본-9.png&quot; data-origin-width=&quot;1500&quot; data-origin-height=&quot;600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Y9LAo/btr37BwohDl/Rk2oSVgIngaZfGAoN3q9b1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Y9LAo/btr37BwohDl/Rk2oSVgIngaZfGAoN3q9b1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Y9LAo/btr37BwohDl/Rk2oSVgIngaZfGAoN3q9b1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FY9LAo%2Fbtr37BwohDl%2FRk2oSVgIngaZfGAoN3q9b1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1500&quot; height=&quot;600&quot; data-filename=&quot;RxSwift의 사본-9.png&quot; data-origin-width=&quot;1500&quot; data-origin-height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;안녕하세요 :D 망고입니다 &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;SwiftUI로 TabView 만드는 방법에 대해 알아보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;TabView&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TabView는 Uikit의 UITabBarController라고 생각하면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만드는 방법은 Uikit에 비해 매우 간단합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1678947526574&quot; class=&quot;swift&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    var body: some View {
        TabView {
            FirstView()
                .tabItem {
                    Image(systemName: &quot;1.circle&quot;)
                    Text(&quot;First&quot;)
                }
            
            SecondView()
                .tabItem {
                    Image(systemName: &quot;2.circle&quot;)
                    Text(&quot;second&quot;)
                }

            ThirdView()
                .tabItem {
                    Image(systemName: &quot;3.circle&quot;)
                    Text(&quot;third&quot;)
                }
        }
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TabView안에 각각의 View를 넣고 tabItem을 통해 이미지와 텍스트를 지정해줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqq721/btr35xuzui0/Uy7idjEi0Ev5oUNBugjw9k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqq721/btr35xuzui0/Uy7idjEi0Ev5oUNBugjw9k/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;630&quot; data-origin-height=&quot;1314&quot; data-filename=&quot;스크린샷 2023-03-16 오후 3.12.42.png&quot; width=&quot;300&quot; height=&quot;626&quot; data-widthpercent=&quot;33.33&quot; style=&quot;width: 32.55814%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqq721/btr35xuzui0/Uy7idjEi0Ev5oUNBugjw9k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbqq721%2Fbtr35xuzui0%2FUy7idjEi0Ev5oUNBugjw9k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;630&quot; height=&quot;1314&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lHpb2/btr36HjtXHw/yI1CTeCE8ixmPVPzIAVMK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lHpb2/btr36HjtXHw/yI1CTeCE8ixmPVPzIAVMK1/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;630&quot; data-origin-height=&quot;1314&quot; data-filename=&quot;스크린샷 2023-03-16 오후 3.12.55.png&quot; width=&quot;300&quot; height=&quot;626&quot; data-widthpercent=&quot;33.33&quot; style=&quot;width: 32.55814%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lHpb2/btr36HjtXHw/yI1CTeCE8ixmPVPzIAVMK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlHpb2%2Fbtr36HjtXHw%2FyI1CTeCE8ixmPVPzIAVMK1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;630&quot; height=&quot;1314&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ONYht/btr4gWlCOgP/6miPZDdycaf4kwudiTUMkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ONYht/btr4gWlCOgP/6miPZDdycaf4kwudiTUMkk/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;630&quot; data-origin-height=&quot;1314&quot; data-filename=&quot;스크린샷 2023-03-16 오후 3.13.05.png&quot; width=&quot;300&quot; height=&quot;626&quot; data-widthpercent=&quot;33.34&quot; style=&quot;width: 32.55814%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ONYht/btr4gWlCOgP/6miPZDdycaf4kwudiTUMkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FONYht%2Fbtr4gWlCOgP%2F6miPZDdycaf4kwudiTUMkk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;630&quot; height=&quot;1314&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>iOS/SwiftUI</category>
      <category>swiftUI tabview</category>
      <category>tabView</category>
      <author> Mango</author>
      <guid isPermaLink="true">https://island-developer.tistory.com/159</guid>
      <comments>https://island-developer.tistory.com/159#entry159comment</comments>
      <pubDate>Thu, 16 Mar 2023 15:24:06 +0900</pubDate>
    </item>
    <item>
      <title>SwiftUI - Apple Sign In With Firebase</title>
      <link>https://island-developer.tistory.com/157</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;RxSwift의 사본-8.png&quot; data-origin-width=&quot;1500&quot; data-origin-height=&quot;600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wquae/btr3TGqjaxc/dKITMoBiByfwmLaKozSDh1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wquae/btr3TGqjaxc/dKITMoBiByfwmLaKozSDh1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wquae/btr3TGqjaxc/dKITMoBiByfwmLaKozSDh1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fwquae%2Fbtr3TGqjaxc%2FdKITMoBiByfwmLaKozSDh1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1500&quot; height=&quot;600&quot; data-filename=&quot;RxSwift의 사본-8.png&quot; data-origin-width=&quot;1500&quot; data-origin-height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;안녕하세요 :D 망고입니다 &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;SwiftUI로 Firebase와 연동한 Apple 로그인 하는 방법에 대해 알아보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;Firebase&lt;/h2&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;Firebase 홈페이지에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;새 프로젝트를 생성&lt;/b&gt;하고&amp;nbsp;&lt;b&gt;Authentication&lt;/b&gt;로 간 뒤&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Sign-in-method&lt;/b&gt;에서 새 제공업체 추가를 누르고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Apple을 추가&lt;/b&gt;해준다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-03-14 오후 5.34.37.png&quot; data-origin-width=&quot;2116&quot; data-origin-height=&quot;458&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dRMdKR/btr3HVWONCY/TclzUY8YQ4hBnY1OYqhsgk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dRMdKR/btr3HVWONCY/TclzUY8YQ4hBnY1OYqhsgk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dRMdKR/btr3HVWONCY/TclzUY8YQ4hBnY1OYqhsgk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdRMdKR%2Fbtr3HVWONCY%2FTclzUY8YQ4hBnY1OYqhsgk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2116&quot; height=&quot;458&quot; data-filename=&quot;스크린샷 2023-03-14 오후 5.34.37.png&quot; data-origin-width=&quot;2116&quot; data-origin-height=&quot;458&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-03-14 오후 5.34.10.png&quot; data-origin-width=&quot;360&quot; data-origin-height=&quot;398&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xwY1X/btr3J2HVErG/9Ip6aKCVmQnPYBURgVwnPk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xwY1X/btr3J2HVErG/9Ip6aKCVmQnPYBURgVwnPk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xwY1X/btr3J2HVErG/9Ip6aKCVmQnPYBURgVwnPk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxwY1X%2Fbtr3J2HVErG%2F9Ip6aKCVmQnPYBURgVwnPk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;360&quot; height=&quot;398&quot; data-filename=&quot;스크린샷 2023-03-14 오후 5.34.10.png&quot; data-origin-width=&quot;360&quot; data-origin-height=&quot;398&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;그 다음 Xcode로 돌아와 SPM을 이용해 firebase SDK(&lt;a style=&quot;background-color: #e6f5ff; color: #0070d1; text-align: start;&quot; href=&quot;https://github.com/firebase/firebase-ios-sdk.git&quot;&gt;github.com/firebase/firebase-ios-sdk.git&lt;/a&gt;) 를 설치한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-03-13 오후 8.00.28.png&quot; data-origin-width=&quot;1550&quot; data-origin-height=&quot;496&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kKe8H/btr3GT4V9j9/ImF1bPsgM9WUpIuAwtR5Sk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kKe8H/btr3GT4V9j9/ImF1bPsgM9WUpIuAwtR5Sk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kKe8H/btr3GT4V9j9/ImF1bPsgM9WUpIuAwtR5Sk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkKe8H%2Fbtr3GT4V9j9%2FImF1bPsgM9WUpIuAwtR5Sk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1550&quot; height=&quot;496&quot; data-filename=&quot;스크린샷 2023-03-13 오후 8.00.28.png&quot; data-origin-width=&quot;1550&quot; data-origin-height=&quot;496&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;PROJECT -&amp;gt; Package Dependencies -&amp;gt; &amp;nbsp;+ 버튼 클릭&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-03-13 오후 8.00.56.png&quot; data-origin-width=&quot;752&quot; data-origin-height=&quot;150&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mWsKp/btr3uEAwSZO/G7sNoH89LuP35ucKiKoYZK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mWsKp/btr3uEAwSZO/G7sNoH89LuP35ucKiKoYZK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mWsKp/btr3uEAwSZO/G7sNoH89LuP35ucKiKoYZK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmWsKp%2Fbtr3uEAwSZO%2FG7sNoH89LuP35ucKiKoYZK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;752&quot; height=&quot;150&quot; data-filename=&quot;스크린샷 2023-03-13 오후 8.00.56.png&quot; data-origin-width=&quot;752&quot; data-origin-height=&quot;150&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;firebase-ios-sdk를 설치해주고&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-03-13 오후 8.03.15.png&quot; data-origin-width=&quot;1288&quot; data-origin-height=&quot;572&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l9cPi/btr3BvXzFj8/8XV0kWkMKjRgvO6SPgKjHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l9cPi/btr3BvXzFj8/8XV0kWkMKjRgvO6SPgKjHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l9cPi/btr3BvXzFj8/8XV0kWkMKjRgvO6SPgKjHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl9cPi%2Fbtr3BvXzFj8%2F8XV0kWkMKjRgvO6SPgKjHk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1288&quot; height=&quot;572&quot; data-filename=&quot;스크린샷 2023-03-13 오후 8.03.15.png&quot; data-origin-width=&quot;1288&quot; data-origin-height=&quot;572&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;FirebaseAuth를 선택해 Add Packge해준다.&lt;/p&gt;
&lt;figure data-ke-type=&quot;image&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; data-ke-style=&quot;alignCenter&quot;&gt;
&lt;figcaption style=&quot;display: none;&quot;&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Apple&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Apple 로그인을 사용하기 위해서 &lt;a href=&quot;https://developer.apple.com/account/resources/identifiers/list&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://developer.apple.com/account/resources/identifiers/list&lt;/a&gt;&amp;nbsp;로 이동한 뒤&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-03-13 오후 8.31.48.png&quot; data-origin-width=&quot;1118&quot; data-origin-height=&quot;296&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cek3w1/btr3Lq8fJd8/VcHC1Qlmgao9STgaLqLqkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cek3w1/btr3Lq8fJd8/VcHC1Qlmgao9STgaLqLqkk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cek3w1/btr3Lq8fJd8/VcHC1Qlmgao9STgaLqLqkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcek3w1%2Fbtr3Lq8fJd8%2FVcHC1Qlmgao9STgaLqLqkk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;132&quot; data-filename=&quot;스크린샷 2023-03-13 오후 8.31.48.png&quot; data-origin-width=&quot;1118&quot; data-origin-height=&quot;296&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Identifiers&lt;/b&gt;에서 &lt;b&gt;+버튼&lt;/b&gt;을 눌러 추가해준다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-03-13 오후 8.32.32.png&quot; data-origin-width=&quot;1754&quot; data-origin-height=&quot;324&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCbuKJ/btr3GTYbuBx/lzeavmklwxkKugmMrFuns0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCbuKJ/btr3GTYbuBx/lzeavmklwxkKugmMrFuns0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCbuKJ/btr3GTYbuBx/lzeavmklwxkKugmMrFuns0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCbuKJ%2Fbtr3GTYbuBx%2FlzeavmklwxkKugmMrFuns0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;92&quot; data-filename=&quot;스크린샷 2023-03-13 오후 8.32.32.png&quot; data-origin-width=&quot;1754&quot; data-origin-height=&quot;324&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;App IDs&lt;/b&gt;를 클릭하고 &lt;b&gt;Continue&lt;/b&gt; 해준다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-03-13 오후 8.34.09.png&quot; data-origin-width=&quot;1886&quot; data-origin-height=&quot;726&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c5cTpj/btr3J27CYJb/zWfXp3mUk8l9Jlt8Afa0Ak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c5cTpj/btr3J27CYJb/zWfXp3mUk8l9Jlt8Afa0Ak/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c5cTpj/btr3J27CYJb/zWfXp3mUk8l9Jlt8Afa0Ak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc5cTpj%2Fbtr3J27CYJb%2FzWfXp3mUk8l9Jlt8Afa0Ak%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;192&quot; data-filename=&quot;스크린샷 2023-03-13 오후 8.34.09.png&quot; data-origin-width=&quot;1886&quot; data-origin-height=&quot;726&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: left;&quot;&gt;Description과 &lt;span style=&quot;color: #000000; text-align: left;&quot;&gt;Bundle ID를 넣어준다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-03-13 오후 8.35.00.png&quot; data-origin-width=&quot;710&quot; data-origin-height=&quot;118&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6mN7a/btr3LHIUQRg/60C0w5n2HTjWJ6eviXO9EK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6mN7a/btr3LHIUQRg/60C0w5n2HTjWJ6eviXO9EK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6mN7a/btr3LHIUQRg/60C0w5n2HTjWJ6eviXO9EK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6mN7a%2Fbtr3LHIUQRg%2F60C0w5n2HTjWJ6eviXO9EK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;710&quot; height=&quot;118&quot; data-filename=&quot;스크린샷 2023-03-13 오후 8.35.00.png&quot; data-origin-width=&quot;710&quot; data-origin-height=&quot;118&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: left;&quot;&gt;&lt;b&gt;Capabilities&lt;/b&gt;에서 &lt;b&gt;Sign In with Apple&lt;/b&gt;을 선택하고 저장해준다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-03-13 오후 8.48.35.png&quot; data-origin-width=&quot;1964&quot; data-origin-height=&quot;740&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/baCQVZ/btr3HT4pgBD/ogtgjNORUxEpL10rZ15Zh1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/baCQVZ/btr3HT4pgBD/ogtgjNORUxEpL10rZ15Zh1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/baCQVZ/btr3HT4pgBD/ogtgjNORUxEpL10rZ15Zh1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbaCQVZ%2Fbtr3HT4pgBD%2FogtgjNORUxEpL10rZ15Zh1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;226&quot; data-filename=&quot;스크린샷 2023-03-13 오후 8.48.35.png&quot; data-origin-width=&quot;1964&quot; data-origin-height=&quot;740&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;Xcode로 돌아가 &lt;b&gt;TARGETS&lt;/b&gt; -&amp;gt; &lt;b&gt;Signing&amp;amp;Capabilities &lt;/b&gt;에서 + 버튼을 눌러 &lt;b&gt;Sign in with Apple&lt;/b&gt;을 추가해준다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;Code&lt;/h2&gt;
&lt;pre id=&quot;code_1678795663179&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import AuthenticationServices&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1678792512562&quot; class=&quot;swift&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SignInWithAppleButton { (request) in
                        loginData.nonce = randomNonceString()
                        request.requestedScopes = [.email, .fullName]
                        request.nonce = sha256(loginData.nonce)
                        
                    } onCompletion: { (result) in
                        switch result {
                        case .success(let user):
                            print(&quot;success&quot;)
                            guard let credential = user.credential as? ASAuthorizationAppleIDCredential else {
                                print(&quot;error with firebase&quot;)
                                return
                            }
                            loginData.authenticate(credential: credential)
                        case .failure(let error):
                            print(error.localizedDescription)
                        }
                    }&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;원하는 위치에 &lt;b&gt;SignInWithAppleButton&amp;nbsp;&lt;/b&gt;만들어준다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;pre id=&quot;code_1678795669368&quot; class=&quot;elm&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import Firebase
import CryptoKit
import AuthenticationServices&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1678792457494&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class LoginViewModel: ObservableObject {
    
    @Published var nonce = &quot;&quot;
    
    func authenticate(credential: ASAuthorizationAppleIDCredential) {
        //getting token
        guard let token = credential.identityToken else {
            print(&quot;error with firebase&quot;)
            return
        }
        
        guard let tokenString = String(data: token, encoding: .utf8) else {
            print(&quot;error with token&quot;)
            return
        }
        
        let firebaseCredential = OAuthProvider.credential(withProviderID: &quot;apple.com&quot;, idToken: tokenString, rawNonce: nonce)
        Auth.auth().signIn(with: firebaseCredential) { result, err in
            if let err = err {
                print(err.localizedDescription)
            }
            
            print(&quot;로그인 완료&quot;)
        }
    }
}

// Helper for Apple Login with Firebase
func sha256(_ input: String) -&amp;gt; String {
    let inputData = Data(input.utf8)
    let hashedData = SHA256.hash(data: inputData)
    let hashString = hashedData.compactMap {
        String(format: &quot;%02x&quot;, $0)
    }.joined()
    
    return hashString
}

func randomNonceString(length: Int = 32) -&amp;gt; String {
    precondition(length &amp;gt; 0)
    let charset: [Character] =
    Array(&quot;0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._&quot;)
    var result = &quot;&quot;
    var remainingLength = length
    
    while remainingLength &amp;gt; 0 {
        let randoms: [UInt8] = (0 ..&amp;lt; 16).map { _ in
            var random: UInt8 = 0
            let errorCode = SecRandomCopyBytes(kSecRandomDefault, 1, &amp;amp;random)
            if errorCode != errSecSuccess {
                fatalError(
                    &quot;Unable to generate nonce. SecRandomCopyBytes failed with OSStatus \(errorCode)&quot;
                )
            }
            return random
        }
        
        randoms.forEach { random in
            if remainingLength == 0 {
                return
            }
            
            if random &amp;lt; charset.count {
                result.append(charset[Int(random)])
                remainingLength -= 1
            }
        }
    }
    
    return result
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;pre id=&quot;code_1678795828056&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import SwiftUI
//import Firebase

@main
struct 앱 이름: App {
    
    //@UIApplicationDelegateAdaptor(AppDelegate.self) var delegate 
    
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

/*
class AppDelegate: NSObject, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -&amp;gt; Bool {
        FirebaseApp.configure()
        return true
    }
}
*/&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;주석 처리 된 부분을 추가해준다.&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;Firebase로 가면 로그인이 된걸 확인할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-03-14 오후 5.29.51.png&quot; data-origin-width=&quot;2116&quot; data-origin-height=&quot;676&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/G2zWf/btr3S0916Tl/aAi54s32dJXvMrCPvrkXek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/G2zWf/btr3S0916Tl/aAi54s32dJXvMrCPvrkXek/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/G2zWf/btr3S0916Tl/aAi54s32dJXvMrCPvrkXek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FG2zWf%2Fbtr3S0916Tl%2FaAi54s32dJXvMrCPvrkXek%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2116&quot; height=&quot;676&quot; data-filename=&quot;스크린샷 2023-03-14 오후 5.29.51.png&quot; data-origin-width=&quot;2116&quot; data-origin-height=&quot;676&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>iOS/SwiftUI</category>
      <category>Apple Login</category>
      <category>Firebase</category>
      <category>SwiftUI Apple Login</category>
      <author> Mango</author>
      <guid isPermaLink="true">https://island-developer.tistory.com/157</guid>
      <comments>https://island-developer.tistory.com/157#entry157comment</comments>
      <pubDate>Tue, 14 Mar 2023 21:19:59 +0900</pubDate>
    </item>
    <item>
      <title>SwiftUI - System Icons</title>
      <link>https://island-developer.tistory.com/153</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;RxSwift의 사본-11.png&quot; data-origin-width=&quot;1500&quot; data-origin-height=&quot;600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SVOoe/btsajdpG94i/KXLLpKnBtb9QSTjBRSXkv0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SVOoe/btsajdpG94i/KXLLpKnBtb9QSTjBRSXkv0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SVOoe/btsajdpG94i/KXLLpKnBtb9QSTjBRSXkv0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSVOoe%2FbtsajdpG94i%2FKXLLpKnBtb9QSTjBRSXkv0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1500&quot; height=&quot;600&quot; data-filename=&quot;RxSwift의 사본-11.png&quot; data-origin-width=&quot;1500&quot; data-origin-height=&quot;600&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;안녕하세요 :D 망고입니다 &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;SwiftUI의 System&amp;nbsp;Icons에 대해 알아보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #555555; text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;System Icons&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #555555; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;Apple에서 기본 제공되는 아이콘들이다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2 style=&quot;color: #555555; text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 style=&quot;color: #555555; text-align: left;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;기본적인 사용 방법&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1681648082528&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Image(systemName: &quot;아이콘 이름&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1681648110679&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Image(systemName: &quot;heart&quot;) //빈 아이콘
Image(systemName: &quot;heart.fill&quot;) //채워진 아이콘&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;이런식으로 systemName: 아이콘 이름을 해주면 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;아이콘 이름은 &lt;a href=&quot;https://developer.apple.com/sf-symbols/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://developer.apple.com/sf-symbols/&lt;/a&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;을 다운 받으면 편하게 볼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-04-16 오후 9.33.29.png&quot; data-origin-width=&quot;1702&quot; data-origin-height=&quot;1188&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dj3hu8/btsahzT7uGy/TyF6UgVTkf1lJNYFlbyY2k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dj3hu8/btsahzT7uGy/TyF6UgVTkf1lJNYFlbyY2k/img.png&quot; data-alt=&quot;이런식으로 편하게 확인 가능!&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dj3hu8/btsahzT7uGy/TyF6UgVTkf1lJNYFlbyY2k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdj3hu8%2FbtsahzT7uGy%2FTyF6UgVTkf1lJNYFlbyY2k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;707&quot; height=&quot;493&quot; data-filename=&quot;스크린샷 2023-04-16 오후 9.33.29.png&quot; data-origin-width=&quot;1702&quot; data-origin-height=&quot;1188&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이런식으로 편하게 확인 가능!&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;옵션들&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1681648178384&quot; class=&quot;less&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.font(.system(size: 36)) // 크기변경
.foregroundColor(.red) // 색상변경&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1681648202044&quot; class=&quot;swift&quot; data-ke-language=&quot;swift&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.resizable()
.scaledToFit() //or .scaledToFill()
.frame(width: 200, height: 200) //프레임 크기에 맞게 크기변경
.clipped() // 프레임 크기 넘어간거 잘라줌&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>iOS/SwiftUI</category>
      <category>Icon</category>
      <category>SwiftUI</category>
      <author> Mango</author>
      <guid isPermaLink="true">https://island-developer.tistory.com/153</guid>
      <comments>https://island-developer.tistory.com/153#entry153comment</comments>
      <pubDate>Thu, 9 Mar 2023 14:22:01 +0900</pubDate>
    </item>
  </channel>
</rss>