Syntax similar to Rust
var
(mutable) vslet
(immutable)- Type inference
- Emojis are valid variable names (??)
nil
-safety: declare optionals like this:Int?
- Unwrap:
if let x = optionalVariable { }
- Optional chaining:
person?.residence?.address
- Unwrap:
- Data Structures: Tuples (index with
.i
), Structs, Classes - No braces around
if
/switch
/... (thank god) - Type casts:
as!
(can crash),as?
(returnsnil
on fail) - Guard:
guard condition else {}
- Nice for early returns:
guard req.isValid else { return }
- Nice for early returns:
Any
,AnyObject
: Unknown type- Computed properties
- include
willSet
&didSet
observers - use
oldValue
&newValue
- include
Strings #
.count
for length (.isEmpty
for.count == 0
)- No single quotes,
String
is coerced toCharacter
- Can be
.lowercased
- Interpolation:
"Variable a has value \(a)"
Loops #
- For:
for n in 0...8
;for (i, char) in "ABCD".enumerated()
- While:
while condition
Functions #
- Declared with
func
- Parameter labels:
1func sayHello(to person: String) {
2 print("Hello \(person)")
3}
4sayHello(to: "Denis <3")
_
label to drop
Enums #
1enum Compass {
2 case north east, south, west
3}
4let heading: Compass = .west
Structs #
- Value types
- Can contain functions
- These are immutable by default
- Mutation: need to be
mutating func
- Use
self
to reference current instance
- Constructor function:
init
- Preferred over classes
Classes #
- Reference types
Generics #
Type constraints:
1struct DictionaryA<Key: Hashable, Value> {}
2struct DictionaryB<Key, Value> where Key : Hashable {}
Protocols #
- What others call an
interface
- Generics via
associatedType TypeName
: gets inferred
Extensions #
- Add stuff to defined types
- You can add: computed properties, methods, initializers, protocol implementation
- You can't add: properties
1extension UIColor {
2 static var coolColor: UIColor {
3 return UIColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 1.0)
4 }
5}
Closures #
- Syntax:
let closure = { val in ... }
- Type:
(string: String) -> Void
Collections #
- Arrays
- Dictionaries:
var scores: [String: Int] = ["Richard": 500, "Luke": 300]
- value types
UIKit #
- Inheritance-based; base class:
UIVIew
- Outlets: Drag-&-drop connection between UI & code (annotation
@IBOutlet
for UI elements,@IBAction
for functions) - Uses MVC (Model, View, Controller)
Delegates #
- Hand off responsibilities to other object
- Example:
1class MyViewController: UITableViewDelegate {
2 myTableView.delegate = self
3}
Navigation #
- Transition using Sequges
UINavigationController
: Provides navigation UIUITabBarController
: Bottom tab bar
View Controller #
AppDelegate #
- Single instance for application
- Stuff like
configurationForConnecting
,didFinishLaunchingWithOptions
:
1func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
2 return true
3}
SceneDelegate #
- Per scene (i.e. per split view in iPadOS)
- Stuff like
func sceneDidDisconnect(_ scene: UIScene) { }
Auto Layout #
- Leading & trailing: left & right, except they support RTL-Layouts
Safe Area #
- Space that doesn't contain views
- Prevent collisions with dynamic island, bottom navigation, ...
Constraints #
- Rules where to align views
- Examples: Center, position relative to other view, size relative to other view
- Usually attach to Safe Area instead of whole device
Intrinsic Sizes #
- Some views know their size (labels, switches, ...)
- Only need position, not size
Hugging & Compressing #
- Views don't want to grow, so they hug their content
- Views have compression resistance priority (to determine who shrinks)
- Equal priorities: layout ambiguities
Variants #
- Attributes based on device class (think CSS media queries)
- Sizes:
Compact
(iPhone),Regular
(iPad),Any
Views #
Scroll View #
- Makes stuff scrollable (duh)
.frame
: How large is the visible "window"?.contentSize
- Insets: Add padding
- Has
UIScrollViewDelegate
(scrollViewDidScroll
,viewForZooming
, ...)
Table View #
- Subclass of
UIScrollView
- Shows vertical list of items (supports sections)
- Static vs. dynamic
- Styles: Plain, Grouped, Inset Grouped
- Uses cells (with default styles)
Collection Views #
- Subclass of
UIScrollView
- Uses separate layout object (can change betweeen them)
- Has abstract
UICollectionViewLayout
baseclass - Provided by UIKit:
UICollectoinViewFlowLayout
(handles common cases like grids)
- Has abstract
- Compositional layouts as alternative to building layout
- Compose layouts from smaller ones
NSCollectionLayoutItem
: Cell or supplementary view; needs sizeNSCollectionLayoutGroup
: One or many items, defined as horizontal, vertical or custom; needs sizeNSCollectionLayoutSection
: Configurable to scroll orthogonally to collection view
- Cells don't have builtin styles
Search Controller #
- Search functionality, integrated with navigation controllers
- Optional: secondary view to display result
Animations #
1UIView.animate(withDuration: 2.0) {
2 view.alpha = 0
3}
- Animate-able: alpha, backgroundColor, bounds, center, frame, transform
Data changes #
- Update views with
reloadData()
- Animate changes:
performBatchUpdates()
- Uses diffable datasources
Web access #
try await URL(string: "https://alexbaron.me")!
- Query params:
URLComponents(string: "...").queryItems = [URLQueryItem(name: "key", value: "value")]
Concurrency #
- Use async to free up main thread
- Actors: Organize multithreading;
MainActor
for UIKit Main-Thread DispatchQueue.global(qos: .background).async { DispatchQueue.main.async { } }
SwiftUI #
- Declarative
- MVVM instead of MVC
- Up to 10 children per trailing closure (-> stuff like
ForEach
needed) - Idea: DSL for UI
- Bindings:
$varname
,@Binding
Modifiers #
- Adjust views: return another view
- order matters
- Auto-applied to children
- Common examples:
.font
.foregroundColor
,.background
.frame
.padding
.overlay
: Add stuff above
XCode #
- Live Preview in the
Canvas
view - Provide dummy data:
PreviewProvider
- Options: preffered color scheme (light/dark), device, environment (dynamic font size, ...)
- Attribute Inspector: Change Code from UI (apparently pretty smart)
Layout Views #
- Push-out vs. pull-in
VStack
,HStack
,ZStack
: pull-in (all up to 10 children)LazyVStack
&LazyHStack
List
: A list; supportsSection
sForm
Spacer
: Evenly-spaced spaces, supportsminLength
MVVM #
- Model / View / ViewModel
- ViewModel: Contains state, uses bindings
Navigation #
- NavigationStack
- NavigationLink
@Environment
&.environmentObject(...)
for params
Storing Data #
Serialization #
- Use
Codable
protocol - Convert with
try? PropertyListEncoder().encode(myData)
File Manager #
- Get path(s):
FileManager.default.urls(for: .documentDirectory, in: .useDomainMask).first!
- Write:
encodedStuff.write(to: url, options: .noFileProtection)
- Read:
try? Data(contentsOf: url)