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

In this tutorial, you’ll learn all about SF Symbols as well as how to create your own custom symbols to help your app stand out from the crowd! :]

SF Symbols are a set of over 2,400 symbols, or icons, curated by Apple. They’re designed to work well with the default system font on Apple devices called San Francisco. They provide an easy way to add iconography to your projects, as they come in a wide variety of sizes and weights. With so many ready-made options, you’re likely to find the perfect fit for your app’s style. And, if you can’t find exactly what you need, you can create it.

Here, you’ll add new bling icons to an app showing the status of London Underground train lines, commonly known as the Tube. In the process, you’ll learn how to:

  • Integrate SF Symbols into your app.
  • Associate different SF Symbols with different statuses.
  • Create your own, custom symbols for use in your app.

Getting Started

First, download the project materials using the Download Materials button at the top or bottom of this tutorial and open the starter project in Xcode.

The app displays the current status of Tube lines. You’ll add to the project by associating an SF Symbol with each status and having it display in the app. This way, users can get the information they need with a glance.

Build and run the app.

TubeStatus Starter Project

Uh oh! It errors! This is because you need to set up the app to fetch data for the tube lines. This is what you’ll do now after going through a walk-through of how the app works.

Note: If you aren’t interested in learning about the inner workings of the app, you can skip ahead to Setting up TransportAPI.

Getting Acquainted with the App

Open AppMain.swift. The main view displays a view called TubeStatusView, which acts as the root view of the app.

Next, open TubeStatusView.swift. TubeStatusView observes a model object of type TubeStatusViewModel. The body of the view displays a ZStack that sets the background color of the view and then displays a Loadable on top.

Loadable shows different content depending on the loading state:

  • A spinning activity indicator while waiting for data.
  • An error if loading the data fails.
  • The contents of the view builder once the data has loaded successfully.

Once data loading completes, TubeStatusView shows LineStatusRow for each line. These are contained in a ScrollView. It also displays Text showing when the data was last updated.

Notice how the view also contains onAppear(perform:). This calls loadData() of the view when it first appears on the screen. This method asks the model to perform fetchCurrentStatus by calling perform(action:).

Open LineStatusRow.swift and have a quick look around. This is a simple view that displays the status of a particular Tube line. You can look at the SwiftUI previews to see what these rows will look like.

Importing Models and Data

Next, open TubeStatusViewModel.swift. The important parts of this class are marked under Actions and Action Handlers.

You’ve already seen how TubeStatusView calls perform(action:) when it appears on the screen. By passing the fetchCurrentStatus enum as the action, this method calls fetchCurrentStatus().

fetchCurrentStatus() calls fetchStatus() on an instance variable of type conforming to the TubeLinesStatusFetcher protocol. This handles fetching the data from the API. Once fetched, tubeStatusState is updated. As this is a published object, SwiftUI handles updating the UI automatically.

Adding TransportAPI Functionality

Open TransportAPIService.swift in the API group. This class handles fetching the JSON data from a network request in fetchStatus() and decodes the JSON into the AllLinesStatus struct.

The important part to note in this class is appId and appKey on lines 82 and 83. These values are loaded from the app’s Info.plist, specifically from the TRANSPORT_API_SERVICE_APP_ID and TRANSPORT_API_SERVICE_APP_KEY keys, respectively.

Open Info.plist. Note how the values aren’t set to any sort of valid ID, but instead set to $(TRANSPORT_API_SERVICE_APP_ID) and $(TRANSPORT_API_SERVICE_APP_KEY). The $(...) syntax is called variable substitution. It tells Xcode to substitute the value in the Info.plist with the value of the key from a configuration file when building the app. You’ll set this up in just a moment.

Open the Project Info panel by clicking the TubeStatus project in the Project navigator. Then, click TubeStatus underneath the Project heading.

Xcode project info for TubeStatus

The Debug configuration loads a Debug configuration file with a similar setup for Release.

Setting up TransportAPI

This app uses a free third-party API called TransportAPI to get up-to-date information about the various Tube lines. Before you begin, you need to register and create a new app.

The TransportAPI Website

Go to the TransportAPI Developer Portal and click Sign up in the header.

The TransportAPI Developer Portal

Fill out the form, check the reCAPTCHA checkbox, and click Sign up. A confirmation screen will ask you to check your email.

The TransportAPI Developer Sign-Up Form

You’ll receive two emails. The first contains details on how to activate your account. The second confirms that you’ve successfully created a new Application Key.

Follow the instructions in the first email to activate your account, then sign in to your new account in the Developer Portal. The landing page shows you the credentials — App ID and App Key — that have just been created. Keep this tab open, as you’ll use these values shortly.

The TransportAPI Developer Landing Page

Connecting the API

Now, it’s time to connect the Transport API to your app.

First, open Debug.xcconfig. Here, you’ll find TRANSPORT_API_SERVICE_APP_ID and TRANSPORT_API_SERVICE_APP_KEY with dummy values. Set each to the values provided by the Transport API Developer Portal.

Build and run your app — at last!

TubeStatus Starter Project

However, you shouldn’t store your API key in the app like this, even if you use an .xcconfig. In a production app, you should proxy requests from your app through you own server, and have that server make the requests to the Transport API on your behalf. You can do this easily using a service like AWS Lambda.

Then, if you need to change API key, or if the Transport API introduces a breaking change, you only need to update your server rather than requiring your users to download a new version of your app!

Note: Xcode Configuration (.xcconfig) files are great for providing build-specific configuration for your app. For example, you could use a staging server URL when running on the simulator and a different URL in production.