iOS Newsletter #5: What’s New in Swift 3.1?

Swift 3.1 is out, and it should be source-compatible for a change 😈. Some highlighted features and improvements are failable numeric conversions, additions to the `Sequence` protocol, improvements to extensions and support for nested generics. The easiest way to take advantage of Swift 3.1 is to get the new Xcode 8.3 and pray no new Xcode bugs have been introduced 😏.

Read More

How to run SwiftLint autocorrect on each Git commit

SwiftLint was developed by the nice folks @realm. It's a great open-source tool for establishing and enforcing a formal coding style in Swift. It runs on the command-line, but it can be hooked into Xcode directly too. It also boasts an "autocorrect" feature, which sweeps through your code and automatically fixes the most trivial violations (e.g., colon positioning, double white spaces, etc.). I created a Git commit hook which does exactly this, every time a team member makes changes.

Read More

Abolish Retain Cycles in Swift with a Single Unit Test

Can't believe we're still dealing with this in 2017? Well, that makes two of us. While retain cycles are easy to fix, they're also hard to spot while eyeballing a codebase. Recently, I've found that a single unit test can provide solace. With just a few lines of code, it runs continuously as you make changes, all the while verifying you haven't introduced any new memory leaks.

Read More

Loading custom fonts programmatically in Swift 3

How do you include custom fonts in your application, if they don't reside in the main bundle? In this case, loading them through the conventional PLIST method doesn't work, and you will need to resort to CoreGraphics to register them programmatically. 

Typefaces are an essential part of good design. On iOS, custom fonts can be added to apps through a somewhat convoluted process. Chris Ching has a good write-up on the topic, but in short: ensure the font files are properly included in your app's target and declare them in your app's Info.plist ("Fonts provided by application"). This works well in the straightforward case where the fonts are simply embedded into the main app bundle.

You quickly run into the limits of the PLIST-based registration method when they live outside of the main bundle, e.g. in a separate .framework. In this case, simply register the fonts using the older CoreGraphics APIs.

Marco Arment described the approach on his blog back in 2012, but the example code he lists is Objective-C. Fortunately, the Swift version of this code is much less cumbersome than its Obj-C counterpart, as less C-trickery is required:

// Load bundle which hosts the font files. Bundle has various ways of locating bundles.
// This one uses the bundle's identifier
guard let bundle = Bundle(identifier: "some.framework.identifier")
else { return }

// List the fonts by name and extension, relative to the bundle
let fonts = [
    bundle.url(forResource: "gotham_book", withExtension: "ttf"),
    bundle.url(forResource: "gotham_medium", withExtension: "ttf")
]

// Iterate over the resulting urls, filtering out nil-values with .flatMap()
for url in fonts.flatMap({ $0 }) {
  // Create a CGDataPRovider and a CGFont from the URL.
  // Register the font with the system.
    if let dataProvider = CGDataProvider(url: url as CFURL) {
        let font = CGFont(dataProvider)
        CTFontManagerRegisterGraphicsFont(font, nil)
    }
}

Just make sure you don't forget to remove any duplicate PLIST declarations, or your app will throw an exception at startup.

Update

@sveinhal in the comments suggested this functional rewrite of the above code, which is way more succinct if that's your cup of tea:

let fonts = [
bundle.url(forResource: "gotham_book", withExtension: "ttf"),
bundle.url(forResource: "gotham_medium", withExtension: "ttf"),
]

fonts
.flatMap { $0 }
.flatMap { CGDataProvider(url: $0 as CFURL) }
.map(CGFont.init)
.forEach { CTFontManagerRegisterGraphicsFont($0, nil) }