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?
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?
@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?
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))
}
}
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:
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.