(I tried to post in the Apple dev forums but they don't really work yet.)
I'd never seen this before:
How are you supposed to format it if you define the arguments locally?
Text(
"""
\(
{ var nameComponents = PersonNameComponents()
nameComponents.givenName = "Given"
nameComponents.familyName = "Family"
return nameComponents as NSPersonNameComponents
} (),
formatter: {
let formatter = PersonNameComponentsFormatter()
formatter.style = .long
return formatter
} ()
)
"""
)
Lantua
2
You mean ExpressibleByStringInterpolation? Most of the SwiftUI types use LocalizedStringKey which has its own StringInterpolation. You can consult StringInterpolationProtocol on how the transformation work.
TD;DR, LocalizedStringKey supports:
\(x as String)
-
\(x as T, specifier: y as String) where T is the curious _FormatSpecifiable
-
\(x as Subject, formatter: y as Formatter?) where
-
Subject is NSObject, or
-
Subject is ReferenceConvertible.
And the new ones (beta):
\(x as Text)
\(x as Image)
\(x as ClosedRange<Date>)
\(x as DateInterval)
\(x as Date, style: y as Text.DateStyle)
You can also add your own if you'd like.
3 Likes
Thanks!
Can it be formatted without """ or a giant line with semicolons?
Lantua
4
I'm pretty sure it works the same way with all string literals (Strings and Characters–String Literal). They only differ in how special characters, like \r\n\t, are handled*.
I don't think it'd work with semicolon, a; b would make them multi-statements, rather than an expression, which is what the interpolation needs (they're just normal functions).
* Since #"extended string#" also changes how \ is handled. You'd need to match the number of # in the beginning for \ to have effect, so you'd need \###(x) instead of regular \(x) if you use ###"..."###.
1 Like
It works. I don't know the reasoning. I just saw \() not working on one line so I added more "s (the above) and that works too. They just seem redundant because it's not a multi-line literal.
Text(
"\( { var nameComponents = PersonNameComponents(); nameComponents.givenName = "Given"; nameComponents.familyName = "Family"; return nameComponents as NSPersonNameComponents } (), formatter: { let formatter = PersonNameComponentsFormatter(); formatter.style = .long; return formatter } () )"
)
Lantua
6
Oh I see. That would work. What you’re essentially doing is creating a closure (bag of statements) and then call it, not too dissimilar to calling a function. So it’s an expression alright.
Because this:
{
var nameComponents = PersonNameComponents()
nameComponents.givenName = "Given"
nameComponents.familyName = "Family"
return nameComponents as NSPersonNameComponents
} ()
is just this:
// Defined somewhere else
func foo() -> NSPersonNameComponent {
var nameComponents = PersonNameComponents()
nameComponents.givenName = "Given"
nameComponents.familyName = "Family"
return nameComponents as NSPersonNameComponents
}
// simple function call
foo()
And since Swift can also use semicolon to separate statements (in addition to new line), this:
let formatter = PersonNameComponentsFormatter()
formatter.style = .long
return formatter
is the same as this
let formatter = PersonNameComponentsFormatter(); formatter.style = .long; return formatter
ole
(Ole Begemann)
7
The specifier argument takes a printf-style format string. Example:
Text("\(Double.pi, specifier: "%.4f")")
produces the text "3.1416", and
Text("0x\(255, specifier: "%llX")")
produces "0xFF".
SwiftUI uses the _FormatSpecifiable protocol to make this interpolation available to the standard number types. The integer and floating-point types from the stdlib conform to it, plus CGFloat. (Float16 doesn't in Xcode 12 beta 1 – I don't know if that's an oversight.)