💬 Pofat 的話
這期我調整了一下週報的結構,從 community,forum 和近期的 commit 這三個不同面向來分類我挑選的新聞,希望能給讀者更清晰的閱讀體驗,也更容易找到自己想看的範圍。
如果喜歡本期的內容或新的週報結構請務必按下 ❤️ 或 💬 留言給我回饋,也請訂閱我的 Patreon 支持我🙏,可以幫助我做得更好。
🌎 On Swift Community
全面重新用 Swift 打造的古老專案 - Graphing Calculator
Ron Avitzur 從 1985 年開始打造一個可以繪製數學方程式圖形的軟體工具,其所用的技術幾乎也都停留在了 80 年代。然而一次 Apple AR 技術的遊玩體驗讓 Ron 興起了從頭用 Swift 重寫的決心。
最終的心得是,更少、更簡潔和更好維護的程式碼,但在性能方面因為安全性的關係仍難企及 C++,當然後者的高性能也有著相對脆弱的代價。
我認為它的重寫對照表很有趣,截取部分如下:
pthreads -> Swift structure concurrency
C++ char -> Swift String
AppKit/UIKit -> SwiftUI
OpenGL -> SceneKit & Metal
1-2-N 法則
無論是測試或者切分方法,一種理想上的完美方針是一直測到或切到最小單位(atomic),但何謂最小單位?
只為小而小最後通常落入無窮無盡的瑣碎之海,執行上並不實際。這裡有個不錯的判斷法則來做為切分界線實務上的依據:
是 P 還 Q?
Swift 小猜謎,先別急著打開 Xcode 或編輯器,猜猜看結果是什麼?
(解答於此)
🗣️ On Swift Forum
Optional Comparison Revisited
Optional
為什麼不能讓它比大小呢?
其實原本是可以的,但 SE-0121 移除了 Comparable 。主因是由於隱含著兩種不同的型別,在排序等 Array 的操作可能出現驚喜(啊我堂堂一個 .none
到底算老幾?)
相等的定義很明確,但比大小(或先後順序)就相對有「模糊空間」了,可能因場合而會有不同的狀況,最後決定把這個行為留給使用者自行掌控。在 SE-0121 中舉的例子是 filter:
這讓我想起一件有點相關的往事,曾經我參與的一個專案在 app 完全沒更新,僅是使用者升級至 iOS 12 的情況下網路請求量爆增,一度讓後端差點掛點,使用者只是升個級怎麼會這樣呢?
經過查找後發現原來有個下載更新的邏輯是拿兩個格式為 NSNumber
的時間數字用 > 相比,這種比法完全錯誤,變成是在相比指標的位址。只是好巧不巧地它在 iOS 12 前會在某些範圍內正常運作,因為 tagged pointer(一種用位址表示實際數值以節省記憶體空間用量的方法)的緣故。
然而 iOS 12 因為安全性的考量就加上了 mask ,改變了 tagged pointer 的表示方法(看到位址就能知道值著實有隱憂),於是這個 > 就炸裂了。。。
我的程式會動,也不過是一連串的巧合罷了。
Double 到 CGFloat 的無縫接軌有代價嗎?
先說結論:用 Double 沒壞處,永遠優先考慮使用。
相信大家在寫 UI code 的 layout 時可能都經歷過要把 Double
轉成 CGFloat
、或讓 CGFloat
大舉入侵你專案各處的經驗。因為在 Swift 中 Double
和 CGFloat
是兩個不同的 struct ,在 ObjC 中 CGFloat
則只是 double
的別名(除了 watchOS 是 float
外)所以不成問題。 而 SE-0307 則讓兩者做隱式的無縫轉換,增加了不少易用性。
透過這樣的轉換,實際上可以將兩者視為同樣的型別,所以你應該優先使用更普遍的基本型別 Double
。
Type-private Access Level
相信大家可能都有過想在一個新檔案 extension 某個物件時,發現要用到的變數是 private
而獲取不到,最後只好搬回同一個檔案並改成 fileprivate
,最終該檔案長成一個龐然大物。
這個提議正是為此而來,由於上述也是我個人經驗,我也是支持方。提議下面的反應正反方都有,其中最值得一提的是 Dave DeLong引述了一個 Erica Sadun的陳年提案 - Flexible Access Control Scoping。
內容非常有趣,透過定義 accessgroup
可以達成自定義的 access level (這個關鍵字運作模式相似決定 operator 順序的 precedencegroup
),還允許了一次性的 access level 定義,非常有彈性
,可惜它停留在五年前的時光之中。
🎉 Swift commits
[TypeChecker] Don’t crash if a ExplicitCastExpr doesn’t have a cast type
這修復了下述的程式碼引發的 crash
[5.7][SE-0358][stdlib] Adopt primary associated types
SE-0358 的實現,從此我們可以這樣接受一個 ID 為 UUID 的 Identifiable 型別:
[5.7][Sema] Use ExistentialType for Any and AnyObject
這個 PR 修復了 compiler 中會把(any Any).Type
當做 Any.Type
的 bug (前者是 Existential Type 後者是 Protocol Type)。
🤪 Pofat 選推
時事梗(We will adopt your baby 是美國大法官宣佈墮胎權利不受憲法保障後一對男女所舉的看板文字,該句馬上成為爆紅的迷因)
一次就看懂 Swift actor:
軟體工程師的進...化(?