I created a custom string interpolation function that allows me to pass in a string format specifier. I've noticed that, for whatever reason it does not work inside of a SwiftUI Text view unless I use the init(verbatim:) initializer. Consider this code:
import SwiftUI
struct ContentView: View {
let price = 5.99
var body: some View {
Text("The price is $\(price, format: "%.2f")")
}
}
extension String.StringInterpolation {
mutating func appendInterpolation(_ value: Double, format: String) {
appendInterpolation(String(format: format, value))
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
I get the error
Incorrect argument label in call (have '_:format:', expected '_:specifier:')
It seems that there's some other interpolation function using '_:specifier:', but I want to use my own custom function.
If I change
Text("The price is $\(price, format: "%.2f")")
to
Text(verbatim: "The price is $\(price, format: "%.2f")")
then it works fine. Why?
How can I implement the interpolation function in such a way that it works inside Text views?
Lantua
2
Text.init uses LocalizedStringKey, so you need to extend the interpolation there.
Also, I’d try to avoid using a common structure like \(double, format: format) in case SwiftUI decides to add it unless it’s intentional, maybe add some prefix?
@Lantua Is there anyway to extend both String and LocalizedStringKey using a protocol extension? I'd prefer not to duplicate code.
1 Like
young
(rtSwift)
4
If this is all you want, LocalizedStringKey can do it already, just do:
Text("The price is $\(price, specifier: "%.2f")")
@young But what if I want to make custom interpolation functions that work with both LocalizedStringKey and normal strings? How do I avoid writing a separate interpolation function for each?
young
(rtSwift)
6
The Text("abcd string literal") initializor is meant for localization as it do lookup of Localizable.strings. You might be able to extend it, but it worn't do lookup of your extension, I don't think.
If you just want your own interpolation on String, use:
Text(verbatim: "The price is $(price, format: "%.2f")")
This one takes a String so your custom interpolation should just work, but then you cannot localize it.
I don't care about lookups, but I also don't want to have to type the extra parameter verbatim every time I want to do string interpolations. I've discovered how to write a extension for localized strings and for regular strings, but I would like to know if I can write just a single function in a protocol extension so that I don't have to duplicate code. Is this possible? Currently, I have to do this. Notice that the functions are exactly the same.
public extension LocalizedStringKey.StringInterpolation {
mutating func appendInterpolation(_ value: Double, format: String) {
appendInterpolation(String(format: format, value))
}
}
public extension String.StringInterpolation {
mutating func appendInterpolation(_ value: Double, format: String) {
appendInterpolation(String(format: format, value))
}
}
young
(rtSwift)
8
In this case, then it makes no sense to extend LocalizedStringKey.StringInterpolation
Text(_:)
Text(verbatim:)
are two different functions, you have to type it out so the compiler can tell what you want. It can't read you mind.
odmir
(Ricardo Nogueira)
9
Making a new protocol with the correct required method and extension, and then extending LocalizedStringKeys/String.StringInterpolation with this new protocol seems to work for me:
protocol Formattable {
mutating func appendInterpolation(_: String)
}
extension Formattable {
mutating func appendInterpolation(_ value: Double, format: String) {
appendInterpolation(String(format: format, value))
}
}
extension LocalizedStringKey.StringInterpolation: Formattable {}
extension String.StringInterpolation: Formattable {}
2 Likes
I should've been more clear about this. What I meant was that I don't want to have to type Text(verbatim: "abc") everytime I want to do a string interpolation. I want to be able to just type Text("abc") and be able to use the same string interpolation functions as if I had just used a normal string.
@odmir has provided the exact answer that I'm looking for. Thanks Odmir!
Don't forget about how powerful protocol extensions are.
1 Like