我的代碼很簡單,在 ContentView.swift 檔案中:
import SwiftUI
struct NavTab {
let name: String
}
let tab0 = NavTab(name: "tab0")
struct ContentView: View {
var body: some View {
Text("Hello, world!")
.onAppear {
print("tab0.name is \(tab0.name)") // Line 1
}
}
}
運行代碼,會列印出tab0.name is "tab0",沒錯。
但是如果你在第 1 行添加斷點,然后在斷點處中斷,在除錯控制臺中輸入“po tab0.name”,你會看到 tab0.name 等于“”:
(lldb) po tab0.name
""
(lldb) po tab0
? NavTab
- name : ""
這是為什么?我是不是誤會了什么?謝謝!;)
uj5u.com熱心網友回復:
請注意,全域變數和靜態屬性是延遲計算的(請參閱語言指南):
全域常量和變數總是延遲計算,類似于延遲存盤屬性。與惰性存盤屬性不同,全域常量和變數不需要使用惰性修飾符進行標記。
區域常量和變數永遠不會延遲計算。
當斷點被命中時,“第 1 行”尚未運行,因此tab0尚未計算全域常量,因此其值全為零。當解釋為 aString時,表示空字串。
您可以通過添加列印某些內容的初始化程式來驗證這一點:
struct NavTab {
let name: String
init(name: String) {
self.name = name
print("init!")
}
}
@main
struct testApp: App {
var body: some Scene {
print("ContentView!")
return WindowGroup {
ContentView()
}
}
}
并看到它直到該print("tab0.name is \(tab0.name)")行之后才被呼叫。輸出:
ContentView!
init!
tab0.name is tab0
但這只是圖片的一半。為什么tab0.name在 LLDB 中評估不呼叫 gettertab0并使其初始化?
我沒有找到任何檔案,但我懷疑這是 LLDB 的一個怪癖。我懷疑當你這樣做時po tab0.name,LLDB 會直接訪問tab0存盤的記憶體區域,而不是呼叫它的 getter(也許是一種優化?)。它知道 where tab0is 因為您當前與 wheretab0宣告的檔案位于同一個檔案中。如果tab0在另一個檔案中宣告,po tab0.name則將導致tab0按照您的預期進行初始化:
(lldb) po tab0.name
init!
"tab0"
這就是為什么我懷疑這只是 LLDB 的一個怪癖。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/454707.html
上一篇:結構型:六. 組合模式
下一篇:泛型型別的轉換無法編譯
