<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>寫程式 &#8211; 隨心所欲</title>
	<atom:link href="https://doeverythingiwant.com/category/coding/feed/" rel="self" type="application/rss+xml" />
	<link>https://doeverythingiwant.com</link>
	<description>iOS Developer 的隨筆記錄</description>
	<lastBuildDate>Sun, 08 Mar 2026 09:39:52 +0000</lastBuildDate>
	<language>zh-TW</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://doeverythingiwant.com/wp-content/uploads/2025/08/cropped-0802.png</url>
	<title>寫程式 &#8211; 隨心所欲</title>
	<link>https://doeverythingiwant.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>[AI] Xcode 26 與 AI</title>
		<link>https://doeverythingiwant.com/ai-xcode-26-and-ai/</link>
					<comments>https://doeverythingiwant.com/ai-xcode-26-and-ai/#respond</comments>
		
		<dc:creator><![CDATA[艾普利]]></dc:creator>
		<pubDate>Sun, 08 Mar 2026 09:39:49 +0000</pubDate>
				<category><![CDATA[寫程式]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[Apple intelligence]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[Xcode]]></category>
		<guid isPermaLink="false">https://doeverythingiwant.com/?p=2512</guid>

					<description><![CDATA[Photo by Immo Wegmann on Unspl&#8230;]]></description>
										<content:encoded><![CDATA[
<p class="has-text-align-center">Photo by <a href="https://unsplash.com/@tinkerman?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" target="_blank" rel="noopener">Immo Wegmann</a> on <a href="https://unsplash.com/photos/a-piece-of-cardboard-with-a-keyboard-appearing-through-it-vi1HXPw6hyw?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" target="_blank" rel="noopener">Unsplash</a></p>



<p>Xcode 26 終於可以使用 AI 啦~~雖然去年的發表了，我因為公司在趕專案累到爆，回家就不想開電腦，前一陣子才開始使用，覺得很好玩(?)</p>



<p>不過，相信很多人應該都有用 Claude code 這位神奇的夥伴，和在 Xcode 裡直接使用體驗不太一樣。 </p>



<p>這篇簡單寫一下要怎麼使用，最後加上我個人的小心得</p>



<span id="more-2512"></span>



<h2 class="wp-block-heading">前置作業</h2>



<ul class="wp-block-list">
<li>需要有 Xcode 26</li>



<li>macOS 需要升到Tahoe</li>



<li>ChatGPT 帳號或 Claude 的付費帳號<br></li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Xcode 26</h2>



<p>設定 AI Tool 的方式，先點開 Xcode 的 Setting </p>


<div class="wp-block-image">
<figure class="aligncenter size-large is-resized"><img fetchpriority="high" decoding="async" width="470" height="578" src="https://doeverythingiwant.com/wp-content/uploads/2026/03/AI01.png" alt="" class="wp-image-2514" style="width:446px;height:auto" srcset="https://doeverythingiwant.com/wp-content/uploads/2026/03/AI01.png 470w, https://doeverythingiwant.com/wp-content/uploads/2026/03/AI01-244x300.png 244w" sizes="(max-width: 470px) 100vw, 470px" /></figure>
</div>


<p>在左側選單上可以看到 Intelligence 的選項，Xcode 內建 ChatGPT 與 Claude ，只要點下去登入就可以了，ChatGPT 免費帳號就可以使用，但 Claude 必須要是付費帳號才可以使用 。</p>


<div class="wp-block-image">
<figure class="aligncenter size-large is-resized"><img decoding="async" width="1024" height="822" src="https://doeverythingiwant.com/wp-content/uploads/2026/03/AI02-1024x822.png" alt="" class="wp-image-2515" style="aspect-ratio:1.2457363416976752;width:730px;height:auto" srcset="https://doeverythingiwant.com/wp-content/uploads/2026/03/AI02-1024x822.png 1024w, https://doeverythingiwant.com/wp-content/uploads/2026/03/AI02-300x241.png 300w, https://doeverythingiwant.com/wp-content/uploads/2026/03/AI02-768x617.png 768w, https://doeverythingiwant.com/wp-content/uploads/2026/03/AI02-1536x1233.png 1536w, https://doeverythingiwant.com/wp-content/uploads/2026/03/AI02-1170x939.png 1170w, https://doeverythingiwant.com/wp-content/uploads/2026/03/AI02-585x470.png 585w, https://doeverythingiwant.com/wp-content/uploads/2026/03/AI02.png 1724w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>
</div>


<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">使用方式</h2>


<div class="wp-block-image is-style-default">
<figure class="alignleft size-full is-resized"><img decoding="async" width="784" height="2140" src="https://doeverythingiwant.com/wp-content/uploads/2026/03/AI03.png" alt="" class="wp-image-2518" style="aspect-ratio:0.3663558394999438;width:240px;height:auto" srcset="https://doeverythingiwant.com/wp-content/uploads/2026/03/AI03.png 784w, https://doeverythingiwant.com/wp-content/uploads/2026/03/AI03-110x300.png 110w, https://doeverythingiwant.com/wp-content/uploads/2026/03/AI03-375x1024.png 375w, https://doeverythingiwant.com/wp-content/uploads/2026/03/AI03-768x2096.png 768w, https://doeverythingiwant.com/wp-content/uploads/2026/03/AI03-563x1536.png 563w, https://doeverythingiwant.com/wp-content/uploads/2026/03/AI03-750x2048.png 750w, https://doeverythingiwant.com/wp-content/uploads/2026/03/AI03-585x1597.png 585w" sizes="(max-width: 784px) 100vw, 784px" /></figure>
</div>


<p>首先，要切到 AI 功能，可以由圖示中的 (1) 的按鈕作切換</p>



<p>(2) 的按鈕可以選擇想要使用的AI 模型是哪一種</p>



<p>(3) 可以選擇對話串</p>



<p>(4) 是歷史記錄，不過，不知道是不是因為我使用的是免費帳號，只要重開Xcode 後，歷史記錄就會消失了</p>



<p>(5) 就是下Prompt 的地方</p>



<p></p>



<p></p>



<p></p>



<p></p>



<p></p>



<p></p>



<p></p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Coding</h2>



<p>在範例圖中，我下了「在頂部加上搜尋列」，它就會自動幫我修改程式，會先告訴你會怎麼調整，然後就會直接調整了。</p>



<p>AI 調整的部分會用彩色Highlight 標示，一般有使用 Git 的話，也會用單一顏色來表示調整過的地方，說不定Apple 就是為了特別區別自己調整的與 AI 調整的才用彩色Highlight。</p>



<p>手機使用 AI 的時候也會有彩色Highlight出現，Apple 就是這一點我覺得做得很不錯，統一提示，只要在Apple 的產品看到彩色Highlight就會知道是AI 的東西</p>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="2334" height="1390" src="https://doeverythingiwant.com/wp-content/uploads/2026/03/AI04.png" alt="" class="wp-image-2519" srcset="https://doeverythingiwant.com/wp-content/uploads/2026/03/AI04.png 2334w, https://doeverythingiwant.com/wp-content/uploads/2026/03/AI04-300x179.png 300w, https://doeverythingiwant.com/wp-content/uploads/2026/03/AI04-1024x610.png 1024w, https://doeverythingiwant.com/wp-content/uploads/2026/03/AI04-768x457.png 768w, https://doeverythingiwant.com/wp-content/uploads/2026/03/AI04-1536x915.png 1536w, https://doeverythingiwant.com/wp-content/uploads/2026/03/AI04-2048x1220.png 2048w, https://doeverythingiwant.com/wp-content/uploads/2026/03/AI04-1920x1143.png 1920w, https://doeverythingiwant.com/wp-content/uploads/2026/03/AI04-1170x697.png 1170w, https://doeverythingiwant.com/wp-content/uploads/2026/03/AI04-585x348.png 585w" sizes="(max-width: 2334px) 100vw, 2334px" /></figure>
</div>


<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">心得</h2>



<p>在 Xcode 使用 AI 就是這麼簡單，我個人覺得比 Claude code 的入門簡單一點，不過，Claude code 能做的事情很多，多學一點完全沒有問題。</p>



<p>在上面的範例中，下完指令之後它就會自動修改程式，實際上，若使用在即有專案它遇到問題的時候也是會先詢問，例如「這會影響到某個檔案是否需要一起調整」、「這需要看某個檔案是否可以檢視它」之類的。</p>



<p>若是請它調整即有的程式，我會先要求提出調整計畫，確認它會修改什麼、怎麼修改，才讓它執行，不會一下子就讓它調整。</p>



<p>當把AI 做為小幫手的時候，比較需要學習的是Prompt 要怎麼下，它寫出來的東西也要Review 。 我個人這陣子的使用心得是覺得很有趣，當然也會有覺得害怕的部分，但有趣佔大多數，它會寫出一些我從來沒有想過的方式，也可以學習，就是和過去一樣「把好的東西學起來」。</p>



<p>最後祝大家 Coding 愉快</p>



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://doeverythingiwant.com/ai-xcode-26-and-ai/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>[SwiftUI] AttributedString and Hyperlink</title>
		<link>https://doeverythingiwant.com/swiftui-attributedstring-and-hyperlink/</link>
					<comments>https://doeverythingiwant.com/swiftui-attributedstring-and-hyperlink/#respond</comments>
		
		<dc:creator><![CDATA[艾普利]]></dc:creator>
		<pubDate>Sun, 18 May 2025 09:33:16 +0000</pubDate>
				<category><![CDATA[寫程式]]></category>
		<category><![CDATA[AttributedString]]></category>
		<category><![CDATA[Hyperlink]]></category>
		<category><![CDATA[iOS]]></category>
		<guid isPermaLink="false">https://doeverythingiwant.com/?p=2466</guid>

					<description><![CDATA[Photo by Vladislav Klapin on U&#8230;]]></description>
										<content:encoded><![CDATA[
<p class="has-text-align-center">Photo by <a href="https://unsplash.com/@lemonvlad?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash" target="_blank" rel="noopener">Vladislav Klapin</a> on <a href="https://unsplash.com/photos/a-person-holding-up-a-sign-that-says-hello-PVr9Gsj93Pc?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash" target="_blank" rel="noopener">Unsplash</a></p>



<p>記得還在寫 UIKit 的時候，其實很不喜歡寫 <code>AttributedString</code> 就覺得很麻煩，因為通常會有這樣的需求都是因為想要做超連結(Hyperlink)，記得那時候要做到這樣是很麻煩的，除了要使用 <code>AttributedString</code>外，還要做點擊開網頁…通常&#8230;&#8230;都會想盡辨法打消設計師們的念頭。</p>



<span id="more-2466"></span>



<p>最近因為工作上的需要，所以就來去找找SwiftUI 要怎麼做超連結(Hyperlink)的方式，發現比起過去簡單很多，無論是在設定URL 或是 Handle Action 都很簡單，好用很多。</p>



<h2 class="wp-block-heading">Text</h2>



<p>若是想要在一串文字中間加上不同的字體或顏色，最常想到的就是 <a href="https://developer.apple.com/documentation/foundation/attributedstring" target="_blank" rel="noopener">AttributedString</a> ，不過，若不是想要做超連結的話，SwiftUI 的 <code>Text</code> 就可以做到了，像這樣:</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-swift" data-lang="Swift"><code> Text(&quot;Hello, world! &quot;)
 +
 Text(&quot;Go google &quot;)
   .foregroundColor(.orange)
 +
 Text(&quot;website&quot;)</code></pre></div>



<p>印出來的結果會是這樣。</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="548" height="86" src="https://doeverythingiwant.com/wp-content/uploads/2025/05/截圖-2025-05-04-下午4.35.17.png" alt="" class="wp-image-2467" srcset="https://doeverythingiwant.com/wp-content/uploads/2025/05/截圖-2025-05-04-下午4.35.17.png 548w, https://doeverythingiwant.com/wp-content/uploads/2025/05/截圖-2025-05-04-下午4.35.17-300x47.png 300w" sizes="(max-width: 548px) 100vw, 548px" /></figure>



<p>不過，如果想要加上 <code>.onTapGesture</code> 的話就沒有辨法了，用 <code>+</code> 串連的<code>Text</code>已經不是單純的 <code>Text</code> ，無法使用<code>.onTapGesture</code> 所以，想要做超連結的話，還是用<code>AttributedString</code>比較好。</p>



<h2 class="wp-block-heading"><code>AttributedString</code></h2>



<p><a href="https://developer.apple.com/documentation/foundation/attributedstring" target="_blank" rel="noopener">AttributedString</a> 是可以讓一串文字裡加入不同樣式的一種方式，這次特別寫出超連結的做法，它的做法是計算出特定字串的 Range ，再依據這個 Range 中的字是需要什麼樣式和顏色，只要能讓它知道需要不一樣的字是什麼，基本上就沒什麼問題。</p>



<p><code>AttributedString</code>中的 <code>AttributeScopes.FoundationAttributes</code> 裡有提供 <code>Link</code> 參數，就是用來做為超連結使用的。</p>



<p>以下是實作方式</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-swift" data-lang="Swift"><code>private func getLinkText(_ text: String, linkText: String, linkURL: String) -&gt; AttributedString {
    var attributedString = AttributedString(text)
    attributedString.font = .systemFont(ofSize: 14, weight: .regular)
    attributedString.foregroundColor = Color.gray
        
    if let range = attributedString.range(of: linkText) {
        attributedString[range].font = .systemFont(ofSize: 14, weight: .medium)
        attributedString[range].foregroundColor = Color.orange
        attributedString[range].link = URL(string: linkURL)
    }
        
    return attributedString
}</code></pre></div>



<p>解析一下程式碼</p>



<ul class="wp-block-list">
<li><code>var attributedString = AttributedString(text)</code> ，這裡的 <code>text</code> 需要是全部的句子</li>



<li><code>attributedString.range(of: linkText)</code>，<code>linkText</code> 就是想要做成超連結的文字段</li>



<li><code>attributedString[range].link</code>，這裡寫入想要開啟的網站</li>
</ul>



<p><code>font</code> 與 <code>foregroundColor</code> 可以自行設定，應該有人有發現，像 <code>View</code> 的 <code>foregroundColor</code> 已經<mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-red-color">Deprecated</mark> 了，現在都使用 <code>foregroundStyle</code> ，但這裡的 <code>foregroundColor</code> 是 <code>AttributeScopes</code>裡的，不是 <code>View</code> 的喔。</p>



<h2 class="wp-block-heading">Handle link</h2>



<p>已經組好有中間有超連結的字串了，再來就直接用 <code>Text</code> 就可以了，最後的範例是要怎麼Handle link 行為</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-swift" data-lang="Swift"><code>Text(getLinkText(&quot;Hello, world! Go google&quot;, linkText: &quot;google&quot;, linkURL: &quot;https://www.google.com.tw&quot;))
                .environment(\.openURL, OpenURLAction { _ in
                    return .systemAction
                })</code></pre></div>



<p>重要的就是使用 <a href="https://developer.apple.com/documentation/swiftui/openurlaction" target="_blank" rel="noreferrer noopener">OpenURLAction</a> ，與 <code>environment(\.openURL)</code> 一起使用，就可以Handle Link Text 點擊的行為，範例上寫的 <code>.systemAction</code> 的行為，就是指外開至Safari ，以下簡單說明 <code>OpenURLAction</code> 的回傳值。</p>



<ul class="wp-block-list">
<li><a href="https://developer.apple.com/documentation/swiftui/openurlaction/result/handled" target="_blank" rel="noreferrer noopener">handled</a> : 就是自行處理，例如，想要直接用 <code>.sheet</code> 開啟網頁，這時候就需要 <code>return handled。</code></li>



<li><a href="https://developer.apple.com/documentation/swiftui/openurlaction/result/discarded" target="_blank" rel="noopener">discarded</a> : 就是不做任何處理。</li>



<li><a href="https://developer.apple.com/documentation/swiftui/openurlaction/result/systemaction" target="_blank" rel="noopener">systemAction</a> : 就是直接外開至Safari ，由Safari 幫你開網頁</li>



<li><a href="https://developer.apple.com/documentation/swiftui/openurlaction/result/systemaction(_:)" target="_blank" rel="noopener">systemAction(_:)</a> : 是用 Safari 開，但是還可以帶別的 URL 或是需要加工URL (這個URL 是指Swift 裡的 <a href="https://developer.apple.com/documentation/Foundation/URL" target="_blank" rel="noopener">URL</a> 物件喔)</li>
</ul>



<h2 class="wp-block-heading">最後</h2>



<p>只要記得上述這些東西，就可以比較簡單地寫出超連結的文字了，畢竟是手機，建議二組超連結的文字不要太近，不然很容易會點錯喔…</p>



<p>最後，祝大家 Coding 愉快!!</p>



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://doeverythingiwant.com/swiftui-attributedstring-and-hyperlink/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>[iOS] Xcode Preview trouble shootings</title>
		<link>https://doeverythingiwant.com/ios-xcode-preview-trouble-shootings/</link>
					<comments>https://doeverythingiwant.com/ios-xcode-preview-trouble-shootings/#respond</comments>
		
		<dc:creator><![CDATA[艾普利]]></dc:creator>
		<pubDate>Sat, 01 Feb 2025 09:26:31 +0000</pubDate>
				<category><![CDATA[寫程式]]></category>
		<category><![CDATA[Preview]]></category>
		<category><![CDATA[SwiftUI]]></category>
		<category><![CDATA[Xcode]]></category>
		<guid isPermaLink="false">https://doeverythingiwant.com/?p=2377</guid>

					<description><![CDATA[自從開始使用 SwiftUI 後，Xcode 內的 Prev&#8230;]]></description>
										<content:encoded><![CDATA[
<p>自從開始使用 SwiftUI 後，Xcode 內的 Preview 就變得非常重要，且它本身也是非常好用的東西，可以即時顯示 UI的樣式，大多數的情況下，可以說是完全反應結果，真的很好用。</p>



<p>但是在某些情況下就是無法顯示出來，會讓人覺得很煩燥，有一種解決方式是把 Perviews simulator 刪除，讓它自動重新再產生。</p>



<span id="more-2377"></span>



<p>有不少人覺得Preview 不好用，主要有幾個理由：如果不是 M系列 CPU 根本很難出現、電腦會變慢、三步五十就壞掉…等等。我自己剛開始在用的時候，也常常不知道為什麼它會跑不出來或是壞掉，簡單去研究一下才知道一些事情，也大概知道為什麼會這樣。</p>



<p>如果你的 Xcode 也常常Preview 上一秒還可以用下一秒就跑不出來的話，接下來要說的方法，說不定可以解決你的煩惱!</p>



<h2 class="wp-block-heading">認識一下 Xcode Preview</h2>



<p>在使用 SwiftUI 時，Xcode 畫面右邊這區就是 Preview畫面出現的地方，在 Xcode 裡是叫 Canvas，它是用來呈現寫在 <code>#Preview</code> 裡的程式碼，雖然不知道是不是大家都這樣，但我習慣叫它Preview 而不是 Canvas。實際上它也是把模擬器跑起來，所以若不是使用Apple 的 M 系列核心，會很難跑起來…</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="617" src="https://doeverythingiwant.com/wp-content/uploads/2025/02/Preview-1024x617.png" alt="" class="wp-image-2390" srcset="https://doeverythingiwant.com/wp-content/uploads/2025/02/Preview-1024x617.png 1024w, https://doeverythingiwant.com/wp-content/uploads/2025/02/Preview-300x181.png 300w, https://doeverythingiwant.com/wp-content/uploads/2025/02/Preview-768x463.png 768w, https://doeverythingiwant.com/wp-content/uploads/2025/02/Preview-1536x926.png 1536w, https://doeverythingiwant.com/wp-content/uploads/2025/02/Preview-2048x1234.png 2048w, https://doeverythingiwant.com/wp-content/uploads/2025/02/Preview-1920x1157.png 1920w, https://doeverythingiwant.com/wp-content/uploads/2025/02/Preview-1170x705.png 1170w, https://doeverythingiwant.com/wp-content/uploads/2025/02/Preview-585x353.png 585w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<h2 class="wp-block-heading">Preview的一些問題</h2>



<p>Preview 算是可以即時顯示出程式碼修改後的結果，是真的很方便，但是有時候也是會跑不出來，當然語法寫錯或是有些資料沒有給它(Preview 使用到得資料需要寫在 <code>#Preview</code> 裡，它是獨立的)，就無法顯示出來。這樣的問題可以檢查一下基本上就可以解決了，但有時候就是明明沒什麼問題，但一直轉半天畫面都沒有出現。</p>



<p>在個人經驗裡有二個情況比較容易發生</p>



<ul class="wp-block-list">
<li>在二、三個專案中切換</li>



<li>在不同的Git branch 中切換</li>
</ul>



<p>實作過程中難免會需要在不同的專案或不同的 Branch 中切換，就可能會<strong>遇到上一秒還顯示出現，下一秒就顯示不出來</strong>情況。</p>



<h2 class="wp-block-heading">解決方式</h2>



<p>如果是在同一個專案發生這個情況可以先試試 <strong>Clear Build + Delete DerivedData </strong>，也許就可以解決這個問題，但如果怎麼樣都無法解決的話，可以試試下面方式。</p>



<p>順便提一下，想刪除 <strong>DerivedData</strong> 可以從下圖開啟資料夾，再把資料夾裡的東西全丟到垃圾筒即可</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="677" src="https://doeverythingiwant.com/wp-content/uploads/2025/02/0201-1024x677.png" alt="" class="wp-image-2392" srcset="https://doeverythingiwant.com/wp-content/uploads/2025/02/0201-1024x677.png 1024w, https://doeverythingiwant.com/wp-content/uploads/2025/02/0201-300x198.png 300w, https://doeverythingiwant.com/wp-content/uploads/2025/02/0201-768x508.png 768w, https://doeverythingiwant.com/wp-content/uploads/2025/02/0201-1536x1016.png 1536w, https://doeverythingiwant.com/wp-content/uploads/2025/02/0201-1170x774.png 1170w, https://doeverythingiwant.com/wp-content/uploads/2025/02/0201-780x516.png 780w, https://doeverythingiwant.com/wp-content/uploads/2025/02/0201-585x387.png 585w, https://doeverythingiwant.com/wp-content/uploads/2025/02/0201-263x175.png 263w, https://doeverythingiwant.com/wp-content/uploads/2025/02/0201.png 1666w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="541" src="https://doeverythingiwant.com/wp-content/uploads/2025/02/02012-1024x541.png" alt="" class="wp-image-2393" srcset="https://doeverythingiwant.com/wp-content/uploads/2025/02/02012-1024x541.png 1024w, https://doeverythingiwant.com/wp-content/uploads/2025/02/02012-300x158.png 300w, https://doeverythingiwant.com/wp-content/uploads/2025/02/02012-768x406.png 768w, https://doeverythingiwant.com/wp-content/uploads/2025/02/02012-1170x618.png 1170w, https://doeverythingiwant.com/wp-content/uploads/2025/02/02012-585x309.png 585w, https://doeverythingiwant.com/wp-content/uploads/2025/02/02012.png 1522w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>剛剛有說到，其實Preview 也是跑模擬器，所以直接全部刪除讓它們重新產生，就和<strong>Delete DerivedData</strong> 的作法差不多，因為不確定到底是什麼問題就直接全刪，和「重開機治百病」一樣的感覺 <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<p>首先，開啟Terminal，不需要移動到其他位置，然後輸入以下指令</p>



<pre class="wp-block-code"><code>xcrun simctl --set previews delete unavailable</code></pre>



<p>會需要跑一點點時間，跑完之後會出現以下文字</p>



<pre class="wp-block-code"><code>Using Previews Device Set: '/Users/userName/Library/Developer/Xcode/UserData/Previews/Simulator Devices'</code></pre>



<p>這樣當你重新開啟 Xcode 之後，Preview 的模擬器就會再重新Create，這樣也許可以解決 Preview 轉半天沒有出現的情況。</p>



<p>希望這個方式能有幫助~</p>



<p>最後，祝大家 Coding 愉快!!</p>



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://doeverythingiwant.com/ios-xcode-preview-trouble-shootings/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>[iOS] Codable 有關的那些小事情</title>
		<link>https://doeverythingiwant.com/codable-decoder/</link>
					<comments>https://doeverythingiwant.com/codable-decoder/#respond</comments>
		
		<dc:creator><![CDATA[艾普利]]></dc:creator>
		<pubDate>Sun, 08 Dec 2024 08:11:47 +0000</pubDate>
				<category><![CDATA[寫程式]]></category>
		<category><![CDATA[codable]]></category>
		<category><![CDATA[Decoder]]></category>
		<category><![CDATA[iOS]]></category>
		<guid isPermaLink="false">https://doeverythingiwant.com/?p=2372</guid>

					<description><![CDATA[說到 Codable 已經推出很久了，也用了好幾年了，但是對它還是不算是很了解，該怎麼說呢，因為Codable 最常運用在解析 API Response，基本上寫完之後，除非API 回傳值要改變，你大概到離職的那一刻都不會再去修改它了，所以即使它推出了很多年了，實際上接觸的時間意外地少。
最近正好有機會再次寫不少 Codable 的部分，發現了一些過去不知道的東西，把它們記錄在這裡。]]></description>
										<content:encoded><![CDATA[
<p class="has-text-align-center">Photo by <a href="https://unsplash.com/@markusspiske?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash" target="_blank" rel="noopener">Markus Spiske</a> on <a href="https://unsplash.com/photos/matrix-movie-still-iar-afB0QQw?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash" target="_blank" rel="noopener">Unsplash</a></p>



<p>說到 Codable 已經推出很久了，也用了好幾年了，但是對它還是不算是很了解，該怎麼說呢，因為Codable 最常運用在解析 API Response，基本上寫完之後，除非API 回傳值要改變，大概到離職的那一刻都不會再去修改它了，所以即使它推出了很多年了，實際上接觸的時間意外地少。</p>



<p>最近正好有機會再次寫不少 Codable 的部分，發現了一些過去不知道的東西，把它們記錄在這裡。</p>



<span id="more-2372"></span>



<h2 class="wp-block-heading">CodingKey</h2>



<p>最常使用在API 回傳值的Key 風格 不是 Swift 習慣的風格，做為對應解析之用</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-swift" data-lang="Swift"><code>enum CodingKeys: String, CodingKey {
    case id = &quot;product_id&quot;
    case name
    case description
    case expiryDate = &quot;expiry_date&quot;
}</code></pre></div>



<p>在API 回傳值裡的 <code>product_id</code> 就會被放到 <code>id</code>裡，這是非常好用的地方。</p>



<p>另一個好用的地方在於也可以讓decoder只解析寫在 CodingKeys 裡的那些參數，舉個例</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-swift" data-lang="Swift"><code>struct SubItem: Decodable,Identifiable {
   var id = UUID().string
   var name: String
   var description: String
   var isActive: Bool
}</code></pre></div>



<p><code>SubItem</code> conform Identifiable protocol ，因此有一個參數是<code>id</code> 且還是直接使用UUID，並不希望它被拿來當解析用的參數時，就可以使用 CodingKey來避開 <code>id</code> ，就不需要再寫 <code>init(from decoder: any Decoder)</code></p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-swift" data-lang="Swift"><code>struct SubItem: Decodable,Identifiable {
   var id = UUID().string
   var name: String
   var description: String
   var isActive: Bool

   enum CodingKeys: String, CodingKey {
    case name
    case description
    case isActive 
  }
}</code></pre></div>



<h2 class="wp-block-heading">Try? &amp; decodeIfPresent()</h2>



<p>基於因為不知道API 會回傳什麼，是否真的會依照文件回傳，為了讓App 不會因為回傳值問題需導至 Crash，一般而言，除非100%保証一定會有值的情況下，大多數參數都會被設定為 Optional，在解析的時候就會用上  <code>decodeIfPresent</code> ，當回傳值完全沒有這個參數，或是參數是nil(null)的時候，它會回傳 nil。</p>



<p>一般情況下，這樣就幾乎不會有什麼問題，但是，就是這個但是，當回傳值是有值的時候，但偏偏回傳的資料型態是錯誤的，這樣的寫法就還是會解析失敗，導致整個物件都會是nil。</p>



<p>如果你是覺得「為什麼會回傳資料型態不同的資料來啊? 這不合理啊」，沒錯，理解上不應該出現回傳值的資料有誤的情況，多數情況下都會要求修正。因為App 端對於資料型態相對來說是嚴格的，解析失敗最後就可能造成 Crash ，所以最好是大家都遵守好訂好的資料型態，不應該回傳不正確的型態。</p>



<p>在有點歷史的產品裡或是一開始就沒有 App 端產品就可能會發生，回傳值會變成不預期的資料型態問題，且可能也不是馬上可以修正的情況，這種時候就需要先確認有問題的資料是不是需要用的，若是需要用的就必須要再另外處理，若是不需要用的資料，就是<code>try?</code> 出馬的時候了!</p>



<p><code>try?</code> 本來就是在解析失敗的時候會回傳nil ，本來比較常會和 <code>decode</code>() 一起使用，如果和 <code>decodeIfPresent</code> 一起使用，所有可以會造成問題的情況都會包含到，這樣就比較不用怕因為資料型態解析失敗問題，當然，前提是有問題的資料並不是會使用到的資料</p>



<p>以下就是合體技的寫法</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-plain"><code>init(from decoder: any Decoder) throws {
   let container = try decoder.container(keyedBy: CodingKeys.self)
   id = try? container.decodeIfPresent(String.self, forKey: .id)
   name = try? container.decodeIfPresent(String.self, forKey: .name)
}</code></pre></div>



<h2 class="wp-block-heading">假如運氣特好遇到…</h2>



<p>萬一真的運氣特好遇到同一支API 回傳值在不同情況下某一個參數會回傳完全不同的型態，偏偏你又必須要使用這些參數，那只好自定義解析方式了，方法上網Google 一下就會找得到了，不然也可以詢問 Claude AI. </p>



<p>其方式是 <code>extenstion KeyedDecodingContainer</code> 這個Struct ，寫一個通用的 <code>decode</code>，之後就可以利用這個 <code>decode</code> 為它加上一些自定義的解析方式</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-swift" data-lang="Swift"><code>func decodeAny&lt;T&gt;(_: T.Type, forKey key: K, transform: ((Any) -&gt; T?)? = nil) throws -&gt; T? {
        guard contains(key) else { return nil }
        
        //預設轉換邏輯
        let defaultTransform: (Any) -&gt; T? = { value in
            if let typedValue = value as? T {
                return typedValue
            }
            
            if let stringConvertible = T.self as? LosslessStringConvertible.Type {
                let stringValue = String(describing: value)
                return stringConvertible.init(stringValue) as? T
            }
            
            return nil
        }
        
        let transformer = transform ?? defaultTransform
        
        //不同型別的解法
        let attempts: [(Any.Type, (K) throws -&gt; Any)] = [
            (String.self, {try decode(String.self, forKey: $0) as Any}),
            (Int.self, {try decode(Int.self, forKey: $0) as Any}),
            (Double.self, {try decode(Double.self, forKey: $0) as Any}),
            (Bool.self, {try decode(Bool.self, forKey: $0) as Any})
        ]
        
        // value: 取得API 資料的型態,transformed: 利用transformer 解析成需要的型態
        for(_, decoder) in attempts {
            if let value = try? decoder(key),
               let transformed = transformer(value) {
                return transformed
            }
        }
    
        return nil
    }</code></pre></div>



<p>例如 <code>Bool</code> 是最常遇到擁有各種不同型態的表示法的，就可以為它來寫一個方便的解析方式</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-swift" data-lang="Swift"><code>func decodeBool(forKey key: K) throws -&gt; Bool? {
        try decodeAny(Bool.self, forKey: key) { value in
            switch value {
            case let boolValue as Bool:
                return boolValue
            case let intValue as Int:
                return intValue != 0
            case let doubleValue as Double:
                return doubleValue != 0
            case let stringValue as String:
                let lowercased = stringValue.lowercased()
                if [&quot;true&quot;, &quot;t&quot;, &quot;yes&quot;, &quot;1&quot;].contains(lowercased) { return true }
                if [&quot;false&quot;, &quot;f&quot;, &quot;no&quot;, &quot;0&quot;].contains(lowercased) { return false }
                return nil
            default nil
            }
        }
    }</code></pre></div>



<p>說真的，最好是不要遇到需要這樣寫的情況，為什麼呢? 主要的原因是萬一真的是 API 的錯誤，但因為App 端有自定義解析的方式，所以就解析成功了，那麼就可能完全不會有人知道可能真的是資料錯誤的問題，當這樣資料數量多了之後，也許就會造成後續資料分析有誤，或有些神奇的情況。</p>



<p>最後，祝大家 Coding 愉快!!</p>
]]></content:encoded>
					
					<wfw:commentRss>https://doeverythingiwant.com/codable-decoder/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>[iOS] Network Monitor</title>
		<link>https://doeverythingiwant.com/ios-network-monitor/</link>
					<comments>https://doeverythingiwant.com/ios-network-monitor/#respond</comments>
		
		<dc:creator><![CDATA[艾普利]]></dc:creator>
		<pubDate>Sun, 20 Oct 2024 14:25:17 +0000</pubDate>
				<category><![CDATA[寫程式]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[network monitor]]></category>
		<category><![CDATA[SwiftUI]]></category>
		<guid isPermaLink="false">https://doeverythingiwant.com/?p=2361</guid>

					<description><![CDATA[Photo by Frederik Lipfert on U&#8230;]]></description>
										<content:encoded><![CDATA[
<p class="has-text-align-center">Photo by <a href="https://unsplash.com/@frederikli?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash" target="_blank" rel="noopener">Frederik Lipfert</a> on <a href="https://unsplash.com/photos/a-person-holding-an-iphone-in-their-hand-y67dwfB2AiM?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash" target="_blank" rel="noopener">Unsplash</a></p>



<p>在iOS12之前想要偵測網路狀態的話，大家都會使用 Reachability 這套官方工具，且有 <a href="https://developer.apple.com/library/archive/samplecode/Reachability/Introduction/Intro.html" data-type="link" data-id="https://developer.apple.com/library/archive/samplecode/Reachability/Introduction/Intro.html" target="_blank" rel="noreferrer noopener">Demo Code</a> 可以直接使用，所以只要說到偵測網路第一時間一定會想到使用 Reachability。</p>



<p>在 iOS 12之後官方推出了 <a href="https://developer.apple.com/documentation/network" target="_blank" rel="noreferrer noopener">Network Kit</a> 其中有很多與網路相關的服務，期中一個就可以用來偵測網路狀態，程式碼比過去少又比較清楚，配合現在官方主推的 SwiftUI 也很好用。</p>



<span id="more-2361"></span>



<h2 class="wp-block-heading">Monitor</h2>



<h3 class="wp-block-heading">Create Publisher</h3>



<p>像這樣的Monitor 是建議獨立建立一個 Class 來處理，不要放在其他的Class 裡面</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-swift" data-lang="Swift"><code>import Network

class NetworkMonitor: ObservableObject {
    
    @Published private(set) var isConnected: Bool = false
    @Published private(set) var networkType: NWInterface.InterfaceType? = .other
}</code></pre></div>



<p>首先，記得要 <code>import Network</code>，為了能讓SwiftUI 使用記得要Conform <code>ObservableObject</code></p>



<p><code>isConnected</code> 就是在確認是否為連線狀態，<code>networkType</code> 就是屬於那一種連線類型，官方有分為 <code>wifi</code>、<code>cellular</code>…等等，詳細分類可以參考 <a href="https://developer.apple.com/documentation/network/nwinterface/interfacetype" target="_blank" rel="noreferrer noopener">NWInterface.InterfaceType</a> 的說明。</p>



<h3 class="wp-block-heading">Create Monitor</h3>



<div class="hcb_wrap"><pre class="prism line-numbers lang-swift" data-lang="Swift"><code>let networkMonitor = NWPathMonitor()
let workQueue = DispatchQueue(label: &quot;NetworkMonitor&quot;)</code></pre></div>



<p>接著往下建立 Monitor ，在Network Kit 裡有一個Class 是 <a href="https://developer.apple.com/documentation/network/nwpathmonitor" data-type="link" data-id="https://developer.apple.com/documentation/network/nwpathmonitor" target="_blank" rel="noreferrer noopener">NWPathMonitor</a> ，它就是用來偵測網路狀態的，上述這樣的寫法表示要偵測所有型態的網路，有需要的話也可以指定想要偵測的網路型態。</p>



<p>一般來說偵測網路的動作一定不可以影響到主線程的運行，因此我們需要新增一條負責偵測網路用的 <code>DispatchQueue</code>，名稱可以自訂，這裡是稱它為 <code>NetworkMonitor</code>。</p>



<h3 class="wp-block-heading">Create Path update handler</h3>



<div class="hcb_wrap"><pre class="prism line-numbers lang-swift" data-lang="Swift"><code>networkMonitor.pathUpdateHandler = { [weak self] path in
    self?.isConnected = path.status == .satisfied
    self?.networkType = path.availableInterfaces.first?.type
}</code></pre></div>



<p>當網路狀態改變的時候，可以在 <code>pathUpdateHandler</code> 這個 Closure 取得資訊，會回傳 <code>NWPath</code> 這個物件，它有網路狀態的相關資訊。</p>



<h3 class="wp-block-heading">Start</h3>



<div class="hcb_wrap"><pre class="prism line-numbers lang-swift" data-lang="Swift"><code>networkMonitor.start(queue: workQueue)</code></pre></div>



<p>最後再開始偵測，記得指定先前設定好的Queue</p>



<p>完整的程式如下</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-swift" data-lang="Swift"><code>class NetworkMonitor: ObservableObject {
    
    @Published private(set) var isConnected: Bool = false
    @Published private(set) var networkType: NWInterface.InterfaceType? = .other
    
    let networkMonitor = NWPathMonitor()
    let workQueue = DispatchQueue(label: &quot;NetworkMonitor&quot;)
    
    init() {
        
        networkMonitor.pathUpdateHandler = { [weak self] path in
            self?.isConnected = path.status == .satisfied
            self?.networkType = path.availableInterfaces.first?.type
        }
        
        networkMonitor.start(queue: workQueue)
    }
}</code></pre></div>



<h3 class="wp-block-heading">View</h3>



<p>接著就可以將這個NetworkMonitor 放到View 上使用，以下是一個簡單的範例</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-swift" data-lang="Swift"><code>struct ContentView: View {
    
    @StateObject var networkMonitor = NetworkMonitor()
    
    var body: some View {
        VStack {
            Label {
                Text(networkMonitor.isConnected ? &quot;Connected&quot; : &quot;Disconnected&quot;)
            } icon: {
                Image(systemName: networkMonitor.isConnected ? &quot;network&quot; : &quot;network.slash&quot;)
                    .foregroundStyle(networkMonitor.isConnected ? .green : .red)
            }

        }
        .padding()
    }
}</code></pre></div>



<p>當然，App 應該只會有一個 Network Monitor ，這個時候可以使用 <code>EnvironmentObject</code> 的方式來傳遞 Network Monitor，寫法可以參考以下方式，當然要從哪裡開始建立 Network Monitor 都可以依照個人需求，理論上應該是App 開啟時就需要做偵測啦，記得使用 <code>.environmentObject()</code>來讓其他畫面可以使用 <code>EnvironmentObject</code> 方式讀取到 Network Monitor。</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-swift" data-lang="Swift"><code>@main
struct NetworkDemoApp: App {
    
    @StateObject var networkMonitor = NetworkMonitor()
    
    var body: some Scene {
        WindowGroup {
            ContentView()
                .environmentObject(networkMonitor)
        }
    }
}</code></pre></div>



<div class="hcb_wrap"><pre class="prism line-numbers lang-swift" data-lang="Swift"><code>struct ContentView: View {
    
    @EnvironmentObject var networkMonitor: NetworkMonitor
    
    var body: some View {
        VStack {
            Label {
                Text(networkMonitor.isConnected ? &quot;Connected&quot; : &quot;Disconnected&quot;)
            } icon: {
                Image(systemName: networkMonitor.isConnected ? &quot;network&quot; : &quot;network.slash&quot;)
                    .foregroundStyle(networkMonitor.isConnected ? .green : .red)
            }

        }
        .padding()
    }
}</code></pre></div>



<p>最後，祝大家 Coding 愉快!!</p>



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://doeverythingiwant.com/ios-network-monitor/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>SwiftUI &#8211; Drop &#038; Drag List</title>
		<link>https://doeverythingiwant.com/swiftui-drop-drag-list/</link>
					<comments>https://doeverythingiwant.com/swiftui-drop-drag-list/#respond</comments>
		
		<dc:creator><![CDATA[艾普利]]></dc:creator>
		<pubDate>Sun, 09 Jun 2024 10:41:02 +0000</pubDate>
				<category><![CDATA[寫程式]]></category>
		<category><![CDATA[Drop and Drag]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[SwiftUI]]></category>
		<guid isPermaLink="false">https://doeverythingiwant.com/?p=2280</guid>

					<description><![CDATA[忘記是那一年的WWDC公布了一個拖曳相關的功能，主要是讓你可&#8230;]]></description>
										<content:encoded><![CDATA[
<p>忘記是那一年的WWDC公布了一個拖曳相關的功能，主要是讓你可以將iPhone 的資料像是圖片之類的丟到iPad 或Mac 上，因此有了 API 可以用在 Drop &amp; Drag 動作上。</p>



<p>最近因為工作需要花了一些時間在研究Drop &amp; Drag 應該要怎麼寫，需要實作的是一般的拖拉元件改變它的順序，並不需要讓它能拖到另一個裝置上，寫作上就會比較簡單一點。</p>



<span id="more-2280"></span>



<p>參考以下文件與官方網站來練習</p>



<p><a href="https://dogpa0130.medium.com/swift-practice-177-swiftui-%E6%8B%96%E6%9B%B3-drop-drag-%E6%94%B9%E8%AE%8A%E9%99%A3%E5%88%97array%E4%BD%8D%E7%BD%AE-b63ff5edb935" target="_blank" rel="noreferrer noopener">Swift Practice # 177 SwiftUI 拖曳 Drop &amp; Drag 改變陣列Array位置</a></p>



<p><a href="https://mobileappsacademy.medium.com/drag-and-drop-list-in-swiftui-30b53682d447" target="_blank" rel="noreferrer noopener">Drag and Drop List in SwiftUI</a></p>



<p><a href="https://developer.apple.com/documentation/swiftui/drag-and-drop" target="_blank" rel="noreferrer noopener">Apple Documentation &#8211; Drag and Drop</a></p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Start</h2>



<p>一開始當然要先做一個要進行拖曳的List，建立一個顯示各種茶的List</p>



<p>建立List 的 Item View</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-swift" data-lang="Swift"><code>struct TeaItemView: View {
    
    var title: String
    
    var body: some View {
        HStack {
            Text(title)
                .font(.system(size: 26))
        }
        .frame(maxWidth: .infinity)
        .padding(.vertical, 30)
        .background(.green)
        .clipShape(RoundedRectangle(cornerRadius: 20))
        
    }
}</code></pre></div>



<p>再建立一個用 <code>ForEach</code> 做的 List </p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-swift" data-lang="Swift"><code>import SwiftUI

struct ContentView: View {
    
    @State private var draggedItem: String?
    @State private var fruitItems = [&quot;&#x1fad6; Tea&quot;, &quot; &#x2615; Coffee&quot;, &quot; &#x1f9c3; Juice&quot;, &quot;&#x1f9cb;Pearl milk tea&quot;, &quot;&#x1f95b; Milk&quot;, &quot;&#x1f379; Fruit tea&quot;, &quot;&#x1f9c9; Mate tea&quot;, &quot;&#x1f375; Matcha tea&quot;]
    
    var body: some View {
        
        ScrollView(showsIndicators: false) {
            VStack(spacing: 10) {
                ForEach(fruitItems, id: \.self) { fruit in
                    TeaItemView(title: fruit)
                }
            }
            .padding(.horizontal, 20)
        }
        .background(.black)
    }
}</code></pre></div>



<p><code>draggedItem</code> 是負責記錄要被拖曳的元件，再來Run 一下程式，會出現下面畫面</p>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="295" height="640" src="https://doeverythingiwant.com/wp-content/uploads/2024/06/teaList.gif" alt="" class="wp-image-2285"/></figure>
</div>


<h2 class="wp-block-heading">DrogDelegate</h2>



<p>如果要讓List 的元件可以被拖曳，必須實作 DropDelegate 這個Protocol，新增一個 DropDragDelegate 來實作它</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-swift" data-lang="Swift"><code>import SwiftUI

struct DropDrapDelegate: DropDelegate {
    
    let destinationItem: String
    
    @Binding var fruits: [String]
    @Binding var draggedItem: String?
    
    func dropUpdated(info: DropInfo) -&gt; DropProposal? {
        return DropProposal(operation: .move)
    }
    
    func performDrop(info: DropInfo) -&gt; Bool {
        draggedItem = nil
        return true
    }
    
    func dropEntered(info: DropInfo) {
        if let draggedItem {
            let fromIndex = fruits.firstIndex(of: draggedItem)
            if let fromIndex {
                let toIndex = fruits.firstIndex(of: destinationItem)
                if let toIndex, fromIndex != toIndex {
                    withAnimation {
                        self.fruits.move(fromOffsets: IndexSet(integer: fromIndex), toOffset: (toIndex &gt; fromIndex ? (toIndex + 1) : toIndex))
                    }
                }
            }
        }
    }
}</code></pre></div>



<p>在這個 Delegate 中有幾個需要實作的 function</p>



<p><code>func dropUpdated(info: DropInfo) -> DropProposal?</code>  </p>



<p>宣告這個拖曳是要什麼動作，以範例來說只是要做移動，所以是 <code>.move</code>，可以去官方文件查看 <code>DropProposal</code> 可以知道更多設定值，預設值會是 <code>nil</code>。</p>



<p><code>func performDrop(info: DropInfo) -> Bool</code></p>



<p>拖曳完成的時候會呼叫到它，回傳 <code>true</code> 表示 Drop was successful</p>



<p><code>func dropEntered(info: DropInfo)</code></p>



<p>在這個拖曳要做些什麼? 這是我對這個function 的理解，這個範例主要是要交換順序，所以裡面寫的就是交換的方式</p>



<h2 class="wp-block-heading">View</h2>



<p>再回到 View ，將 <code>OnDrop</code> 與 <code>OnDrag</code> 加到剛剛寫好的 List 中</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-swift" data-lang="Swift"><code>ScrollView(showsIndicators: false) {
    VStack(spacing: 10) {
        ForEach(fruitItems, id: \.self) { fruit in
            TeaItemView(title: fruit)
                .onDrag({
                    draggedItem = fruit
                    return NSItemProvider()
                })
                .onDrop(of: [.text], delegate: DropDrapDelegate(destinationItem: fruit, fruits: $fruitItems, draggedItem: $draggedItem))
            
        }
    }
    .padding(.horizontal, 20)
}
.background(.black)
</code></pre></div>



<p><code>onDrag</code> </p>



<p>這個的重點在於 <code>NSItemProvider</code> ，<code>NSItemProvider</code> 它是為了在進行 <code>Drag-and-drop</code> 或是 <code>Copy-and-paste</code> 時傳送資料或檔案用的，設定方式我自己是不太理解，常見的設定是 <code>URL</code>，這個範例用不到，就直接建立一個空的ItemProvider，若有需要傳送資料到不同裝置上的話應該需要留意一下。</p>



<p><code>onDrop(of:delegate:)</code></p>



<p>設定Type與Delegate ，Delegate 就是先前建立的 DropDrapDelegate，直接代需要的參考就好。</p>



<p>Type的設定有二種方式，第一種是給它 <code>The uniform type identifiers</code> ，這是需要可以辨識要傳送的資料，查了一下，應該是可以自定這個 Identifier。第二種是設定 <code>UTType</code> ，在範例中的 <code>[.text]</code> 就是 <code>UTType</code> 裡的 <code>Text</code>，在官方文件中可以看到很多種類型，那<code>UTType</code>是什麼? 它其實就是指要進行<code>load, send, or receive</code>的資料類型。</p>



<p>加上 <code>onDrag</code> 與 <code>onDrop</code> 之後就可以進行拖曳了</p>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="295" height="640" src="https://doeverythingiwant.com/wp-content/uploads/2024/06/Finish.gif" alt="" class="wp-image-2288"/></figure>
</div>


<p>可以在 <a href="https://github.com/AprilXMoon/DragDropDemo" target="_blank" rel="noreferrer noopener">Github</a> 上下載這個範例程式</p>



<p>最後祝大家 Coding 愉快!!</p>
]]></content:encoded>
					
					<wfw:commentRss>https://doeverythingiwant.com/swiftui-drop-drag-list/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>SwiftUI 與 Gif</title>
		<link>https://doeverythingiwant.com/swiftui-gif/</link>
					<comments>https://doeverythingiwant.com/swiftui-gif/#respond</comments>
		
		<dc:creator><![CDATA[艾普利]]></dc:creator>
		<pubDate>Sun, 04 Feb 2024 08:40:58 +0000</pubDate>
				<category><![CDATA[寫程式]]></category>
		<category><![CDATA[Gif]]></category>
		<category><![CDATA[SwiftUI]]></category>
		<guid isPermaLink="false">https://doeverythingiwant.com/?p=2191</guid>

					<description><![CDATA[Photo by Євгенія Височина on U&#8230;]]></description>
										<content:encoded><![CDATA[
<p class="has-text-align-center">Photo by <a href="https://unsplash.com/@eugenivy_now?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash" target="_blank" rel="noopener">Євгенія Височина</a> on <a href="https://unsplash.com/photos/a-group-of-wrapped-presents-under-a-christmas-tree-bh1fKYXv2cA?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash" target="_blank" rel="noopener">Unsplash</a></p>



<p>SwiftUI 本身的Image 並沒有支援 Gif 檔案，若是想要放動畫的除了用程式去寫外，現在有 Lottie 可以使用，SwiftUI 其實也是可以使用 Gif Image ，不過畢需要透過WKWebView 來實現</p>



<span id="more-2191"></span>



<p>先找一個gif 圖，本次使用的是這個櫻花的圖示</p>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="256" height="256" src="https://doeverythingiwant.com/wp-content/uploads/2023/12/cherry-blossoms.gif" alt="" class="wp-image-2193"/><figcaption class="wp-element-caption">GIF by <a href="https://pixabay.com/users/viaductk-34217157/?utm_source=link-attribution&amp;utm_medium=referral&amp;utm_campaign=animation&amp;utm_content=6383" target="_blank" rel="noopener">viaductk</a> from <a href="https://pixabay.com//?utm_source=link-attribution&amp;utm_medium=referral&amp;utm_campaign=animation&amp;utm_content=6383" target="_blank" rel="noopener">Pixabay</a></figcaption></figure>
</div>


<p>這個檔案需要放在專案裡面，不需要放在 Assets 因為它並不是單純的圖片</p>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="454" height="388" src="https://doeverythingiwant.com/wp-content/uploads/2023/12/000.png" alt="" class="wp-image-2194" srcset="https://doeverythingiwant.com/wp-content/uploads/2023/12/000.png 454w, https://doeverythingiwant.com/wp-content/uploads/2023/12/000-300x256.png 300w" sizes="(max-width: 454px) 100vw, 454px" /></figure>
</div>


<p><code>WKWebView</code> 是UIView 現在屬於WebKit 底下，UIView 是屬於 UIKit 底下，而UIKit元件要使用在 SwiftUI 上需要用<code>UIViewRepresentable</code> 做處理，官方有一個<a href="https://developer.apple.com/tutorials/swiftui/interfacing-with-uikit" target="_blank" rel="noreferrer noopener">教學</a>，有興趣的可以看一看，最主要就是需要實作二個function</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-swift" data-lang="Swift"><code>func makeUIView(context: Context) -&gt; UIView { }
func updateUIView(_ uiView: UIView, context: Context) { }</code></pre></div>



<p>在有<code>Delegate</code> 的情況就是要實作 <code>class Coordinator</code>，詳細可以看教學或是上網找一下相關教學</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">實作</h2>



<p>這次主要使用的是 <code>WKWebView</code> 因此上述 <code>UIView</code> 的部分都需要改成 <code>WKWebView</code></p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-swift" data-lang="Swift"><code>func makeUIView(context: Context) -&gt; WKWebView {
    let webView = WKWebView()
    let url = Bundle.main.url(forResource: imageName, withExtension: &quot;gif&quot;)!
    let data = try! Data(contentsOf: url)
        
    webView.load(data, mimeType: &quot;image/gif&quot;, characterEncodingName: &quot;UTF-8&quot;, baseURL: url.deletingLastPathComponent())
        
    return webView
}

func updateUIView(_ uiView: WKWebView, context: Context) {
    uiView.reload()
}</code></pre></div>



<p>剛剛有說過 <code>WKWebView</code> 是屬於 WebKit 底下，所以要記得 <code>import WebKit</code>，簡單說明一下程式碼</p>



<ul class="wp-block-list">
<li>建立一個 <code>WKWebView</code> 做為回傳值</li>



<li><code>url</code> 參數取得gif 位置，<code>forResource</code> 是代入圖片名稱，因為希望能任意填入名稱，所以使用一個參數代表 image name，<code>Bundle.main.url()</code> 的回傳值是 Optional ，由於Gif 圖示一定要放在檔案裡，基本上不會有nil 的情況，所以就直接最後加上 !</li>



<li><code>data</code> 參數將圖片轉成 data，回傳值也是Optional的，如上述所說，這裡也直接使用 <code>try!</code> 來處理</li>



<li>最後讓webView 去取讀這個檔案
<ul class="wp-block-list">
<li><code>mimeType</code> 就是指 Internet media type，寫web 的朋友們應該都很清楚，這是用來表示這是什麼樣的檔案，在此當然是 &#8220;image/gif&#8221;，有興趣可以看一下<a href="https://zh.wikipedia.org/zh-tw/%E4%BA%92%E8%81%94%E7%BD%91%E5%AA%92%E4%BD%93%E7%B1%BB%E5%9E%8B" target="_blank" rel="noreferrer noopener">維基百科</a>的說明</li>



<li><code>characterEncodingName</code>，使用 UTF-8 來做解碼方式</li>
</ul>
</li>



<li><code>updateUIView()</code> 只需要做一件事，就是 <code>reload()</code> 就好了</li>
</ul>



<p>這樣就完成啦~ 很簡單對吧~ </p>



<p>最後的結果就像這樣，加上 .frame 就可以調整大小，使用上非常方便</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-swift" data-lang="Swift"><code>VStack {
   GifImageView(imageName: &quot;cherry-blossoms&quot;)
       .frame(width: 60, height: 60)
   Text(&quot;Hello, world!&quot;)
}
.padding()</code></pre></div>


<div class="wp-block-image wp-duotone-unset-1">
<figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="295" height="640" src="https://doeverythingiwant.com/wp-content/uploads/2023/12/demo.gif" alt="" class="wp-image-2199"/></figure>
</div>


<p>不知道未來 SwiftUI 會不會發展出自己的 WebView ，或是 Image 之後也可以支援 Gif 檔案，在那之前就用 WKWebView 來呈現Gif 圖示吧</p>



<p>最後祝大家 Coding 愉快!!</p>



<p>可以在<a href="https://github.com/AprilXMoon/GifImage" target="_blank" rel="noreferrer noopener">這裡</a>取得此Demo 檔案喔~</p>
]]></content:encoded>
					
					<wfw:commentRss>https://doeverythingiwant.com/swiftui-gif/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>SDK, Framework and Library</title>
		<link>https://doeverythingiwant.com/sdk_framework_library/</link>
					<comments>https://doeverythingiwant.com/sdk_framework_library/#respond</comments>
		
		<dc:creator><![CDATA[艾普利]]></dc:creator>
		<pubDate>Sun, 17 Dec 2023 09:47:07 +0000</pubDate>
				<category><![CDATA[寫程式]]></category>
		<category><![CDATA[Framework]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[Librar]]></category>
		<category><![CDATA[SDK]]></category>
		<guid isPermaLink="false">https://doeverythingiwant.com/?p=2206</guid>

					<description><![CDATA[Photo by Safar Safarov on Unsp&#8230;]]></description>
										<content:encoded><![CDATA[
<p class="has-text-align-center">Photo by <a href="https://unsplash.com/@safarslife?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash" target="_blank" rel="noopener">Safar Safarov</a> on <a href="https://unsplash.com/photos/turned-on-gray-laptop-computer-MSN8TFhJ0is?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash" target="_blank" rel="noopener">Unsplash</a></p>



<p>前些日子突然和同事聊起了 SDK、Framework 和 Library 差別在哪裡? </p>



<p>就我所知 SDK 包含了一堆東西，UI、function …等等，就範圍來說是最大的，Framework 和 Library 很像，都是有一些funcation 可以讓開發人員呼叫。</p>



<p>嗯…感覺好像不是很清楚，還記得以前有找過資料，但是後來都忘記了，想說正好有個機會重新再把這三個東西了解更多一點</p>



<span id="more-2206"></span>



<h2 class="wp-block-heading">SDK</h2>



<p>SDK(<em>Software Development Kit</em>) 軟體開發套件，感覺只要有帶 Kit 這個字的總是有一群東西…</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>A software development kit (SDK) is a collection of software development tools in one installable package. They facilitate the creation of applications by having a compiler, debugger and sometimes a software framework. They are normally specific to a hardware platform and operating system combination. To create applications with advanced functionalities such as advertisements, push notifications,etc; most application software developers use specific software development kits.</p>
<cite>Wikipedia</cite></blockquote>



<p>SDK 除了包含 Framework 外還有compiler、 debugger。</p>



<p>舉例的話，對開發者來說，我們常常在工作時說的 iOS 就是一個 SDK，iOS SDK 提供 iOS App 的開發環境，當然要透過 Xcode 這個IDE (<em>integrated development environment</em>)工具來開發，同理也有 Android SDK。</p>



<p>這和使用者常常指的iOS 不一樣，iPhone 的iOS 是 Operating Systems 是負責管理App的系統，不要搞錯了喔~</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Framework</h2>



<p>Framework 就如其名，是一個框架，一個package</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Software framework is an abstraction in which software, providing generic functionality, can be selectively changed by additional user-written code, thus providing application-specific software. It provides a standard way to build and deploy applications and is a universal, reusable software environment that provides particular functionality as part of a larger software platform to facilitate the development of software applications, products and solutions.</p>
<cite>Wikipedia</cite></blockquote>



<p>Framework 基本上提供了許多可以幫助你完成應用程式的一些元件。</p>



<p>舉例來說，SwiftUI &amp; UIKit 它們都是Framework ，它們提供了很多 UI 相關框架(元件)讓開發者只需要加上一些程式碼就可以完成畫面，至於像是 Text 是怎麼處理多語系與字型、List 是怎麼讓畫面可以下拉更新，這些都不需要開發者處理。</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Library</h2>



<p>Library 就是一堆函式的集合，最早在學習 C++ 的時候就知道的名詞</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Library is a collection of non-volatile resources used by computer programs, often for software development. These may include configuration data, documentation, help data, message templates, pre-written code and subroutines, classes, values or type specifications.</p>
<cite>Wikipedia</cite></blockquote>



<p>Library &#8230; 嗯…看來就是一堆可以提供你呼叫用的function、class、 data ，這個就有點難舉例了…</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Library vs Framework</h2>



<p>說起來其實 Library 和 Framework 很像，上網找了一下多數說二者之間的差別在於<em> Inversion of Control</em> </p>



<p>Library 的話，開發者可以呼叫 Library 裡的 function 做一些處理，最後會得到結果，然後再由開發者決定要做些什麼處理，控制權是在開發者手上的</p>



<pre class="wp-block-code"><code>You own the control</code></pre>



<p>Framework提供了框架並擁有內建行為，開發者可以依照Framework 提供的框架，填入一些程式碼，讓 Framework 來幫你處理後面的事情，你只需要在框架指定的地方寫上程式碼就行了，控制權反而是在 Framework 手上，這種情況就稱為 <em>Inversion of Control</em> </p>



<pre class="wp-block-code"><code>The framework calls you</code></pre>



<h2 class="wp-block-heading">總結</h2>



<p>SDK : 包含 Libraries、Frameworks、Tools、Documentation ，所表示的概念比較大範圍</p>



<p>Framework: 提供框架(包含現成可用的程式)，呼叫時通常只需要再寫上一些程式碼即可，控制權是屬於 Framework的</p>



<p>Library: 提供可讓開發者呼叫的 function、data、class…等，控制權是屬於開發者的</p>



<p>最後照慣例祝大家 Coding 愉快!!</p>
]]></content:encoded>
					
					<wfw:commentRss>https://doeverythingiwant.com/sdk_framework_library/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>從零開始學SwiftData</title>
		<link>https://doeverythingiwant.com/learningswiftdata/</link>
					<comments>https://doeverythingiwant.com/learningswiftdata/#respond</comments>
		
		<dc:creator><![CDATA[艾普利]]></dc:creator>
		<pubDate>Tue, 10 Oct 2023 02:31:00 +0000</pubDate>
				<category><![CDATA[寫程式]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[SwiftData]]></category>
		<guid isPermaLink="false">https://doeverythingiwant.com/?p=2112</guid>

					<description><![CDATA[Photo by Nathan da Silva on Un&#8230;]]></description>
										<content:encoded><![CDATA[
<p class="has-text-align-center">Photo by <a href="https://unsplash.com/@silvawebdesigns?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash" target="_blank" rel="noopener">Nathan da Silva</a> on <a href="https://unsplash.com/photos/k-rKfqSm4L4?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash" target="_blank" rel="noopener">Unsplash</a></p>



<p>WWDC23 中發表了一個新的Framework &#8211; SwiftData，它是本機端資料儲存方式之一，過去若想用DB方式將資料存在本機端最常用的就二種，一是iOS本家的Core Data，另一個就是第三方工具的SQLite，Core Data 雖然很好用，但是前置作業非常麻煩，設定完之後一定不會記得，所以SQLite看起來比較多人喜歡。</p>



<p>然而SwiftData 簡化了非常多Core Data 需要做的事情，讓資料儲存變得非常簡單，當然也完全支援SwiftUI，這樣的東西怎麼可以不學起來呢?</p>



<p>本篇主要會使用Apple 與 AppCoda 的教學來學習</p>



<span id="more-2112"></span>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p>想要使用SwiftData 需要使用 <strong>Xcode15 &amp; iOS 17</strong> 才行</p>



<p>本篇的參考教學文章在此</p>



<p>Apple</p>



<ul class="wp-block-list">
<li><a href="https://developer.apple.com/videos/play/wwdc2023/10154/" target="_blank" rel="noreferrer noopener">WWDC23 Build an app with SwiftData</a></li>



<li>Sample code <a href="https://developer.apple.com/documentation/SwiftUI/Building-a-document-based-app-using-SwiftData" target="_blank" rel="noreferrer noopener">Building a document-based app using SwiftData</a></li>
</ul>



<p>AppCoda</p>



<ul class="wp-block-list">
<li><a href="https://www.appcoda.com/swiftdata/" target="_blank" rel="noreferrer noopener">Getting Started with SwiftData for SwiftUI Development</a></li>
</ul>



<p>本文章的程式碼多數來自於Apple的 Sample code</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p>SwiftData 是和Core Data 一樣可以讓你將資料儲存在本機端中，它特別的地方在於可以直接將寫好的DataModel 變成是儲存的物件且寫法非常簡單，首先需要寫好一個DataModel，請注意必需要使用Class 才行</p>



<h2 class="wp-block-heading">建立Model</h2>



<p>若是下載原本的Sample code 的話配合WWDC23的影片一起學習會比較好喔，我是直接抓重點來說，借用在 Building a document-based app using SwiftData 的範例中的 Card DataModel</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-swift" data-lang="Swift" data-show-lang="1"><code>final class Card {
    var front: String
    var back: String
    var creationDate: Date

    init(front: String, back: String, creationDate: Date = .now) {
        self.front = front
        self.back = back
        self.creationDate = creationDate
    }
}</code></pre></div>



<p>若要把這個Card 變成 SwiftData 的 Model的話，只要做二個步驟</p>



<p>第一是<strong> import SwiftData</strong></p>



<p>第二是在 Class 加上 <strong>@Model</strong></p>



<p>好，完工</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-swift" data-lang="Swift"><code>import SwiftData

@Model
final class Card {
    var front: String
    var back: String
    var creationDate: Date

    init(front: String, back: String, creationDate: Date = .now) {
        self.front = front
        self.back = back
        self.creationDate = creationDate
    }
}</code></pre></div>



<p>沒錯，就是這麼簡單! 如果想要設定 Unique Key 例如像是 ID 之類的，當然可以設定，只要在參數前面加上 <code>@Attribute(.unique)</code> 就行了</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-swift" data-lang="Swift"><code>@Model
final class Card {
    @Attribute(.unique) var cardId: String
    ...
}</code></pre></div>



<p>還有一個比較特別的寫法是，如果哪天想要為這個參數變更名字，又不想要讓這個參數變成是一個新的參數，可以使用 <code>@Attribute(originalName:)</code>，這樣它就會自動對應到過去的名稱</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-swift" data-lang="Swift"><code>@Model
final class Card {
    @Attribute(originalName: &quot;creationDate&quot;) var creation_Date: Date
    ...
}</code></pre></div>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">在SwiftUI 上使用</h2>



<p>接著說明怎麼串接到 SwiftUI 的畫面裡，先找到有 <code>@main</code> 的檔案，在 <code>ContentView()</code> 下加上</p>



<p><code>.modelContainer(for: Card.self)</code>，modelContainer 記得先前在使用Core Data 的時候也有類似的設定，這裡是把想要做為SwiftData 的model 在 for: 後面，當然可以寫很多個用Array 形式來寫</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-swift" data-lang="Swift"><code>import SwiftUI
import SwiftData

@main
struct SwiftDataFlashCardSample: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
                .modelContainer(for: Card.self)
        }
    }
}</code></pre></div>



<p>接著在需要使用SwiftData 的View 上宣告 modelContext ，這就是用來做新增與刪除，再來就是要做Query ，只要宣告要使用的參數，這裡是 <code>var cards: [Card]</code>，在最前面的地方寫上 <code>@Query</code> 就完成了，</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-swift" data-lang="Swift"><code>import SwiftData
struct ContentView: View {
    @Environment(\.modelContext) private var modelContext
    @Query private var cards: [Card]
    ...
}</code></pre></div>



<p>也可以在Query 的時候加上 Sort 或 Filter</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-swift" data-lang="Swift"><code>@Query(sort: \.creationData) private var cards: [Card]
@Query(filter: #Predicate&lt;Person&gt; { Person in $0.name == &quot;John&quot; }) private var persons: [Person]</code></pre></div>



<p>加上 <code>@Query</code> 的參數就會自動追蹤變化，在參數有變更的時候自動更新畫面，所以並不需要特別做什麼處理。</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">資料操作</h2>



<p>接著來說操作，資料操作主要的就是三個動作，新增(insert)、修改(update)與刪除(Delete)</p>



<h2 class="wp-block-heading">Insert</h2>



<p>Insert 的時候要使用到先前宣告過的 modelContext，呼叫 insert 的 function 即可</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-swift" data-lang="Swift"><code>let newCard = Card(front: &quot;Sample Front&quot;, back: &quot;Sample Back&quot;)
modelContext.insert(newCard)</code></pre></div>



<h2 class="wp-block-heading">Update</h2>



<p>其實寫上 <code>@Model</code> 的 Data Object，SwiftData 就會自動追蹤參數變化，只要是已經有新增過的 Item 不需要特別寫些什麼，SwiftData 就會自動去更新它的參數內容</p>



<h2 class="wp-block-heading">Delete </h2>



<p>Delete 的時候和 Insert 一樣，可以告訴它想刪除的item 是那一個，也可以寫條件刪除</p>



<div class="hcb_wrap"><pre class="prism line-numbers lang-swift" data-lang="Swift"><code>let card = Cards[0]
modelContext.delete(card)</code></pre></div>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p>目前感覺SwiftData 比起Core Data 來說簡單很多，不過畢竟 SwiftData 才剛推出，功能就沒有 Core Data強大，就如同SwiftUI 剛推出的時候一樣，有很多UIKit 很容易做到的事情，SwiftUI 還沒有支援，相信之後SwiftData 功能會慢慢變多，就等它未來發展啦</p>



<p>最後祝大家 Coding 愉快!!</p>



<p>可以在<a href="https://github.com/AprilXMoon/Todolist" target="_blank" rel="noreferrer noopener">這裡</a>下載我依照 AppCoda 教學做出的Sample code</p>
]]></content:encoded>
					
					<wfw:commentRss>https://doeverythingiwant.com/learningswiftdata/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>從零開始寫 WatchOS(3) &#8211; Trouble Shootings</title>
		<link>https://doeverythingiwant.com/learning_watchos3_trouble_shootings/</link>
					<comments>https://doeverythingiwant.com/learning_watchos3_trouble_shootings/#respond</comments>
		
		<dc:creator><![CDATA[艾普利]]></dc:creator>
		<pubDate>Sun, 16 Jul 2023 09:24:32 +0000</pubDate>
				<category><![CDATA[寫程式]]></category>
		<category><![CDATA[iOS]]></category>
		<category><![CDATA[WatchOS]]></category>
		<guid isPermaLink="false">https://doeverythingiwant.com/?p=2072</guid>

					<description><![CDATA[Photo by Raagesh C on Unsplash&#8230;]]></description>
										<content:encoded><![CDATA[
<p class="has-text-align-center">Photo by <a href="https://unsplash.com/@raagesh?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" target="_blank" rel="noopener">Raagesh C</a> on <a href="https://unsplash.com/wallpapers/iphone/apple-watch?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText" target="_blank" rel="noopener">Unsplash</a></p>



<p>當好不容易把Watch OS App 寫好之後，開開心心按下 Run 然後就發現怎麼跑起來和我想像的不一樣? 就算是用實機也無法順利執行App，如果你也有這個煩惱(?) 這篇把我在開發過程中遇到的問題紀錄下來，也許可以幫助到你</p>



<span id="more-2072"></span>



<h2 class="wp-block-heading">Pair Watch with simulator</h2>



<p>實機的話就比較不會有配對問題，若想要用Simulator 來跑的話，要怎麼樣才能配對Watch ?</p>



<p>首先，請記得下載 Watch Simulator，沒下載就什麼都不用說了</p>



<p>打開Xcode 之後請到 <strong>Window</strong> -> <strong>Devices and Simulators</strong>，選擇想要使用的Simulator在畫面上可以看到 Paired watches 這區，按下 + </p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="686" src="https://doeverythingiwant.com/wp-content/uploads/2023/07/w001-1024x686.png" alt="" class="wp-image-2073" srcset="https://doeverythingiwant.com/wp-content/uploads/2023/07/w001-1024x686.png 1024w, https://doeverythingiwant.com/wp-content/uploads/2023/07/w001-300x201.png 300w, https://doeverythingiwant.com/wp-content/uploads/2023/07/w001-768x514.png 768w, https://doeverythingiwant.com/wp-content/uploads/2023/07/w001-1536x1028.png 1536w, https://doeverythingiwant.com/wp-content/uploads/2023/07/w001-2048x1371.png 2048w, https://doeverythingiwant.com/wp-content/uploads/2023/07/w001-1920x1286.png 1920w, https://doeverythingiwant.com/wp-content/uploads/2023/07/w001-1170x783.png 1170w, https://doeverythingiwant.com/wp-content/uploads/2023/07/w001-585x392.png 585w, https://doeverythingiwant.com/wp-content/uploads/2023/07/w001-263x175.png 263w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>接著就可以選取想要配對的Watch，要記得自己配對的機種，之後在跑程式的時候記得要跑有配對的Simulator 才行喔</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="532" src="https://doeverythingiwant.com/wp-content/uploads/2023/07/w002-1024x532.png" alt="" class="wp-image-2074" srcset="https://doeverythingiwant.com/wp-content/uploads/2023/07/w002-1024x532.png 1024w, https://doeverythingiwant.com/wp-content/uploads/2023/07/w002-300x156.png 300w, https://doeverythingiwant.com/wp-content/uploads/2023/07/w002-768x399.png 768w, https://doeverythingiwant.com/wp-content/uploads/2023/07/w002-585x304.png 585w, https://doeverythingiwant.com/wp-content/uploads/2023/07/w002.png 1098w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<h2 class="wp-block-heading">明明沒有出現 Error 訊息，資料卻沒有互相傳遞?</h2>



<p>這時候需要<strong>檢查二個地方</strong></p>



<h3 class="wp-block-heading">First</h3>



<p><strong>iOS App Target </strong>中的 <strong>General</strong> -><strong> Frameworks, Libraries and Embedded Content</strong>，是否有把 Watch OS App 給加進去</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="179" src="https://doeverythingiwant.com/wp-content/uploads/2023/07/w003-1024x179.png" alt="" class="wp-image-2077" srcset="https://doeverythingiwant.com/wp-content/uploads/2023/07/w003-1024x179.png 1024w, https://doeverythingiwant.com/wp-content/uploads/2023/07/w003-300x52.png 300w, https://doeverythingiwant.com/wp-content/uploads/2023/07/w003-768x134.png 768w, https://doeverythingiwant.com/wp-content/uploads/2023/07/w003-1536x268.png 1536w, https://doeverythingiwant.com/wp-content/uploads/2023/07/w003-1920x336.png 1920w, https://doeverythingiwant.com/wp-content/uploads/2023/07/w003-1170x205.png 1170w, https://doeverythingiwant.com/wp-content/uploads/2023/07/w003-585x102.png 585w, https://doeverythingiwant.com/wp-content/uploads/2023/07/w003.png 1968w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<h3 class="wp-block-heading">Second</h3>



<p>Watch OS Target 中的 Info 裡 <code>WKCompanionAppBundleIdentifier</code> ，這個參數後面要帶上 iOS App 的Bundle id，Watch OS App 是用這個參數在找要連接的 iOS App 所以可不要寫錯了</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="36" src="https://doeverythingiwant.com/wp-content/uploads/2023/07/w004-1024x36.png" alt="" class="wp-image-2078" srcset="https://doeverythingiwant.com/wp-content/uploads/2023/07/w004-1024x36.png 1024w, https://doeverythingiwant.com/wp-content/uploads/2023/07/w004-300x11.png 300w, https://doeverythingiwant.com/wp-content/uploads/2023/07/w004-768x27.png 768w, https://doeverythingiwant.com/wp-content/uploads/2023/07/w004-1170x41.png 1170w, https://doeverythingiwant.com/wp-content/uploads/2023/07/w004-585x21.png 585w, https://doeverythingiwant.com/wp-content/uploads/2023/07/w004.png 1410w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<h2 class="wp-block-heading">打包失敗</h2>



<p>在好不容易跑起來且測試沒有問題時，要打包卻發現打包失敗!?</p>



<p>這時候請檢查 iOS App 與 Watch OS App 的 <strong>Version &amp; Build number 是否有一致</strong>，若沒有一致的話，會打包失敗的</p>



<p></p>



<p>以上皆是我自己遇到的問題，若有誤歡迎告知</p>



<p>最後祝大家 Coding 愉快!!</p>
]]></content:encoded>
					
					<wfw:commentRss>https://doeverythingiwant.com/learning_watchos3_trouble_shootings/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
