<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Swift on Joe's Blog</title><link>https://shinrenpan.github.io/tags/swift/</link><description>Recent content in Swift on Joe's Blog</description><generator>Hugo</generator><language>zh-tw</language><copyright>© Shinren Pan. All rights reserved.</copyright><lastBuildDate>Mon, 15 Jun 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://shinrenpan.github.io/tags/swift/index.xml" rel="self" type="application/rss+xml"/><item><title>WWDC26 What's New in Swift</title><link>https://shinrenpan.github.io/2026-06-15/</link><pubDate>Mon, 15 Jun 2026 00:00:00 +0000</pubDate><guid>https://shinrenpan.github.io/2026-06-15/</guid><description>&lt;p&gt;每年 WWDC 的 What&amp;rsquo;s New in Swift session 都是個節奏很快的大雜燴——語言改動、標準庫、效能、生態系全塞在一起。這篇只挑對 iOS 開發者日常最有感的部分。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="-日常語言改善"&gt;🧹 日常語言改善&lt;/h2&gt;
&lt;p&gt;這類改動不會讓你的架構換血，但真的很煩的地方終於修了。&lt;/p&gt;
&lt;h3 id="async-可以用在-defer-裡"&gt;async 可以用在 defer 裡&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;div style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;3
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;4
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;5
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;6
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;7
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;8
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;9
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#57606a"&gt;// 以前這樣會編譯錯誤&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#cf222e"&gt;defer&lt;/span&gt; &lt;span style="color:#1f2328"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; await cleanup&lt;span style="color:#1f2328"&gt;()&lt;/span&gt; &lt;span style="color:#57606a"&gt;// ❌&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#1f2328"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#57606a"&gt;// 現在可以了&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#cf222e"&gt;defer&lt;/span&gt; &lt;span style="color:#1f2328"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; await cleanup&lt;span style="color:#1f2328"&gt;()&lt;/span&gt; &lt;span style="color:#57606a"&gt;// ✅&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#1f2328"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;做資源清理的時候（關 file handle、送 analytics event），cleanup 本身是 async 的，以前要繞很醜的路。現在直接支援。&lt;/p&gt;</description></item><item><title>Swift 網路層生存指南 (Final) —— JPNetworking</title><link>https://shinrenpan.github.io/2026-06-14/</link><pubDate>Sun, 14 Jun 2026 00:00:00 +0000</pubDate><guid>https://shinrenpan.github.io/2026-06-14/</guid><description>&lt;p&gt;前三篇（&lt;a href="https://shinrenpan.github.io/2026-01-01"&gt;1&lt;/a&gt;、&lt;a href="https://shinrenpan.github.io/2026-01-10"&gt;2&lt;/a&gt;、&lt;a href="https://shinrenpan.github.io/2026-02-06"&gt;3&lt;/a&gt;）講完了救災概念——SafeBox 處理型別錯置、ShieldedResponse 導航巢狀 JSON、BaseResponse 統一外殼解析。&lt;/p&gt;
&lt;p&gt;這篇把這套思路打包成 Swift Package：&lt;a href="https://github.com/shinrenpan/JPNetworking"&gt;JPNetworking&lt;/a&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="-架構概覽"&gt;🏛️ 架構概覽&lt;/h2&gt;
&lt;pre class="mermaid"&gt;flowchart TD
 A([URLSession.request]) --&amp;gt; B[Build URLRequest]
 B --&amp;gt; C[networkLogger .request]
 C --&amp;gt; D[URLSession.data]
 D --&amp;gt; E{statusCode}
 E --&amp;gt;|401| F{refresher &amp;amp; 首次 401?}
 F --&amp;gt;|no| ERR([throw APIError])
 F --&amp;gt;|yes| G[TokenRefresher.refresh]
 G --&amp;gt; D
 E --&amp;gt;|other| H[networkLogger .response]
 H --&amp;gt; I[EndPoint.validate]
 I --&amp;gt;|throws| ERR
 I --&amp;gt;|ok| J[decode]
 J --&amp;gt;|throws| ERR
 J --&amp;gt;|ok| K([Return T])
 D --&amp;gt;|network error| L{retriesLeft &amp;gt; 0?}
 L --&amp;gt;|yes| D
 L --&amp;gt;|no| ERR
 &lt;/pre&gt;

&lt;hr&gt;
&lt;h2 id="-安裝"&gt;📦 安裝&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;div style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;
&lt;table style="border-spacing:0;padding:0;margin:0;border:0;"&gt;&lt;tr&gt;&lt;td style="vertical-align:top;padding:0;margin:0;border:0;"&gt;
&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;1
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;2
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;3
&lt;/span&gt;&lt;span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"&gt;
&lt;pre tabindex="0" style="background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-swift" data-lang="swift"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#57606a"&gt;// Package.swift&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dependencies&lt;span style="color:#1f2328"&gt;:&lt;/span&gt; &lt;span style="color:#1f2328"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#1f2328"&gt;.&lt;/span&gt;package&lt;span style="color:#1f2328"&gt;(&lt;/span&gt;url&lt;span style="color:#1f2328"&gt;:&lt;/span&gt; &lt;span style="color:#0a3069"&gt;&amp;#34;https://github.com/shinrenpan/JPNetworking&amp;#34;&lt;/span&gt;&lt;span style="color:#1f2328"&gt;,&lt;/span&gt; from&lt;span style="color:#1f2328"&gt;:&lt;/span&gt; &lt;span style="color:#0a3069"&gt;&amp;#34;0.1.0&amp;#34;&lt;/span&gt;&lt;span style="color:#1f2328"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#1f2328"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;或在 Xcode：&lt;strong&gt;File → Add Package Dependencies&lt;/strong&gt;。&lt;/p&gt;</description></item></channel></rss>