01 Aug 2020
So following Apple’s announcement during WWDC 2020 that they’ll be transitioning the Mac away from Intel processors to Apple Silicon it’s now time for everybody to get their software ready.
The transition this time can be considered somewhat easier for most people, especially those who are already supporting arm64 on iOS but there is still work to be done to ensure that tooling and pre-compiled distributions support both architectures ready for when Mac using Apple Silicon are made publicly available. If you haven’t already seen it, a lot of this is covered in the Port your Mac app to Apple Silicon WWDC Session Video.
If you’re using Xcode to compile your command line tools then things are pretty simple as long as you are setting the ARCHS
build setting to $(ARCHS_STANDARD)
(the default). In Xcode 12, this value is described as Standard Architectures (64-bit Intel and ARM) but if you’re using Swift Package Manager to build and distribute your binary or library, there is no such option.
Instead, starting in Swift Package Manager for Swift 5.3 (Xcode 12), the swift-build
executable has now introduced the --arch
option (apple/swift-package-manager#2787).
Building a Universal Binary
Firstly, make sure that you are using the correct version of Xcode/Swift:
$ xcrun swift build --version
Swift Package Manager - Swift 5.3.0
Note: If this is not Swift 5.3 or greater, use xcode-select -s
to switch to the Xcode 12 beta.
Now, when compiling your package, specify both architectures to compile a Universal Binary:
$ xcrun swift build -c release --arch arm64 --arch x86_64
To verify that your built binary contains both architectures, you can use the lipo -info
command to inspect a binary and confirm:
$ lipo -info .build/apple/Products/Release/swiftlint
Architectures in the fat file: .build/apple/Products/Release/swiftlint are: x86_64 arm64
And there you have it, building your Swift Package as a Universal Binary is as simple as that!
06 Feb 2017
So you’ve seen Firebase Remote Config and decided that it would go great in your Swift project? You’re right, it will but if like me you’ve noticed that the design of the SDK doesn’t play very well with all of your other beautiful looking strictly typed Swift code then this post is for you.
Note: I don’t cover setting up Firebase in this post, just using FIRRemoteConfig
in a configured project. Check out one of these guides for help with the setup part.
Lets take this basic example:
let count = FIRRemoteConfig.remoteConfig()["maximum_item_count"].numberValue?.intValue ?? 10
There are a few problems here:
- Damn it doesn’t look great.
numberValue
returns an optional.
- The key/value pattern means that you can’t guarantee that you’ve not made a typo or updated the key name somewhere else.
- Because of the optional, you either have to force unwrap or have a fallback.
- Carelessly force unwrapping is never a good thing and defeats the object of Swift’s type safety.
- Having a fallback defeats the object of the nice default values that you specify upon initialising Remote Config.
- Littering all your classes with
import FirebaseRemoteConfig
will probably be a pain to undo once you decide to move away from Firebase.
It would be a lot nicer if we could do something like this instead:
let count = Config.shared.maxItemCount
Config.swift
The interface for my Config
class is pretty simple:
import Foundation
import FirebaseRemoteConfig
final class Config {
/// The shared instance of config to use
static let shared: Config = Config()
/// The maximum number of items that are allowed in this mystery app
let maxItemCount: Int
/// The initialiser is private as intended use is via the `shared` static property.
private init() {
...
}
}
The idea is simple: Initialise all the properties on the shared instance after performing the initial fetch and then trigger another fetch after so that we can be ready to load any changes the next time the app launches.
This is intentional to ensure that the values in Config
are all fetched from a consistent data source (i.e to avoid accidentally reading one default value before calling activateFetched
and then another remote value after the fetch completed).
As a result, the initialiser looks like this:
// 1. Configure for dev mode if we need it, otherwise a 1 hour expiration duration
let remoteConfig = FIRRemoteConfig.remoteConfig()
#if DEBUG
let expirationDuration: TimeInterval = 0
remoteConfig.configSettings = FIRRemoteConfigSettings(developerModeEnabled: true)!
#else
let expirationDuration: TimeInterval = 3600
#endif
// 2. Set our default values and keys
remoteConfig.setDefaults([
"maximum_item_count": 42 as NSNumber
])
// 3. Activate any fetched values before we read anything back
remoteConfig.activateFetched()
// 4. Now set the properties on config based on what we have currently
self.maxItemCount = remoteConfig["maximum_item_count"].numberValue!.intValue
// 5. Perform the next fetch so that it's ready when we re-launch
remoteConfig.fetch(withExpirationDuration: expirationDuration) { status, _ in
print("[Config] Fetch completed with status:", status, "(\(status.rawValue))")
}
Here is a breakdown of what we are doing:
- If the app is running in debug mode, I enable dev mode and disable the
expirationDuration
so that the config refreshes each time. This is very handy during development but will get you throttled server side if you release something like that to production.
- Set the default keys and values. I’ve opted to do this in code and not by using a plist so that I can have visibility of all the keys and values later on when I fetch them.
- Activate any fetched parameters from the previous launch before we attempt to read them.
- Read the fetched or default parameters back and set them as instance variables.
- Perform a fetch asynchronously to get any changes that we can then activate the next time we launch the app.
There are still a few non-swifty looking bits here because I’m not using any form of constants to define the duplicate usage of maximum_item_count
and I’m also force unwrapping the value however it does come with the following upsides:
- Only requires a single unit test to ensure that any of the force unwrapping isn’t causing a crash.
- All the non-swifty looking code is isolated in a single file instead of across my entire project.
- I could easily update the
Config
class in the future to completely remove the dependancy of Firebase from my project if I wanted to.
- The rest of my code looks fabulous (kinda).
The complete class can be found here if you wish to grab a copy. Enjoy!
Note
Due to the nature of Swift, the static shared
property won’t be initialised until you try to access it. This means that it might be useful doing something like the following in your AppDelegate if you want to ensure that the next fetch is performed as soon as possible:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
FIRApp.configure()
_ = Config.shared
return true
}
I’m sure that could be done in a nicer way but I’ll let you figure that out :)
11 Sep 2016
After watching the WWDC 2016 Session 803 video on Typography and Fonts I decided that this would be a good place to start with the whole blog posts thing.
It turns out that fonts are actually very complex things but to keep this short and sweet, I’m just going to talk about one thing that caught my eye.
Small Caps
Usually you only ever come across uppercase or lowercase letters however, small caps bring an additional member to this group. They’re essentially a smaller version of uppercase letters that almost align with the lowercase letters in a font.
Good: The text in the centre is rendered using the same font but with the small caps feature enabled.
You might be wondering why you don’t just use a smaller point size instead? Well if you like your interfaces to be pixel perfect (don’t we all?) then you will notice that after you found the appropriate point size, other features of the font such as the weight and spacing are also adjusted meaning that your two fonts will look different next to each other.
Bad: The text in the centre is the same font but 10 points smaller than the other labels.
Small caps allow the font designer to actually add an additional glyph specifically designed to be used in this case. This means that the font is correctly optimised resulting in something that looks a little like the first picture rather than the second. A minor difference but a good one.
This does however mean that in order to use small caps, the font designer must have explicitly supported this feature.
Use Cases
Small caps are designed to be subtle and can come in very handy when you’re trying to perfect your designs. The case study from Apple demonstrates how they are used on the Apple TV to distinguish a title in a table without it drawing the users attention away from the actual content.
The Director, Cast and Writer headings use small caps to keep the text size and alignment consistent with the rest of the content.
Another use could be to offer a subtle hierarchy of information. For example, if you wanted to display a number but did not want to emphasise the text next to it then small caps could be used to offer a nicer alternative to just using lowercase letters.
An example could be showing the time in a 12 hour format.
Implementation
Small caps can be enabled on a font by enabling their relative Font Feature. The documentation for this is a bit patchy but for actual information around the available font features you can visit the fonts section of the developer site.
To actually take advantage of the font features in code you can do this at a fairly high level by modifying a UIFontDescriptor
(The same also applies for NSFontDescriptor
on macOS).
Lets take a look at a simple implementation:
let systemFont = UIFont.systemFont(ofSize: 24.0, weight: UIFontWeightLight)
let smallCapsDesc = systemFont.fontDescriptor.addingAttributes([
UIFontDescriptorFeatureSettingsAttribute: [
[
UIFontFeatureTypeIdentifierKey: kUpperCaseType,
UIFontFeatureSelectorIdentifierKey: kUpperCaseSmallCapsSelector
]
]
])
let font = UIFont(descriptor: smallCapsDesc, size: systemFont.pointSize)
Here is a breakdown of the above code:
- Get an existing font descriptor from a font of our choice.
- Create a new font descriptor adding additional attributes via the
addingAttributes(_:)
method.
- Specify the additional font features we would like via the
UIFontDescriptorFeatureSettingsAttribute
attribute key.
- Create a new font object with the new font descriptor and the original point size.
The UIFontDescriptorFeatureSettingsAttribute
attribute is in a bit of a weird structure however it’s simple once you understand it.
An array of dictionaries representing non-default font feature settings. Each dictionary contains UIFontFeatureTypeIdentifierKey
and UIFontFeatureSelectorIdentifierKey
.
So we essentially want an array of dictionaries containing both the feature selector and type identifier. These values map back to the values referenced in the TrueType Font Feature documentation I linked to earlier.
You can also find the provided constants in <CoreText/SFNTLayoutTypes.h>
. Note that there is no nice link between feature types and their supported selectors so you just have to read the comments within the header.
Tips & Tricks
Different Combinations
There are actually a couple of ways to use small caps and there are some things to note because you might actually want to use them in a different way to get your desired outcome.
Looking back into the SFNTLayoutTypes.h
header, you will see that there is both a kUpperCaseType
and kLowerCaseType
feature. This gives you two different ways in that you can apply small caps and it essentially means you either make all uppercase letters into small caps or make all lowercase letters into small caps.
By mixing the input text and the feature type that you use, you will get a different output. I’ve put together the table to show the differences.

