簡體   English   中英

為什么 LocalizedStringKey 的行為取決於我是否將字符串插值傳遞給它的初始化程序?

[英]Why does the behaviour of LocalizedStringKey depend on whether I pass a string interpolation to its initialiser?

在嘗試回答這個問題時,我發現了一個奇怪的行為。

Text(LocalizedStringKey("Hello \(Image(systemName: "globe"))"))

顯示一個地球儀,但是

Text(LocalizedStringKey("Hello {world}".replacingOccurrences(of: "{world}", with: "\(Image(systemName: "globe"))")))
Text(LocalizedStringKey("Hello" + "\(Image(systemName: "globe"))"))

顯示“Hello”,然后是 SwiftUI 的內部術語混亂。

一個更簡單的例子是:

let x = "\(Image(systemName: "globe"))"
print(LocalizedStringKey.init(x))
print(LocalizedStringKey.init("\(Image(systemName: "globe"))"))

我傳遞給LocalizedStringKey.init的值應該是相同的,都是"\(Image(systemName: "globe"))" ,但是第一個打印

LocalizedStringKey(key: "%@", hasFormatting: true, arguments: [...])

和第二次打印

LocalizedStringKey(key: "Image(provider: SwiftUI.ImageProviderBox<SwiftUI.Image.(unknown context at $7ff91ccb3380).NamedImageProvider>)", hasFormatting: false, arguments: [])

似乎LocalizedStringKey.init改變其行為取決於我傳遞的 arguments 是否是(插值的)字符串文字。

據我所見,對LocalizedStringKey.init的兩個調用正在調用相同的初始化程序。 LocalizedStringKey中只有一個無參數標簽的初始化程序,它接受一個String

如果還有一個使用LocalizedStringKey的初始化程序,結果會更容易理解。 LocalizedStringKey 有自定義的字符串插值規則,畢竟是專門針對Image的。 但據我所知,這是唯一沒有參數標簽的初始化程序。

如果初始化程序的參數是@autoclosure () -> String ,這也是可以理解的。 如果我傳入的表達式被延遲評估,則該方法可能能夠以我不知道的某種方式“窺視”閉包。 但該參數不是自動關閉。

這里似乎發生的是編譯器正在創建一個LocalizedStringKey ,其key與您傳入的插值模式相同,即使參數是String

這里到底發生了什么? 我是否錯過了某個隱藏的初始化程序?

TL;DR :您看到的行為來自ExpressibleByStringInterpolation 但請繼續閱讀以獲得更多樂趣!

如果您認為LocalizedStringKey純粹是為了方便 SwiftUI 接口元素在使用字符串文字時“免費”本地化,那么它會變得更容易理解。 只有一個實時時間您可以直接使用它。

考慮Text 有兩個相關的初始化器:

init(_ key: LocalizedStringKey, tableName: String? = nil, bundle: Bundle? = nil, comment: StaticString? = nil)

它將嘗試本地化傳入的文本,以及

init<S>(_ content: S) where S : StringProtocol

這將顯示字符串而不改變它。

如果調用Text("Hello") ,使用哪個初始化程序?

字符串文字符合StringProtocol ,但LocalizedStringKey也是ExpressibleByStringLiteral 編譯器不知道該選擇哪一個。

為了獲得“免費”本地化, StringProtocol初始化程序用@_disfavoredOverload標記,它告訴編譯器假設字符串文字是LocalizableStringKey而不是String

因此, Text("Hello")Text(LocalizedStringKey("Hello"))是等價的。

let string = "Hello"
Text(string)

在這種情況下,沒有沖突 - 編譯器使用StringProtocol初始化程序並且字符串未本地化。

這和你的問題有什么關系? LocalizedStringKey也是ExpressibleByStringInterpolation ,這是您的“隱藏初始化程序”的來源。 但就像上面的例子一樣,這只有在你使用單個內插字符串初始化它時才會起作用。

Text("Hello \(Image(systemName: "globe"))")

您正在傳遞一個插值字符串,因此編譯器可以處理它並將圖像添加到插值中。

Text("Hello {world}".replacingOccurrences(of: "{world}", with: "\(Image(systemName: "globe"))"))

在這里,首先對replacingOccurrences(of:進行評估,這意味着您的參數是一個String ,它不被視為通過字符串插值表示的 LocalizedStringKey 。您基本上看到的是圖像的描述。

帶有+的示例也會發生類似的情況。 這隱含地生成了一個String ,因此您失去了LocalizedStringKey為您提供的特殊圖像插值。

對於您的最后一個代碼示例:

let x = "\(Image(systemName: "globe"))"
print(LocalizedStringKey.init(x))
print(LocalizedStringKey.init("\(Image(systemName: "globe"))"))

x是一個包含圖像描述的字符串。 請記住,只有LocalizedStringKey具有真正理解和表示Image的魔力。 任何其他字符串插值將回退到插值 object 的描述。

第一個初始化程序傳遞一個字符串(它被視為一個鍵,如果您在運行時生成鍵並希望使用它們進行查找,那是您真正直接使用LocalizedStringKey的唯一一次)。

第二個初始化程序使用ExpressibleByStringInterpolation並使用LocalizedStringKey.StringInterpolation將圖像插入其內部存儲,然后可以由Text呈現。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM