Just enough Swift

Use this page as a reference only; the focus is on Hotwire Native and Rails, not Swift.

It is essential to have Xcode installed to create applications for Apple devices. This guide uses version 16.1. Before moving forward, let's highlight a few aspects of Swift development, always with an emphasis on Hotwire Native.

Delegates

Delegates are one of the most important design patterns in iOS. They allow one object (the "delegate") to receive and respond to events from another object. In the context of Hotwire Native, delegates are often used to handle events from WebViews and other UIKit components.

Imagine you have a button that needs to notify another object when it is clicked. Here’s a simple example to demonstrate this:

protocol ButtonDelegate {
    func buttonWasClicked()
}

class Button {
    var delegate: ButtonDelegate?

    func click() {
        print("Botão foi clicado!")
        delegate?.buttonWasClicked() // Notifica o delegate
    }
}

class ButtonHandler: ButtonDelegate {
    func buttonWasClicked() {
        print("O delegado foi notificado: botão clicado!")
    }
}

With the delegate pattern set up, you can implement functionality like this:

let button = Button()
let handler = ButtonHandler()

button.delegate = handler // The delegate
button.click() // Simulate the button click via delegate

Scenes

Scenes are responsible for managing windows and the lifecycle of screens in iOS. Introduced in iOS 13, they allow apps to support multitasking. The SceneDelegate is where the main app interface is configured.

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    var window: UIWindow?

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        guard let windowScene = (scene as? UIWindowScene) else { return }
        let window = UIWindow(windowScene: windowScene)
        window.rootViewController = ViewController()
        self.window = window
        window.makeKeyAndVisible()
    }
}

At this stage, the ViewController is set as the main screen of the app in the scene(_:willConnectTo:) method.

Controllers

Controllers, such as UIViewController, are the foundation for creating screens in iOS. They manage the screen's content and respond to lifecycle events, such as when the screen appears or disappears.

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white
        print("Tela carregada!")
    }
}

In this context, the viewDidLoad method is called the first time the screen loads, and the screen’s background is set to white.

Classes

Classes are reference types, meaning that when an object is created from a class, it can be shared across different parts of the code. Additionally, classes support inheritance, allowing one class to inherit properties and methods from another.

class Person {
    var name: String

    init(name: String) {
        self.name = name
    }

    func sayHello() {
        print("Hello, \(name)!")
    }
}

// Create a Person object 
let person = Person(name: "Mary")
person.sayHello() // Output: Hello, Mary!

Structs

Structs are value types, meaning that when you copy a struct, each copy has its own independent values. They are widely used in Swift to represent simple data structures.

struct Person {
    var name: String

    func sayHello() {
        print("Hello, \(name)!")
    }
}

// Create an instance of the struct
var person = Person(nome: "John")
person.sayHello() // Output: Hello, John!

If a struct is copied and the copy is modified, the original value remains unchanged:

var anotherPerson = person
anotherPerson.name = "Ana"

print(person.name)         // Output: John
print(anotherPerson.name)  // Output: Ana

Differences Between Classes and Structs

Aspect Class Struct
Type Reference Value
Copyability Shares the same object Each copy is independent
Inheritance Supports inheritance Does not support inheritance
Common Uses Complex objects with mutable state Simple and immutable data

Extensions

Extensions allow you to add new functionalities to existing classes, structs, enums, or protocols without altering the original code. For instance, you can extend the String type to add new methods.

extension String {
    func greeting() {
        print("Hello, \(self)!")
    }
}

// Usando a extensão
let name = "Charles"
name.greeting() // Output: Hello, Charles!

Utilize extensions para organizar o código.

struct Rectangle {
    var width: Double
    var height: Double
}

// Adicionando um método com extension
extension Rectangle {
    func calculateArea() -> Double {
        return width * height
    }
}

let rectangle = Rectangle(width: 5, height: 10)
print(rectangle.calculateArea()) // Output: 50.0

Summary of Classes, Structs, and Extensions

When to Use Classes, Structs, and Extensions:

Variables

Types of Variables

Variables can be defined using the keywords var and let.

var nome = "John"
let age = 30

Type Inference or Explicit Type Declaration

Swift allows you to define variables using type inference (where the type is determined automatically) or explicit declaration (where the type is specified by the developer).

var message = "Hello World"

let pi: Double = 3.14159

Optional Variables

Swift uses optionals to represent variables that may or may not have a value (i.e., they can be nil). This helps prevent runtime errors when accessing non-existent values.

An optional is declared by adding a ? after the type:

var name: String? = "Emily"

if let extractedName = name {
    print("Hello, \(extractedName)!")
} else {
    print("Name is nil.")
}

Forced Unwrapping (!): Use it only if you are certain the optional contains a value, as attempting to access a nil value will result in a runtime error.

let name: String? = "Emily"
print(name!)

Lazy

Variables declared with lazy are initialized only when accessed for the first time. This is useful for saving memory in resource-intensive calculations or operations.

class Person {
    lazy var details: String = "Loading info..."
}

let person = Person()
print(person.details) // Inicializa e acessa a variável

Summary

These are essential concepts to understand when working on iOS/Swift and Hotwire Native projects.

Once again, use this section as a reference, as the primary focus of this book is Hotwire Native and Rails.