As you can see from the above example, you will need to choose the correct combination of input text along with the feature type that you decide to use. For example, you will probably never want to use a capitalised string in conjunction with kUpperCaseType
.
Numbers and Punctuation
Numbers and punctuation will also be treated as uppercase letters when a small caps feature is applied meaning they are also shrunk down. This can be useful in some cases but if you don’t want to apply small caps to these then you need to make sure you use an NSAttributedString
where you only apply the small caps font to the parts you wish to modify.
Extension
You might have noticed that code example above to achieve small caps is kind of bloated when you compare it to a one line UIFont
initialiser. Below you can find a sample extension I’ve put together to make this a little bit simpler.
public extension UIFont {
/// Helper method to create a UIFont with updated attributes applied to the UIFontDescriptor
///
/// - parameter attributes: The new attributes to apply to the fontDescriptor
///
/// - returns: A UIFont object with the new attributes appended to the receivers fontDescriptor
func addingAttributes(_ attributes: [String : Any] = [:]) -> UIFont {
return UIFont(descriptor: fontDescriptor.addingAttributes(attributes), size: pointSize)
}
/// Returns a UIFont object based on the receiver with small caps applied to upper case letters
var addingUpperCaseSmallCaps: UIFont {
return addingAttributes([
UIFontDescriptorFeatureSettingsAttribute: [
[
UIFontFeatureTypeIdentifierKey: kUpperCaseType,
UIFontFeatureSelectorIdentifierKey: kUpperCaseSmallCapsSelector
]
]
])
}
/// Returns a UIFont object based on the receiver with small caps applied to lower case letters
var addingLowerCaseSmallCaps: UIFont {
return addingAttributes([
UIFontDescriptorFeatureSettingsAttribute: [
[
UIFontFeatureTypeIdentifierKey: kLowerCaseType,
UIFontFeatureSelectorIdentifierKey: kLowerCaseSmallCapsSelector
]
]
])
}
}
If you have any suggestions to improve the extension then please leave a comment on the gist.
09 Sep 2016
The start of something new
I’ve just spent the last four days in Aberystwyth, Wales at iOS Dev UK.
Something I’ve done two years in a row now and I’ve loved every minute of it.
Back in 2015 on the 4 hour train journey back to Bristol I told myself that I wanted to start getting involved with the community more. The idea was that I would start a blog to share things I learn as I go about my day to day job as an iOS Developer.
Fast forward a year and I find myself on the exact same journey home with the exact same feeling I had last year. This time I’m forcing myself to do something about it so here I am starting a blog. I’m pretty new to all of this so you’ll probably find that it’s going to be a bit crap to start with but hey, we’ve all got to start somewhere right? Feedback is welcome!
So anyway. I’ve got a day off work today and I’m about to embark on another 3 hour train journey to visit some family over the weekend so now is the perfect time to get an actual development related blog post up right? Wish me luck.
About Me
My name is Liam Nichols, I’m currently a Senior iOS Developer at Rockpool Digital in Bristol.
I also twitter as @liamnichols_ on the Internet from time to time.
After finding this book in my local Library back sometime around 2011, I found myself bodging apps together when I wasn’t busy stacking shelves at Asda.
By doing this, I was able to work my way into a real job as an iOS Developer across the country in Bristol and with the support of some great people, I’m still here over 3 and a half years later and loving every minute of it.
That should probably do it for now but if for some reason you want to find out more then feel free to tweet me or email me at liam.nichols.ln@gmail.com.