Swift

Swift is a general-purpose, open-source programming language developed by Apple Inc. back in 2014. It is designed to be a modern, safe, fast, and expressive language that is both easy to learn and powerful to use.

Developing for Apple platforms

When developing for Apple platforms such as iOS, iPadOS, macOS, or watchOS, there are several important considerations to keep in mind. Here is an overview of what to think about:

  1. Design and User Experience (UX): Apple emphasizes intuitive and visually appealing app designs. Understand the Human Interface Guidelines (HIG) specific to each platform and follow the recommended design principles. Pay attention to consistency, clarity, and ease of use to ensure a great user experience.
  2. Programming Languages and Tools: Apple primarily uses Swift and Objective-C programming languages for app development. Familiarize yourself with these languages and their respective frameworks, such as SwiftUI, UIKit, or AppKit. Utilize Xcode, Apple's integrated development environment (IDE), for coding, debugging, and testing your applications.
  3. Device Compatibility: Consider the various Apple devices your app will run on, like iPhone, iPad, Mac, or Apple Watch. Adapt your app's user interface and features to different screen sizes, resolutions, and interactions specific to each device. Leverage responsive layout techniques, adaptive design, or platform-specific APIs accordingly.
  4. App Store Guidelines: Adhere to Apple's strict App Store guidelines, ensuring your app meets their requirements for content, functionality, and security. Avoid any violations that may lead to rejection from the App Store or app removal. Stay updated with the latest policies and guidelines to avoid any potential pitfalls.
  5. Integration with Apple Ecosystem: Apple platforms provide numerous APIs and frameworks for integrating with their ecosystem. Explore functionalities like SiriKit, Apple Pay, Apple Maps, HealthKit, HomeKit, or ARKit to enhance your app's capabilities and offer seamless integration with other Apple services.
  6. Security and Privacy: Apple prioritizes user privacy and security. Ensure your apps handle user data responsibly, follow best practices for securing sensitive information, and respect user consent. Understand and implement Apple's security features like Keychain, App Sandbox, Data Protection, or Face ID/Touch ID authentication.
  7. App Testing and Optimization: Thoroughly test your app on different devices, environments, and OS versions using simulators and physical devices. Pay attention to performance optimization, memory management, and power efficiency. Utilize Apple's developer tools like Instruments or XCTest framework for automated testing.
  8. App Store Optimization (ASO): When preparing to launch your app on the App Store, consider optimizing its visibility and discoverability. Focus on factors like app name, description, keywords, screenshots, app previews, and ratings/reviews. Additionally, develop a robust marketing strategy to promote your app effectively.
  9. App Store Review Process: Understand Apple's review process and timelines for app submissions. Be prepared for potential iterations or rejections during the review process. Ensure compliance with legal requirements, copyright restrictions, and content guidelines to expedite the approval process.
  10. Continuous Learning and Updates: Stay updated with Apple's latest software releases, frameworks, and best practices. Attend WWDC (Apple's Worldwide Developers Conference), read Apple's developer documentation, participate in developer forums, and engage with the broader developer community to enhance your skills and stay abreast of the latest trends.

This can be summarized in the Four Pillars of Apple Development.

Four Pillars of Apple Development

  1. Tools
    • xcode
    • iOS simulator
    • Instrument
  2. Language
    • Swift
    • Design patterns
    • Supporting frameworks
  3. Application Design
    • App flow
    • Correct UI
    • Apple HIG (Human Interface Guideline)
  4. Rules
    • Default behaviour
    • Customising behaviour
    • Signing & submitting apps

Async/Await

The `await` keyword is a word to acknowledge to ourselvs and swift and this code might "go to sleep" here.

