Safely access Apple's SF Symbols using static typing

Last update: May 17, 2022

Build Status Swift: 5 Version: 2.1.3 Platforms: iOS – tvOS – watchOS – macOS License: MIT
SwiftPM: Compatible Carthage: Compatible CocoaPods: Compatible

Supported VersionsMotivationInstallationUsageContributingLicenseIssuesPull Requests

Supported Versions

SFSafeSymbols supports multiple SF Symbols versions at the same time by utilizing the @availability flag. The following versions are currently supported:

  • SF Symbols 2.1 (@available(iOS 14.2, macOS 11.0, tvOS 14.2, watchOS 7.1, *))
  • SF Symbols 2.0 (@available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *))
  • SF Symbols 1.0 (@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *))

Motivation

At WWDC 2019, Apple announced a new library of icons that came included with that year's new operating system versions. To browse them, there's even a dedicated Mac app called SF Symbols. However, developers still have to copy the name of an icon and reference it unsafely, resulting in code like this:

UIImage(systemName: "circle.fill")

It didn't take long until first ideas came up to make these icons accessible in a safe way using a framework. And this is just what SFSafeSymbols does!

Installation

SFSafeSymbols can be installed via the Swift Package Manager (recommended), Carthage or CocoaPods.

Supported platforms are iOS (11.0+), tvOS (11.0+), watchOS (6.0+) and macOS (10.13+), although the actual functionality is of course only accessible starting with iOS 13.0, tvOS 13.0, watchOS 6.0 and macOS 11.0.

Swift Package Manager (Xcode-integrated)

To integrate SFSafeSymbols using the Xcode-built-in SPM, choose FileSwift PackagesAdd Package Dependency. Enter the following url: https://github.com/piknotech/SFSafeSymbols and click Next. When asked about the version, leave the preselection and click Next. In the following step, select SFSafeSymbols as the package product and click Finish unless you really want to use SFSafeSymbols-Dynamic and know what you are doing.

Swift Package Manager (standalone)

To integrate using the standalone version of Apple's Swift Package Manager, add the following as a dependency to your Package.swift:

.package(url: "https://github.com/piknotech/SFSafeSymbols.git", .upToNextMajor(from: "2.1.3"))

After specifying "SFSafeSymbols" as a dependency of the target in which you want to use it, run swift package update.

Carthage

Add the following entry to your Cartfile:

github "piknotech/SFSafeSymbols" ~> 2.1.3

Then run carthage update.

CocoaPods

Add the following entry to your Podfile:

pod 'SFSafeSymbols', '~> 2.1.3'

Then run pod install.

Usage

All the system icons are accessible via the SFSymbol enum. They are named similar to Apple's names, but use a lower camel case style and prefix names with leading numbers with a _ character:

c.circle        ~> SFSymbol.cCircle
e.circle.fill   ~> SFSymbol.eCircleFill
11.circle.fill  ~> SFSymbol._11CircleFill

A SF Symbol UIImage can now be initialized using the SFSymbol enum. This image is already unwrapped, so you get a UIImage instead of a UIImage?:

UIImage(systemSymbol: .cCircle)
UIImage(systemSymbol: SFSymbol.eCircleFill)
UIImage(systemSymbol: ._11CircleFill, withConfiguration: /* Some UIImage.Configuration */)

A SF Symbol SwiftUI.Image can also be initialized using the SFSymbol enum:

Image(systemSymbol: .cCircle)
Image(systemSymbol: SFSymbol.eCircleFill)

There are also SwiftUI.Label initializers:

Label("MyText", systemSymbol: .cCircle)
Label(LocalizedStringKey("my.text"), systemSymbol: SFSymbol.eCircleFill)

... and interfaces for UIButton:

