当我试图回答这个问题时,我发现了一种奇怪的行为。
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
似乎改变了它的行为,这取决于我传递的参数是否为(内插的)字符串文字。
据我所见,对LocalizedStringKey.init
的两个调用正在调用相同的初始化项。在一个参数-无标签初始化器中只有LocalizedStringKey
,它需要一个String
。
如果还有一个接受LocalizedStringKey
的初始化器,那么结果就会更容易理解。毕竟,LocalizedStringKey
有自定义字符串插补规则和Image
。但据我所知,这是唯一没有参数标签的初始化器。
如果初始化程序的参数是@autoclosure () -> String
,这也是可以理解的。如果我传入的表达式是惰性计算的,则该方法可能能够以一些我所不知道的方式“窥视”闭包。但是参数不是自动闭包。
这里所发生的事情似乎是编译器正在创建一个LocalizedStringKey
,其中key
与您传入的插值模式相同,尽管参数是一个String
!
这到底是怎么回事?我是不是错过了一个隐藏的首字母?
发布于 2022-09-16 03:57:35
TL;博士:你所看到的行为来自于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
的神奇力量。任何其他字符串插值都将回到插值对象的描述。
第一个初始化器是传递一个字符串(如果您在运行时生成键并希望使用它们来查找,则这是唯一一次真正直接使用LocalizedStringKey
)。
第二个初始化器使用ExpressibleByStringInterpolation
,并使用LocalizedStringKey.StringInterpolation
将图像插入到其内部存储中,然后由Text
呈现。
https://stackoverflow.com/questions/73743661
复制相似问题