Swift Tip: Local Struct Definitions
While working on our re-implementation of the Swift Talk backend in Swift, we stumbled across βΒ or stumbled over? β a somewhat obscure language feature. Thankfully, it turned out to be helpful, and maybe you'll find it useful too.
We're using Swift's Codable
feature to generate and parse the JSON and XML strings needed for API requests. This technique is something we talk about in Swift Talk 115 (a public episode) and 116, where we implement a custom XML decoder.
Let's say we need to send the following XML to the server:
<billing_info>
<account_id>Some UUID</account_id>
<token_id>Some Token</token_id>
</billing_info>
Instead of generating this XML string using string interpolation, we create a codable struct that represents the contents of the XML:
struct UpdateBillingInfo: Codable, RootElement {
var account_id: UUID
var token_id: String
static let rootElementName = "billing_info"
}
Then we use our custom XML encoder to turn an UpdateBillingInfo
value into an XML string. The XML encoder can take care of all the proper formatting and escaping, no matter what data we have to send.
Often, we don't need to use these structs elsewhere, we only need to use them in the function that generates the request. Cluttering the namespace with all these types is an unwelcome side-effect of this approach, even if we make them private or nest them within another struct.
As it happens, we can define a struct even more locally: within the body of a function!
Here's a function that generates the request with the payload above, with the struct neatly tucked away in its local scope:
func updatePaymentMethod(for accountId: UUID, token: String) -> RemoteEndpoint<RecurlyResult<BillingInfo>> {
struct Update: Codable, RootElement {
var account_id: UUID
var token_id: String
static let rootElementName = "billing_info"
}
let url = ;...
return RemoteEndpoint(xml: .put, url: url, value: Update(account_id: accountId, token_id: token))
}
This way, we can still have all the advantages of using the Codable
infrastructure for serializing data, without cluttering the namespace with extraneous types. It also becomes very clear that this type is an implementation detail of the function.
For more useful stumbles, subscribe to Swift Talk. π€