首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么LocalizedStringKey的行为取决于我是否将字符串内插传递给它的初始化项?

为什么LocalizedStringKey的行为取决于我是否将字符串内插传递给它的初始化项?
EN

Stack Overflow用户
提问于 2022-09-16 10:48:09
回答 1查看 91关注 0票数 3

当我试图回答这个问题时,我发现了一种奇怪的行为。

代码语言:javascript
运行
复制
Text(LocalizedStringKey("Hello \(Image(systemName: "globe"))"))

显示一个地球仪,但是

代码语言:javascript
运行
复制
Text(LocalizedStringKey("Hello {world}".replacingOccurrences(of: "{world}", with: "\(Image(systemName: "globe"))")))
Text(LocalizedStringKey("Hello" + "\(Image(systemName: "globe"))"))

显示"Hello“,后面是SwiftUI的内部术语混乱。

一个更小的例子是:

代码语言:javascript
运行
复制
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 似乎改变了它的行为,这取决于我传递的参数是否为(内插的)字符串文字。

据我所见,对LocalizedStringKey.init的两个调用正在调用相同的初始化项。在一个参数-无标签初始化器中只有LocalizedStringKey,它需要一个String

如果还有一个接受LocalizedStringKey的初始化器,那么结果就会更容易理解。毕竟,LocalizedStringKey 有自定义字符串插补规则Image。但据我所知,这是唯一没有参数标签的初始化器。

如果初始化程序的参数是@autoclosure () -> String,这也是可以理解的。如果我传入的表达式是惰性计算的,则该方法可能能够以一些我所不知道的方式“窥视”闭包。但是参数不是自动闭包。

这里所发生的事情似乎是编译器正在创建一个LocalizedStringKey,其中key与您传入的插值模式相同,尽管参数是一个String

这到底是怎么回事?我是不是错过了一个隐藏的首字母?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-09-16 11:57:35

TL;博士:你所看到的行为来自于ExpressibleByStringInterpolation。但是为了更多的乐趣继续读吧!

如果您认为LocalizedStringKey纯粹是一种方便,可以让SwiftUI接口元素在使用字符串文本时“免费”本地化,那么它就更容易理解。只有一次你会直接使用它。

考虑一下Text。有两个相关的初始化器:

代码语言:javascript
运行
复制
init(_ key: LocalizedStringKey, tableName: String? = nil, bundle: Bundle? = nil, comment: StaticString? = nil)

它将尝试本地化传入的文本,以及

代码语言:javascript
运行
复制
init<S>(_ content: S) where S : StringProtocol

它将显示字符串而不改变它。

如果您调用Text("Hello"),则使用哪个初始化程序?

字符串文字符合StringProtocol,但LocalizedStringKey也是ExpressibleByStringLiteral。编译器不知道要选择哪一个。

为了获得“免费”的本地化,StringProtocol初始化器被标记为@_disfavoredOverload,这告诉编译器假定字符串文本是LocalizableStringKey而不是String

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

代码语言:javascript
运行
复制
let string = "Hello"
Text(string)

在这种情况下,没有冲突-编译器使用StringProtocol初始化程序,并且字符串没有本地化。

这和你的问题有什么关系?LocalizedStringKey也是ExpressibleByStringInterpolation,这就是你的“隐藏初始化器”的来源。但是就像上面的例子一样,只有当你用一个插入的字符串初始化它时,这才会起作用。

代码语言:javascript
运行
复制
Text("Hello \(Image(systemName: "globe"))")

您正在传递一个内插字符串,因此编译器可以处理它并将图像添加到插值中。

代码语言:javascript
运行
复制
Text("Hello {world}".replacingOccurrences(of: "{world}", with: "\(Image(systemName: "globe"))"))

在这里,首先对replacingOccurrences(of:进行计算,这意味着您的参数是一个String,它不被视为通过字符串插值表示的LocalizedStringKey。你基本上看到了图像的描述。

+的示例也会发生类似的情况。这就隐式地形成了一个String,所以你失去了LocalizedStringKey给你的特殊图像插值。

对于最后一个代码示例:

代码语言:javascript
运行
复制
let x = "\(Image(systemName: "globe"))"
print(LocalizedStringKey.init(x))
print(LocalizedStringKey.init("\(Image(systemName: "globe"))"))

x是一个包含图像描述的字符串。记住,只有LocalizedStringKey才有真正理解和表示Image的神奇力量。任何其他字符串插值都将回到插值对象的描述。

第一个初始化器是传递一个字符串(如果您在运行时生成键并希望使用它们来查找,则这是唯一一次真正直接使用LocalizedStringKey )。

第二个初始化器使用ExpressibleByStringInterpolation,并使用LocalizedStringKey.StringInterpolation将图像插入到其内部存储中,然后由Text呈现。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73743661

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档