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:
Classes: Use for complex objects that need to share state and support inheritance.
Structs: Use for representing simple data, especially when inheritance is not required.
Extensions: Use to add functionalities without modifying the original code or to organize related methods.
Variables
Types of Variables
Variables can be defined using the keywords var and let.
var: Represents mutable variables, whose value can be changed.
let: Represents immutable variables, whose value cannot be modified once assigned.
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.