Swift Reference
Kip Landergren
(Updated: )
My cheat sheet for the Swift programming language covering best practices, comments, and helpful resource links.
Contents
- Swift Version Note
- Swift Terminology
- Keywords
- Sequence
- Array
- Date
- DateFormatter
- Dictionary
- Int
- NumberFormatter
- TimeInterval
- Switch Statements
- enum
- Numbers
- Foundation
- Range Operators
- Type Casting
- Attributes
- Comments
- Swift Package Manager
- Compiler Flags
- Best Practices
- Format Strings
- Resources
- References
- Frequently Asked Questions (FAQ)
Swift Version Note
The following document refers to Swift version 5.2.
Swift Terminology
- library
- a collection of code or data that can be imported
- module
- a single unit of code distribution
- package
- a collection of Swift source files and a manifest file conforming to a
PackageDescription
; could be a library or executable
Keywords
static
struct Foo {
// indicates a type property, callable on
// the Foo type as Foo.bar, scoped to the
// type Foo
static var bar = "bar"
// indicates a type method, callable on
// the Foo type as Foo.baz().
static func baz() { /* do something */ }
}
Sequence
filter(_:)
is equivalent to Ruby’s “accept”: if the predicate returns true, the element will be included in the returned array.
Array
Array length / array size / array count:
let length = array.count
Sort array using NSSortDescriptor
objects:
let sorted = (unsorted as NSArray).sortedArrayUsingDescriptors([sortDescriptors])
Check if array contains any matching predicate:
let outcome = array.contains(where: { $0.hasProperty })
Filter array for elements that satisfy predicate:
let objectsWithProperty = array.filter { $0.hasProperty }
Date
Get Unix epoch time as TimeInterval
, typealias
for Double
:
let secondsSinceEpoch = Date().timeIntervalSince1970
DateFormatter
When in doubt, review the archived Date Formatting Guide.
Localized Dates
Important:
- set
locale
before callingsetLocalizedDateFormatFromTemplate(_:)
- users can override AM/PM vs 24-hour time setting
let usDateFormatter = DateFormatter()
usDateFormatter.locale = Locale(identifier: "en_US")
usDateFormatter.setLocalizedDateFormatFromTemplate("yMMMd")
print(usDateFormatter.string(from: Date())) // Apr 20, 2020
let frDateFormatter = DateFormatter()
frDateFormatter.locale = Locale(identifier: "fr_FR")
frDateFormatter.setLocalizedDateFormatFromTemplate("yMMMd")
print(frDateFormatter.string(from: Date())) // 20 avr. 2020
Unicode Date Format Patterns
Based on tr35-31:
y | Year. e.g. “AD 2020” becomes “2020” |
yy | Year, maximum length of 2. e.g. “AD 2020” becomes “20” |
yyy | Year, with up to 2 spaces of padding. e.g. “AD 20” becomes “020” |
yyyy | Year, with up to 3 spaces of padding. e.g. “AD 20” becomes “0020” |
yyyyy | Year, with up to 4 spaces of padding. e.g. “AD 2020” becomes “02020” |
M | Month, numerical. e.g. “April” becomes “4” |
MM | Month, numerical, with zero padding. e.g. “April” becomes “04” |
MMM | Month, abbreviation. e.g. “April” becomes “Apr” |
MMMM | Month, full name. e.g. “April” becomes “April” |
MMMMM | Month, narrow name. e.g. “April” becomes “A” |
Note: I have yet to determine whether Unicode Date Format Patterns is independent of, or an extension of, ISO 8601 date format patterns.
Dictionary
Dictionary literal (note: type hinting often required for complex value types):
let dataSource: [Int:[CustomType]] = [
0: FooEnum.allCases,
1: BarEnum.allCases,
2: BazEnum.allCases,
]
Dictionary with an empty array as default value:
let unknown = dataSource[3, default: []]
Iterating entries:
for (key, value) in dataSource {
// do something
}
Int
Integer Operators
// any remainder is discarded
1 / 4 // 0
2 / 4 // 0
3 / 4 // 0
4 / 4 // 1
5 / 4 // 1
6 / 4 // 1
NumberFormatter
Getting a localized ordinal number:
let ordinalFormatter = NumberFormatter()
ordinalFormatter.numberStyle = .ordinal
let one = NSNumber(value: 1)
let first = ordinalFormatter.string(from: one)!
print(first) // 1st
NumberFormatter.Style Values
Refer to NumberFormmatter.Style documentation.
TimeInterval
typealias
for Double
, always in seconds.
Switch Statements
Important points:
- must be exhaustive
- no implicit fall-through
break
not required
enum
enum CompassPoint: Int, CaseIterable {
case north // rawValue of 0
case south
case east
case west
}
Note:
- an
enum
cannot contain stored properties. - if inheriting from
Int
, first case is 0 CaseIterable
gives access toallCases
, which is collection of all case statements
Numbers
Int |
signed integer value type |
Float |
single-precision floating-point value type |
Double |
double-precision floating-point value type |
Foundation
NSSet
Convert to Array
:
guard let set = nsset as? Set<Element> else { /* handle it */ }
let array = Array(set)
Useful Classes
NSCountedSet
Range Operators
for _ in 0...3 { /* 0, 1, 2, 3 */ } // closed range operator
for _ in 0..<3 { /* 0, 1, 2 */ } // half-open range operator
let letters = ['a','b','c','d','e']
for _ in letters[...2] { /* a, b, c */ } // one-sided closed range (from beginning)
for _ in letters[2...] { /* c, d, e */ } // one-sided closed range (to end)
for _ in letters[..<2] { /* a, b */ } // one-sided half-open range (from beginning)
for _ in letters[2..&;t] { /* c, d */ } // one-sided half-open range (to end)
Type Casting
Type Checking
To check if foo
is of subclass type Bar
:
if foo is Bar {
print("it is!")
}
Downcasting
To conditionally downcast, returning nil
if failure:
if let bar = foo as? Bar {
// work with bar
}
To force downcast, generating a runtime error if failure:
let bar = foo as! Bar
Attributes
available
Swift attributes documentation has full information about platforms, versions, and available explanations. Use @available
to indicate declaration life cycle, calling with platform names, their optional version numbers, and optional explanations:
@available(platform-name version-number, *)
Mark a method deprecated for all platforms, with a message:
@available(*, unavailable, message: "now obsolete")
Comments
Code Comments
Normal comments that appear in code.
Single Line
// this is a comment!
Multi-Line
/*
This is a multi-line comment!
*/
Inline
guard let foo = bar as? Qux else { /* inline comment */ fatalError() }
Swift Comments and Xcode
Horizontal Delimiter
// MARK: -
creates a solitary horizontal delimiter in the Xcode jump bar and minimap
Headings
// MARK: Delegate Methods
creates a heading with text “Delegate Methods” in the Xcode jump bar and minimap
// MARK: - Delegate Methods
creates a horizontal delimiter, followed by a heading with text “Delegate Methods” in the Xcode jump bar and minimap
Action Items
Note: As far as I can tell there is no additional management of action items beyond special formatting in the jump bar
// TODO: finish implementing delegate methods
creates a to-do item with text “finish implementing delegate methods” in the Xcode jump bar
// FIXME: broken on horizontally compact
creates a fix-me item with text “broken on horizontally compact” in the Xcode jump bar
Documentation Comments
Displayed in Xcode tooltips and the “Quick Help” area.
Single Line
/// this is a documentation comment! (note the third slash)
Multi-Line
/**
This is a multi-line documentation comment!
(note the second asterisk)
*/
Refer to the official Swift Markup Formatting Reference for information on how to improve the utility and presentation of your documentation comments.
Swift Package Manager
Package Properties
- uses semantic versioning
Creating a Package
- via Xcode
- via
swift package
(note: does not create package directory) - version resolution looks for git tags
- naming conventions are not set in stone; consider UpperCamelCase
Working with Packages
- can be added as target dependency within Xcode
- dependencies can be added as paths to remote repositories or local file:// URLs
- GitHub private repositories are supported; one way is to generate an access token for Xcode with repo permissions. Note that Xcode will crawl your starred repositories and populate the list of potential Swift packages with them, and there are a lot of false positives. I have not found a permissions configuration to prevent this.
- packages for a project can be updated to their latest versions in Xcode via:
- File
- Swift Packages
- Update to Latest Package Versions
- Swift Packages
- File
- ensure that file
Package.resolved
is committed - deletion is possible by removing it from the target
Note: there are special considerations when working with a local override of a remote package.
Command line usage:
$ swift package --help
$ swift package [subcommand] --help
Compiler Flags
Warn on function bodies that take longer than 100 ms to type check:
-Xfrontend -warn-long-function-bodies=100
Warn on expressions that take longer than 100 ms to type check:
-Xfrontend -warn-long-expression-type-checking=100
Best Practices
Avoiding Force Casts
Rather than:
let foo = bar as! Qux
Prefer:
guard let foo = bar as? Qux else {
// handle unsuccessful cast
}
Singleton Usage
Refer to Apple’s Cocoa Design Patterns document Managing a Shared Resource Using a Singleton.
General
- consider naming instances of optional types with the prefix
maybe
- prefer
Date()
toDate.init()
Format Strings
%d |
signed 32-bit integer |
%@ |
object |
More info in this Stack Overflow question: “What are the supported Swift String format specifiers?”.
Resources
Documentation
- Projects
- Standard Library
- Numbers and Basic Values
- struct Int
- Strings and Text
- struct String
- Collections
- struct Array
- struct Dictionary
- Sequence and Collection Protocols
- protocol Sequence
- Numbers and Basic Values
- Core Libraries
- Foundation
- Data Formatting
- struct Locale
- Dates and Times
- struct Date
- class DateFormatter
- struct Locale
- typealias TimeInterval
- Filters and Sorting
- class NSExpression
- class NSSortDescriptor
- Resources
- Data Formatting
- libdispatch (Grand Central Dispatch)
- XCTest
- Foundation
- Swift Package Manager
- Standard Library
- The Swift Book
Resources
WWDC
Code
- apple/swift-package-manager GitHub repository
References
Frequently Asked Questions (FAQ)
Does Swift support the equivalent of anonymous interfaces?
No, the closest you can get are on-the-spot implementations of protocols via structs or classes defined in whatever execution context you are working.
What Date Format Strings Does Swift Use?
Swift uses Unicode Date Format Patterns, indicated from DateFormatter.dateFormat documentation linking to Date Formatting Guide. Note that there are specific Unicode Technical Reports that different systems conform to.