SF Symbols for iOS: Getting Started

Learn to use SF Symbols, both existing and custom, to show data in an engaging way. By Tom Elliott.

4.5 (8) · 1 Review

Download materials
Save for later
Share
You are currently viewing page 3 of 4 of this article. Click here to view the first page.

Switching Between Mock Data and Actual Data

Now, look at DebugDataService.swift. There are only a few lines of code here, but quite a lot going on! This is what the code in this file does:

  1. First, the file imports Combine to give it access to the Future class.
  2. Next, it defines DebugDataService as conforming to TubeLinesStatusFetcher.
  3. Then, it implements fetchStatus — the only method required by TubeLinesStatusFetcher.
  4. Finally, it returns debugData wrapped in a Future. This debugData is the data you added in the previous section.

To use the debug line status fetcher, create a Swift file called TubeLinesStatusFetcherFactory.swift and add the following code:

// 1
enum TubeLinesStatusFetcherFactory {
  // 2
  static func new() -> TubeLinesStatusFetcher {
    // 3
    #if DEBUG
    if ProcessInfo.processInfo.environment["USE_DEBUG_DATA"] == "true" {
      return DebugDataService()
    }
    #endif
    // 4
    return TransportAPIService()
  }
}

Here’s what’s happening:

  1. As you only want static methods on this entity, it’s implemented as a caseless enum. You could use a struct here instead, but it would be possible to needlessly instantiate a struct, so an enum is a better choice.
  2. Define a single static method, new(), which returns an object conforming to TubeLineStatusFetcher.
  3. If running in debug mode and USE_DEBUG_DATA is set to true, return an instance of DebugDataService created previously.
  4. Otherwise, return an instance of TransportAPIService, which fetches the real data from the Transport API.

Finally, open AppMain.swift and find this line:

model: TubeStatusViewModel(tubeLinesStatusFetcher: TransportAPIService())

Replace it with the following:

model: TubeStatusViewModel(
  tubeLinesStatusFetcher: TubeLinesStatusFetcherFactory.new())

Here, you’re adding another layer of indirection and initializing TubeStatusViewModel with whatever fetcher TubeLinesStatusFetcherFactory decides to provide for it rather than using TransportAPIService directly.

Using the DebugData Scheme

Now, time to test it out! Make sure to select the Debug Data scheme.

The DebugData Scheme in Xcode

Now, build and run the app.

Viewing debug data in the Simulator

This is a great example of the power and flexibility of both protocol-oriented programming and dependency injection.

By passing the data-fetching service as a dependency into TubeStatusViewModel, it was simple to replace how the data was fetched with a different implementation.

By only providing TubeStatusViewModel with the protocol that the data-fetching service uses to return the data — and not the implementation — the view model doesn’t deal with how the data is fetched. It could be hard-coded or downloaded via a JSON API.

Understanding Restrictions on Using SF Symbols

Before you go crazy and add SF Symbols everywhere, be aware that restrictions exist on where and how you can use them.

Quoted directly from Apple’s Human Interface Guidelines:

“You may not use SF Symbols — or glyphs that are substantially or confusingly similar — in your app icons, logos, or any other trademark-related use. Apple reserves the right to review and, in its sole discretion, require modification or discontinuance of use of any Symbol used in violation of the foregoing restrictions, and you agree to promptly comply with any such request.”

“You may not use SF Symbols — or glyphs that are substantially or confusingly similar — in your app icons, logos, or any other trademark-related use. Apple reserves the right to review and, in its sole discretion, require modification or discontinuance of use of any Symbol used in violation of the foregoing restrictions, and you agree to promptly comply with any such request.”

Additionally, SF Symbols are considered to be system-provided images and thus are covered by the Xcode and Apple SDK license agreements.

Furthermore, 124 SF Symbols aren’t allowed to be exported, modified or used for any purpose other than Apple-specific technologies.

Apple publishes a full list of these more restricted icons. The right-hand pane in the SF Symbols app also details any extra restrictions when you select a symbol.

Restrictions in the SF Symbols App

Creating Custom SF Symbols

Even though Apple has provided thousands of different symbols in the SF Symbol library, it’s impossible to cover every conceivable image you may need in your app. What Apple has done instead is make it really easy for you to build your own custom symbols, when needed.

SF Symbols are built as vector graphics in an SVG file with a very specific formatting. At the top level, the file must contain three layers: Symbols, Guides and Notes. Each of these layers then contains sub-layers. For example, the Symbols layer contains 27 sub-layers — one for each of the variants available.

Furthermore, Apple makes it easy to create your own symbols by allowing you to export existing symbols from the SF Symbols app. That way, all the formatting is already present and you just need to change whatever you want to customize.

When building a custom symbol, it’s a good idea to find a built-in symbol that’s as close as possible to what you’re trying to draw and then adapt it to your needs.

You’re now going to see how to add a custom symbol into your app.

Making an “Information” Symbol

For this section, you need a vector art app that can edit SVG images.

Many different options are available, including paid products like Adobe Illustrator, Sketch, Figma and Affinity Designer. Most of these offer free trials. Open-source products are also available, like Inkscape and OpenOffice Draw.

This tutorial uses Affinity Designer, but the process should be similar in other vector art apps.

Importing the Exclamation Mark Symbol

Open the SF Symbols app on your Mac and search for the exclamationmark.circle symbol. Select it, and choose File ▸ Export Custom Symbol Template…. Save the symbol template on your machine and open it in your vector graphics app.

The exported Symbol in Affinity Designer

As you can see, the SVG file contains 27 separate images for each of the 9 font weights and 3 sizes.

Updating all 27 images would take a long time, but fortunately you don’t need to change any that you aren’t going to use. The only variant you need here is Regular-M, as that’s all this app uses. Apple recommends you create Regular S/M/L and Semi-bold S/M/L, as many of the common UIKit controls use these variants.

Customizing the Exclamation Mark Symbol

Find the Regular-M variant near the center of the canvas. Each symbol is built as a group in the SVG. Delete the exclamation mark in the center of the circle. You may need to ungroup the layer first, depending on which vector art app you’re using.

Removing the exclamation mark

Next, add a text block to the layer and type a lowercase i. Size it to 64pt in SF Pro and weight Heavy. Then place it at the center of the circle.

Adding a letter i

Each variant in a custom SF Symbol can only contain shapes/curves. They must not contain text, bitmaps or any other type of object. Convert your i text layer into a curve. In Affinity Designer, do this by selecting Layer ▸ Convert to Curves.

Make sure your new layer is a sub-layer of the Regular-M group. Then, save or export your new symbol as an SVG called information.svg.

Switch to the SF Symbols app and select File ▸ Validate Custom Symbols…, then select the file you just saved. If you’ve done everything correctly, your new symbol will be validated — yay!

Validating custom Symbol in SF Symbols app