To use async and await with Swift, follow these steps:

  1. Define an asynchronous function: Start by marking the function with the `async` keyword to indicate that it is an asynchronous function. For example:

    func fetchData() async throws -> Data { // Async function implementation }

Note that the function's return type can be a normal type or a type wrapped in a `Task` (which allows cancellation and other task management).

  1. Use the `await` keyword: Inside the asynchronous function, use the `await` keyword to pause the function's execution until the awaited operation completes. This can be done with an asynchronous function call or by awaiting a task directly.

    let result = await fetchData()

  2. Handle errors: If the awaited operation can throw an error, use a `do-catch` block to handle any potential exceptions.

    do { let result = try await fetchData() / Handle the success case } catch { / Handle the error case }

Note that when an error is thrown inside an asynchronous function and not caught within that function, it automatically propagates as a failure.

  1. Call an asynchronous function from a non-async context: If you need to call an asynchronous function from a non-async context (like a regular function or a property), use the `await` keyword within a `Task.run` block.

    Task { let result = try await fetchData() // Handle the result }

By wrapping the asynchronous call within a `Task`, you create an isolated asynchronous context within a non-async context.

## Assets

App Bundle

The app bundle in iOS refers to a directory structure containing all the necessary resources and executable code for an iOS app. It includes the app's executable file (the compiled code), as well as various resource files such as images, sounds, and localized content. The app bundle is created during the building and compiling process in Xcode and is the container for the final app that is distributed to users. When users download and install an app from the App Store, they are essentially installing and unpacking the app bundle onto their devices.

### Opening Files

Open a text file in an app bundle.

func loadFile() { if let fileUrl = Bundle.main.url(forResource: "some-file", withExtension: "txt") { if let fileContents = try? String(contentsOf: fileUrl) { fileContents // do some work with the string "filecontents" } }

Extension to Bundle

To decode from the app bundle, can we make an extension to it.

extension Bundle { func decode(_ file: String) -> [String: Astronaut] { guard let url = self.url(forResource: file, withExtension: nil) else { fatalError("Failed to locate \(file) in bundle") // It is correct to fatalError with data that we have shipped to the AppStore. }

guard let data = try? Data(contentsOf: url) else { fatalError("Failed to load \(file) from bundle.") }

let decoder = JSONDecoder()

guard let loaded = try? decoder.decode([String: Astronaut].self, from: data) else { fatalError("Failed to decode \(file) from bundle.") }

return loaded } }

You can then use it like this.

struct ContentView: View { let astronauts = Bundle.main.decode("astronauts.json")

var body: some View { Text("\(astronauts.count)") } }

Core ML

Start with opening the CreateML app in XCode.

"BetterRest" mini project on calculating sleep from Hacking with Swift.

import CoreML import SwiftUI

struct ContentView: View { @State private var wakeUp = defaultWakeTime @State private var sleepAmount = 8.0 @State private var coffeAmount = 1

@State private var alertTitle = "" @State private var alertMessage = "" @State private var showingAlert = false

static var defaultWakeTime: Date { var components = DateComponents() components.hour = 7 components.minute = 0 return Calendar.current.date(from: components) ?? Date.now }

var body: some View { NavigationStack { Form { VStack(alignment: .leading, spacing: 30) { Text("When do you want to wake up") .font(.headline) DatePicker("Please enter a time", selection: $wakeUp, displayedComponents: .hourAndMinute) .labelsHidden() .datePickerStyle(.wheel) } Section("Desired amount of sleep") { Stepper("\(sleepAmount.formatted()) hours", value: $sleepAmount, in: 4…12, step: 0.25) }

Section("Daily coffee intake") { Stepper(coffeAmount == 1 ? "1 cup" : "\(coffeAmount) cups", value: $coffeAmount, in: 1…20) Picker("Cups", selection: $coffeAmount) { ForEach(1..<22) { Text("\($0 - 1) cups") } } } Section("Recommended bedtime") { let bedTime = calculateBedtime() Text(bedTime, format: .dateTime.hour().minute()) .font(.largeTitle) } } .navigationTitle("Better Rest") } }

func calculateBedtime() -> Date { do { let config = MLModelConfiguration() let model = try SleepCalculator(configuration: config)

let components = Calendar.current.dateComponents([.hour, .minute], from: wakeUp) let hour = (components.hour ?? 0) * 60 * 60 let minute = (components.minute ?? 0) * 60

let prediction = try model.prediction(wake: Double(hour + minute), estimatedSleep: sleepAmount, coffee: Double(coffeAmount))

let sleepTime = wakeUp - prediction.actualSleep return sleepTime

} catch { return Date.now } } }

Errors

Use `fatalError` to signal that the app should crash.

fatalError("Could not find the ffile in he bundle.")

## Extensions Advantage of extensions:

  1. gives code completion
  2. code is logically ordered in the correct type

2a. conformance grouping: adding a protocol conformance to a type as an extension, with all the required methods inside of the extension (makes it obvious which methods are belonging to/used for what). 2b. purpose grouping: creating extensions to do specific tasks, which is a way to break down the overview of a large type into smaller chunks

  1. extension has access to the internal properties and methods of the type

    var quote = " The truth is rarely pure and never simple " let trimmed = quote.trimmingCharacters(in: .whitespacesAndNewlines) // to have to write this each time is a bit lengthy, so we write an extension to make this easier print(trimmed)

Naming guidelines are that, if you return a new value, rahter than change it in place, then use word endings like "ed" or "ing". Can also add properties, but they can only be computed properties.

extension String { func trimmed() -> String { self.trimmingCharacters(in: .whitespacesAndNewlines) }

mutating func trim() { self = self.trimmed() }

var lines: [String] { self.components(separatedBy: .newlines) } }

print(quote.trimmed()) print(quote.trim())

let lyric = """ I keep must havve tos sto must stop moving can have music """

print(lyric.lines.count)

### Creating a struct with an extension initializer

Then we can have a computed property for "readingHours", but can also specify it if want to.

struct Book { let title: String let pageCount: Int let readingHours: Int }

extension Book { init(title: String, pageCount: Int) { self.title = title self.pageCount = pageCount self.readingHours = pageCount / 50 } }

let lotr = Book(title: "Lord of the rings", pageCount: 500, readingHours: 30) let rump = Book(title: "killen på ladan", pageCount: 100) print(rump.readingHours)

### Protocol Extensions

[Protocol extensions](https://www.hackingwithswift.com/quick-start/understanding-swift/when-are-protocol-extensions-useful-in-swift)

extension Array { // this is an extension to array to make is easier to reason about if it is empty or not var isNotEmpty: Bool { isEmpty == false } }

let guests = ["Mario", "Luigi", "Peach"]

if guests.isNotEmpty { print("Guest count: \(guests.count)") }

Array, String, Dictionary etc all adhere to a protocol called Collection. We can write an extension on the collection protocol and can then still

extension Collection { var isStillNotEmpty: Bool { isEmpty == false } }

guests.isStillNotEmpty

protocol Person { var name: String { get } func sayHello() }

extension Person { func sayHello() { print("hi, I'm \(name)") } }

struct Employee: Person { let name: String // don't need to add the "sayHello()" method since a default one is provided by the protocol }

let kippe = Employee(name: "Kippe") kippe.sayHello()

A protocol is a way of describing what properties and methods something must have.

/ Adopting / Conforming to a protocol is a way of making something adhere to that convention protocol Identifiable { var id: String {get set} / requires all types which conform to this protocol to have a "id" property with type String which can be read (get) and written to (set) } struct User: Identifiable { //This struct conforms to the "Identifiable" protocol var id: String } func displayID(thing: Identifiable) { //this funtion accepts any "Identifiable" object print("My ID is \\(thing.id)") }

// Protocol inheritance: it is possible to inherit from multiple protocols at the same time protocol Payable { func calculateWages() -> Int }

protocol NeedsTraining { func study() }

protocol HasVacation { func takeVacation(days: Int) }

protocol Employee: Payable, NeedsTraining, HasVacation { }

// Extensions: allow you to add methods to existing types, to make them do things they weren’t originally designed to do. extension Int { func squared() -> Int { return self \* self } } let number = 8 number.squared()

extension Int { var isEven: Bool { return self % 2 == 0 } } number.isEven

/ Protocol extension: Protocols let you describe what methods something should have, but don’t provide the code inside. Extensions let you provide the code inside your methods, but only affect one data type – you can’t add the method to lots of types at the same time. / Protocol extensions solve both those problems: they are like regular extensions, except rather than extending a specific type like Int you extend a whole protocol so that all conforming types get your changes. let pythons = ["Eric", "Graham", "John", "Michael", "Terry", "Terry"] //array conforms to Collection protocol let beatles = Set(["John", "Paul", "George", "Ringo"]) //set conforms to Collection protocol

extension Collection { func summarize() { print("There are \\(count) of us:")

for name in self { print(name) } } } pythons.summarize() beatles.summarize()

// Protocol-oriented-programming: crafting your code around protocols and protocol extensions protocol Identifiera { var id: String { get set } func identify() } extension Identifiera { func identify() { print("My ID is \\(id)") } } struct Användare: Identifiera { var id: String } let puppe = Användare(id: "puppe") puppe.identify()

## Optionals

## Protocols

Protocol is a type. They let us talk about the functionality we are interested in, rather than the specific types. It is possible to conform to more than one protocol.

If you have class inheritance, then put the classes first and the protocols after.

For properties, do you have to specify the type and if we should be able to read `{ get }` or read and write `{ get set }`.

<table border="2" cellspacing="0" cellpadding="6" rules="groups" frame="hsides"> <caption class="t-above"><span class="table-number">Table 1:</span> Protocols</caption>

<colgroup> <col class="org-left" />

<col class="org-left" /> </colgroup> <thead> <tr> <th scope="col" class="org-left">Protocol</th> <th scope="col" class="org-left">Description</th> </tr> </thead>

<tbody> <tr> <td class="org-left"><a href="https://developer.apple.com/documentation/swift/customstringconvertible">CustomStringConvertible</a></td> <td class="org-left">produce strings from custom types</td> </tr>

<tr> <td class="org-left">Identifiable</td> <td class="org-left">Must contain an item called <code>id</code> which must be unique</td> </tr> </tbody> </table>

## Create a protocol

protocol Vehicle { var name: String { get } var currentPassangers: Int { get set } func estimateTime(for distance: Int) -> Int // If you want to work with this protocol, then you have to implement these two methods func travel(distance: Int) }

<a id="org4465187"></a>

## Conforming to a protocol

Adopting or Conforming to a protocoll requires the methods listed in the protocol to be implemented.

struct Bicycle: Vehicle { let name = "Bicycle" var currentPassangers = 1 func estimateTime(for distance: Int) -> Int { distance / 10 } func travel(distance: Int) { print("I'm cycling \(distance)km.") } }

struct Car: Vehicle { let name = "Car" var currentPassangers: Int = 1 func estimateTime(for distance: Int) -> Int { distance / 50 } func travel(distance: Int) { print("I'm driving \(distance)km.") } func openSunroof() { print("It's a sunny day!") } }

func commute(distance: Int, using vehicle: Vehicle) { // here we can use 'Vehicle' type since we are conforming to the Vehicle protocol if vehicle.estimateTime(for: distance) > 100 { print("That's tooo slow! I'll try a different vehicle.") } else { vehicle.travel(distance: distance) } }

func getTravelEstimates(using vehicles: [Vehicle], distance: Int) { for vehicle in vehicles { let estimate = vehicle.estimateTime(for: distance) print("\(vehicle.name): \(estimate) hours to travel \(distance)km") } }

let car = Car() commute(distance: 100, using: car)

let bicycle = Bicycle() commute(distance: 50, using: bicycle)

getTravelEstimates(using: [bicycle, car], distance: 100)

## Opaque return types

Both Int and Bool adheres to the Equatable protocol.

func getRandomNumber() -> some Equatable { Int.random(in: 1…6) }

func getRandomBool() -> some Equatable { Bool.random() }

print(getRandomNumber() = getRandomNumber()) print(getRandomBool() = getRandomBool())

some indicates a box whose contained value has a type known to the compiler at compile time. any indicates a box whose contained value has a type not known to the compiler at compile time.

## Codable

A protocol that allows easy conversion between a struct or a class and JSON or XML.

To make a struct conform to the `Codable` protocol do.

  1. Add the `Codable` protocol conformance to your struct declaration.
  2. Implement the `CodingKeys` enumeration to specify the keys for the properties you want to encode or decode.
  3. Implement the `init(from decoder: Decoder)` initializer to decode the properties from the given decoder.
  4. Implement the `encode(to encoder: Encoder)` method to encode the properties to the given encoder.

    struct Person: Codable { let name: String let age: Int

    // Define CodingKeys enumeration enum CodingKeys: String, CodingKey { case name case age }

    // Implement init(from decoder: Decoder) initializer init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) name = try container.decode(String.self, forKey: .name) age = try container.decode(Int.self, forKey: .age) }

    // Implement encode(to encoder: Encoder) method func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(name, forKey: .name) try container.encode(age, forKey: .age) } }

Working with JSON.

struct User: Codable { let name: String let address: Address }

struct Address: Codable { let street: String let city: String }

struct ContentView: View { var body: some View { Button("Decode JSON") { let input = """ { "name": "Taylor Swift", "address": { "street": "555, Taylor Swift Avenue", "city": "Nashville" } } """

let data = Data(input.utf8)

if let user = try? JSONDecoder().decode(User.self, from: data) { print(user.address.street) } } } }

### @Published and Codable

`@Published` can't by iteself conform to codable. To make a struct or class which uses `@Published` conform to codable, do we have to define how the encode and decode should happen.

To define encode and decode do we have to create an enum which is typically called `CodingKeys`, which conforms to `CodingKey`.

`required` means that this has to be included if it is sub-classed. Alternatively could the whole class be set as `final`.

For the decoding part are we telling the `Decoder` that we should use the keys with the `keyedBy` parameter.

For encoding do we need to create a function, which has the encoding keys as parameters.

class User: ObservableObject, Codable { enum CodingKeys: CodingKey { case name }

@Published var name = "Hugo Hugginson"

required init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) name = try container.decode(String.self, forKey: .name) }

func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(name, forKey: .name) } }

## Identifiable

Requires that the struct or class contains an `id` item which is unique. We can then omit the `id` part of, for example `ForEach` loops, since we already guarantee that it is there.

struct ExpenseItem: Identifiable { let id = UUID() let name: String let type: String let amount: Double }

struct ContentView: View { @StateObject var expenses = Expenses()

var body: some View { NavigationStack { List { ForEach(expenses.items) { item in // we don't need "id" since expenses conforms to "Identifiable" Text("\(item.name): \(item.id)") } .onDelete(perform: removeItems) } .navigationTitle("iExpense") .toolbar { Button { let expense = ExpenseItem(name: "Test", type: "Personal", amount: 5) expenses.items.append(expense) } label: { Image(systemName: "plus") } } } }

func removeItems(at offsets: IndexSet) { expenses.items.remove(atOffsets: offsets) } }

<a id="org422382d"></a>

struct Album { let title: String let artist: String let year: Int

func printSummary() { print("\(title) \(year) by \(artist)") } }

let mupp = Album(title: "muff", artist: "heija", year: 2023) mupp.printSummary()

struct Employee { let name: String / since name is a constant, if it also would have a default, then would we have to remove it from the argument list var vacationRemaining: Int = 0 / since vacationRemaining is a var, can we also ask for the value when calling it is an argument

mutating func takeVacation(days: Int) { if vacationRemaining > days { vacationRemaining -= days // the data inside of a struct is immutable print("I'm going on vacation!") print("Vacation days remaining: \(vacationRemaining)") } else { print("Oops there aren't enough days remaining. Number of days remaining are currently \(vacationRemaining)") } } }

var archer = Employee(name: "mefisto", vacationRemaining: 50) // Is mutable so can't use "let" archer.takeVacation(days: 34) archer.takeVacation(days: 13) archer.takeVacation(days: 5 )

<a id="org046eac8"></a>

## Computing proptery values dynamically

/ two types of properties: / 1. stored properties: value is placed into the struct directly // 2. computed properties: recalculates the value of the property every time it is accessed

struct EmployeeAgain { let name: String var vacationAllocated = 14 var vacationTaken = 0

var vacationRemaining: Int { / computed property get { / the getter vacationAllocated - vacationTaken } set { / the setter vacationAllocated = vacationTaken + newValue / newValue is automatically created for us by swift } }

mutating func takeVacation(days: Int) { if vacationRemaining > days { vacationTaken += days print("I'm going on vacation!") print("Vacation days remaining: \(vacationRemaining)") } else { print("Oops there aren't enough days remaining. Number of days remaining are currently \(vacationRemaining)") } } }

var pontus = EmployeeAgain(name: "pontus") print("\(pontus.name) has vacation allocated \(pontus.vacationAllocated) and vacation taken \(pontus.vacationTaken) which gives vacation remaining \(pontus.vacationRemaining)") pontus.takeVacation(days: 3) print("\(pontus.name) has vacation allocated \(pontus.vacationAllocated) and vacation taken \(pontus.vacationTaken) which gives vacation remaining \(pontus.vacationRemaining)") pontus.takeVacation(days: 10) print("\(pontus.name) has vacation allocated \(pontus.vacationAllocated) and vacation taken \(pontus.vacationTaken) which gives vacation remaining \(pontus.vacationRemaining)")

<a id="orgde2e91d"></a>

## Getter and Setter

/ Assigning to a computed property with "getter" and "setter". / getter = is code that reads // setter = is code that writes

pontus.vacationRemaining = 30 print("\(pontus.name) has vacation allocated \(pontus.vacationAllocated) and vacation taken \(pontus.vacationTaken) which gives vacation remaining \(pontus.vacationRemaining)")

<a id="org88a3a9c"></a>

### Property observer

/ this is code which runs whenever a property is changed / there are two forms: / 1. did set: runs code after a property has been changed / 2. will set: runs code when a property is about to change

struct Game { var score = 0 { didSet { print("Score is now \(score)") } } }

var game = Game() game.score += 10 game.score += 2 game.score += 99

struct App { var contacts = [String]() { willSet { print("Current value is: \(contacts)") print("New value will be: \(newValue)") } didSet { print("There are now \(contacts.count) contacts: \(oldValue)") print("New value is: \(contacts)") } } }

var app = App() app.contacts.append("Adrian E") app.contacts.append("Allen W") app.contacts.append("Puppe Rull")

<a id="org00d7979"></a>

## Custom initializers

/ - no func keyword before init / - init does not have an explicit return type, they just always return the data they belong to // - "self" means assign the name property to self-name-property

struct Player { let name: String let number: Int

init(name: String) { // there is no "func" keyword here (for structs) self.name = name number = Int.random(in: 1..<100) print("Player \(self.name) created with a number of \(number)") } }

let player = Player(name: "Megan R") let puppe = Player(name: "Puppe")

/ The memberwise initializer (that one provided by struct) goes away if we provide our own. / A way around this is to extend the memberwise initializer, rather than substitute it // This saves us work when instantiating.

struct Golfer { var name: String var yearsActive = 0 }

extension Golfer { init() { self.name = "Anonymous" self.yearsActive = 0 print("Creating an anonymous golfer.") } }

let roslin = Golfer(name: "Roslin") let anon = Golfer() let anon2 = Golfer()

<a id="org191cd1b"></a>

## Access Control

"privacy is power – what people don’t know, they can’t ruin.”

// making something private, let's only methods inside of the struct to alter the variable.

/ private: Don't let anything outisde the struct use this / fileprivate: Don't let anything outside the current file use this / public: Let anyone, anywhere to use this / private(set): Let anyone read this property, but only let my internal methods write to it. For example, you can read the value of bankaccount but you can't change it

struct BankAccount { private(set) var funds = 0

mutating func deposit(amount: Int) { funds += amount } mutating func withdraw(amount: Int) -> Bool { if funds > amount { funds -= amount return true } else { return false } } }

var account = BankAccount() account.deposit(amount: 1000) let success = account.withdraw(amount: 2000)

if success { print("Withdrew money successfully") } else { print("Failed to oget the money.") }

// account.funds -= 10000 doesnt work print(account.funds)

<a id="orgbc44c15"></a>

## static

// static variables are acting on a struct/class level

struct School { static var studentCount = 0

static func add(student: String) { print("\(student) joined the school.") studentCount += 1 } }

School.add(student: "pelle")

/ Mising static and non-static has two rules: / 1. you can't access non-static properties/methods from static properties/methods // 2. When accessing "Self" (with a capital "S"), then it points to the current type of struct

struct AppData { static let version = "1.3 beta 2" static let saveFilename = "settings.json" static let homeURL = "https://gronberg.org" }

AppData.version

struct Hacker { let username: String let password: String

static let example = Hacker(username: "haXXon", password: "6ecriit") }

print(Hacker.example)

struct Car { let model: String let seats: Int let maxGear: Int private(set) var currentGear = 1

mutating func gearUp() { if currentGear < maxGear { currentGear += 1 print("Shifting gear from \(currentGear - 1) to \(currentGear)") } else { print("Already at maximum gear.") } } mutating func gearDown() { if currentGear > 1 { currentGear -= 1 print("Shifting gear down from \(currentGear + 1) to \(currentGear)") } else { print("Already at lowest gear.") } } }

var ford = Car(model: "ford", seats: 4, maxGear: 5)

ford.gearUp() ford.gearUp() ford.gearUp() ford.gearUp() ford.gearUp() ford.gearDown() ford.gearDown()

There are two ways to construct new types. The most common one is with structs.

Structures (and classes): can have their own variables and constants (called properties) and functions (called methods) struct Sport { var name: String //properties can have default values just like for regular variables } var tennis = Sport(name: "Tennis") print(tennis.name) tennis.name = "Basket" print(tennis.name)

// Computed properties struct Sporten { var name: String var isOlympicSport: Bool

var olympicStatus: String { if isOlympicSport { return "\\(name) is an Olympic sport" } else { return "\\(name) is not an Olympic sport" } } } let chessBoxing = Sporten(name: "Chessboxing", isOlympicSport: false) print(chessBoxing.isOlympicSport)

struct Wine { //wine price calculator var age: Int var isVintage: Bool var price: Int { if isVintage { return age + 20 } else { return age + 5 } } } let malbec = Wine(age: 2, isVintage: true) print(malbec.price)

struct Medicine { var amount: Int var frequency: Int var dosage: String { return "Take \\(amount) pills \\(frequency) times a day." } } let råtta = Medicine(amount: 3, frequency: 15) print(råtta.dosage)

// Property observers: makes it possible to execute code before (willSet) or after (didSet) a property is changed struct Progress { var task: String var amount: Int { didSet { //to take action before a property is changed use "willSet" print("\\(task) is now \\(amount)% complete.") } } } var progress = Progress(task: "Loading data", amount: 0) progress.amount = 30 progress.amount = 40 progress.amount = 80

struct Person { var clothes: String { willSet { updateUI(msg: "I'm changing from \\(clothes) to \\(newValue).") } didSet { updateUI(msg: "I just changed from \\(oldValue) to \\(clothes).") } } } func updateUI(msg: String) { print(msg) } var miffo = Person(clothes: "hellraisor hjälm") miffo.clothes = "säck byxor"

/ Methods: functions inside of structs are called "methods" but they start with the "func" keyword / methods can use the properties which are in the struct struct City { var population: Int func collectTaxes() -> Int { return population \* 1000 } } let london = City(population: 5) london.collectTaxes()

// Mutating: swift won't let you write methods which change properties unless you specifically request it struct Personen { var name: String mutating func makeAnonymous() { name = "Anonymous" } } var person = Personen(name: "Ed") person.makeAnonymous()

// Properties and methods for Strings (Strings are structs) let string = "Do or do not, there is not try" print(string.count) print(string.hasPrefix("Do")) print(string.uppercased()) print(string.sorted()) print(string.lowercased())

// Properties and methods of Arrays (Arrays are structs) var toys = ["Woody"] //one simple array (type toys. to get XCode completion) print(toys.count) toys.append("Buzz") toys.firstIndex(of: "Buzz") print(toys.sorted()) toys.remove(at: 0) print(toys.sorted())

/ Initializers: are special methods that provide different ways to creat stucts / Default initializer is "memberwise initializer", which ask you to provide a value for each property when you create the stuct struct User { var username: String init() { username = "Anon" print("Creating a new user.") } } var user = User() user.username = "puppe"

struct Starship { var name: String var maxWarp: Double init(starshipName: String, starshipMaxWarp: Double) { name = starshipName maxWarp = starshipMaxWarp print("\\(name) is flying away at warpspeed \\(maxWarp)") } } let voyager = Starship(starshipName: "Puppesskepp", starshipMaxWarp: 3.3)

/ self: Referring to the current instance / Use "self" within the method to point to whatever instance of the struct is currently being used. The self value is useful when you create initilizers that have the same parameter name as the property struct Personerna { var name: String //name property init(name: String) { print("\\(name) was born!") self.name = name //name parameter } }

// Lazy properties: are only created once they are accessed struct FamilyTree { init() { print("Creating family tree") } } struct People { var name: String lazy var familyTree = FamilyTree() //using the FamilyTree struct and creating it lazily init(name: String) { self.name = name } } var lars = People(name: "Lars") lars.familyTree

// Static properties and methods: are part of the struct itself rather than an instance of the struct struct Student { static var classize = 0 //this var belongs to the struct rather than an instance of the struct and can be accessed from all instances of the struct. This can't be access from any non-static properties from the struct var name: String init(name: String) { self.name = name Student.classize += 1 } } print(Student.classize) let mefisto = Student(name: "Mefisto") print(Student.classize)

// Access control: restricts which code can use properties and methods. Is used for structs and classes

struct Persson { private var id: String /makes it impossible to read this id outside of the struct init(id: String) { self.id = id } func identify() -> String { //makes it possible to read "id" through this function outside of the stuct return "My social security number is \\(id)" } } let ed = Persson(id: "666666") / ed.id - will not work since "id" is set to private // Public: use public to let all other code use the property and method

<a id="orgaaa8673"></a>

[SwiftUI](https://developer.apple.com/documentation/swiftui/) gives us the functionality provided by the SwiftUI framework.

Get help with choosing [SwiftUI property wrappers](https://www.hackingwithswift.com/articles/227/which-swiftui-property-wrapper).

<a id="org0059bce"></a>

## Alerts

struct ContentView: View { @State private var showingAlert = false

var body: some View { Button("Show Alert") { showingAlert = true } .alert("Important message", isPresented: $showingAlert) { Button("Delete", role: .destructive) { } Button("Cancel", role: .cancel) { } } message: { Text("Please read this") } } }

<a id="orgcd38a8b"></a>

### Using Buttons and Alerts

struct ContentView: View { @State private var showingScore = false @State private var maximumNumberOfGuessesReached = false @State private var scoreTitle = "" @State private var score = 0 @State private var countries = ["Estonia", "France", "Germany", "Ireland", "Italy", "Monaco", "Nigeria", "Poland", "Russia", "Spain", "UK", "US"].shuffled() @State private var correctAnswer = Int.random(in: 0…2) @State private var tappedFlag = 0 @State private var numberOfGuesses = 0

var body: some View { ZStack { / LinearGradient(gradient: Gradient(colors: [Color(red: 1, green: 0.8, blue: 0), Color(red: 0.4, green: 0, blue: 1)]), startPoint: .top, endPoint: .bottom) / .ignoresSafeArea() RadialGradient(stops: [ .init(color: .blue, location: 0.3), .init(color: .black, location: 0.8) ], center: .top, startRadius: 200, endRadius: 700) .ignoresSafeArea()

VStack { Spacer() Text("Guess the Flag") .font(.largeTitle.bold()) .foregroundColor(.white)

VStack(spacing: 15) { VStack(spacing: 10) { Text("Tap the flag of") .foregroundStyle(.secondary) .font(.subheadline.weight(.heavy))

Text(countries[correctAnswer]) //.foregroundColor(.white) .font(.largeTitle.weight(.semibold)) }

ForEach(0..<3) { number in Button { flagTapped(number) tappedFlag = number } label: { Image(countries[number]) .renderingMode(.original) .clipShape(Capsule()) .shadow(radius: 10) } } } .frame(maxWidth: .infinity) .padding(.vertical, 20) .background(.regularMaterial) .clipShape(RoundedRectangle(cornerRadius: 20))

Spacer() Spacer()

Text("Score: \(score)") .foregroundColor(.white) .font(.title.bold())

Spacer() } .padding() } .alert(scoreTitle, isPresented: $showingScore) { Button("Continue", action: askQuestion) } message: { Text("\(scoreTitle == "Correct" ? "" : "That is the flag of \(countries[tappedFlag])")") } .alert("Final Result", isPresented: $maximumNumberOfGuessesReached) { Button("Reset", action: resetGame) } message: { Text("Final score is \(score) out of 8") } }

func flagTapped(_ number: Int) { numberOfGuesses += 1 if number = correctAnswer { score + 1 askQuestion() } else { scoreTitle = "Wrong" showingScore = true }

if numberOfGuesses > 7 { maximumNumberOfGuessesReached = true } }

func askQuestion() { countries.shuffle() correctAnswer = Int.random(in: 0…2) }

func resetGame() { score = 0 numberOfGuesses = 0 } }

<a id="orge76a799"></a>

## Animations

In SwiftUI are the animation becoming functions of our state, just like the views are.

The easiest animation to create is where the animation is an implicit one.

<a id="orga296094"></a>

### Types of animations

  • Ease in ease out.
  • easeIn
  • easeInOut
  • easeOut
  • Stiffness

[Creating implicit animations](https://www.hackingwithswift.com/books/ios-swiftui/creating-implicit-animations):

struct ContentView: View { @State private var animationAmount = 1.0

var body: some View { VStack { Button("Tap me") { animationAmount += 1 } .padding(50) .background(.red) .foregroundColor(.white) .clipShape(Circle()) .scaleEffect(animationAmount) .blur(radius: (animationAmount - 1 ) * 2) .animation( .easeInOut(duration: 1) .repeatCount(11, autoreverses: true), value: animationAmount )

} } }

[Customizing animations](https://www.hackingwithswift.com/books/ios-swiftui/customizing-animations-in-swiftui)

struct ContentView: View { @State private var animationAmount = 1.0

var body: some View { VStack { Button("Tap me") { // animationAmount += 1 } .padding(50) .background(.red) .foregroundColor(.white) .clipShape(Circle()) .overlay( Circle() .stroke(.red) .scaleEffect(animationAmount) .opacity(2 - animationAmount) .animation( .easeInOut(duration: 1) .repeatCount(11, autoreverses: false), value: animationAmount ) ) .onAppear { animationAmount = 2 }

} } }

<a id="org048a009"></a>

### Animating bindings

[Animating bindings](https://www.hackingwithswift.com/books/ios-swiftui/animating-bindings)

The animation() modifier can be applied to any SwiftUI binding, which causes the value to animate between its current and new value

struct ContentView: View { @State private var animationAmount = 1.0

var body: some View { print(animationAmount) return VStack { VStack { Stepper("Scale amount", value: $animationAmount.animation( .easeInOut(duration: 1) .repeatCount(7, autoreverses: true) ), in: 1…10)

Spacer()

Button("Tap me") { animationAmount += 1 } .padding(50) .background(.red) .foregroundColor(.white) .clipShape(Circle()) .scaleEffect(animationAmount) } } } }

<a id="org336ef8a"></a>

### Explicit Animations

Use `withAnimation` to get an explicit animation.

struct ContentView: View {

@State private var animationAmount = 0.0

var body: some View { Button("Tap me") { withAnimation(.interpolatingSpring(stiffness: 9, damping: 1.0)) { animationAmount += 360 } } .padding(50) .background(.red) .foregroundColor(.white) .clipShape(Circle()) .clipShape(Circle()) .rotation3DEffect(.degrees(animationAmount), axis: (x: 1, y: 0.5, z: 0.5)) } }

<a id="orgef52b36"></a>

### Transitions

Use several animations on a view. The animation is applied to all modifiers above the animation.

struct ContentView: View {

@State private var enabled = false @State private var animationAmount = 0.0

var body: some View { Button("Tap me") { enabled.toggle() } .frame(width: 200, height: 200) .background(enabled ? .blue : .red) .animation(.default, value: enabled) .foregroundColor(.white) .clipShape(RoundedRectangle(cornerRadius: enabled ? 60 : 0)) .animation(.interpolatingSpring(stiffness: 10, damping: 1), value: enabled) } }

<a id="org2ff3a42"></a>

### Animating Gestures

The explicit animation is better for drag and drop (at least in this case).

struct ContentView: View {

@State private var dragAmount = CGSize.zero // CG = core graphics

@State private var enabled = false @State private var animationAmount = 0.0

var body: some View { LinearGradient(gradient: Gradient(colors: [.yellow, .red]), startPoint: .topLeading, endPoint: .bottomTrailing) .frame(width: 300, height: 200) .clipShape(RoundedRectangle(cornerRadius: 10)) .offset(dragAmount) .gesture( DragGesture() .onChanged { dragAmount = $0.translation } .onEnded { _ in withAnimation { / This is the explicit animation dragAmount = .zero } } ) / .animation(.spring(), value: dragAmount) // This is (would be if used) an implicit animation } }

<a id="org2ddfd9e"></a>

### Animating Drag Gestures

struct ContentView: View { let letters = Array("Hello, SwiftUI") @State private var enabled = false @State private var dragAmount = CGSize.zero

var body: some View { HStack(spacing: 0) { ForEach(0..<letters.count) { num in Text(String(letters[num])) .padding(5) .font(.title) .background(enabled ? .blue : .red) .offset(dragAmount) .animation( .default.delay(Double(num) / 20), value: dragAmount ) } } .gesture( DragGesture() .onChanged { dragAmount = $0.translation } .onEnded { _ in dragAmount = .zero enabled.toggle() } ) } }

<a id="org7ec9d72"></a>

### Showing and hiding views

This uses an asymetric transition.

struct ContentView: View { @State private var enabled = false @State private var isShowingRed = false

var body: some View { VStack { Button("Tap me") { withAnimation { isShowingRed.toggle() } }

if isShowingRed { Rectangle() .fill(.red) .frame(width: 200, height: 200) .transition(.asymmetric(insertion: .scale, removal: .opacity)) } } } }

<a id="orgda656d3"></a>

### Build custom transitions using ViewModifier

Create a struct with `ViewModifier`.

struct CornerRotateModifier: ViewModifier { let amount: Double let anchor: UnitPoint

func body(content: Content) -> some View { content .rotationEffect(.degrees(amount), anchor: anchor) .clipped() } }

extension AnyTransition { static var pivot: AnyTransition { .modifier( active: CornerRotateModifier(amount: -90, anchor: .topLeading), identity: CornerRotateModifier(amount: 0, anchor: .topLeading)) } }

struct ContentView: View { @State private var isShowingRed = false

var body: some View { ZStack { Rectangle() .fill(.blue) .frame(width: 200, height: 200)

if isShowingRed { Rectangle() .fill(.red) .frame(width: 200, height: 200) .transition(.pivot) } } .onTapGesture { withAnimation { isShowingRed.toggle() } } } }

<a id="org08d5d26"></a>

## Bindings

In SwiftUI, bindings are a way to create two-way communication between views and their underlying data. Bindings allow you to bind a value from a source of truth (such as a state property) to a view, and any changes made to the view will also update the underlying data, and vice versa.

To create a binding, you typically use the `State` property wrapper to define a state property in a view. This tells SwiftUI that the property is mutable and can be modified within the view. The state property holds the source of truth for the view, and any changes made to it will trigger an update of the view.

Once you have a state property, you can create a binding to it by using the `$` prefix. For example, if you have a state property "name", you can create a binding to it like this: =@Binding var name: String\`. You can then pass this binding to child views, allowing them to modify and access the value in a two-way manner.

When you pass a binding to a child view, you can use it to read the value using `$name.wrappedValue`, and modify the value using `$name.wrappedValue ​= "New Name"`. Any changes made to the value using the binding will also update the source of truth, thus triggering an update of the view.

Bindings are particularly useful when dealing with user input, as they allow you to easily capture and react to changes made by the user. For example, you can bind a text field to a state property using the `TextField` view, and any changes made by the user will automatically update the corresponding state property, which in turn triggers a re-rendering of the view.

Suppose we have a simple counter view in SwiftUI, and we want to display the value of the counter and the ability to increment it. We can use the `@Binding` property wrapper to achieve this:

struct CounterView: View { @Binding var counter: Int

var body: some View { VStack { Text("Counter: \(counter)") .font(.headline) Button(action: { self.counter += 1 }) { Text("Increment") } } } }

Then, create a parent view that initializes the counter and passes it as a binding to the `CounterView`:

struct ContentView: View { @State private var count = 0

var body: some View { VStack { CounterView(counter: $count) Spacer() Text("Parent Counter: \(count)") } .padding() } }

In the above code, we initialize a `@State` property `count` in the parent view, and then pass it as a binding `$count` to the `CounterView`. Now, whenever we tap the "Increment" button in the `CounterView`, it will update the `count` property in the parent view, and the parent view will automatically re-draw itself with the updated value.

This way, we achieve two-way data binding between the `CounterView` and the parent view using `@Binding`, where changes in the `CounterView` affect the parent view and vice versa.

Bindings aren’t magic: `@State` takes away some boilerplate code for us but it is also possible to create and manage bindings by hand.

struct ContentView: View { @State private var selection = 0

var body: some View { let binding = Binding( get: { selection }, set: { selection = $0 } )

return VStack { Picker("Select a number", selection: binding) { ForEach(0..<3) { Text("Item \($0)") } } .pickerStyle(.segmented) } } }

See also [Working with bindings](https://www.hackingwithswift.com/guide/ios-swiftui/2/2/key-points) on Hacking with Swift.

<a id="org069ed21"></a>

## Button

Good to use ternary operators.

struct ContentView: View { @State private var useRedText = false

var body: some View { Button("Hello World") { // flip the Boolean between true and false useRedText.toggle() } .foregroundColor(useRedText ? .red : .blue) } }

Button("Tap Count: \\(tapCount)")

This is a button.

Button("Delete selection", action: executeDelete)

func executeDelete() { print("Now deleting…") }

Many buttons:

VStack { Button("Button 1") { } .buttonStyle(.bordered) Button("Button 2", role: .destructive) { } .buttonStyle(.bordered) Button("Button 3") { } .buttonStyle(.borderedProminent) Button("Button 4", role: .destructive) { } .buttonStyle(.borderedProminent) }

Customize buttons:

Button { print("Button was tapped") } label: { Text("Tap me!") .padding() .foregroundColor(.white) .background(.red) }

Use a image for the button.

Button { print("Edit button was tapped") } label: { Image(systemName: "pencil") }

or for both image and text do:

Button { print("Edit button was tapped") } label: { Label("Edit", systemImage: "pencil") }

Tip: If you find that your images have become filled in with a color, for example showing as solid blue rather than your actual picture, this is probably SwiftUI coloring them to show that they are tappable. To fix the problem, use the renderingMode(.original) modifier to force SwiftUI to show the original image rather than the recolored version.

<a id="org8904695"></a>

### Role

Use role with button to indicate how it should be used. Role `.destructive` will make it red.

Button("Delete selection", role: .destructive, action: executeDelete)

<a id="orga8fa15b"></a>

### Borders

Use one of the built-in styles for buttons: .bordered and .borderedProminent.

VStack { Button("Button 1") { } .buttonStyle(.bordered) Button("Button 2", role: .destructive) { } .buttonStyle(.bordered) Button("Button 3") { } .buttonStyle(.borderedProminent) Button("Button 4", role: .destructive) { } .buttonStyle(.borderedProminent) }

If you want to customize the colors used for a bordered button, use the tint() modifier like this.

Button("Button 3") { } .buttonStyle(.borderedProminent) .tint(.mint)

<a id="org01fe826"></a>

### Custom Button

If you want something completely custom, you can pass a custom label using a second trailing closure.

Button { print("Button was tapped") } label: { Text("Tap me!") .padding() .foregroundColor(.white) .background(.red) }

This is particularly common when you want to incorporate images into your buttons.

SwiftUI has a dedicated Image type for handling pictures in your apps, and there are three main ways you will create them:

Image("pencil") will load an image called “Pencil” that you have added to your project. Image(decorative: "pencil") will load the same image, but won’t read it out for users who have enabled the screen reader. This is useful for images that don’t convey additional important information. Image(systemName: "pencil") will load the pencil icon that is built into iOS. This uses Apple’s SF Symbols icon collection, and you can search for icons you like – download Apple’s free SF Symbols app from the web to see the full set. By default the screen reader will read your image name if it is enabled, so make sure you give your images clear names if you want to avoid confusing the user. Or, if they don’t actually add information that isn’t already elsewhere on the screen, use the Image(decorative:) initializer.

Because the longer form of buttons can have any kind of views inside them, you can use images like this:

Button { print("Edit button was tapped") } label: { Image(systemName: "pencil") }

Button { print("Edit button was tapped") } label: { Label("Edit", systemImage: "pencil") }

Tip: If you find that your images have become filled in with a color, for example showing as solid blue rather than your actual picture, this is probably SwiftUI coloring them to show that they are tappable. To fix the problem, use the renderingMode(.original) modifier to force SwiftUI to show the original image rather than the recolored version.

<a id="orgb54427e"></a>

## Color

  • Color.black or .primary or .secondary
  • .background(.red)
  • .foregroundStyle

<a id="orga5af7de"></a>

### Frame

Color.red .frame(minWidth: 200, maxWidth: .infinity, maxHeight: 200)

<a id="org4996e84"></a>

### Gradients

VStack(spacing: 20) { ZStack { Color(red: 1, green: 0.8, blue: 0) HStack(spacing: 30) { Button("Delete First Selection", role: .destructive, action: executeDelete) Text("Second").foregroundColor(.cyan) Text("Third").foregroundColor(.yellow) } .background(.indigo) } .background(.indigo) HStack { Spacer() ZStack { Color.secondary .frame(maxWidth: 60) Text("First").foregroundColor(.white) } Spacer() ZStack { VStack(spacing: 0) { Color.primary Color.yellow } Text("Second") .foregroundStyle(.white) .padding(30) .background(.ultraThinMaterial) } Spacer() ZStack { LinearGradient(gradient: Gradient(colors: [.white, .black]), startPoint: .top, endPoint: .bottom) Text("Third") .foregroundStyle(.green) } Spacer() } HStack { Spacer() Text("First") LinearGradient(gradient: Gradient(stops: [ .init(color: .blue, location: 0.4), .init(color: .black, location: 0.8) ]), startPoint: .top, endPoint: .bottom) Spacer() Text("Second") RadialGradient(gradient: Gradient(colors: [.indigo, .white]), center: .center, startRadius: 10, endRadius: 50) Spacer() Text("Third") Spacer() } ZStack { AngularGradient(gradient: Gradient(colors: [.red, .yellow, .green, .blue, .purple, .red]), center: .center) Text("Your content") .foregroundColor(.white) .background(.blue) } .background(.green) }

<a id="org313e2a4"></a>

### Material

ZStack { VStack(spacing: 0) { Color.red Color.blue }

Text("Your content") .foregroundColor(.secondary) .padding(50) .background(.ultraThinMaterial) } .ignoresSafeArea()

<a id="orgf7a8d2f"></a>

### Extend Colors

<a id="orgf15b951"></a>

## Dates

Working with dates. Do you use `Calendar` to get dates.

func getCurrentDate() { var componenets = DateComponents() componenets.hour = 8 componenets.minute = 0 let date = Calendar.current.date(from: componenets) ?? Date.now // good idea to nil coalesce down to Date.now in case something goes wrong }

<a id="orgec72047"></a>

## DateFormatter

In Swift, you can use the `DateFormatter` class to format a date in the desired format. Here's an example of how to write a date in the \`Date\` type way:

import Foundation

// Create a DateFormatter instance let dateFormatter = DateFormatter()

// Set the desired date format dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"

// Get the current date let currentDate = Date()

// Format the date as a string let dateString = dateFormatter.string(from: currentDate)

// Print the formatted date string print(dateString)

In the example above, the date format is set to "yyyy-MM-dd HH:mm:ss", which represents the year, month, day, hour, minute, and second. You can customize the format as per your requirement by referring to the Unicode Technical Standard #35 - Date Format Patterns documentation.

<a id="org4876066"></a>

## DatePicker

The SwiftUI DatePicker is a user interface control that allows users to select a date or time. It is a built-in input control provided by Apple's SwiftUI framework, which enables developers to create user interfaces across Apple platforms like iOS, macOS, watchOS, and tvOS.

struct ContentView: View { @State private var wakeUp = Date.now let tomorrow = Date.now.addingTimeInterval(86400)

var body: some View { VStack { DatePicker("Please enter a time", selection: $wakeUp, in: Date.now…tomorrow) / .labelsHidden() / if you don't want to show the date text } } }

If you want to display only date or time then use the argument `displayedComponents:`.

You can customize the DatePicker's appearance and behavior by modifying its properties according to your needs. For instance, you can set the `datePickerStyle` property to `.compact` or `.wheel` to change the style of the picker.

<a id="org5d237fc"></a>

## Disable

Disable forms, sections and UI elements with modifier `.disabled()`.

@State private var username = "" @State private var email = "" var disableForm: Bool { username.count < 5 || email.count < 5 }

var body: some View { VStack { TextField("Username", text: $username) TextField("Email", text: $email) Section { Button("Create account") { print("creating account with username: \(username) and email: \(email)") } } .disabled(disableForm)

<a id="org3998a57"></a>

## Drawing

<a id="org52fc03b"></a>

## Environment modifier

Many modifiers can be applied to containers, which allows us to apply the same modifier to many views at the same time.

However, a child modifier will take preceedens over a parent modifier.

VStack { Text("Gryffindor") .font(.largeTitle) / child modifier .blur(radius: 0) / unable to override like this, however it is possible to set a higher int for radius and get that effect .blur(radius: 5) / this works Text("Hufflepuff") Text("Ravenclaw") Text("Slytherin") } .font(.title) .blur(radius: 3) / this is not a environment modifier, so it can't be overridden

<a id="org209fc47"></a>

## ForEach

ForEach: can loop over arrays and ranges. Can, for example, be used to loop over an array and have each shown as a text view, or loop over an array of menu items and have each one shown as an image. ForEach is not hit by the 10-view limit.

struct ContentViewForEach: View { var body: some View { Form { ForEach(0..<100) { number in Text("Row \(number)") } } } }

struct ContentViewForEachClosureShortHand: View { var body: some View { Form { ForEach(0..<100) { Text("Row \($0)") } } } }

<a id="org721973f"></a>

## Form

Form is for user input.

<a id="orga81e0fd"></a>

## Gestures

Swipe up, down, left and right.

.gesture(DragGesture(minimumDistance: 3.0, coordinateSpace: .local) .onEnded { value in print(value.translation) switch(value.translation.width, value.translation.height) { case (…0, -30…30): print("left swipe") case (0…, -30…30): print("right swipe") case (-100…100, …0): print("up swipe") case (-100…100, 0…): print("down swipe") default: print("no clue") } } )

<a id="orga09e6a0"></a>

## GridItem

`GridItem` allows you to specify the size and behavior of items in a grid layout. You can customize properties such as minimum size, maximum size, and the behavior of the grid when there is extra space available.

Use `LazyVGrid` or `LazyHGrid` to create a grid layout in your SwiftUI view. Each grid item will be represented by a child view.

LazyVGrid(columns: [gridItem, gridItem, gridItem], spacing: 10) { ForEach(0..<10) { index in Text("Item \(index)") .frame(height: 100) // Adjust the frame size as needed } }

In this example, we use `LazyVGrid` to create a vertical grid layout with three columns, each using the `gridItem` previously defined. The `spacing` parameter specifies the spacing between items.

Customize the appearance and behavior of your grid using modifiers such as \`aspectRatio\`, \`alignment\`, and \`scrollDirection\`. For example, you can modify the aspect ratio of each grid item like this:

LazyVGrid(columns: [gridItem], alignment: .center, spacing: 10) { // Grid items here } .aspectRatio(1.5, contentMode: .fit)

This will maintain a fixed aspect ratio for each item in the grid layout.

<a id="org10a75a1"></a>

### Fixed

For example, you can create a `GridItem` with a fixed width.

struct ContentView: View { let layout = [ GridItem(.fixed(80)), GridItem(.fixed(80)), GridItem(.fixed(80)) ]

var body: some View { ScrollView { LazyVGrid(columns: layout) { ForEach(0..<1000) { Text("Item \($0)") } } }

} }

<a id="org4210ed5"></a>

### Adaptive

Adaptive sizing will squeeze in as many columns as possible, considering the parameter `minimum` size.

struct ContentView: View { let layout = [ GridItem(.adaptive(minimum: 80, maximum: 120)), // maximum is not required ]

var body: some View { ScrollView { LazyVGrid(columns: layout) { ForEach(0..<1000) { Text("Item \($0)") } } }

} }

In this case, the grid item's width will adapt to fit the available space, with a minimum width of 100.

<a id="org89383b1"></a>

## Group

Groups are a way to get around the 10 item limit of SwiftUI.

Form { Group { Text("Hello, world!") Text("Hello, world!") Text("Hello, world!") Text("Hello, world!") Text("Hello, world!") Text("Hello, world!") }

Group { Text("Hello, world!") Text("Hello, world!") Text("Hello, world!") Text("Hello, world!") Text("Hello, world!") } }

Groups don’t actually change the way your user interface looks, they just let us work around SwiftUI’s limitation of ten child views inside a parent – that’s text views inside a form, in this instance.

<a id="org05dc682"></a>

## Image

Working with images in SwiftUI involves a few key steps:

  1. Add images to the project:
    • Start by adding the image files to your project's asset catalog or bundle.
    • You can either drag and drop the image files into the asset catalog or manually include them in the bundle.
  2. Use images in SwiftUI views:
    • Create a new SwiftUI view or modify an existing one where you want to display the image.
    • Import the Swift UI module if it's not already imported.
    • Use the \`Image\` view in your SwiftUI view hierarchy to display the image.
    • Pass the name of the image file from the asset catalog or bundle as a parameter to the \`Image\` view constructor.
  3. Modifying image appearance:
    • You can apply various modifiers to the \`Image\` view to modify its appearance, such as resizable(), aspectRatio(), frame(), etc.
    • These modifiers allow you to resize, scale, apply aspect ratio, or set frames for the image.
  4. Handle images from different sources:
    • SwiftUI provides options to handle images from different sources, such as local files, remote URLs, or dynamically generated images.
    • For local files, you can directly use the image file name from the asset catalog or bundle.
    • For remote URLs, you can use \`URLImage\` or \`AsyncImage\` views to load images asynchronously.
    • For dynamically generated images, you can use a combination of Swift's \`UIImage\` and SwiftUI's \`Image\` views.
  5. Image caching and optimization:
    • For efficient image loading and caching, you can use third-party libraries like \`SDWebImageSwiftUI\`, \`Kingfisher\`, or \`Nuke\`.
    • These libraries handle image caching, prefetching, and provide additional options for image processing.
  6. Supporting dark mode and dynamic type:
    • SwiftUI automatically handles dark mode and dynamic type resizing for images added to the asset catalog.
    • You can provide different image variations for different appearances, such as light and dark mode.

<a id="org330f8bc"></a>

### Images and colors

struct ContentView: View { var countries = ["Estonia", "France", "Germany", "Ireland", "Italy", "Monaco", "Nigeria", "Poland", "Russia", "Spain", "UK", "US"] var correctAnswer = Int.random(in: 0…2)

var body: some View { ZStack { Color.secondary.ignoresSafeArea() VStack(spacing: 30) { VStack { Text("Tap the flag of").foregroundColor(.white) Text(countries[correctAnswer]).foregroundColor(.white) }

ForEach(0..<3) { number in Button { // flag was tapped } label: { Image(countries[number]) .renderingMode(.original) } } } } } }

<a id="org936e3e1"></a>

### Clipping image to frame

Use `clipped()` to remove parts of the image which don't fit inside a given `frame`.

Image("NiceImage") .frame(width: 300, height: 300) .clipped()

<a id="org1cf940d"></a>

### Resizing image to frame

Change size of an image with `resizable()` and `frame()`.

Image("exampleImage") .resizable() .frame(width: 200, height: 200) // Set the desired width and height

Use scaleToFit to make the whole image fit inside the frame. Some parts of the frame might be left empty.

Image("exampleImage") .resizable() .scaleToFit() .frame(width: 200, height: 200)

Use scaleToFill to make the image cover the whole whole frame. Some parts of the image might not be visible inside of the frame.

Image("exampleImage") .resizable() .scaleToFill() .frame(width: 200, height: 200)

<a id="org2c7079b"></a>

### Geometry reader

GeometryReader is a view container in SwiftUI that provides access to the size and position information of its parent view. It allows you to create dynamic layouts and precise positioning of child views based on the available space.

Add a GeometryReader view as the top-level container of your view hierarchy. You can use it as a modifier or a standalone view. For example:

var body: some View { GeometryReader { geo in VStack { // Your child views } } }

Inside the GeometryReader closure, you can access the geometry parameter which provides information about the available size and position of the parent view. This parameter includes properties like: size, safeAreaInsets, and others.

Use the geometry information to position and size your child views accordingly. You can apply layout constraints, aspect ratios, alignments, or any other adjustments using geometry properties.

Create a resizable square that always fills the available space.

var body: some View { GeometryReader { geo in Rectangle() .frame(width: min(geometry.size.width, geometry.size.height), height: min(geometry.size.width, geometry.size.height)) .foregroundColor(.blue) } }

By using the geometry.size.width and geometry.size.height properties of the GeometryReader, the Rectangle will adjust its size to always be a square, regardless of the available space.

  1. Adjust image to center

    To adjust image to center, use two frames. One for the image and one for GeometryReader.

    GeometryReader { geo in Image("example-image") .resizable() .scaledToFit() .frame(width: geo.size.width * 0.7) .frame(width: geo.size.width, height: geo.size.height)

<a id="orgd524f4f"></a>

### Async Image

Use for images coming from outside the app bundle.

To get the image to show at a particular scale, do use `scale` or first create a placeholder for the image and make sure the image fits inside the placeholder.

AsyncImage(url: URL(string: "logo.png"), scale: 3)

To resize the image will we use a version of AsyncImage which passes us the image once it has been downloaded.

AsyncImage(url: URL(string: "logo.png")) { image in image .resizable() .scaledToFit() } placeholder: { // Color.red ProgressView() } .frame(width: 200, height: 200)

The third way is to use `AsyncImage` so that it tells us if the image has loaded, or if we got an error or if the image has not loaded yet.

AsyncImage(url: URL(string: "logo.png")) { phase in if let image = phase.image { image .resizable() .scaledToFit() } else if phase.error != nil { Text("There was an error loading the image.\n\(phase.error.debugDescription)") } else { ProgressView() } } .frame(width: 300, height: 300)

<a id="org05032ed"></a>

## Keyboard

  • .decimalPad
  • Fix focus for keyboards:
    • `@FocusState private var amountIsFocused: Bool`
    • `TextField("Amount", value: $checkAmount, format: .currency(code: Locale.current.currency?.identifier ?? "EUR"))` `.keyboardType(.decimalPad)` `.focused($amountIsFocused)`
    • `Button("Done") {amountIsFocused = false }`

<a id="org1e37b99"></a>

## Layout

Use this as example for a nice design with VStacks.

struct ContentView: View { @State private var showingScore = false @State private var scoreTitle = "" @State private var score = 0 @State private var countries = ["Estonia", "France", "Germany", "Ireland", "Italy", "Monaco", "Nigeria", "Poland", "Russia", "Spain", "UK", "US"].shuffled() @State private var correctAnswer = Int.random(in: 0…2)

var body: some View { ZStack { / LinearGradient(gradient: Gradient(colors: [Color(red: 1, green: 0.8, blue: 0), Color(red: 0.4, green: 0, blue: 1)]), startPoint: .top, endPoint: .bottom) / .ignoresSafeArea() RadialGradient(stops: [ .init(color: .blue, location: 0.3), .init(color: .black, location: 0.8) ], center: .top, startRadius: 200, endRadius: 700) .ignoresSafeArea()

VStack { Spacer() Text("Guess the Flag") .font(.largeTitle.bold()) .foregroundColor(.white)

VStack(spacing: 15) { VStack(spacing: 10) { Text("Tap the flag of") .foregroundStyle(.secondary) .font(.subheadline.weight(.heavy))

Text(countries[correctAnswer]) //.foregroundColor(.white) .font(.largeTitle.weight(.semibold)) }

ForEach(0..<3) { number in Button { flagTapped(number) } label: { Image(countries[number]) .renderingMode(.original) .clipShape(Capsule()) .shadow(radius: 10) } } } .frame(maxWidth: .infinity) .padding(.vertical, 20) .background(.regularMaterial) .clipShape(RoundedRectangle(cornerRadius: 20))

Spacer() Spacer()

Text("Score: \(score)") .foregroundColor(.white) .font(.title.bold())

Spacer() } .padding() } .alert(scoreTitle, isPresented: $showingScore) { Button("Continue", action: askQuestion) } message: { Text("Your score is \(scoreTitle == "Correct" ? "" : "still ")\(score)") } }

func flagTapped(_ number: Int) { if number = correctAnswer { scoreTitle = "Correct" score + 1 } else { scoreTitle = "Wrong" } showingScore = true }

func askQuestion() { countries.shuffle() correctAnswer = Int.random(in: 0…2) } }

<a id="org3560010"></a>

## List

List is for representation of data. (Form is for user input.)

<table border="2" cellspacing="0" cellpadding="6" rules="groups" frame="hsides">

<colgroup> <col class="org-left" />

<col class="org-left" /> </colgroup> <thead> <tr> <th scope="col" class="org-left">Modifier</th> <th scope="col" class="org-left">Description</th> </tr> </thead>

<tbody> <tr> <td class="org-left">listStyle</td> <td class="org-left">.grouped</td> </tr> </tbody> </table>

Lists can be created dynamically.

List(0..<5) { Text("Dynamics \($0)") }

If you need a identifier for the list use parameter `id`.

let favouriteNumbers = [1, 1, 2, 3, 5, 8, 13]

List(favouriteNumbers, id: \.self) { Text($0.description) // need description since these are integers }

<a id="org0058046"></a>

### Building Lists

struct ExpenseItem { let name: String let type: String let amount: Double }

class Expenses: ObservableObject { @Published var items = [ExpenseItem]() }

struct ContentView: View { @StateObject var expenses = Expenses()

var body: some View { NavigationStack { List { ForEach(expenses.items, id: \.name) { item in Text(item.name) } .onDelete(perform: removeItems) } .navigationTitle("iExpense") .toolbar { Button { let expense = ExpenseItem(name: "Test", type: "Personal", amount: 5) expenses.items.append(expense) } label: { Image(systemName: "plus") } } } }

func removeItems(at offsets: IndexSet) { expenses.items.remove(atOffsets: offsets) } }

<a id="orgd4f18af"></a>

### onDelete and Edit Button

Only exists on ForEach() so we have to use ForEach to be able to delete.

struct ContentView: View { @State private var numbers = [Int]() @State private var currentNumber = 1

var body: some View { NavigationView { VStack { List { ForEach(numbers, id: \.self) { Text("Row \($0)") } .onDelete(perform: removeRows) }

Button("Add number") { numbers.append(currentNumber) currentNumber += 1 } } .navigationTitle("Delete several") .toolbar { EditButton() } } }

func removeRows(at offsets: IndexSet) { numbers.remove(atOffsets: offsets) }

<a id="orgf7fb4f4"></a>

## Modifiers

<a id="orgc8eacc3"></a>

### onDelete

Do something when something is deleted.

struct ContentView: View { @State private var numbers = [Int]() @State private var currentNumber = 1

var body: some View { NavigationView { VStack { List { ForEach(numbers, id: \.self) { Text("Row \($0)") } .onDelete(perform: removeRows) }

Button("Add number") { numbers.append(currentNumber) currentNumber += 1 } } .navigationTitle("onDelete") .toolbar { EditButton() } } }

func removeRows(at offsets: IndexSet) { numbers.remove(atOffsets: offsets) } }

<a id="orgb701bc8"></a>

## Navigation

Use `NavigationStack` and `NavigationLink` to create stacks of views and navigation between them.

NavigationStack { //prevents the scrolling from going over the clock NavigationLink { Text("This is the link") } label: { Text("This is the text taking you to the link") .padding() } .navigationTitle("This is the title") }

`navigationBarTitle` is a modifier. Modifiers are regular methods with one small difference. They always return a new instance on whatever you use them on. Use displayMode: .inline to get a smaller title

Create a list of views like so.

NavigationStack { List(0..<100) { row in NavigationLink { Text("Detail of \(row)") } label: { Text("Navigate to \(row)") } } }

<a id="org91a17f0"></a>

### NavigationStack with NavigationLink and NavigationDestination

struct ContentView: View { var body: some View { NavigationStack { NavigationLink("Simple String", value: "ABC") .navigationDestination(for: String.self) { string in Text(string) } } } }

And in a list.

struct ContentView: View { var body: some View { NavigationStack { List { NavigationLink("Simple String", value: "ABC") .navigationDestination(for: String.self) { string in // these types have to be hashable Text(string) .foregroundColor(.red) } } } } }

<a id="orgd529881"></a>

### Programmatic Navigation

This is the correct way to navigate around an application.

struct Article: Identifiable, Hashable { let id = UUID() let title: String let author: String }

extension Article { static let examples: [Article] = [ .init(title: "Making of plupp", author: "Bosse"), .init(title: "the day", author: "killen"), .init(title: "mom kids", author: "lady g") ] }

struct Person: Identifiable, Hashable { let id = UUID() let name: String let age: Int }

extension Person { static let examples: [Person] = [ .init(name: "Steve", age: 33), .init(name: "Maria", age: 31), .init(name: "Marta", age: 19), .init(name: "Peter", age: 9) ] }

struct ContentView: View { @State private var path = NavigationPath()

var body: some View { NavigationStack(path: $path) { List { Section("People") { ForEach(Person.examples) { person in NavigationLink(value: person) { VStack(alignment: .leading) { Text(person.name) Text(person.age, format: .number) .foregroundColor(.secondary) } } } } Section("Articles") { ForEach(Article.examples) { article in NavigationLink(value: article) { VStack(alignment: .leading) { Text(article.title) .font(.headline) Text(article.author) .font(.subheadline) } } } } } .navigationDestination(for: Person.self) { person in Text(person.name) .font(.headline) } .navigationDestination(for: Article.self) { article in VStack { Text(article.title) .font(.headline) Button("Back") { path.removeLast() } Button("Pop to root") { path.removeLast(path.count) // removes all items in path }

Button("Navigate to person") { path.append(Person.examples[0]) } } } } } }

<a id="orgfd11318"></a>

### Toolbar

The \`toolbar\` modifier in SwiftUI's \`NavigationView\` allows us to add custom buttons and views to the toolbar of a navigation stack. The toolbar appears at the top of the screen and can contain various controls and buttons.

Here's an example of how to work with the \`toolbar\` modifier:

import SwiftUI

struct ContentView: View { var body: some View { NavigationView { VStack { Text("Home View") NavigationLink("Go to Detail", destination: DetailView()) } .navigationTitle("Home") .toolbar { ToolbarItem(placement: .navigationBarTrailing) { Button(action: { / Add action for the button here print("Search button tapped") }) { Image(systemName: "magnifyingglass") } } ToolbarItem(placement: .navigationBarTrailing) { Button(action: { / Add action for the button here print("Settings button tapped") }) { Image(systemName: "gear") } } } } } }

struct DetailView: View { var body: some View { Text("Detail View") .navigationTitle("Detail") } }

struct ContentViewPreviews: PreviewProvider { static var previews: some View { ContentView() } }

In the above example, we have a \`NavigationView\` with a \`VStack\` as the root view. Inside the \`VStack\`, we have a \`Text\` view and a \`NavigationLink\` to the \`DetailView\`. The toolbar is customized using the \`toolbar\` modifier.

Inside the \`toolbar\` modifier, we add two \`ToolbarItem\`s with \`placement\` set to \`.navigationBarTrailing\` to position them on the right side of the toolbar. Each \`ToolbarItem\` contains a \`Button\` with an action closure for handling button taps. We can customize the appearance of the buttons by adding images from the SF Symbols library.

To add more buttons or controls to the toolbar, we can simply add additional \`ToolbarItem\`s with the desired placement and content.

Note that the \`toolbar\` modifier is available in iOS 14 and later.

<a id="orga2486ff"></a>

## Picker

Pickerview lets us show various options for users to select from.

struct ContentView: View { let students = ["Harry", "Hermoine", "Ron"] //students does not need to be marked with @State since it is a constant @State private var selectedStudent = 0 //this value can change which is why it is marked with @State

var body: some View { VStack { Picker("Select your student", selection: $selectedStudent) { //picker has a label "Select your student" which tells us what it does and is also used by screen readers. $selectedStudent has a two way binding which means it will update the property as the user moves the picker ForEach(0 ..< students.count) { //counts from 0 and up to but excluding the number of students in our array Text(self.students[$0]) //creates one text view for each studentname } } Text("You chose: Student # \(students[selectedStudent])") } } }

struct ContentView: View { let students = ["Harry", "Muppen", "Hermoine"] @State private var selectedStudent = "Harry"

var body: some View { NavigationStack { Form { Picker("Select your student", selection: $selectedStudent) { ForEach(students, id: \.self) { // use of the id: \.self - makes this unique Text($0) } } } } } }

<a id="org89d542a"></a>

### Picker with enum

Use a Picker with an enum by useing the `CaseIterable` protocol.

Start with defining your enum type with the options you want to display in the Picker.

enum Fruit: String, CaseIterable { case apple case banana case orange }

Create a new property in your SwiftUI view to hold the selected enum value. For example:

@State private var selectedFruit: Fruit = .apple

Inside the view's body, add a Picker view and bind it to the selected enum value using the \`selection\` parameter. Use a `ForEach` loop to iterate over the enum cases and create a PickerRow for each case.

Picker("Select a Fruit", selection: $selectedFruit) { ForEach(Fruit.allCases, id: \.self) { fruit in Text(fruit.rawValue.capitalized) } } .pickerStyle(SegmentedPickerStyle())

Alternatively use a different Picker style like `.pickerStyle(WheelPickerStyle())` or `.pickerStyle(DefaultPickerStyle())`.

Optionally, add an `onChange` modifier to perform any action when the selected value changes.

.onChange(of: selectedFruit) { newFruit in print("Selected fruit: \(newFruit.rawValue)") }

<a id="org48a7f15"></a>

### Invalid selection

This error usually occurs when using a \`Picker\` in SwiftUI and not providing a valid selection binding or assigning a tag to the picker view. To fix this error, follow these steps:

  1. Check if you have correctly assigned a `@State` variable as the selection binding in the `Picker`. For example:

    @State private var selectedOption = 0

    Picker(selection: $selectedOption, label: Text("Select Option")) { Text("Option 1").tag(0) Text("Option 2").tag(1) }

  2. Make sure that you have assigned a tag to each \`Picker\` option by using the \`tag(\_:)\` method. The tag should correspond to the selection binding type. In the example above, the \`tag\` values are \`0\` and \`1\`, which matches the type of \`selectedOption\`.

If you are using a different type for the selection binding, ensure that the assigned tags match that type (e.g., if your selection binding is of type \`String\`, the tags should be \`String\` values).

<a id="org941b07b"></a>

### Segmented

// Adding a segmented control for tip percentages struct ContentViewSegmeetedControl: View { @State private var checkAmount = "" @State private var numberOfPeople = 2 @State private var tipPercentage = 2

let tipPercentages = [10, 15, 20, 25, 0]

var body: some View { NavigationView { Form { Section { TextField("Amount", text: $checkAmount) .keyboardType(.decimalPad) Picker("Number of people", selection: $numberOfPeople) { ForEach(2 ..< 100) { Text("\($0) people") } } } Section(header: Text("How much percentage do you want to leave?")) { //gives a small explanation bar instead of a new text block

Picker("Tip percentage", selection: $tipPercentage) { ForEach(0 ..< tipPercentages.count) { Text("\(self.tipPercentages[$0])%") } } .pickerStyle(SegmentedPickerStyle()) //used when only showing a smaller set of options } Section { Text("$\(checkAmount)") } } .navigationBarTitle("WeSplit") } } }

struct ContentViewCalculation: View { @State private var checkAmount = "" @State private var numberOfPeople = 2 @State private var tipPercentage = 2

let tipPercentages = [10, 15, 20, 25, 0]

var totalPerPerson: Double { let peopleCount = Double(numberOfPeople + 2) //have to add two to compensate for how we gave the default let tipSelection = Double(tipPercentages[tipPercentage]) //tipPercentage integer stores an index inside the tipPercentages array rather than the actual tip percentage let orderAmount = Double(checkAmount) ?? 0 //nil coalescing which sends back 0 as default

let tipValue = orderAmount / 100 * tipSelection let grandTotal = orderAmount + tipValue let amountPerPerson = grandTotal / peopleCount

return amountPerPerson }

var body: some View { NavigationView { Form { Section { TextField("Amount", text: $checkAmount) .keyboardType(.decimalPad) Picker("Number of people", selection: $numberOfPeople) { ForEach(2 ..< 100) { Text("\($0) people") } } } Section(header: Text("How much percentage do you want to leave?")) {

Picker("Tip percentage", selection: $tipPercentage) { ForEach(0 ..< tipPercentages.count) { Text("\(self.tipPercentages[$0])%") } } .pickerStyle(SegmentedPickerStyle()) } Section { Text("$\(totalPerPerson, specifier: "%.2f")") //the specifier is from C programming. %.2f means a two digit floating point number. %f means any sort of floating-point number. %g does the same thing but removes insignificant zeroes from the end } } .navigationBarTitle("WeSplit") } } }

<a id="org75ad09a"></a>

## Property Wrappers

<a id="orgfa965f8"></a>

### @State

Use for local changes in Structs.

<a id="org37b8ab5"></a>

### @Published and @StateObject

Use `@Published` in a class which should notify about changes to its properties.

Use the `@StateObject` when you create the data for the fist time. The struct using `@StateObject` must conform to the `ObserableObject`.

When you want to observe a class instance, then use the `@ObservedObject` instead.

class User: ObservableObject { @Published var firstName = "Bilbo" @Published var lastName = "Baggins" }

struct ContentView: View { @StateObject private var user = User()

var body: some View { VStack { List { Text("Your name is \(user.firstName) \(user.lastName).")

TextField("First name", text: $user.firstName) TextField("Last name", text: $user.lastName) } } } }

<a id="org56d419b"></a>

### @Environment

All the stuff which is related to the users environment.

Also used to dismiss a view.

struct SecondView: View { @Environment(\.dismiss) var dismiss

let name: String var body: some View { Text("hi \(name)") Button("Dismiss") { dismiss() } } }

struct ContentView: View { @State private var showingSheet = false

var body: some View { VStack { Text("hi") Button("Show Sheet") { showingSheet.toggle() } .sheet(isPresented: $showingSheet) { SecondView(name: "muppen") } } } }

<a id="org54dabb6"></a>

### Sharing Objects

User different property wrappers to share objects.

struct ExpenseItem: Identifiable { let id = UUID() let name: String let type: String let amount: Double }

class Expenses: ObservableObject { @Published var items = [ExpenseItem]() }

struct AddView: View { @ObservedObject var expenses: Expenses

@State private var name = "" @State private var type = "Personal" @State private var amount = 0.0

let types = ["Business", "Personal"]

var body: some View { NavigationStack { Form { TextField("Name", text: $name) Picker("Type", selection: $type) { ForEach(types, id: \.self) { Text($0) } } TextField("Amount", value: $amount, format: .currency(code: "USD")) .keyboardType(.decimalPad) } .navigationTitle("Add new expense") } } }

struct AddViewPreviews: PreviewProvider { static var previews: some View { AddView(expenses: Expenses()) } }

struct ContentView: View { @StateObject var expenses = Expenses() @State private var showingAddExpense = false

var body: some View { NavigationStack { List { ForEach(expenses.items) { item in // we don't need "id" since expenses conforms to "Identifiable" Text("\(item.name): \(item.id)") } .onDelete(perform: removeItems) } .navigationTitle("iExpense") .toolbar { Button { showingAddExpense = true } label: { Image(systemName: "plus") } } .sheet(isPresented: $showingAddExpense) { AddView(expenses: expenses) } } }

func removeItems(at offsets: IndexSet) { expenses.items.remove(atOffsets: offsets) } }

<a id="org6acf72e"></a>

## Safe Area

  • Don't put content of the safe area.
  • .ignoresSafeArea()

<a id="org116822a"></a>

## Scroll View

Use scroll view to enable vertical and horizontal scrolling.

ScrollView { VStack(spacing: 10) { ForEach(0..<100) { Text("Item \($0)") .font(.title) } } .frame(maxWidth: .infinity) // Extend the scrollable view/area across the whole screen (horizontally) }

A scrollview can be `.horizontal` or `.vertical`

ScrollView(.horizontal) { HStack(spacing: 10) { ForEach(0..<100) { Text("Item \($0)") .font(.title) } } .frame(maxWidth: .infinity) // Extend the scrollable view/area across the whole screen (horizontally) }

<a id="org36b530e"></a>

## Shapes

Use `clipShape` to change the shape of images. Use `.shadow` to give shadow.

struct ContentView: View { @State private var showingScore = false @State private var scoreTitle = "" @State private var score = 0 @State private var countries = ["Estonia", "France", "Germany", "Ireland", "Italy", "Monaco", "Nigeria", "Poland", "Russia", "Spain", "UK", "US"].shuffled() @State private var correctAnswer = Int.random(in: 0…2)

var body: some View { ZStack { LinearGradient(gradient: Gradient(colors: [Color(red: 1, green: 0.8, blue: 0), Color(red: 0.4, green: 0, blue: 1)]), startPoint: .top, endPoint: .bottom) .ignoresSafeArea() VStack(spacing: 30) { VStack(spacing: 10) { Text("Tap the flag of") .foregroundColor(.white) .font(.subheadline.weight(.heavy))

Text(countries[correctAnswer]) .foregroundColor(.white) .font(.largeTitle.weight(.semibold)) }

ForEach(0..<3) { number in Button { flagTapped(number) } label: { Image(countries[number]) .renderingMode(.original) .clipShape(Capsule()) .shadow(radius: 10) } } } } .alert(scoreTitle, isPresented: $showingScore) { Button("Continue", action: askQuestion) } message: { Text("Your score is \(scoreTitle == "Correct" ? "" : "still ")\(score)") } }

func flagTapped(_ number: Int) { if number = correctAnswer { scoreTitle = "Correct" score + 1 } else { scoreTitle = "Wrong" } showingScore = true }

func askQuestion() { countries.shuffle() correctAnswer = Int.random(in: 0…2) } }

<a id="orgb9e599c"></a>

## Stacks

  • Stacks can be inside each other
  • User Spacer() to put space between items in the stack
  • Stacks have parameters of `alignment` and `spacing`

<a id="org392926d"></a>

### VStack

VStack(spacing: 20, alignment: .leading) { Text("Hello, world!") Text("This is inside a stack") }

<a id="org96e4712"></a>

### HStack

<a id="org4ef259e"></a>

### ZStack

ZStack { Text("Hello, world!") Text("This is inside a stack") }

Ignore safe area.

ZStack { Color.red Text("Your content") } .ignoresSafeArea()

<a id="org0d3c7a8"></a>

### Lazy Stacks

LazyStacks are not generating all the items of a stack immediately but rather as necessary.

A lazystack will take up the full width (if it is a `LazyVStack`), since it won't know how big items further down the list is.

<a id="orgcae03bc"></a>

## State

Views are a function of their state. The state of an app can only be determined by following the exact number of steps which were performed to reach a given state. Most of the apps don't bother about saving all these steps, which is why it is rare to see an app save the exact state of an app.

There are several way of storing state in SwiftUI. @State is specifically designed for simple properties that are stored in one view. That is why Apple recommends we add "private" access control to those properties.

`@State` is a property wrapper, which gets rid of the problem with immutability in a struct.

struct ContentViewButtonPress: View { @State private var tapCount = 0 var body: some View { Button("Tap Count: \(tapCount)") { self.tapCount += 1 //ContentViewButtonPress is a struct and is thus a constant, which is immutable } } }

Binding state to user interface controls requires that we specifies where Swift should store the state of the text user input. Use `$` to:

  1. show the value of this property here and
  2. write any changes back to the property. This is called a two-way binding

\#+begin<sub>src</sub> swift :eval no struct ContentViewBindingState: View { @State private var name = "" //creates an empty variable for "name" var body: some View { Form { TextField("Enter you name", text: \(name) //adds the "name" property for text. Have to use "\)" to make Swift "write any changes back to the property" Text("Your name is \\(name).") //we don't need the "$" sign here since we only want to read it and don't want to write it back again. } } }

<a id="orga380b05"></a>

## Stepper

Use stepper to give the possibility to pick a value. Use `in:` with a range to specify in which range values can be picked. Use `step:` to specify the amount of how much to change per step.

struct ContentView: View { @State private var sleepAmount = 8.0

var body: some View { Stepper("\(sleepAmount.formatted()) hours", value: $sleepAmount, in: 4…12, step: 0.25) // formatted() makes the number more human friendly } }

<a id="orgc0f929c"></a>

## Structure

  • Form
  • Group

<a id="org082723e"></a>

## Text

struct ContentView: View { let motto1 = Text("Draco dormiens") let motto2 = Text("nunquam titillandus")

var body: some View { VStack { motto1 .font(.bold) motto2 } } }

<a id="org9fcfbae"></a>

## TextField

// Reading text from the user with TextField struct ContentViewTextField: View { @State private var checkAmount = "" //We have to use a string since SwiftUI must use strings to store text field values @State private var numberOfPeople = 2 //setting two people to split the bill by default @State private var tipPercentage = 2 //this value will be used from a predetermined array of tip sizes

let tipPercentages = [10, 15, 20, 25, 0] //array of different tip sizes. tipPercentage[2] is 20%

var body: some View { Form { Section { /this will create a scrolling entry form with one section TextField("Amount", text: $checkAmount) //when using TextFields in forms, then is the first parameter a string used as placeholder text for the form. The second parameter is a two-way binding to checkAmount .keyboardType(.decimalPad) / } Section { Text("$\(checkAmount)") } } } }

// Creating pickers in a form: pickers do look differently depending on which device and context the picker is inside. Pickers, like text fields, need a two-way binding to a property so they can track their value. struct ContentViewPickersInForm: View { @State private var checkAmount = "" @State private var numberOfPeople = 2 @State private var tipPercentage = 2

let tipPercentages = [10, 15, 20, 25, 0]

var body: some View { NavigationView { //has to be present for Swift to be able to glide over the user uses the picker (below) Form { Section { TextField("Amount", text: $checkAmount) .keyboardType(.decimalPad) Picker("Number of people", selection: $numberOfPeople) { ForEach(2 ..< 100) { Text("\($0) people") } } } Section { Text("$\(checkAmount)") } } .navigationBarTitle("WeSplit") //the title for the NavigationView has to be attached to the form rather than the View since there can be more than one title } } }

<a id="org73ce2d2"></a>

## View

struct ContentView: View { //creats the struct ContentView, which inherits from the protocol "View" var body: some View { //This means that it will return something that conforms to the "View" protocol. The "some" keyword restricts the view which is returned to always be of the same kind Text("Hello, World!") //text Views will automatically wrap across multiple lines as needed } }

struct ContentViewWithForm: View { var body: some View { Form { /forms can scroll Text("Hello, World!") / you can maximum have 10 children inside a parent all across SwiftUI Text("Hello, World!") Text("Hello, World!") } } }

struct ContentViewWithGroups: View { var body: some View { Form { Group { // create groups to create several parents with children Text("Hello, World!") Text("Hello, World!") Text("Hello, World!") Text("Hello, World!") Text("Hello, World!") Text("Hello, World!") } Section { //use section to make groups which are in descreet visual chunks (like the iPhone Settings app) Text("Hello, World!") Text("Hello, World!") Text("Hello, World!") Text("Hello, World!") Text("Hello, World!") Text("Hello, World!") Text("Hello, World!") } } } }

<a id="org2938c01"></a>

### Properties as Views

Creating views as properties can be helpful to keep your body code clearer – not only does it help avoid repetition, but it can also get more complex code out of the body property.

Swift doesn’t let us create one stored property that refers to other stored properties, because it would cause problems when the object is created. This means trying to create a TextField bound to a local property will cause problems.

However, you can create computed properties if you want, like this:

var motto1: some View { Text("Draco dormiens") }

This is often a great way to carve up your complex views into smaller chunks, but be careful: unlike the body property, Swift won’t automatically apply the @ViewBuilder attribute here, so if you want to send multiple views back you have three options.

First, you can place them in a stack, like this:

var spells: some View { VStack { Text("Lumos") Text("Obliviate") } }

If you don’t specifically want to organize them in a stack, you can also send back a Group. When this happens, the arrangement of your views is determined by how you use them elsewhere in your code:

var spells: some View { Group { Text("Lumos") Text("Obliviate") } }

The third option is to add the @ViewBuilder attribute yourself, like this:

@ViewBuilder var spells: some View { Text("Lumos") Text("Obliviate") }

Of them all, I prefer to use @ViewBuilder because it mimics the way body works, however I’m also wary when I see folks cram lots of functionality into their properties – it’s usually a sign that their views are getting a bit too complex, and need to be broken up.

<a id="org95f9c52"></a>

### View Composition

Can create a new view and reuse it later.

struct CapsuleText: View { var text: String

var body: some View { Text(text) .font(.largeTitle) .padding() .foregroundColor(.white) .background(.blue) .clipShape(Capsule()) } }

struct ContentView: View { var body: some View { VStack(spacing: 10) { CapsuleText(text: "First") CapsuleText(text: "Second") } } }

Of course, we can also store some modifiers in the view and customize others when we use them. For example, if we removed foregroundColor() from CapsuleText, we could then apply custom colors when creating instances of that view like this:

VStack(spacing: 10) { CapsuleText(text: "First") .foregroundColor(.white) CapsuleText(text: "Second") .foregroundColor(.yellow) }

<a id="orgfde62fd"></a>

### Custom Properties

To create a custom modifier, create a new struct that conforms to the ViewModifier protocol. This has only one requirement, which is a method called body that accepts whatever content it’s being given to work with, and must return some View.

For example, we might say that all titles in our app should have a particular style, so first we need to create a custom ViewModifier struct that does what we want:

struct Title: ViewModifier { func body(content: Content) -> some View { content .font(.largeTitle) .foregroundColor(.white) .padding() .background(.blue) .clipShape(RoundedRectangle(cornerRadius: 10)) } }

We can now use that with the modifier() modifier – yes, it’s a modifier called “modifier”, but it lets us apply any sort of modifier to a view.

struct ContentView: View { var body: some View { VStack { Text("Hello World") .modifier(Title()) } } }

Custom modifiers can do much more than just apply other existing modifiers – they can also create new view structure, as needed. Remember, modifiers return new objects rather than modifying existing ones, so we could create one that embeds the view in a stack and adds another view.

It is easier to work with custom properties if we do an extension on `View`.

extension View { func titleStyle() -> some View { modifier(Title()) } }

struct ContentView: View { var body: some View { VStack { Text("Hello World") .titleStyle() } } }

Custom modifiers can do much more than just apply other existing modifiers – they can also create new view structure, as needed. Remember, modifiers return new objects rather than modifying existing ones, so we could create one that embeds the view in a stack and adds another view.

struct Watermark: ViewModifier { var text: String

func body(content: Content) -> some View { ZStack(alignment: .bottomTrailing) { content Text(text) .font(.caption) .foregroundColor(.white) .padding(5) .background(.black) } } }

extension View { func watermarked(with text: String) -> some View { modifier(Watermark(text: text)) } }

Color.blue .frame(width: 300, height: 200) .watermarked(with: "Hacking with Swift")

<a id="org63706be"></a>

### Custom Containers

Creating customer containers: https://www.hackingwithswift.com/books/ios-swiftui/custom-containers

<a id="org23e85ba"></a>

### ContentView<sub>Previews</sub>

struct ContentViewPreviews: PreviewProvider { static var previews: some View { ContentView() } /This code will not be part of the final app that goes to the app store. It is used specifically by Xcode to show a preview of your UI design alongside your code. This feature uses the "Canvas" which is found under the "Editor" menu item. } / To resume the automatic updating press <Option + Cmd + P>

// Form: scrolling lists of static controls (text, images) but can also include user interactive controls (text fields, buttons, toggle switches)

<a id="orga076f41"></a>

### View as a property

To use `ViewBuilder` is the preferred way to creating views as properties.

@ViewBuilder var section: some View { Text("Draco dormiens nunquam titillandus") }

<a id="org87d1339"></a>

### View Composition

View composition is a powerful feature in SwiftUI that allows you to create complex user interfaces by combining multiple smaller views. There are several ways to work with view composition in SwiftUI:

  1. Nesting Views: SwiftUI allows you to nest views inside each other to create a hierarchical structure. For example, you can place a Text view inside a VStack, and then place that VStack inside a ZStack. This nesting allows for easy organization and structuring of your user interface.
  2. Creating Reusable Views: You can create reusable views by defining custom SwiftUI structs that conform to the View protocol. These custom views can be used anywhere in your code, just like any other built-in SwiftUI view. To use a custom view, you simply initialize it and add it to your view hierarchy.

    struct CustomView: View { var text: String

    var body: some View { Text(text) } }

    struct ContentView: View { var body: some View { VStack { Text("hello, SwiftUI!") CustomView(text: "some more text") CustomView(text: "another custom view with different text color") .foregroundColor(.blue) } } }

  3. Extracting Subviews: If you find yourself repeating similar patterns of views, you can extract them into separate subviews to enhance reusability and maintainability. This helps in modularizing your code and simplifies the debugging process. You can create subviews like any other views, but they are dedicated to rendering a specific part of your user interface.
  4. Combining Views: Sometimes, you may need to combine multiple views together to create more complex UI components. SwiftUI provides various layout views, such as VStack, HStack, and ZStack, to arrange multiple views in vertical, horizontal, or overlapping stacks respectively.
  5. Using SwiftUI's Built-in Views and Modifiers: SwiftUI provides a wide range of built-in views and modifiers that can be chained together to create powerful compositions. For example, you might use a combination of Text, Image, and Button views, with modifiers like padding, spacing, and alignment, to design a user-friendly interface.

By leveraging these techniques, you can easily build complex user interfaces in SwiftUI with a highly modular and reusable codebase.

<a id="org6071ae6"></a>

### Custom View Modifier

To create a custom view modifier, create a new struct that conforms to the `ViewModifier` protocol. This has only one requirement, which is a method called `body` that accepts whatever content it’s being given to work with, and must return some `View`.

struct Title: ViewModifier { func body(content: Content) -> some View { content .font(.largeTitle) .foregroundColor(.white) .padding() .background(.blue) .clipShape(RoundedRectangle(cornerRadius: 10)) } }

Text("Hello World") .modifier(Title())

It is a good idea to create an extension for `View` to make it easier to work with the new modifier.

extension View { func titleStyle() -> some View { modifier(Title()) } }

This will call the method (`titleStyle`) which then in turn will call the modifier `Title()`.

<a id="org1a502a5"></a>

### Showing and hiding views

Define the condition under which another view (sheet) should be shown and show it when a condition is fullfilled.

struct SecondView: View { @Environment(\.dismiss) var dismiss

let name: String var body: some View { Text("hi \(name)") Button("Dismiss") { dismiss() } } }

struct ContentView: View { @State private var showingSheet = false

var body: some View { VStack { Text("hi") Button("Show Sheet") { showingSheet.toggle() } .sheet(isPresented: $showingSheet) { SecondView(name: "muppen") } } } }

<a id="org34eeedc"></a>

Good to store default user data. Max up to 500kB

`UserDefaults.standard` is built-in. For more advanced use cases can UserDefaults be used with something like than `.standard`.

UserDefaults lets us store small amounts of data easily – it’s automatically attached to our app, which means it’s there ready to load as soon as our app launches. While it’s very useful (and you’ll be relying on its heavily!) it does have two drawbacks:

  1. You should only store small amounts of data there – anything over about 512KB is dubious.
  2. You can only store certain types of data easily; everything else must use Codable first to get some binary data.

The list of types that are supported by UserDefaults is short (also includes the array and dictionary version of these types):

  • strings
  • numbers
  • dates
  • URLs
  • binary data

These things are stored in a plist (property list) file.

struct ContentView: View { @State private var tapCount = UserDefaults.standard.integer(forKey: "Tap")

var body: some View { Text("Just tap a lot…") Button("Tap count: \(tapCount)") { tapCount += 1 UserDefaults.standard.set(tapCount, forKey: "Tap") } } }

You can also use `@AppStorage` (with some limitations). AppStorage can also read from the same keys as are set by `UserDefaults`.

struct ContentView: View { @AppStorage("Tap Count") private var tapCount = 0

var body: some View { Text("Just tap a lot…") Button("Tap count: \(tapCount)") { tapCount += 1 } } }

or refer back to the UserDefaults key "Tap" we used previously.

struct ContentView: View { @AppStorage("Tap") private var tapCount = 0

var body: some View { Text("Just tap a lot…") Button("Tap count: \(tapCount)") { tapCount += 1 } } }

<a id="org2dcc364"></a>

### Read Data from UserDefaults

To read and save all the data stored in UserDefaults and @AppStorage from a device, you can follow these steps:

  1. Connect your device to your macOS computer.
  2. Launch Xcode and open your project.
  3. Open the "Devices and Simulators" window by navigating to "Window" > "Devices and Simulators" in the Xcode menu.
  4. Make sure your device is selected in the left panel of the "Devices and Simulators" window.
  5. Click on the disclosure triangle next to your device name to expand it.
  6. Under the "Installed Apps" section, find your app and click on the "gear" icon at the bottom left corner of the app icon.
  7. Select "Download Container&#x2026;" from the dropdown menu.
  8. Choose a location on your Mac to save the container file.
  9. Once the container file is saved, right-click on it and select "Show Package Contents".
  10. Navigate to the "Library" folder in the package contents.
  11. Within the "Library" folder, you should find the "Preferences" folder. Open it.
  12. Inside the "Preferences" folder, you will find plist files containing the data stored in UserDefaults and @AppStorage for your app.
  13. Copy these plist files to a safe location on your Mac for backup or further examination.

<a id="org3b1bb37"></a>

### Delete all data stored with UserDefaults

To delete all the data stored in UserDefaults or @AppStorage from a device, you can follow these steps:

  1. UserDefaults:
    • Open Xcode and go to "Window" -> "Devices and Simulators".
    • Connect your device to the computer.
    • Select the device from the left sidebar and click on the "View Device Logs" button.
    • In the console, type \`e -l objc &#x2013; (void)[[NSUserDefaults standardUserDefaults] removePersistentDomainForName:[[NSBundle mainBundle] bundleIdentifier]]\`.
    • Press Enter to execute the command.
    • This will remove all the data stored in UserDefaults for your app.
  2. @AppStorage:
    • Unfortunately, there is no built-in way to access or remove data stored using @AppStorage in Swift.
    • The @AppStorage property wrapper uses UserDefaults internally to store and retrieve data.
    • To remove data stored using @AppStorage, you can follow the same steps as for UserDefaults to clear all the data stored in UserDefaults.

<a id="orge6e69e3"></a>

<a id="org9f4a943"></a>

## URLSession

Use `URLSession` to get data from the web.

struct Response: Codable { var results: [Result] }

struct Result: Codable { var trackId: Int var trackName: String var collectionName: String }

struct ContentView: View { @State private var results = [Result]()

var body: some View { List(results, id: \.trackId) { item in VStack(alignment: .leading) { Text(item.trackName) .font(.headline) Text(item.collectionName) } } .task { await loadData() } }

func loadData() async { guard let url = URL(string: "https://itunes.apple.com/search?term=taylor+swift&entity=song") else { print("Invalid URL") return } do { let (data, _) = try await URLSession.shared.data(from: url) // What is coming in the second parameter is the metadata, which we don't use

if let decodedResponse = try? JSONDecoder().decode(Response.self, from: data) { results = decodedResponse.results } } catch { print("Invalid data: \(error.localizedDescription)") } } }

<a id="orgeba5161"></a>

<a id="org2912b8f"></a>

## @autoclosure

An attribute attached to function parameters that are closures, which asks Swift to silently wrap any code using it in a closure rather than requiring users to do it by hand. This is used rarely, but it's important in the assert() function.

<a id="org12a8cbf"></a>

## @available

An attribute attached to types or functions that mark them as being available or unavailable to specific versions of Swift or operating systems.

<a id="org3a9ba05"></a>

## @discardableResult

An attribute attached to methods that return a value, marking the return value as safe to ignore if the caller wants to. When this is not used, Swift will show a warning if you don't do something with the function's return value.

<a id="orgadb8b52"></a>

## @dynamicCallable

An attribute attached to types to mark them as being directly callable, primarily so that Swift can interact more easily with dynamic languages such as Python.

<a id="org71574d3"></a>

## @dynamicMemberLookup

An attribute attached to types to mark them as being able to handle undefined properties using special methods, primarily so that Swift can interact more easily with dynamic languages such as Python.

<a id="org244cb05"></a>

## @escaping

An attribute attached to function parameters that are closures, which tells Swift the closure will be used after the function has returned. This will in turn cause Swift to store the closure safely so that it doesn't get destroyed prematurely.

<a id="org11957ef"></a>

## @objc

An attribute used to mark methods and properties that must be accessible to Objective-C code. Swift does not make its code accessible to Objective-C by default to avoid making the code larger than it needs to be.

<a id="org251b80d"></a>

## @objcMembers

An attribute used to mark classes where all properties and methods must be accessible to Objective-C code. Swift does not make its code accessible to Objective-C by default to avoid making the code larger than it needs to be.

<a id="orgea435f4"></a>

## @unknown

An attribute attached to the default case of switch blocks that allows code to handle enum cases that may be added at some point in the future, without breaking source compatibility.

<a id="org8db1150"></a>

## Access control

A set of keywords that control how properties may be accessed by other code. open means the property can be accessed and overridden from anywhere, public means the property may be accessed from anywhere but overridden only within the module it came from, internal means the property may be accessed from anywhere inside the same module, fileprivate means the property may be accessed from anywhere inside the same file, and private means the property may be accessed from anywhere inside the same type.

<a id="org30406a4"></a>

## ABI

The description of how the Swift compiler produces binaries: how data structures are laid out in memory and accessed, how functions are called, and so on.

<a id="orgc8dc44b"></a>

## API

The collection of classes, structs, methods, and properties exposed by a library to solve a particular problem. Short for Application Programming Interface.

<a id="orgc0b4c25"></a>

## Argument

The name for a value that is being passed into a function, to be used inside the function. For example, in sayHello(to: "Paul") the to part is an argument. Many people just say "parameter" rather than "argument", but argument is technically correct.

<a id="org18123e8"></a>

## Associated type

A missing type in a protocol that must be specified by whatever type is conforming to the protocol. Associated types allow us to have flexibility when adding conformances: we can say that to conform to our protocol you must have an array of items, but we don't care what the data type of those items is. Associated types are written as one word in Swift: associatedtype. Associated value: A value that has been added to an enum case to provide some extra meaning. For example, you might have an enum case saying the weather is windy, then add an associated value saying how windy.

<a id="orgb81a678"></a>

## Block

Can mean any chunk of code that starts with { and ends with } ("a code block"), but "block" is also the Objective-C name for closures.

<a id="orgacd61c1"></a>

## Boolean

A data type that stores either true or false.

<a id="org307f5f1"></a>

## Brace

The name for opening and closing curly brackets, { and }.

<a id="org74ae4b8"></a>

## Bracket

The name for opening and closing square brackets, [ and ]

<a id="org595d915"></a>

## Break

A keyword that exit the current loop. If used with a labeled statement, e.g. break myLoop, it will break out of the specified block.

<a id="orgfbfbe91"></a>

## Capturing values

The name for the process of closures keeping a reference to values that are used inside the closure but were created outside. This is different from copying: the closure refers to the original values, not its own copies, so if the original values change then the closure's values change too.

<a id="orga0cfbb3"></a>

## CaseIterable

A Swift protocol that can be applied to enums. If the enum has cases with no associated values, the compiler will generate an allCases array that lets you loop over the cases in the enum.

<a id="orga6f807b"></a>

## Catch

A keyword that starts a block of code to handle errors. You can specify what kind of errors should be caught, and use a generic "catch all" block to catch everything else. Paired with do.

<a id="org53806bf"></a>

## CGFloat

A floating-point number that may be equivalent to a Double or Float depending on the platform.

<a id="org41c5ebb"></a>

## Class inheritance

The ability for one class to build on another, inheriting all its methods and properties. Some languages allow one class to inherit from multiple parents, but Swift does not.

<a id="org20a426a"></a>

## Closure

An anonymous function that automatically keeps a reference to any values it uses that were declared outside the function.

<a id="org02d76df"></a>

## Collection

A Swift protocol that is used by sequences types you can traverse multiple times without destroying them or affecting the collection, such as arrays and dictionaries.

<a id="org1d6eeca"></a>

## Comparable

A common Swift protocol that says conforming types can be placed into an order using <.

<a id="org1e8a3d3"></a>

## Compiler directive

One of several special pieces of code written using a #, that act as instructions to the compiler. For example, compiler directives can check whether we're targeting the simulator or not, and compile one of two code variants.

<a id="orgfbca929"></a>

## Compound assignment operator

An operator that modifies a value and assigns it back to the original variable at the same time. For example, score += 1 adds 1 to the current value of score.

<a id="org3b4ef52"></a>

## Computed property

Any property that does not have a simple storage area for its value, and instead is calculated each time the property is accessed by running some code.

<a id="org435dadd"></a>

## Condition

Any check that evaluates to true or false using an if statement. You can provide code to run when your condition is true, as well as an else Conditional conformance: The ability to say that a type conforms to a protocol only if specific conditions are met. For example, Swift's arrays conform to Equatable only if their element also conforms to Equatable.

<a id="orga7e2a50"></a>

## Constant

Any named piece of data in your code that may not change when your program runs.

<a id="orgf0c3469"></a>

## Continue

A keyword that exits the current iteration of a loop, causing the loop to start its next iteration immediately. If used with a labeled statement, e.g. continue myLoop, it will continue the specified block.

<a id="org75bf4f4"></a>

## Controller

A part of your program that handles logic. Part of the Model-View-Controller architecture.

<a id="org7f8fe75"></a>

## Data

A type that holds any kind of binary data.

<a id="org508ee12"></a>

## Default case

A special case for switch blocks that will match all other values.

<a id="org9410088"></a>

## Default parameter

A function parameter that has a default value attached, to allow callers not to provide it and get reasonable behavior. For example, func checkSettings(debugMode: Bool = true) can be called as checkSettings(debugMode: true) or checkSettings(debugMode: false), but also as checkSettings() – missing a debugMode value will assume true, because that's the default value.

<a id="org2f91efc"></a>

## Defer

A keyword that allows us to schedule work for when the current scope is exited.

<a id="org5b1d7a9"></a>

## Deinitializer

A special method that is called when an instance of a class is being destroyed. These may not accept parameters, and do not exist on structs.

<a id="orgf15e2fa"></a>

## Dictionary

A high-performance, unordered collection of values stored using a key for fast access.

<a id="org3ccb036"></a>

## Do

A keyword that starts a block of code that might throw errors. Paired with catch.

<a id="org180f12a"></a>

## Double

A high-precision floating-point number, such as 3.1, or 3.141592654.

<a id="org7dd477a"></a>

## Enum

A set of named values that are easier to remember and safer than just using strings or integers. For example, you might create an enum of directions, using north, south, east, and west – this is much nicer than using 0, 1, 2, and 3, for example. Short for "enumeration". Pronounced as "ee-numb", but "ee-noom" is an accepted variation.

<a id="org361f0a4"></a>

## Equatable

A common Swift protocol that says conforming types can be compared for equality using ==.

<a id="org0b03339"></a>

## Error

A Swift protocol that our own enums can conform to, which we can then use to throw errors from functions.

<a id="org3251960"></a>

## Expression

Some code that evaluates to a value. For example, 12 \* 12 evaluates to 144.

<a id="org9350588"></a>

## Extension

A set of additional methods and computed properties that are added to a concrete type, such as Int.

<a id="org93a730d"></a>

## Fallthrough

A keyword used in switch blocks to mean "carry on executing the case immediately following this one."

<a id="org47bb0f9"></a>

## Failable initializer

An initializer that returns an optional value, because initialization might have failed for some reason. These are written as init?() or init!().

<a id="orgcb29c37"></a>

## Final class

A class that may not be inherited from by anything else.

<a id="orga3b35ef"></a>

## Force unwrap

The process of using the value inside an optional without checking it exists first. If the optional is empty – if it has no value – force unwrapping will crash your code.

<a id="orgfd6b7a1"></a>

## Framework

A collection of code that you are using. Frameworks differ from libraries in that frameworks usually take over control of their operation, and call back to you when they need information.

<a id="org0a6b8cb"></a>

## Function

A named section of your code that performs a specific, reusable task. You might pass in parameters to the function to customize how it runs, and it might return one or more values that are the result of its work.

<a id="orgd87f309"></a>

## Functional programming

A programming approach that favors sending and receiving immutable data to and from functions, avoiding side effects, and composing functions together.

<a id="orgdf8569c"></a>

## Generics

The ability for one type or function to be used with a variety of data types. For example, Swift's arrays are generic, because you can make an array that stores integers, an array that stores strings, and so on.

<a id="orgd880443"></a>

## guard

A piece of Swift syntax that checks whether a condition is true, and forces you to exit the current scope immediately if it is not. This is commonly used as guard let, which checks whether an optional has a value, and, if it does, creates a new constant for that optional's value so it can be used safely. If it has no value, the guard condition fails and you must exit the current scope.

<a id="org57c0ecb"></a>

## Hashable

A common Swift protocol that says conforming types can be represented using hash values.

<a id="org075ed64"></a>

## Higher-order function

A function that accepts another function as a parameter, or sends back a function as its return value.

<a id="orgca0c7e4"></a>

## if let

A piece of Swift syntax that checks whether an optional has a value, and, if it does, creates a new constant for that optional's value so it can be used safely. If it has no value, the if condition fails and you can run an else block instead.

<a id="org1e61457"></a>

## Implicitly unwrapped optional

A special Swift optional that may or may not contain a value, but does not need to be checked before use. If you attempt to use an implicitly unwrapped optional that has no value, your app will crash.

<a id="org22a21e2"></a>

## Indirect enum

An enum that is compiled specially so that it can reference itself in its associated values. For example, if you had a linked list enum that needed to reference another linked list item as an associated value, this would need to be indirect.

<a id="org075797d"></a>

## Infinite loop

A loop that never ends until you say so. This is most commonly done using a boolean variable set to true – you can set it to false as soon as you want the loop to end.

<a id="org0fa0721"></a>

## Initializer

A special method that gets run to create an instance of a struct or class. You can have many initializers, and in the case of classes may call parent initializers inside your own initializer. inout parameter: A function parameter that, when changed inside the function, remains changed outside the function.

<a id="org91031c6"></a>

## Integer

A whole number, such as 5, 55, or 55 million.

<a id="org15a7097"></a>

## Keypath

A way of referring to properties without actually reading them.

<a id="orgc038d8b"></a>

## Keyword

Any word that has specific meaning as a Swift construct, such as class, continue, and try.

<a id="orgd6b4e92"></a>

## Labeled statement

A name attached to a specific block of code, such as a loop or a condition, allowing you to break out of it specifically even if you are inside other blocks. For example, if you are inside a loop that's inside a loop that's inside a third loop, you could exit the outermost loop.

<a id="orgc151bd5"></a>

## Lazy

A keyword that marks a property as being created only when it is first accessed. This is a performance optimization, because it means if the property is never accessed the work required to calculate its value is never done.

<a id="org4bcdf74"></a>

## Library

A collection of code that you are using. Libraries differ from frameworks in that libraries are just collections of classes, structs, enums, and so on, for you to use however you want.

<a id="orge3fec82"></a>

## Memberwise initializer

An initialer for structs that is automatically generated by the Swift compiler, requiring that all properties must have a value. If you implement your own initializer inside the struct the memberwise initializer will no longer be generated by Swift.

<a id="orge24796c"></a>

## Method

A function that belongs to a struct or a class.

<a id="orgcf8d6f0"></a>

## Model

A part of your program that stores data. Part of the Model-View-Controller architecture.

<a id="orgb9afd18"></a>

## Multi-line strings

A string that spans multiple lines. Multi-line strings in Swift must start and end with three double quotes on their own line.

<a id="org0df1fab"></a>

## Mutating method

A method on a struct that will change one of the properties of the struct. This must be used because only variable structs can have mutating methods called on them. Mutating methods are not required for classes, where every method can be mutating without the keyword.

<a id="orge963464"></a>

## Nested type

A class or a struct that is defined inside another class or struct.

<a id="org06d1c4b"></a>

## Nil

Swift's term for missing data. An optional that has no value will be set to nil.

<a id="org56a1465"></a>

## Nil coalescing

An operator in Swift, written as ??, that uses the value from an optional if it has one, or a default value otherwise.

<a id="org3f33561"></a>

## Non-throwing function

A function that cannot throw errors. These must not be marked using throws, and must not use the throw keyword.

<a id="org8c19ba7"></a>

## Objective-C

Apple's first programming language, and the forerunner to Swift.

<a id="org01381f4"></a>

## Operand

The values that work alongside an operator. For example, in 2 + 3 the 2 and 3 are operands.

<a id="org47c31b8"></a>

## Operator

Any symbol that acts as a function on values to its left and/or right. For example, + is an operator that adds two values together.

<a id="orgdcbe367"></a>

## Operator overloading

The ability for one operator, such as + to do multiple things depending on how it's used. For example, 1 + 1 is an integer addition, but "Hello " + "Paul" will join the strings together.

<a id="org7fd2df8"></a>

## Optional

A type that wraps another type, such as String or Int, but adds the ability to store no value at all. "No value" is different from all regular integer values, including zero. Swift uses optionals heavily as a way of providing runtime safety, and the compiler forces us to use them correctly.

<a id="org21bb2cb"></a>

## Optional chaining

The ability to use multiple optional methods or properties in a single line of code. If any of them are nil then execution of that line will stop, but if they all succeed then you will get an optional value back. For example, user?.name?.uppercased().

<a id="org7d8a71d"></a>

## Override method

A class's method that has the same name, parameters, and return type as a method on the class's parent class. The override keyword tells the Swift compiler you understand that you are changing the behavior.

<a id="org77cc1c7"></a>

## Parameter

The name for a value that has been passed into a function, to be used inside the function. For example, in func sayHello(to: String), the to part is a parameter.

<a id="org6c4178f"></a>

## Parameter label

Custom names assigned to function parameters that affect the way they are used externally. For example, in sayHello(to name: String), people calling the function will say sayHello(to: "Paul"), but inside the function you would refer to name.

<a id="org0df0989"></a>

## Parenthesis

The name for opening and closing rounded brackets, ( and ).

<a id="org9f08ab9"></a>

## Polymorphism

The ability for an object to appear as and be used as multiple different types. For example, a Labrador class instance could also be used as a Dog and Mammal if you had defined those as parent classes.

<a id="orgd88c5f1"></a>

## Protocol

A list of criteria that a type must conform to, such as property names and methods. Protocols allow us to treat many objects the same way, because they implement all the behavior required to make the protocol work.

<a id="org0871c71"></a>

## Protocol extension

A set of additional methods and computed properties that are added to a protocol, such as Equatable.

<a id="orgafeb360"></a>

## Protocol inheritance

The ability for one protocol to inherit requirements from another protocol. For example, the Comparable protocol inherits from Equatable.

<a id="orgd27e3e2"></a>

## Protocol-oriented programming

An approach to programming that favors code re-use through protocol extensions, providing the benefits of multiple inheritance without some of the complexity. Specifically, protocol-oriented programming (POP) cannot add stored properties to a type, so there is less cruft.

<a id="org8f71ec8"></a>

## Range

Ranges span the distance between two values, up to and sometimes including the final value. This is mostly used with numbers: 1..<4 includes the numbers 1, 2, and 3, whereas the range 1&#x2026;4 includes the numbers 1, 2, 3, and 4. Ranges can also be made from other data types, such as dates.

<a id="orge2fe6d8"></a>

## Raw strings

The ability to specify custom string delimiters for situations when you want to use backslashes and quote marks without them having their regular meaning.

<a id="org8e606aa"></a>

## Raw value

A simple underlying data type that enum values can be mapped to for the purpose of loading and saving. For example, you might say that the planets Mercury, Venus, and Earth have the integer raw values 1, 2, and 3. Reference type: Any type that stores its data indirectly in memory, with the variable or constant really just being a pointer (or reference) to that piece of memory. If you point a second variable to a reference type, it will point at the same data in memory as the original reference, so the data is shared.

<a id="orgcb28719"></a>

## Repeat loop

A loop that will continue executing as long as its condition is true. If its condition starts false, it will still execute at least once.

<a id="orgb8ac079"></a>

## Rethrowing functions

A function that uses the rethrows keyword so that it throws errors only if the closure it accepts throws errors.

<a id="orgc64cca9"></a>

## Return type

The type of data that a function says it will return. Swift always enforces this, so if you say you will return a string you must do so.

<a id="org3f9ab67"></a>

## Runtime

When your code is running, as opposed to compile time, which is when the code is being built.

<a id="orgbad40e1"></a>

## Scope

A region of code where variables and constants are valid. Each time you use an opening brace you start a new scope: all previous variables and constants remain valid in that scope, but any that are declared inside that scope are only valid until the scope ends with a closing brace.

<a id="orgf706281"></a>

## Selector

A way of referring to functions without actually calling them, usually for the purpose of calling them later on.

<a id="orgbeda81a"></a>

## Serialization

The process of converting objects into text or binary, and vice versa. For example, converting an array of users into JSON, or converting JSON into an array of users.

<a id="org4da9e11"></a>

## Set

A high-performance, unordered collection of values of any type that conforms to the Hashable protocol.

<a id="org66fad34"></a>

## Shorthand parameter name

Special parameter names made available inside closures, written as a dollar sign the numbers starting from 0. For example, if a closure accepts a name string and an age integer, you could refer to the string as $0 and the age as $1. Note: you may not mix and match shorthand syntax with regular syntax.

<a id="org17fb88b"></a>

## some

A keyword that uses an opaque return type – return types such as some View in SwiftUI to mean "some sort of View will be returned but it doesn't matter which type specifically."

<a id="org2260857"></a>

## Statement

Some code that performs an action, such as print(age).

<a id="orge8080fd"></a>

## Static method

A method that is shared across all instances of a struct or class, rather than unique to each instance. Because this is not run on a specific instance of a struct or class, it cannot access any properties that are not also marked static.

<a id="org2748aab"></a>

## Static property

A property that is shared across all instances of a struct or class, rather than unique to each instance.

<a id="org7192234"></a>

## StaticString

A specialized form of Swift's String that must be hand-typed – you must literally type the string directly into your code rather than using string interpolation.

<a id="org2fe3ac8"></a>

## String

A collection of letters, such as "Hello".

<a id="org2431313"></a>

## String interpolation

The ability for Swift to insert the values of variables and constants into strings, such as "Hello, \\(name)."

<a id="org4e200cb"></a>

## Subscript

Special methods that are used with collections, and provide easy access to read and write values in the collection. For example, someArray[3] is a subscript, as is someDictionary["name"].

<a id="org3721c02"></a>

## Syntactic sugar

The name for special Swift syntax that is designed to mask complexity. The name comes from the idea that it's better to create short and sweet syntax that does the same as longer syntax. For example, [String] is syntactic sugar for Array<String>.

<a id="orgd45cd2d"></a>

## Synthesize

The name for when the Swift compiler generates code on your behalf. For example, if you say that a custom struct conforms to Equatable, and all its properties already conform to Equatable, then Swift can synthesize a == function for it.

<a id="org3f11c06"></a>

## Ternary operator

An operator that works with three values, written in Swift as ? :. For example, isEnabled ? 10 : 100 will return 10 if isEnabled is true, and 100 if it's false.

<a id="org0f5210b"></a>

## Throwing function

A function that has the ability to throw errors. These must be marked using the throws keyword in Swift, and called using try.

<a id="orgcd6dcba"></a>

## Trailing closure syntax

The ability for functions that accept a closure as their final parameter to have that closure specified after the function's parentheses, which usually helps make the function call easier to read.

<a id="org9e2d691"></a>

## try catch

The ability to run throwing functions and catch any errors that occur. You must start using a do block, then call any throwing methods inside that using try, and finally add one or more catch blocks to catch any errors. Writing a catch block to catch all errors is sometimes called a Pokémon catch, because "you gotta catch 'em all."

<a id="org8d35bd0"></a>

## Unwrapping optionals

The process of checking whether there is a value inside an optional, and, if there is, extracting that value so it can be used safely.

<a id="org890fd09"></a>

## Value type

Any type that stores its data directly in memory. If you point a second variable to a value type it will always copy the data in its entirety, rather than allowing it to be shared.

<a id="orgdeaf036"></a>

## Variable

Any named piece of data in your code that may change when your program runs.

<a id="orgc28e93c"></a>

## Variadic function

A function that takes one or more values of a specific type, separated by commas. The print() function is variadic, because you can write print(1) to print a single value, or print(1, 2, 3, 4, 5, 6, 7, 8) to print many.

<a id="orga510f0f"></a>

## View

A part of your program that shows visible results to your user. Part of the Model-View-Controller architecture.

<a id="org2938cab"></a>

## Void

The absence of a value. Used most commonly to refer to the return types of functions that return nothing.

<a id="org61410b5"></a>

<a id="org4e2c291"></a>

## WordScramble app

Courtesy of Hacking with Swift.

import SwiftUI

struct ContentView: View { @State private var usedWords = [String]() @State private var rootWord = "" @State private var newWord = ""

@State private var errorTitle = "" @State private var errorMessage = "" @State private var showingError = false

var body: some View { NavigationStack { List { Section { TextField("Enter your word", text: $newWord) .autocapitalization(.none) // turn off default capitalization }

Section { ForEach(usedWords, id: \.self) { word in HStack { Image(systemName: "\(word.count).circle") // Create a little image here Text(word) } } } } .navigationTitle(rootWord) .onSubmit(addNewWord) .onAppear(perform: startGame) .alert(errorTitle, isPresented: $showingError) { Button("OK", role: .cancel) { } } message: { Text(errorMessage) } } }

func addNewWord() { let answer = newWord.lowercased().trimmingCharacters(in: .whitespacesAndNewlines) guard answer.count > 0 else { return }

guard isOriginal(word: answer) else { wordError(title: "Word used already", message: "Be more original") return }

guard isPossible(word: answer) else { wordError(title: "Word not possible", message: "You can't spell that word from \(rootWord)!") return }

guard isReal(word: answer) else { wordError(title: "Word not recognized", message: "You can't juse make up silly words, they have to be real.") return }

withAnimation { usedWords.insert(answer, at: 0) // Insert word at beginning of array } newWord = "" }

func startGame() { if let startWordsURL = Bundle.main.url(forResource: "start", withExtension: "txt") { if let startWords = try? String(contentsOf: startWordsURL) { let allWords = startWords.components(separatedBy: "\n") rootWord = allWords.randomElement() ?? "pickard" return } fatalError("Could not find data inside file start.txt.") } fatalError("Could not find file start.txt in bundle.") }

func isOriginal(word: String) -> Bool { !usedWords.contains(word) }

func isPossible(word: String) -> Bool { var tempWord = rootWord

for letter in word { if let pos = tempWord.firstIndex(of: letter) { tempWord.remove(at: pos) } else { return false } } return true }

func isReal(word: String) -> Bool { let checker = UITextChecker() let range = NSRange(location: 0, length: word.utf16.count) let misspelledRange = checker.rangeOfMisspelledWord(in: word, range: range, startingAt: 0, wrap: false, language: "en")

return misspelledRange.location == NSNotFound }

func wordError(title: String, message: String) { errorTitle = title errorMessage = message showingError = true } }

<a id="org01b0b62"></a>

## Set currency formatter

Display the currency symbol before the numbers, you can modify the format specifier in the \`TextField\` and \`Text\` views.

In the extension \`NumberFormatter.currencyStyle\`, we define a custom formatter that sets the currency format and specifies that the currency symbol should be displayed before the numbers. The \`positiveFormat\` property is set to "\\(formatter.currencySymbol ?? "")#,##0.00", which includes the currency symbol followed by the comma-separated number format.

struct ContentView: View { @State private var checkAmount = 0.0 @State private var numberOfPeople = 2 @State private var tipPercentage = 20

let tipPercentages = [10, 15, 20, 25, 0]

var body: some View { Form { Section { TextField("Amount", value: $checkAmount, format: NumberFormatter.currencyStyle(currencyCode: Locale.current.currency?.identifier ?? "EUR")) .keyboardType(.decimalPad) } Section { Text(checkAmount, format: NumberFormatter.currencyStyle(currencyCode: Locale.current.currency?.identifier ?? "EUR")) } } } }

extension NumberFormatter { static func currencyStyle(currencyCode: String) -> NumberFormatter { let formatter = NumberFormatter() formatter.numberStyle = .currency formatter.currencyCode = currencyCode formatter.positiveFormat = "\(formatter.currencySymbol ?? "")#,##0.00" return formatter } }