let button = UIButton.systemButton(with: .cCircle, target: self, selector: #selector(testMethod))
button.setImage(.eCircleFill, for: .normal)

... and an initializer for UIApplicationShortcutItem:

UIApplicationShortcutIcon(systemSymbol: .cCircle)
UIApplicationShortcutIcon(systemSymbol: SFSymbol.eCircleFill)

... and finally also an initializer for AppKit's NSImage:

NSImage(systemSymbol: .cCircle)
NSImage(systemSymbol: SFSymbol.eCircleFill, accessibilityDescription: "some.description")

Testing

All symbols are tested via a CI (on the latest iOS & tvOS versions), so you can be sure your code won't crash because an image couldn't be found!

Contributing

Contributions are very much welcome! See CONTRIBUTING.md for more information.

License

This library is released under the MIT License. See LICENSE for details.

GitHub

https://github.com/piknotech/SFSafeSymbols
Comments
  • 1. Supporting explicit symbol localization

    Apple mentioned in this WWDC Video (4:10) that explicit localization is supported, and we know what suffixes are supported based on name_availability.plist extracted from the app.

    This issue is for discussion to support this feature or not and to choose the implementation approach. Implementation details (e.g: Naming) will be discussed separately once the PR is made.

    These are the implementations that I have in mind, ordered based on type-safety:

    Implementation 1

    • Providing localized properties on SFSymbol for all the possible localizations, returns a new type LocalizedSFSymbol.
    • Initializing UIImage with LocalizedSFSymbol returns UIImage?.

    Example:

    extension SFSymbol {
    	var ar: LocalizedSFSymbol { LocalizedSFSymbol(rawValue: "\(rawValue).ar") }
    	// all other possible localizations, even ".rtl" which is not available for "character"
    }
    
    let arabicCharacterImage = UIImage(systemSymbol: .character.ar) // UIImage?
    

    Implementation 2

    • Having an internal Dictionary<SFSymbol, Set<Localization>>.
    • Providing localized properties on SFSymbol for all the possible localizations, returns a new type LocalizedSFSymbol? based on the Dictionary.
    • Initializing UIImage with LocalizedSFSymbol returns UIImage.

    Example:

    extension SFSymbol {
    	var ar: LocalizedSFSymbol? {
    		guard localizationDictionary[self]?.contains(.ar) == true else { return nil }
    		return LocalizedSFSymbol(rawValue: "\(rawValue).ar") 
    	}
    	// all other possible localizations, even ".rtl" which is not available for "character"
    }
    
    if let arabicCharacterSymbol = SFSymbol.character.ar {
    	let arabicCharacterImage = UIImage(systemSymbol: arabicCharacterSymbol) // UIImage
    }
    

    Implementation 3

    • Providing a new namespace for each symbol with localization.
    • For each symbol, The new namespace will have only the localization(s) available for this symbol
    • Keeping the default symbols as they are currently for source compatibility.

    Example:

    extension SFSymbol {
    	enum Character {
    		static var ar: SFSymbol { SFSymbol(rawValue: "character.ar") }
    		// all other localizations available for "character" only
    	}
    }
    
    let defaultCharacterImage = UIImage(systemSymbol: .character) // UIImage
    let arabicCharacterImage = UIImage(systemSymbol: .Character.ar) // UIImage
    // or
    let arabicCharacterImage = UIImage(systemSymbol: .Localizable.Character.ar) // UIImage
    

    Implementation 4

    • Same idea as Implementation 3.
    • Instead of keeping the default symbols static in SFSymbol, it would be moved to its dedicated namespace. Avoiding the confusion of .Character and .character.

    Example:

    extension SFSymbol {
    	enum Character {
    		static var default: SFSymbol { SFSymbol(rawValue: "character") }
    		static var ar: SFSymbol { SFSymbol(rawValue: "character.ar") }
    		// all other localizations available for "character" only
    	}
    }
    
    let defaultCharacterImage = UIImage(systemSymbol: .Character.default) // UIImage
    let arabicCharacterImage = UIImage(systemSymbol: .Character.ar) // UIImage
    

    @fredpi @knothed what do you think?

    Reviewed by StevenMagdy at 2021-11-28 00:21
  • 2. Support explicit symbol localization

    Implements #87.

    Following this suggestion by @StevenMagdy, one protocol per localization per availability is created.

    The decision for the protocol names fell on hi and hi_v30 as these are shorter, easier to read and look better than HiLocalizable and HiLocalizableV30. What do you think?

    Additionally, allSymbols was made into an SFSymbolSet which allows to localize all symbols (via allSymbols.hi) and which exposes allSymbolVariants containing every localization variant of every symbol.

    The symbol documentations were adapted to match the actual exposed localizations: when deprecated symbols do not provide some localizations, but only their new versions do, these localizations are not in the documentation of the deprecated symbol to match its actual type. (example in the image) image

    Reviewed by knothed at 2021-12-08 14:29
  • 3. make `SFSymbol` struct

    I believe SFSymbol is naturally a String backed struct, not enum.

    public struct SFSymbol: RawRepresentable {
        
        public let rawValue: String
        
        public init(rawValue: String) {
            self.rawValue = rawValue
        }
    }
    

    When new symbols were added (like #53), user can do it on their own:

    public extension SFSymbol {
        
        @available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *)
        static let sealFill = SFSymbol(rawValue: "seal.fill")
    }
    

    We can also break the massive SFSymbol.swift file into smaller fils (v1, v2, v2.1, deprecated).

    I believe all existing functions won't be compromised. I can work on a pr with your permission.

    Reviewed by ddddxxx at 2021-02-22 09:08
  • 4. Support for SF Symbols v3

    SF Symbols v3 are now officially a thing and the corresponding app to browse them can be downloaded at https://developer.apple.com/sf-symbols/.

    I quickly browsed the app and saw the following new features:

    • There are new types in addition to Monochrome and Multicolor: Hierarchical & Palette. Fortunately, there is a file embedded in the app that tells us everything about the types for each symbol: layerset_availability.plist. I suggest we add this information to each's symbol documentation (similar to the localized versions).
    • There's a new file symbol_categories.plist, but I suggest we just ignore it because there's no real value in adding the symbol category to each's symbol documentation IMO.
    • According to Apple, there are > 600 new symbols. As all files that were used to generate the SFSafeSymbols code are still present in the app, it's probably not much work to create an update for these new versions.
    Reviewed by fredpi at 2021-06-07 22:03
  • 5. Add support for next-generation SFSymbols

    SFSafeSymbols should include support for the new symbols introduced with iOS 14 and the other Apple operating systems.

    Regarding the structuring I suggest the following design:

    enum SFSymbol {
        @available(iOS 13...)
        enum v1 {
            case ...
        }
    
        @available(iOS 14...)
        enum v2 {
            case ...
        }
    }
    

    The SFSymbols 2 app required for parsing the symbol catalog isn't available yet, so I will look into this as soon as the app is available.

    Reviewed by fredpi at 2020-06-24 17:52
  • 6. Add layerset documentation & improve documentation

    This PR adds support for layerset documentation which I stated as a goal for the v3 release (https://github.com/piknotech/SFSafeSymbols/issues/75).

    I also updated the whole documentation style to better align with the way documentation is rendered in Xcode 13.

    With the new documentation style, an exemplary symbol documentation now looks as follows:

    doc

    Notably, when the user types the symbol name, they will now only see the documentation summary in the editor, i. e. the symbol preview. It might be suitable to add a note whether localizations or layersets are available. What do you think? @StevenMagdy @knothed

    Simple summary:

    simple

    Extended summary:

    extended

    In this PR, I shortened the availability descriptions of localizations and layerset iOS 15.0, macOS ..., tvOS ..., watchOS ... to just iOS 15.0. With this, some information is removed, but I think that's okay for the sake of better readability.

    @StevenMagdy I noticed that there are still some TODOs in the Symbols Generator project. Are those still relevant? If true, it would be better to track them in a GitHub issue instead of the code. Would you mind removing the TODOs and creating GitHub issues if needed? You may use this branch and PR; I won't commit further until you reviewed and commented the PR.

    Also I think that the behavior introduced by the use of the localizationsOfAllVersions(of:) is incorrect: E. g., the legacy a is described as offering multiple localizations, but Apple only guarantees that those are available for the successor (character). Therefore, providing the same localization information for both the legacy and the current symbol name isn't correct, right? If you agree, would you mind changing this behavior?

    Reviewed by fredpi at 2021-11-22 16:44
  • 7. Deprecated symbol names?

    Hi, I'm using SFSafeSymbols in my new project, but I get +100 Warnings in my log that several names were deprecated / changed in iOS 14.

    Is there a way to get a release that's for iOS 14+ ? I installed through CocoaPods btw.

    Thanks in advance

    Reviewed by LilaQ at 2022-02-19 01:31
  • 8. StringProtocol type inference issue in SwiftUI's Label initializers

    I just noticed a strange behavior. In SwiftUILabelExtension, the protocol StringProtocol is always matched to String instead of LocalizedStringKey if you write a string literal in your code. This is inconsistent with other SwiftUI native methods. For example:

    // Native SwiftUI:
    Text("some text")                      // inferred as LocalizedStringKey
    Label("some text", systemImage: "...") // inferred as LocalizedStringKey
        .navigationBarTitle("some text")   // inferred as LocalizedStringKey
    
    // SwiftUILabelExtension:
    Label("some text", systemSymbol: .xxx) // hmm... inferred as String... 🤔
    

    So I have to do the following to ensure the text is being localized correctly:

    Label("some text" as LocalizedStringKey, systemSymbol: .xxx) // 🤔
    

    I checked the implementation of SwiftUILabelExtension and it seems to be defined in the same way as in SwiftUI's native methods, but I don't know why the compiler doesn't give priority to matching LocalizedStringKey.

    public extension Label where Title == Text, Icon == Image {
        
        /// Creates a label with a system symbol image and a title generated from a
        /// localized string.
        ///
        /// - Parameter systemSymbol: The `SFSymbol` describing this image.
        init(_ titleKey: LocalizedStringKey, systemSymbol: SFSymbol) {
            self.init(titleKey, systemImage: systemSymbol.rawValue)
        }
        
        /// Creates a label with a system symbol image and a title generated from a
        /// string.
        ///
        /// - Parameter systemSymbol: The `SFSymbol` describing this image.
        init<S>(_ title: S, systemSymbol: SFSymbol) where S : StringProtocol {
            // 🤔 always goes here with S==String...
            self.init(title, systemImage: systemSymbol.rawValue)
        }
    }
    

    I suggest to check if we can find a better way to define the initializer signatures. Because this inconsistent behavior can easily lead to localization bugs, and it is less easy to be found if the app is not fully tested.

    Reviewed by gongzhang at 2020-12-17 08:23
  • 9. Improve package specs

    This PR improves the package specs (Package.swift and SFSafeSymbols.podspec):

    • General: Lower the library requirements to 2016 platforms (iOS 10.0, macOS 10.12, tvOS 10.0, watchOS 3.0).
    • Package.swift: Raise the minimum Swift version to 5.3 to match SFSafeSymbols.podspec.
    • Package.swift: Remove the library type (static/dynamic) which lets SPM picks it automatically (recommended by Apple). Tested successfully on the repo provided in #61.
    • SFSafeSymbols.podspec: Add support for swift 5.4 and 5.5.
    • SFSafeSymbols.podspec: Remove static_framework = true. Fixes #78.
    Reviewed by StevenMagdy at 2021-11-27 04:02
  • 10. Add version 1.1 and 3.3 symbols

    This adds 3.3 symbols which were released with 15.4. While we can wail for the actual SFSymbols.app, it's been a month and I think it's safe to say that it's not going to be released, similar to what they did when they skipped 2.2.

    Adding the symbols based on just info from name_availability.plist have a couple of disadvantages:

    • Symbol preview is not available as a result of how it's currently generated. I think the current "No preview available" is good enough until the app is released.
    • Unavailable layerset info. I've added "Unavailable layerset information" for 3.3 symbols.

    This PR also introduces a new version (1.1), fixing some symbols that were not available in iOS 13.0 but actually available in 13.1.

    Data taken from macOS 12.3.1: ./System/Library/CoreServices/CoreGlyphs.bundle/Contents/Resources/name_availability.plist

    Reviewed by StevenMagdy at 2022-04-09 12:59
  • 11. Rewrite contributing guide

    The (hopefully) last PR before the 3.0 release.

    Addresses #81.

    The changelog file currently doesn't meet the requirements mentioned in the new contributing guide, but I will update it before releasing version 3.0.

    Reviewed by fredpi at 2021-11-24 23:54
  • 12. Add Symbol Categories

    Hi,

    It would be helpful to add the symbol categories from the symbol.categories.plist file in SF Symbols.app to SFSymbol class to make sorting / filtering images in a view easier.

    Reviewed by narwahle at 2022-04-18 13:13
GPUImage 3 is a BSD-licensed Swift framework for GPU-accelerated video and image processing using Metal.
GPUImage 3 is a BSD-licensed Swift framework for GPU-accelerated video and image processing using Metal.

GPUImage 3 Janie Clayton http://redqueengraphics.com @RedQueenCoder Brad Larson http://www.sunsetlakesoftware.com @bradlarson [email protected]

May 23, 2022
SharkCardScan is a Credit/Debit Card scanner built using Apple's Vision Framework.
SharkCardScan is a Credit/Debit Card scanner built using Apple's Vision Framework.

iOS Credit/Debit card scanner, built using Apple's Vision Framework.

Apr 26, 2022
📷 A composable image editor using Core Image and Metal.
📷 A composable image editor using Core Image and Metal.

Brightroom - Composable image editor - building your own UI Classic Image Editor PhotosCrop Face detection Masking component ?? v2.0.0-alpha now open!

May 12, 2022
Script to support easily using Xcode Asset Catalog in Swift.
Script to support easily using Xcode Asset Catalog in Swift.

Misen Misen is a script to support using Xcode Asset Catalog in Swift. Features Misen scans sub-directories in the specified Asset Catalog and creates

Mar 18, 2022
A simple macOS app to read code from images, written purely in Swift using Vision Framework.
A simple macOS app to read code from images, written purely in Swift using Vision Framework.

CodeReader A simple macOS app to read code from images, written purely in Swift using Vision Framework. Usage Drag an image Click the convert button R

Apr 11, 2022
In-app screen recording using ReplayKit in iOS. Written in Swift 5 on Xcode 12.3
In-app screen recording using ReplayKit in iOS. Written in Swift 5 on Xcode 12.3

In-App-ScreenRecording-iOS In-app screen recording using ReplayKit in iOS. Written in Swift 5 on Xcode 12.3 Features: Recording application screen onl

Sep 5, 2021
iOS hashtag generator, using image analysis and discovery
iOS hashtag generator, using image analysis and discovery

Tagger Description Want to be popular on some social network easily? Use Tagger to make your account content more popular and to raise your popularity

Feb 10, 2022
A free, multiplatform SDK for real-time facial motion capture using blendshapes, and rigid head pose in 3D space from any RGB camera, photo, or video.
A free, multiplatform SDK for real-time facial motion capture using blendshapes, and rigid head pose in 3D space from any RGB camera, photo, or video.

mocap4face by Facemoji mocap4face by Facemoji is a free, multiplatform SDK for real-time facial motion capture based on Facial Action Coding System or

May 23, 2022
GPU-based media processing library using Metal written in Swift
GPU-based media processing library using Metal written in Swift

GPU-based media processing library using Metal written in Swift. Overview MetalAcc is a GPU-Based media processing library that lets you apply GPU-acc

Feb 23, 2022
A view that takes a set of images, make transition from one to another by using flipping effects.
A view that takes a set of images, make transition from one to another by using flipping effects.

CDFlipView A view that takes a set of images, make transition from one to another by using flipping effects. Demo Live Demo: https://appetize.io/app/w

Aug 27, 2021
An implementation of High Pass Skin Smoothing using Apple's Core Image Framework
An implementation of High Pass Skin Smoothing using Apple's Core Image Framework

YUCIHighPassSkinSmoothing An implementation of High Pass Skin Smoothing using CoreImage.framework Available on both OS X and iOS. Ports A MetalPetal b

May 19, 2022
A simple UIImageView extension for using initials as a profile image, written in swift
A simple UIImageView extension for using initials as a profile image, written in swift

InitialsImageView An easy, helpful UIImageView extension that generates letter initials as a placeholder for user profile images, with a randomized ba

May 17, 2022
Style Art library process images using COREML with a set of pre trained machine learning models and convert them to Art style.
Style Art library process images using COREML with a set of pre trained machine learning models and convert them to Art style.

StyleArt Style Art is a library that process images using COREML with a set of pre trained machine learning models and convert them to Art style. Prev

Apr 14, 2022
Using remote images in an application is more or less a requirement these days.
Using remote images in an application is more or less a requirement these days.

Imaginary Table of Contents Description Usage Basic Advanced Configuration ImageFetcher Installation Description Using remote images in an application

May 13, 2022
High Quality Image ScrollView using cropped tiled images.
High Quality Image ScrollView using cropped tiled images.

THTiledImageView Feature ?? THTiledImageView fully support UIScrollView. You can subclass it and use it. ?? Support Async Image Downloading & Caching.

Apr 4, 2021
IOS UIImage processing functions using the vDSP/Accellerate framework for speed.

UIImage Image Processing extensions using the vDSP/Accelerate framework.

Apr 15, 2022
Applies filter to a selected image from the Gallery using Combine

CombinePhotoFiltering App CombinePhotoFiltering is an app that applies sepia and bloom to a selected picture from the Photos app. Highlights The app i

Nov 14, 2021
Picture anonymiser using Vision face recognition

?? Anonymojizer [WIP] Anonymize people in photos by replacing their faces by emojis. How to use it ? Pick a photo from the gallery Choose an emoji The

Dec 20, 2021
Photo Gallery App demo using a REST API

Photo Gallery iOS App - (Using Rest API) A demo Photo Gallery App using a Rest API using MVVM architecture in Swift + UIKit. Overview Fully Programmat

Nov 22, 2021