前言
本期是 Swift 編輯組自主整理週報的第二十期,每個模塊已初步成型。各位讀者如果有好的提議,歡迎在文末留言。
Swift 週報在 GitHub 開源,歡迎提交 issue,投稿或推薦內容。目前計劃每兩週週一發佈,歡迎志同道合的朋友一起加入週報整理。
最無情的永遠不是環境,而是缺乏勇氣的內心。Swift社區與你一起,赤膽平亂世,長槍定江山!👊👊👊
週報精選
新聞和社區:擔心泄密!外媒:蘋果公司限制員工使用ChatGPT
提案:value 包展開的元組
Swift 論壇:討論 Xcode 忽略 Package.resolved 文件
推薦博文:萬字長文詳解如何使用 Swift 提高代碼質量
話題討論:
一羣男的在找女朋友,一羣女的在找男朋友,兩羣人互不干涉,什麼原因引起的?
上期話題結果
上期話題討論結果表明對於 AI 是否會取代軟件工程師的問題,大家的觀點存在分歧,而實際的結果可能取決於 AI 技術的發展和與人類工程師的協作方式的演變。讓我們拭目以待。
新聞和社區
擔心泄密!外媒:蘋果公司限制員工使用ChatGPT
中新經緯 5 月 19 日電 據華爾街日報中文網 19 日報道,其獲悉的一份文件以及知情人士的消息顯示,蘋果公司已經限制使用 ChatGPT 和其他外部 AI 工具。
根據這份文件,蘋果公司擔心員工使用這類程序可能會泄露機密數據。該文件還稱,蘋果公司還告訴員工,不要使用微軟所有的 GitHub 的產品 Copilot。Copilot 可以自動編寫軟件代碼。
ChatGPT 是 AI 研究公司 OpenAI 開發的一款人工智能聊天機器人。該產品於 2022 年 11 月發佈,可以進行從歷史到哲學等話題的對話,並對計算機程序代碼提供修改建議。
值得注意的是,在 ChatGPT 爆火的背後,也出現過商業泄密的重大事故。
今年 4 月,據多家媒體報道,三星電子引入聊天機器人 ChatGPT 不到 20 天,便曝出機密資料外泄,如半導體設備測量數據、產品良率等內容。為杜絕類似事故再發生,三星制定相關保護措施,該公司向員工表示,“若採取信息保護緊急措施後仍發生類似事故,公司內部網絡可能會切斷 ChatGPT 連接”。
此外,已經有國家監管機構注意到了數據安全風險。
當地時間 3 月 31 日,意大利個人數據保護局宣佈,即日起禁止使用聊天機器人 ChatGPT ,限制其開發公司 OpenAI 處理意大利用户信息,並開始立案調查。意大利個人數據保護局認為,3 月 20 日 ChatGPT 平台出現了用户對話數據和付款服務支付信息丟失情況,而該平台沒有就收集處理用户信息進行告知,且缺乏大量收集和存儲個人信息的法律依據。(中新經緯APP)
蘋果公司大幅削減其MR頭顯銷售預期,不足百萬台
品玩 5 月 19 日訊,據界面新聞消息,蘋果公司已將其期待已久的混合現實(MR)頭顯的銷售預期下調約三分之二。報道指出,蘋果最初希望每年銷售約 300 萬台,但現在已將銷售預期削減至約 100 萬台,隨後又下調至 90 萬台。該公司將於 6 月 5 日舉行全球開發者大會,預計將在會上展示該產品。該設備的售價預計會高達 3000 美元左右,是 Meta Platforms 最昂貴的 Quest Pro 頭顯售價的三倍。
提案
通過的提案
SE-0396 Never 遵守 Codable 提案通過審查。該提案已在 二十八期週報 正在審查的提案模塊做了詳細介紹。
SE-0398 允許泛型類型對包進行抽象聲明 提案通過審查。該提案已在 二十八期週報 正在審查的提案模塊做了詳細介紹。
正在審查的提案
SE-0398 value 包展開的元組 提案正在審查。
之前的 SE-0393 引入了 Value 和 Type 參數包。該提案允許引用一個包含在重複模式中的 value 包的元組值。
Swift 論壇
1) 討論SwiftUI 圖表、超大數據集和圖表疊加
2) 討論帶有線程安全屬性包裝器的可發送警告
當使用有針對性的嚴格併發進行構建時,我收到一條警告,我想知道除了使我的類型“未經檢查的可發送”之外,我是否可以做任何事情。
考慮一些線程安全的屬性包裝器:
@propertyWrapper struct ThreadSafe<Value: Sendable>: Sendable {
private let lock: Lock<Value>
var wrappedValue: Value {
get { lock.withLock { $0 } }
set { lock.withLock { $0 = newValue } }
}
init(wrappedValue: Value) {
self.init(lock: .init(initialState: wrappedValue))
}
private init(lock: Lock<Value>) {
self.lock = lock
}
}
並考慮使用它來強制執行線程安全和可發送性的類:
final class SomeSendable: Sendable {
@ThreadSafe
var someBool: Bool = false
}
即使我的課程是線程安全的,我仍然收到此警告:
Stored property '_someBool' of 'Sendable'-conforming class 'SomeSendable' is mutable
編譯器診斷似乎沒有檢查屬性包裝器的可發送性。
有沒有辦法在不使我的類型“未選中”的情況下平息此警告?
回答
問題是任何帶有 var 的類總是不可發送的,並且屬性包裝器不允許 let。
但對我來説,真正的問題是 SomeSendable 使用起來真的不是那麼安全,特別是 @ThreadSafe 是不安全的。 它使得以易受競爭影響的方式使用可變狀態變得太容易了。 由於數據被鎖定,您肯定不會遇到運行時崩潰,但您很容易得到不正確的結果。
例如,像旋轉 1,000 個任務來切換布爾值這樣簡單的事情在最後總是會產生一個真值,但有時你會得到假,有時你會得到真:
let object = SomeSendable()
for _ in 1...1000 {
Task { object.toggle() }
}
try await Task.sleep(for: .seconds(1))
print(object.someBool)
這是一個相當大的問題,它正在發生,因為 @ThreadSafe 允許直接寫入底層值。 所以像:
object.someBool = !object.someBool
…隱藏競爭條件。
實際上,您可能應該直接在類中保留 Lock 值,而不是使用 @ThreadSafe 屬性包裝器,然後僅通過它的 withValue 進行變異。 當然,如果可變數據的安全是最重要的問題,那麼您真的應該使用 actor。
3) 討論無法在文檔註釋中使用片段?
我閲讀 SE-0356 的方式應該可以在 Swift 包的 Snippets 文件夾中創建一個片段文件,然後通過@Snippet 在我的文檔評論中引用它。
但這似乎並不像我預期的那樣工作(使用 Xcode 14.3 / Swift 5.8):
@Snippet 給我警告:“符號源文檔不支持指令”
顯示我記錄的類型的快速幫助不包括片段。
使用菜單“產品”>“構建文檔”生成沒有代碼片段的文檔。
回答
片段在 Swift 5.7 中實現,並可通過 swift-docc-plugin 與 SwiftPM 一起使用,但正如其他人指出的那樣,沒有與基於 Xcode 的文檔工作流集成,因為它使用不同的構建系統。 我會更新提案。
4) 討論 Xcode 忽略 Package.resolved 文件
我不確定這是 SPM 問題還是 Xcode 問題,但將 SPM 與 Xcode 一起使用時最令人沮喪的經歷之一是它經常忽略我的 repo 中的 Package.resolved 文件,通常是在切換分支或不同機器之間時。
Package.resolved 文件應該是我的依賴項的真實來源,它永遠不應該被忽略——如果有問題,包解析失敗,但永遠不要改變我的依賴項。
似乎發生的情況是,Xcode 更願意使用其源緩存中恰好滿足包版本要求的庫版本,而不是解析文件中的庫版本。 例如,我有一個版本要求為“2.2.0 up to next minor”的庫。
Package.resolved 文件中有 2.2.3,所以這是我希望始終使用的版本,除非我進行一些會引入衝突的更改。 當我在另一台機器上打開同一個項目時,出於某種原因它堅持要更改為 2.2.2,大概這是它緩存中的版本。 為什麼? 如果可以忽略已解析文件的意義何在?
回答
我可能遺漏了一些細節,但在更新到 Xcode 14.3 並在我們的 CI 中面對這個問題時,我們意識到我們從未使用 -onlyUsePackageVersionsFromResolvedFile 標誌調用 xcodebuild。 現在我們這樣做了,而且 CI 似乎尊重我們的 Package.resolved 文件。
對於我們來説,這個問題只存在於 Xcode 的 GUI 中。 (與此同時,我同樣感到困惑,為什麼需要 -onlyUsePackageVersionsFromResolvedFile 而不是 CLI 和 GUI 的默認模式!)
5) 討論如果沒有 Objective-C 或 Swift,如何在 C 或 C++ 中從 CGDirectDisplayID 檢索顯示名稱?
我試圖在純 C++(或 C)中從 CGDirectDisplayID 獲取顯示名稱
我可以在 Objective-C++ 中做到這一點,類似於:
#import <Foundation/Foundation.h>
#import <CoreGraphics/CoreGraphics.h>
#import <IOKit/graphics/IOGraphicsLib.h>
#import <Cocoa/Cocoa.h>
#include <string>
bool getDisplayNameForDispID(CGDirectDisplayID dispID,
std::string& strOutName)
{
bool bRes = false;
strOutName.clear();
NSArray *screens = [NSScreen screens];
for (NSScreen *screen in screens)
{
NSDictionary* screenDictionary = [screen deviceDescription];
if(screenDictionary)
{
NSNumber* screenID = [screenDictionary objectForKey:@"NSScreenNumber"];
if(screenID)
{
CGDirectDisplayID aID = [screenID unsignedIntValue];
if(aID == dispID)
{
//Got it
NSString* pName = [screen localizedName];
strOutName.assign([pName UTF8String], [pName lengthOfBytesUsingEncoding:NSUTF8StringEncoding]);
bRes = true;
break;
}
}
}
}
return bRes;
}
但是,我不想僅僅為了完成這一項任務而將這個緩慢的 Objective-C 代碼添加到我的項目中。 在低級 C 中,必須有一種方法可以做到這一點。
我知道有一個完整的主題專門討論它。 由於 CGDisplayIOServicePort 已棄用並且僅返回 0 並且任何後續調用都會執行操作,因此請注意,沒有任何解決方法為 macOS Ventura 提供工作。
回答
如果您堅持不直接使用任何 Objective C 代碼,您仍然可以使用 Objective C 運行時 API 從 C 調用 Objective C API,例如:
Class nsScreen = objc_lookUpClass("NSScreen");
objc_object *screens = objc_msgSend(nsScreen, sel_getUid("screens"));
// Desugaring "fast enumeration" is particularly knarly.
// for (NSScreen *screen in screens)
objc_object *enumerator = objc_msgSend(screens, sel_getUid("objectEnumerator"));
objc_object *screen;
while ((screen = objc_msgSend(enumerator, sel_getUid("nextObject")) != nil) {
// ...
}
// ...
你會發現它比 Objective C 代碼(實際上只是這類函數調用的語法糖)要“遲鈍”得多,因為你需要一直轉換所有內容。
我也完全忘記了手動添加內存管理。 你需要保留/釋放一大堆東西。 真是一團糟。 如果你可以管理它,我強烈建議將其編譯為 Objective C。
6) 討論任務取消是否傳播到 URLSession 任務?
let task = Task {
let (data, response) = try await URLSession.shared.data(from: URL(string: "https://some-image-url.com")!)
// ...
}
然後我執行 task.cancel(),URLSession 是否也會自動取消 URLSessionTask? 假設 URLSessionTask 也被取消似乎很粗心,但我找不到關於此事的任何文檔。 但是,如果 URLSessionTask 沒有自動取消,那麼我不得不使用基於閉包的 URLSession.dataTask(with:,completionHandler:) 來獲取對 URLSessionTask 的引用,然後還調用 dataTask.cancel() 在 task.cancel() 之上,這有點奇怪。
回答
import Foundation
func main() async {
let t = Task {
do {
print("\(Date.now): task will start")
let url = URL(string: "https://postman-echo.com/delay/10")!
let request = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalCacheData, timeoutInterval: 60.0)
let (data, response) = try await URLSession.shared.data(for: request)
print("\(Date.now): task did complete, response: \(response), data: \(data)")
} catch {
print("\(Date.now): task did error")
}
}
if true {
try? await Task.sleep(for: .seconds(1))
print("\(Date.now): will cancel task")
t.cancel()
print("\(Date.now): did cancel task")
}
print("\(Date.now): waiting")
try? await Task.sleep(for: .seconds(60))
}
await main()
打印結果:
2023-05-18 08:18:52 +0000: task will start
2023-05-18 08:18:53 +0000: will cancel task
2023-05-18 08:18:53 +0000: did cancel task
2023-05-18 08:18:53 +0000: waiting
2023-05-18 08:18:53 +0000: task did error
7) 討論發展 Swift 工作組
今天,Swift 核心團隊宣佈對 Swift 的結構、工作和周圍的人進行前瞻性的改變。 這些更改包括新的組、名稱、組織以及作為每個組的一流概念的包含。
鏈接:https://www.swift.org/blog/evolving-swift-project-workgroups/
推薦博文
萬字長文詳解如何使用 Swift 提高代碼質量 | 京東雲技術團隊
摘要: 文章介紹瞭如何使用 Swift 提高代碼質量。 Swift 的三個重要特性:富有表現力、安全性和快速。通過使用這些特性,可以提高代碼質量並減少 Crash 的發生率。同時,本文還分享了一些實踐技巧來提高使用 Swift 編寫代碼的效率和可讀性,如利用編譯檢查、減少使用 Any/AnyObject 、不推薦大量使用 Dictionary 數據結構等。最後,從性能優化的角度,談到了使用源代碼打包,減少方法動態派發,使用 Slice 共享內存優化性能等來提高代碼質量。
swiftUI 中視圖疊加的強大能力
摘要: 本博客文章討論了 SwiftUI 中兩個有趣的疊加使用案例。第一個案例涉及使用疊加來保持視圖的結構標識,這對於防止性能問題和狀態丟失至關重要。第二個用例是通過疊加視圖修飾符構建自定義導航轉換,使開發人員能夠創建流暢的動畫而不依賴 NavigationView 或 NavigationStack。提供示例以説明這些概念,並提供其他資源供進一步學習。總體而言,本文展示了 SwiftUI 中疊加功能的強大之處以及它們如何增強應用程序開發中用户體驗。
SwiftUI 中的文件導入和導出
摘要: 本篇博客討論瞭如何使用 fileImporter 和 fileExporter 視圖修飾符在 SwiftU I視圖中導入和導出文件。文章包括兩種操作的代碼示例,以及一個額外部分介紹如何使用 fileMover 視圖修改器進行文件移動。此外,還介紹了 TextDocument 類型,它符合 FileDocument 協議並允許從文件讀取純文本字符串,並將字符串數據導出到文件。總體而言,這篇文章強調了使用這些簡單的視圖修飾符可以輕鬆實現 SwiftUI 應用程序中的文件管理體驗。
話題討論
一羣男的在找女朋友,一羣女的在找男朋友,兩羣人互不干涉,什麼原因引起的?
1、社交隔閡:社交圈子的分隔和交流機會的減少
2、忙碌生活:現代社會的快節奏和高壓力導致個人時間和精力有限
3、數字化社交:社交媒體和在線交友平台的興起導致
4、個人選擇標準的提高:個人對伴侶的要求變得更加苛刻,導致匹配的難度增加
5、社會觀念的變化:個人對戀愛和婚姻的態度發生了變化,導致對尋找戀愛對象的需求減少
歡迎在文末留言參與討論。
關於我們
Swift社區是由 Swift 愛好者共同維護的公益組織,我們在國內以微信公眾號的運營為主,我們會分享以 Swift實戰、SwiftUl、Swift基礎為核心的技術內容,也整理收集優秀的學習資料。
特別感謝 Swift社區 編輯部的每一位編輯,感謝大家的辛苦付出,為 Swift社區 提供優質內容,為 Swift 語言的發展貢獻自己的力量。