Blog

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. πŸ€“


Stay up-to-date with our newsletter or follow us on Twitter.

Back to the Blog

recent posts