Using Swift string literals to load bundle resources

My new iOS fiction project relies heavily on text.

That means I want to make it easy to create that content anywhere, and I want it to be frictionless to drop it into the project as needed.

My solution: Markdown files I can load from the bundle using string literals. Look how easy:

let markdown: MarkdownFile = "markdown.md"

Here’s how to do it.

String literals

In Swift, you use string literals all the time. Usually to initialize strings.

let string: String = "Hello, I am a string."

But Swift includes a protocol called ExpressibleByStringLiteral. Which means if your Swift type adopts it, that type can be initialized with nothing more than a string. While this is immediately convenient, it has real power for assets that need tedious boilerplate. Say, anything that needs to be loaded from a bundle.

Basic example

struct MarkdownFile: ExpressibleByStringLiteral {
    
    let bundleName: String
    let rawMarkdown: String?
    
    init(stringLiteral: String) {
        
        bundleName = stringLiteral
        
        var loadedMarkdown: String? = nil
                
        if let filepath = Bundle.main.path(forResource: bundleName, ofType: nil) {
        //By skipping the ofType argument above, we'll match to the first file whose name
        //exactly matches bundleName
            do {
                let loadedString = try String(contentsOfFile: filepath)
                loadedMarkdown = loadedString
            } catch {
                print("Could not load string: \(error)")
            }
        } else {
            print("Could not find file: \(bundleName)")
        }
        
        rawMarkdown = loadedMarkdown
    }
}

Here’s a basic example of a MarkdownFile struct. It knows two things about itself: the name of the file used to initialize it, and any string it was able to load from a file in the bundle with that name.

On init it goes looking for a bundle resource matching the name it was provided through the string literal. If it finds one, and it can load its contents as a string, those contents are stored to rawMarkdown. If not, rawMarkdown returns nil.

This is already pretty convenient. Again, to initialize, all you need is:

let markdown: MarkdownFile = "markdown.md"

But we can take it further.

Adding convenience

The MarkdownFile struct can be responsible for converting its contents into a display representation, as well. Let’s add a computed property to parse the Markdown into HTML. I’ll be using Ink for this, but you could use any project—or convert it into something else, like NSAttributedString.

var htmlRepresentation: String? {
    if let raw = rawMarkdown {
        return MarkdownParser().html(from: raw)
    } else {
        return nil
    }
}

Putting it all together

With our output property all set up, we have a small, convenient API for handling Markdown files in any way we want. Here’s how we use it:

let markdown: MarkdownFile = "markdown.md"

if let html = markdown.htmlRepresentation {
    webview.loadHTMLString(html, baseURL: nil)
}

self.title = markdown.bundleName

Behind the scenes, lots of stuff is happening to load and parse the file. But when you need Markdown across your project, you need only concern yourself with a filename. If you want to change any part of how this works later on, you have a single struct that’s responsible for all the Markdown behavior in your code.

Full example code here.

Westworld: the market has bad news for plutocrats

I love this new Westworld trailer:

At 1:17, the piano comes in for a stirring Ramin Djawadi rendition of Sweet Child o’ Mine. It’s the emotional current for a montage of escaped android shenanigans with a familiar headliner: Dolores.

Ah, Dolores. Designed by the Westworld park architects to be convenient for guests to consume. A cliche of cloying womanhood to be plundered or abused. Dead thousands of times at the hands of sadistic park guests and the demands of the market.

Dolores, a rogue AI escaped in the real world, bent on revenge. The score is heroic, swelling to suggest this is all part of a grand adventure. Our sweet child coming of age, leaving principled destruction in her wake. It’s Westworld so of course it all goes off the rails by the end.

Still, HBO is selling a finely tuned narrative distilled from decades of experience selling us culturally-relevant stories. Westworld’s relevant point-of-view:

If people are hurting you, the heroic thing is to try and stop them.

HBO’s alchemy of market research and imagination has brought us an impressive share of culture-leading television, from Sex and the City to The Sopranos to Game of Thrones. They have successfully tracked the pulse of shared imagination since the 90’s.

In the guise of Westworld’s Season 3 trailer, they gave us a stylized premonition of Warren vs. Bloomberg. A world on fire, but we’re bringing the fight to the many corrupt, abusive powers that be.

I’m gonna save the fucking world

With Elizabeth Warren flagging in the first contests of the Democratic nomination, people were ready to count her out. Rumors swirled about fundraising woes. Bloomberg has argued that he and Bernie Sanders should be given the room to slug it out, with everyone else dropping out.

America’s Paypig gets roasted.

After Bloomberg’s first debate, Warren had an enormous fundraising day. Booed by the audience, Bloomberg was later forced to confront his history of paying off ex-employees to prevent public criticism, swearing to stop the practice going forward in cases of sexual misconduct. Warren isn’t even in the big chair and she’s already bringing billionaires to heel.

Popular imagination exploded with enthusiasm for Warren’s open contempt for Bloomberg’s power and record. Writing for The New Republic, Heather Souvaine Horn captures it perfectly:

Warren unsheathed her scimitar, aimed for the trouser break, and proceeded to stack bodies by her lectern like an outdoor cat leaving neighborhood mouse carcasses on progressives’ doormat.

Our culture is ready for people who have been excluded from power to rise up and reclaim it. Our culture is ready to hold people accountable for stepping on people’s necks to make their own lives more comfortable.

Westworld, cloaked in the pageantry of a robot uprising, slakes a thirst for tales fitting this bill. It has worn a contempt for the rich and powerful on its sleeve and been rewarded with three seasons of funding so far. But a presidential debate, where real power is confronted, is even more satisfying. Its ripple effects reach beyond cultural imagination, into policy and even accountability.

Somehow, we don’t need to choose between ideas and practical impact. Both are arriving together.

The invisible hand of the market finally giving us something nice.