Swift Cheatsheet¶
¶
¶
יh1⁄4] Confía en el potencial y la programación intuitiva de Apple Idioma seleccionado/h1 "Clase de inscripción" Swift es un lenguaje de programación potente e intuitivo para iOS, macOS, watchOS y tvOS. Escribir código Swift es interactivo y divertido, la sintaxis es concisa pero expresiva, y Swift incluye características modernas amor de los desarrolladores. ▪/p] ■/div titulada
¶
########################################################################################################################################################################################################################################################## Copiar todos los comandos¶
########################################################################################################################################################################################################################################################## Generar PDF seleccionado/button¶
■/div titulada ■/div titulada
Cuadro de contenidos¶
- Instalación
- Basic Syntax
- Variables y Constantes
- Tipos de datos
- Operadores
- Control Flow
- Functions
- Closures
- Las clases y las estructuras
- Propiedades
- Methods
- Inherencia
- Protocolos
- Extensions
- Generics
- Manejo del espejo
- Manejo de memoria
- Concurrencia
- Collections
- Optionals
- Las mejores prácticas
Instalación¶
Instalación de código X¶
# Install Xcode from Mac App Store
# Xcode includes Swift compiler and runtime
# Verify Swift installation
swift --version
# Swift REPL (Read-Eval-Print Loop)
swift
# Swift Package Manager
swift package init
swift build
swift run
Swift en Linux¶
# Download Swift for Linux from swift.org
# Extract and add to PATH
# Ubuntu/Debian
sudo apt-get install clang libicu-dev
# Install Swift
tar xzf swift-5.8-RELEASE-ubuntu20.04.tar.gz
export PATH=/path/to/swift-5.8-RELEASE-ubuntu20.04/usr/bin:$PATH
# Verify installation
swift --version
Sintaxis básica¶
Hola Mundo¶
// Simple print statement
print("Hello, World!")
// Multi-line string
let multilineString = """
This is a
multi-line string
in Swift
"""
print(multilineString)
// String interpolation
let name = "Swift"
let version = 5.8
print("Hello, \(name) \(version)!")
// Comments
// This is a single-line comment
/*
This is a
multi-line comment
*/
/// This is a documentation comment
/// - Parameter name: The name to greet
/// - Returns: A greeting string
func greet(name: String) -> String {
return "Hello, \(name)!"
}
Semicolons and Line Breaks¶
// Semicolons are optional
let a = 1
let b = 2
// Multiple statements on one line require semicolons
let x = 1; let y = 2
// Line breaks are used to separate statements
let firstName = "John"
let lastName = "Doe"
let fullName = firstName + " " + lastName
Variables y Constantes¶
Declaración¶
// Variables (mutable)
var variableName = "I can change"
var age = 25
var height: Double = 5.9
// Constants (immutable)
let constantName = "I cannot change"
let pi = 3.14159
let maxUsers: Int = 100
// Type annotation
var explicitString: String = "This is a string"
var explicitInt: Int = 42
var explicitDouble: Double = 3.14
// Multiple variable declaration
var x = 0.0, y = 0.0, z = 0.0
// Deferred initialization
let deferredConstant: String
if someCondition {
deferredConstant = "Value A"
} else {
deferredConstant = "Value B"
}
Naming Conventions¶
// Use camelCase for variables and functions
var userName = "john_doe"
var isLoggedIn = true
func calculateTotalPrice() -> Double { return 0.0 }
// Use PascalCase for types
class UserManager { }
struct DatabaseConnection { }
enum NetworkError { }
// Use SCREAMING_SNAKE_CASE for constants
let MAX_RETRY_COUNT = 3
let API_BASE_URL = "https://api.example.com"
// Use descriptive names
var currentUserAge = 25 // Good
var a = 25 // Bad
// Boolean variables should be questions
var isVisible = true
var hasPermission = false
var canEdit = true
Tipos de datos¶
Tipos básicos¶
// Integer types
let smallInt: Int8 = 127
let mediumInt: Int16 = 32767
let normalInt: Int32 = 2147483647
let bigInt: Int64 = 9223372036854775807
let unsignedInt: UInt = 42
// Floating-point types
let floatNumber: Float = 3.14159
let doubleNumber: Double = 3.141592653589793
// Boolean
let isTrue: Bool = true
let isFalse: Bool = false
// Character and String
let singleCharacter: Character = "A"
let stringValue: String = "Hello, Swift!"
// Type inference
let inferredInt = 42 // Int
let inferredDouble = 3.14 // Double
let inferredString = "Text" // String
let inferredBool = true // Bool
Manipulación de cuerdas¶
// String creation
let emptyString = ""
let anotherEmptyString = String()
// String interpolation
let name = "Alice"
let age = 30
let message = "My name is \(name) and I'm \(age) years old."
// Multi-line strings
let poem = """
Roses are red,
Violets are blue,
Swift is awesome,
And so are you!
"""
// String operations
let greeting = "Hello"
let world = "World"
let combined = greeting + ", " + world + "!"
// String properties and methods
let text = "Swift Programming"
print(text.count) // 17
print(text.isEmpty) // false
print(text.uppercased()) // SWIFT PROGRAMMING
print(text.lowercased()) // swift programming
print(text.hasPrefix("Swift")) // true
print(text.hasSuffix("ing")) // true
// String indexing
let str = "Hello"
let firstChar = str[str.startIndex] // H
let lastChar = str[str.index(before: str.endIndex)] // o
let secondChar = str[str.index(str.startIndex, offsetBy: 1)] // e
// Substring
let range = str.index(str.startIndex, offsetBy: 1)..<str.index(str.startIndex, offsetBy: 4)
let substring = str[range] // "ell"
Resumen de las colecciones¶
// Array
var numbers = [1, 2, 3, 4, 5]
var strings: [String] = ["apple", "banana", "cherry"]
var emptyArray: [Int] = []
// Set
var uniqueNumbers: Set<Int> = [1, 2, 3, 3, 4] // {1, 2, 3, 4}
var emptySet: Set<String> = []
// Dictionary
var ages = ["Alice": 30, "Bob": 25, "Charlie": 35]
var emptyDict: [String: Int] = [:]
// Tuple
let coordinates = (x: 10, y: 20)
let httpStatus = (404, "Not Found")
let person = (name: "John", age: 30, isEmployed: true)
Operadores¶
Operadores Aritméticos¶
let a = 10
let b = 3
// Basic arithmetic
let sum = a + b // 13
let difference = a - b // 7
let product = a * b // 30
let quotient = a / b // 3
let remainder = a % b // 1
// Unary operators
let positive = +a // 10
let negative = -a // -10
// Compound assignment
var x = 5
x += 3 // x is now 8
x -= 2 // x is now 6
x *= 2 // x is now 12
x /= 3 // x is now 4
x %= 3 // x is now 1
Operadores de comparación¶
let a = 5
let b = 10
// Comparison
let isEqual = (a == b) // false
let isNotEqual = (a != b) // true
let isGreater = (a > b) // false
let isLess = (a < b) // true
let isGreaterOrEqual = (a >= b) // false
let isLessOrEqual = (a <= b) // true
// String comparison
let str1 = "apple"
let str2 = "banana"
let result = str1 < str2 // true (alphabetical order)
// Tuple comparison
let tuple1 = (1, "zebra")
let tuple2 = (2, "apple")
let tupleResult = tuple1 < tuple2 // true (compares first elements)
Operadores lógicos¶
let a = true
let b = false
// Logical NOT
let notA = !a // false
// Logical AND
let andResult = a && b // false
// Logical OR
let orResult = a || b // true
// Short-circuit evaluation
let result = a || expensiveFunction() // expensiveFunction() not called if a is true
Operadores de rango¶
// Closed range (includes both endpoints)
let closedRange = 1...5 // 1, 2, 3, 4, 5
// Half-open range (excludes upper bound)
let halfOpenRange = 1..<5 // 1, 2, 3, 4
// One-sided ranges
let oneSidedRange1 = 2... // 2 to end of collection
let oneSidedRange2 = ...2 // beginning to 2
let oneSidedRange3 = ..<2 // beginning to 2 (excluding 2)
// Using ranges
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
let subset = numbers[2...5] // [3, 4, 5, 6]
for i in 1...5 {
print(i) // Prints 1, 2, 3, 4, 5
}
Nil-Coalescing Operator¶
let optionalName: String? = nil
let defaultName = "Anonymous"
// Nil-coalescing operator
let name = optionalName ?? defaultName // "Anonymous"
// Equivalent to:
let name2 = optionalName != nil ? optionalName! : defaultName
// Chaining nil-coalescing
let a: String? = nil
let b: String? = nil
let c: String? = "Hello"
let result = a ?? b ?? c ?? "Default" // "Hello"
Flujo de control¶
Declaraciones condicionales¶
// if statement
let temperature = 25
if temperature > 30 {
print("It's hot!")
} else if temperature > 20 {
print("It's warm.")
} else {
print("It's cool.")
}
// Ternary operator
let message = temperature > 25 ? "Warm" : "Cool"
// guard statement
func processUser(name: String?) {
guard let userName = name, !userName.isEmpty else {
print("Invalid name")
return
}
print("Processing user: \(userName)")
}
// if let (optional binding)
let optionalNumber: Int? = 42
if let number = optionalNumber {
print("Number is \(number)")
} else {
print("Number is nil")
}
// Multiple optional binding
let optionalName: String? = "Alice"
let optionalAge: Int? = 30
if let name = optionalName, let age = optionalAge, age >= 18 {
print("\(name) is an adult")
}
Interruptor de declaraciones¶
let character = "a"
switch character {
case "a", "e", "i", "o", "u":
print("Vowel")
case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m", "n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z":
print("Consonant")
default:
print("Not a letter")
}
// Switch with ranges
let score = 85
switch score {
case 90...100:
print("A")
case 80..<90:
print("B")
case 70..<80:
print("C")
case 60..<70:
print("D")
default:
print("F")
}
// Switch with tuples
let point = (1, 1)
switch point {
case (0, 0):
print("Origin")
case (_, 0):
print("On x-axis")
case (0, _):
print("On y-axis")
case (-2...2, -2...2):
print("Inside the box")
default:
print("Outside the box")
}
// Switch with value binding
let anotherPoint = (2, 0)
switch anotherPoint {
case (let x, 0):
print("On x-axis at x = \(x)")
case (0, let y):
print("On y-axis at y = \(y)")
case let (x, y):
print("Point at (\(x), \(y))")
}
// Switch with where clause
let yetAnotherPoint = (1, -1)
switch yetAnotherPoint {
case let (x, y) where x == y:
print("On the line x == y")
case let (x, y) where x == -y:
print("On the line x == -y")
case let (x, y):
print("Point at (\(x), \(y))")
}
Loops¶
// for-in loop
let numbers = [1, 2, 3, 4, 5]
for number in numbers {
print(number)
}
// for-in with range
for i in 1...5 {
print("Count: \(i)")
}
// for-in with stride
for i in stride(from: 0, to: 10, by: 2) {
print(i) // 0, 2, 4, 6, 8
}
// for-in with enumerated
let fruits = ["apple", "banana", "cherry"]
for (index, fruit) in fruits.enumerated() {
print("\(index): \(fruit)")
}
// while loop
var count = 0
while count < 5 {
print("Count: \(count)")
count += 1
}
// repeat-while loop (do-while equivalent)
var number = 0
repeat {
print("Number: \(number)")
number += 1
} while number < 3
// Loop control
for i in 1...10 {
if i == 3 {
continue // Skip this iteration
}
if i == 8 {
break // Exit the loop
}
print(i)
}
// Labeled statements
outerLoop: for i in 1...3 {
innerLoop: for j in 1...3 {
if i == 2 && j == 2 {
break outerLoop
}
print("i: \(i), j: \(j)")
}
}
Funciones¶
Funciones básicas¶
// Simple function
func greet() {
print("Hello!")
}
greet()
// Function with parameters
func greet(name: String) {
print("Hello, \(name)!")
}
greet(name: "Alice")
// Function with return value
func add(a: Int, b: Int) -> Int {
return a + b
}
let sum = add(a: 5, b: 3)
// Function with multiple return values
func minMax(array: [Int]) -> (min: Int, max: Int) {
var currentMin = array[0]
var currentMax = array[0]
for value in array[1..<array.count] {
if value < currentMin {
currentMin = value
} else if value > currentMax {
currentMax = value
}
}
return (currentMin, currentMax)
}
let bounds = minMax(array: [8, -6, 2, 109, 3, 71])
print("Min: \(bounds.min), Max: \(bounds.max)")
Parámetros de función¶
// External and internal parameter names
func greet(person name: String, from hometown: String) -> String {
return "Hello \(name)! Glad you could visit from \(hometown)."
}
print(greet(person: "Bill", from: "Cupertino"))
// Omitting external parameter names
func add(_ a: Int, _ b: Int) -> Int {
return a + b
}
let result = add(5, 3) // No parameter labels
// Default parameter values
func greet(name: String, greeting: String = "Hello") -> String {
return "\(greeting), \(name)!"
}
print(greet(name: "Alice")) // Uses default greeting
print(greet(name: "Bob", greeting: "Hi")) // Uses custom greeting
// Variadic parameters
func average(_ numbers: Double...) -> Double {
var total: Double = 0
for number in numbers {
total += number
}
return total / Double(numbers.count)
}
print(average(1, 2, 3, 4, 5)) // 3.0
// In-out parameters
func swapTwoInts(_ a: inout Int, _ b: inout Int) {
let temporaryA = a
a = b
b = temporaryA
}
var someInt = 3
var anotherInt = 107
swapTwoInts(&someInt, &anotherInt)
print("someInt: \(someInt), anotherInt: \(anotherInt)")
Tipos de función¶
// Function as a type
func addTwoInts(_ a: Int, _ b: Int) -> Int {
return a + b
}
func multiplyTwoInts(_ a: Int, _ b: Int) -> Int {
return a * b
}
// Variable of function type
var mathFunction: (Int, Int) -> Int = addTwoInts
print(mathFunction(2, 3)) // 5
mathFunction = multiplyTwoInts
print(mathFunction(2, 3)) // 6
// Function as parameter
func printMathResult(_ mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int) {
print("Result: \(mathFunction(a, b))")
}
printMathResult(addTwoInts, 3, 5)
// Function as return type
func chooseStepFunction(backward: Bool) -> (Int) -> Int {
func stepForward(input: Int) -> Int { return input + 1 }
func stepBackward(input: Int) -> Int { return input - 1 }
return backward ? stepBackward : stepForward
}
let moveNearerToZero = chooseStepFunction(backward: true)
print(moveNearerToZero(5)) // 4
Funciones anidadas¶
func chooseStepFunction(backward: Bool) -> (Int) -> Int {
func stepForward(input: Int) -> Int {
return input + 1
}
func stepBackward(input: Int) -> Int {
return input - 1
}
return backward ? stepBackward : stepForward
}
var currentValue = -4
let moveNearerToZero = chooseStepFunction(backward: currentValue > 0)
while currentValue != 0 {
print("\(currentValue)... ")
currentValue = moveNearerToZero(currentValue)
}
print("zero!")
Cierre¶
Cierre básico¶
// Closure expression syntax
let numbers = [1, 2, 3, 4, 5]
// Full closure syntax
let doubled = numbers.map({ (number: Int) -> Int in
return number * 2
})
// Inferring type from context
let doubled2 = numbers.map({ number in
return number * 2
})
// Implicit returns from single-expression closures
let doubled3 = numbers.map({ number in number * 2 })
// Shorthand argument names
let doubled4 = numbers.map({ $0 * 2 })
// Trailing closure syntax
let doubled5 = numbers.map { $0 * 2 }
// Multiple trailing closures
func loadPicture(from server: String, completion: (String) -> Void, onFailure: (String) -> Void) {
// Implementation
}
loadPicture(from: "server.com") { picture in
print("Loaded: \(picture)")
} onFailure: { error in
print("Failed: \(error)")
}
Valores de captura¶
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0
func incrementer() -> Int {
runningTotal += amount
return runningTotal
}
return incrementer
}
let incrementByTen = makeIncrementer(forIncrement: 10)
print(incrementByTen()) // 10
print(incrementByTen()) // 20
print(incrementByTen()) // 30
let incrementBySeven = makeIncrementer(forIncrement: 7)
print(incrementBySeven()) // 7
print(incrementByTen()) // 40 (still independent)
Escaping Closures¶
var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
completionHandlers.append(completionHandler)
}
func someFunctionWithNonescapingClosure(closure: () -> Void) {
closure() // Called before function returns
}
class SomeClass {
var x = 10
func doSomething() {
someFunctionWithEscapingClosure { self.x = 100 }
someFunctionWithNonescapingClosure { x = 200 }
}
}
let instance = SomeClass()
instance.doSomething()
print(instance.x) // 200
completionHandlers.first?()
print(instance.x) // 100
Autoclosures¶
// Autoclosure delays evaluation
func serve(customer customerProvider: @autoclosure () -> String) {
print("Now serving \(customerProvider())!")
}
serve(customer: "Alex") // String is automatically wrapped in closure
// Autoclosure with escaping
var customerProviders: [() -> String] = []
func collectCustomerProviders(_ customerProvider: @autoclosure @escaping () -> String) {
customerProviders.append(customerProvider)
}
collectCustomerProviders("Barry")
collectCustomerProviders("Daniella")
print("Collected \(customerProviders.count) closures.")
for customerProvider in customerProviders {
print("Now serving \(customerProvider())!")
}
Clases y estructuras¶
Sintaxis básica¶
// Structure
struct Resolution {
var width = 0
var height = 0
// Computed property
var area: Int {
return width * height
}
// Method
mutating func scale(by factor: Int) {
width *= factor
height *= factor
}
}
// Class
class VideoMode {
var resolution = Resolution()
var interlaced = false
var frameRate = 0.0
var name: String?
// Initializer
init(name: String) {
self.name = name
}
// Method
func describe() -> String {
return "VideoMode: \(name ?? "Unknown")"
}
}
// Usage
var someResolution = Resolution(width: 1920, height: 1080)
print(someResolution.area) // 2073600
let someVideoMode = VideoMode(name: "HD")
someVideoMode.resolution = someResolution
someVideoMode.frameRate = 30.0
Iniciadores¶
struct Celsius {
var temperatureInCelsius: Double
// Designated initializer
init(fromFahrenheit fahrenheit: Double) {
temperatureInCelsius = (fahrenheit - 32.0) / 1.8
}
init(fromKelvin kelvin: Double) {
temperatureInCelsius = kelvin - 273.15
}
// Default initializer
init(_ celsius: Double) {
temperatureInCelsius = celsius
}
}
let boilingPointOfWater = Celsius(fromFahrenheit: 212.0)
let freezingPointOfWater = Celsius(fromKelvin: 273.15)
let bodyTemperature = Celsius(37.0)
// Class initializers
class Person {
let name: String
var age: Int
// Designated initializer
init(name: String, age: Int) {
self.name = name
self.age = age
}
// Convenience initializer
convenience init(name: String) {
self.init(name: name, age: 0)
}
}
// Failable initializers
struct Animal {
let species: String
init?(species: String) {
if species.isEmpty {
return nil
}
self.species = species
}
}
let someCreature = Animal(species: "Giraffe")
if let giraffe = someCreature {
print("An animal was initialized with a species of \(giraffe.species)")
}
Valor vs Tipos de referencia¶
// Structures are value types
struct Point {
var x = 0.0, y = 0.0
}
var point1 = Point(x: 1.0, y: 2.0)
var point2 = point1 // Copy is made
point2.x = 3.0
print(point1.x) // 1.0 (unchanged)
print(point2.x) // 3.0
// Classes are reference types
class Size {
var width = 0.0, height = 0.0
}
let size1 = Size()
size1.width = 10.0
let size2 = size1 // Same reference
size2.width = 20.0
print(size1.width) // 20.0 (changed)
print(size2.width) // 20.0
// Identity operators for reference types
if size1 === size2 {
print("size1 and size2 refer to the same instance")
}
if size1 !== size2 {
print("size1 and size2 refer to different instances")
}
Propiedades¶
Propiedades almacenadas¶
struct FixedLengthRange {
var firstValue: Int
let length: Int
// Lazy stored property
lazy var expensiveProperty: String = {
// Expensive computation
return "Computed value"
}()
}
var rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3)
rangeOfThreeItems.firstValue = 6
// Property observers
class StepCounter {
var totalSteps: Int = 0 {
willSet(newTotalSteps) {
print("About to set totalSteps to \(newTotalSteps)")
}
didSet {
if totalSteps > oldValue {
print("Added \(totalSteps - oldValue) steps")
}
}
}
}
let stepCounter = StepCounter()
stepCounter.totalSteps = 200
stepCounter.totalSteps = 360
Propiedades calculadas¶
struct Circle {
var radius: Double = 0.0
var area: Double {
get {
return Double.pi * radius * radius
}
set(newArea) {
radius = sqrt(newArea / Double.pi)
}
}
// Read-only computed property
var circumference: Double {
return 2.0 * Double.pi * radius
}
}
var circle = Circle(radius: 5.0)
print(circle.area) // 78.54
circle.area = 100.0
print(circle.radius) // 5.64
Violadores de bienes¶
@propertyWrapper
struct TwelveOrLess {
private var number = 0
var wrappedValue: Int {
get { return number }
set { number = min(newValue, 12) }
}
}
struct SmallRectangle {
@TwelveOrLess var height: Int
@TwelveOrLess var width: Int
}
var rectangle = SmallRectangle()
print(rectangle.height) // 0
rectangle.height = 10
print(rectangle.height) // 10
rectangle.height = 24
print(rectangle.height) // 12
// Property wrapper with parameters
@propertyWrapper
struct SmallNumber {
private var maximum: Int
private var number: Int
var wrappedValue: Int {
get { return number }
set { number = min(newValue, maximum) }
}
init() {
maximum = 12
number = 0
}
init(wrappedValue: Int) {
maximum = 12
number = min(wrappedValue, maximum)
}
init(wrappedValue: Int, maximum: Int) {
self.maximum = maximum
number = min(wrappedValue, maximum)
}
}
struct UnitRectangle {
@SmallNumber var height: Int = 1
@SmallNumber var width: Int = 1
}
struct NarrowRectangle {
@SmallNumber(maximum: 5) var height: Int = 2
@SmallNumber(maximum: 4) var width: Int = 3
}
Tipo¶
struct SomeStructure {
static var storedTypeProperty = "Some value."
static var computedTypeProperty: Int {
return 1
}
}
enum SomeEnumeration {
static var storedTypeProperty = "Some value."
static var computedTypeProperty: Int {
return 6
}
}
class SomeClass {
static var storedTypeProperty = "Some value."
static var computedTypeProperty: Int {
return 27
}
class var overrideableComputedTypeProperty: Int {
return 107
}
}
print(SomeStructure.storedTypeProperty) // "Some value."
print(SomeEnumeration.computedTypeProperty) // 6
print(SomeClass.overrideableComputedTypeProperty) // 107
Métodos¶
Métodos de instalación¶
class Counter {
var count = 0
func increment() {
count += 1
}
func increment(by amount: Int) {
count += amount
}
func reset() {
count = 0
}
}
let counter = Counter()
counter.increment()
counter.increment(by: 5)
print(counter.count) // 6
counter.reset()
// Mutating methods for structures
struct Point {
var x = 0.0, y = 0.0
mutating func moveBy(x deltaX: Double, y deltaY: Double) {
x += deltaX
y += deltaY
}
mutating func moveToOrigin() {
self = Point(x: 0.0, y: 0.0)
}
}
var somePoint = Point(x: 1.0, y: 1.0)
somePoint.moveBy(x: 2.0, y: 3.0)
print("Point is now at (\(somePoint.x), \(somePoint.y))")
Tipo Métodos¶
class SomeClass {
class func someTypeMethod() {
print("Type method called")
}
static func anotherTypeMethod() {
print("Static type method called")
}
}
SomeClass.someTypeMethod()
SomeClass.anotherTypeMethod()
struct LevelTracker {
static var highestUnlockedLevel = 1
var currentLevel = 1
static func unlock(_ level: Int) {
if level > highestUnlockedLevel {
highestUnlockedLevel = level
}
}
static func isUnlocked(_ level: Int) -> Bool {
return level <= highestUnlockedLevel
}
@discardableResult
mutating func advance(to level: Int) -> Bool {
if LevelTracker.isUnlocked(level) {
currentLevel = level
return true
} else {
return false
}
}
}
Herencia¶
Herencia básica¶
// Base class
class Vehicle {
var currentSpeed = 0.0
var description: String {
return "traveling at \(currentSpeed) miles per hour"
}
func makeNoise() {
// Do nothing - an arbitrary vehicle doesn't necessarily make a noise
}
}
// Subclass
class Bicycle: Vehicle {
var hasBasket = false
override var description: String {
return "Bicycle: \(super.description)"
}
}
class Tandem: Bicycle {
var currentNumberOfPassengers = 0
override var description: String {
return "Tandem: \(super.description) with \(currentNumberOfPassengers) passengers"
}
}
// Usage
let bicycle = Bicycle()
bicycle.hasBasket = true
bicycle.currentSpeed = 15.0
print(bicycle.description)
let tandem = Tandem()
tandem.currentSpeed = 22.0
tandem.currentNumberOfPassengers = 2
print(tandem.description)
Arreglo¶
class Train: Vehicle {
override func makeNoise() {
print("Choo Choo")
}
override var currentSpeed: Double {
didSet {
print("Train speed changed to \(currentSpeed)")
}
}
}
class Car: Vehicle {
var gear = 1
override var description: String {
return super.description + " in gear \(gear)"
}
override func makeNoise() {
print("Vroom Vroom")
}
}
let train = Train()
train.makeNoise() // "Choo Choo"
let car = Car()
car.currentSpeed = 25.0
car.gear = 3
print(car.description) // "traveling at 25.0 miles per hour in gear 3"
Preventing Overrides¶
class FinalVehicle {
final var maxSpeed = 100.0
final func startEngine() {
print("Engine started")
}
}
// This would cause a compile error:
// class FastCar: FinalVehicle {
// override func startEngine() { } // Error!
// }
// Final class cannot be subclassed
final class ImmutableClass {
let value = 42
}
// This would cause a compile error:
// class SubClass: ImmutableClass { } // Error!
Protocolos¶
Protocolos básicos¶
protocol SomeProtocol {
var mustBeSettable: Int { get set }
var doesNotNeedToBeSettable: Int { get }
func someMethod()
static func someTypeMethod()
}
protocol FullyNamed {
var fullName: String { get }
}
struct Person: FullyNamed {
var fullName: String
}
class Starship: FullyNamed {
var prefix: String?
var name: String
init(name: String, prefix: String? = nil) {
self.name = name
self.prefix = prefix
}
var fullName: String {
return (prefix != nil ? prefix! + " " : "") + name
}
}
let john = Person(fullName: "John Appleseed")
let ncc1701 = Starship(name: "Enterprise", prefix: "USS")
Métodos necesarios¶
protocol Togglable {
mutating func toggle()
}
enum OnOffSwitch: Togglable {
case off, on
mutating func toggle() {
switch self {
case .off:
self = .on
case .on:
self = .off
}
}
}
var lightSwitch = OnOffSwitch.off
lightSwitch.toggle() // lightSwitch is now .on
Protocolo¶
protocol InheritingProtocol: SomeProtocol {
func anotherMethod()
}
protocol PrettyTextRepresentable: CustomStringConvertible {
var prettyTextualDescription: String { get }
}
extension Person: PrettyTextRepresentable {
var description: String {
return fullName
}
var prettyTextualDescription: String {
return "Person: \(fullName)"
}
}
Protocolos sólo de clase¶
protocol SomeClassOnlyProtocol: AnyObject {
func someMethod()
}
class SomeClass: SomeClassOnlyProtocol {
func someMethod() {
print("Method implemented")
}
}
// This would cause an error:
// struct SomeStruct: SomeClassOnlyProtocol { } // Error!
Protocol Composition¶
protocol Named {
var name: String { get }
}
protocol Aged {
var age: Int { get }
}
struct PersonStruct: Named, Aged {
var name: String
var age: Int
}
func wishHappyBirthday(to celebrator: Named & Aged) {
print("Happy birthday, \(celebrator.name), you're \(celebrator.age)!")
}
let birthdayPerson = PersonStruct(name: "Malcolm", age: 21)
wishHappyBirthday(to: birthdayPerson)
Necesidades del Protocolo Facultativo¶
@objc protocol CounterDataSource {
@objc optional func increment(forCount count: Int) -> Int
@objc optional var fixedIncrement: Int { get }
}
class Counter {
var count = 0
var dataSource: CounterDataSource?
func increment() {
if let amount = dataSource?.increment?(forCount: count) {
count += amount
} else if let amount = dataSource?.fixedIncrement {
count += amount
}
}
}
```_
### Extensiones de Protocolo
```swift
extension Collection {
var isNotEmpty: Bool {
return !isEmpty
}
}
let numbers = [1, 2, 3]
print(numbers.isNotEmpty) // true
// Protocol extension with constraints
extension Collection where Element: Equatable {
func allEqual() -> Bool {
for element in self {
if element != self.first {
return false
}
}
return true
}
}
let equalNumbers = [1, 1, 1]
print(equalNumbers.allEqual()) // true
Extensiones¶
Extensiones básicas¶
extension Double {
var km: Double { return self * 1_000.0 }
var m: Double { return self }
var cm: Double { return self / 100.0 }
var mm: Double { return self / 1_000.0 }
var ft: Double { return self / 3.28084 }
}
let oneInch = 25.4.mm
print("One inch is \(oneInch) meters") // 0.0254 meters
let threeFeet = 3.ft
print("Three feet is \(threeFeet) meters") // 0.914399970739201 meters
Agregar métodos¶
extension Int {
func repetitions(task: () -> Void) {
for _ in 0..<self {
task()
}
}
mutating func square() {
self = self * self
}
}
3.repetitions {
print("Hello!")
}
var someInt = 3
someInt.square() // someInt is now 9
Añadiendo inicializadores¶
struct Size {
var width = 0.0, height = 0.0
}
struct Point {
var x = 0.0, y = 0.0
}
struct Rect {
var origin = Point()
var size = Size()
}
extension Rect {
init(center: Point, size: Size) {
let originX = center.x - (size.width / 2)
let originY = center.y - (size.height / 2)
self.init(origin: Point(x: originX, y: originY), size: size)
}
}
let centerRect = Rect(center: Point(x: 4.0, y: 4.0), size: Size(width: 3.0, height: 3.0))
Añadiendo subscriptos¶
extension Int {
subscript(digitIndex: Int) -> Int {
var decimalBase = 1
for _ in 0..<digitIndex {
decimalBase *= 10
}
return (self / decimalBase) % 10
}
}
746381295[0] // 5
746381295[1] // 9
746381295[2] // 2
746381295[8] // 7
```_
### Agregar tipos anidados
```swift
extension Int {
enum Kind {
case negative, zero, positive
}
var kind: Kind {
switch self {
case 0:
return .zero
case let x where x > 0:
return .positive
default:
return .negative
}
}
}
func printIntegerKinds(_ numbers: [Int]) {
for number in numbers {
switch number.kind {
case .negative:
print("- ", terminator: "")
case .zero:
print("0 ", terminator: "")
case .positive:
print("+ ", terminator: "")
}
}
print("")
}
printIntegerKinds([3, 19, -27, 0, -6, 0, 7]) // + + - 0 - 0 +
Genéricos¶
Funciones genéricas¶
func swapTwoValues<T>(_ a: inout T, _ b: inout T) {
let temporaryA = a
a = b
b = temporaryA
}
var someInt = 3
var anotherInt = 107
swapTwoValues(&someInt, &anotherInt)
print("someInt: \(someInt), anotherInt: \(anotherInt)")
var someString = "hello"
var anotherString = "world"
swapTwoValues(&someString, &anotherString)
print("someString: \(someString), anotherString: \(anotherString)")
Tipos genéricos¶
struct Stack<Element> {
var items: [Element] = []
mutating func push(_ item: Element) {
items.append(item)
}
mutating func pop() -> Element {
return items.removeLast()
}
var isEmpty: Bool {
return items.isEmpty
}
var count: Int {
return items.count
}
}
var stackOfStrings = Stack<String>()
stackOfStrings.push("uno")
stackOfStrings.push("dos")
stackOfStrings.push("tres")
stackOfStrings.push("cuatro")
let fromTheTop = stackOfStrings.pop() // "cuatro"
Tipo Constraints¶
func findIndex<T: Equatable>(of valueToFind: T, in array: [T]) -> Int? {
for (index, value) in array.enumerated() {
if value == valueToFind {
return index
}
}
return nil
}
let doubleIndex = findIndex(of: 9.3, in: [3.14159, 0.1, 0.25])
let stringIndex = findIndex(of: "Andrea", in: ["Mike", "Malcolm", "Andrea"])
// Generic type with multiple constraints
func allItemsMatch<C1: Container, C2: Container>(_ someContainer: C1, _ anotherContainer: C2) -> Bool
where C1.Item == C2.Item, C1.Item: Equatable {
if someContainer.count != anotherContainer.count {
return false
}
for i in 0..<someContainer.count {
if someContainer[i] != anotherContainer[i] {
return false
}
}
return true
}
Tipos asociados¶
protocol Container {
associatedtype Item
mutating func append(_ item: Item)
var count: Int { get }
subscript(i: Int) -> Item { get }
}
struct IntStack: Container {
var items: [Int] = []
mutating func push(_ item: Int) {
items.append(item)
}
mutating func pop() -> Int {
return items.removeLast()
}
// Container protocol conformance
typealias Item = Int
mutating func append(_ item: Int) {
self.push(item)
}
var count: Int {
return items.count
}
subscript(i: Int) -> Int {
return items[i]
}
}
extension Stack: Container {
// No need to declare typealias Item = Element
// Swift can infer that Element is the appropriate type for Item
mutating func append(_ item: Element) {
self.push(item)
}
subscript(i: Int) -> Element {
return items[i]
}
}
Genérico Donde Cláusulas¶
func allItemsMatch<C1: Container, C2: Container>(_ someContainer: C1, _ anotherContainer: C2) -> Bool
where C1.Item == C2.Item, C1.Item: Equatable {
if someContainer.count != anotherContainer.count {
return false
}
for i in 0..<someContainer.count {
if someContainer[i] != anotherContainer[i] {
return false
}
}
return true
}
// Extensions with generic where clauses
extension Stack where Element: Equatable {
func isTop(_ item: Element) -> Bool {
guard let topItem = items.last else {
return false
}
return topItem == item
}
}
extension Container where Item: Equatable {
func startsWith(_ item: Item) -> Bool {
return count >= 1 && self[0] == item
}
}
extension Container where Item == Double {
func average() -> Double {
var sum = 0.0
for index in 0..<count {
sum += self[index]
}
return sum / Double(count)
}
}
Manejo de errores¶
Definir errores¶
enum VendingMachineError: Error {
case invalidSelection
case insufficientFunds(coinsNeeded: Int)
case outOfStock
}
// Custom error with localized description
struct ValidationError: Error, LocalizedError {
let message: String
var errorDescription: String? {
return message
}
}
Funciones de lanzamiento¶
func canThrowErrors() throws -> String {
// Function implementation
return "Success"
}
func cannotThrowErrors() -> String {
// Function implementation
return "Success"
}
struct Item {
var price: Int
var count: Int
}
class VendingMachine {
var inventory = [
"Candy Bar": Item(price: 12, count: 7),
"Chips": Item(price: 10, count: 4),
"Pretzels": Item(price: 7, count: 11)
]
var coinsDeposited = 0
func vend(itemNamed name: String) throws {
guard let item = inventory[name] else {
throw VendingMachineError.invalidSelection
}
guard item.count > 0 else {
throw VendingMachineError.outOfStock
}
guard item.price <= coinsDeposited else {
throw VendingMachineError.insufficientFunds(coinsNeeded: item.price - coinsDeposited)
}
coinsDeposited -= item.price
var newItem = item
newItem.count -= 1
inventory[name] = newItem
print("Dispensing \(name)")
}
}
Manejo de errores¶
let vendingMachine = VendingMachine()
vendingMachine.coinsDeposited = 8
// do-catch
do {
try vendingMachine.vend(itemNamed: "Candy Bar")
} catch VendingMachineError.invalidSelection {
print("Invalid Selection.")
} catch VendingMachineError.outOfStock {
print("Out of Stock.")
} catch VendingMachineError.insufficientFunds(let coinsNeeded) {
print("Insufficient funds. Please insert an additional \(coinsNeeded) coins.")
} catch {
print("Unexpected error: \(error).")
}
// Multiple catch patterns
do {
try vendingMachine.vend(itemNamed: "Candy Bar")
} catch VendingMachineError.invalidSelection, VendingMachineError.insufficientFunds {
print("Invalid selection or insufficient funds.")
} catch {
print("Other error: \(error)")
}
// Converting errors to optional values
func someThrowingFunction() throws -> Int {
return 42
}
let x = try? someThrowingFunction()
// x is of type Int? and equals 42
let y: Int?
do {
y = try someThrowingFunction()
} catch {
y = nil
}
// Disabling error propagation
let z = try! someThrowingFunction()
// If someThrowingFunction() throws an error, you'll get a runtime error
Declaraciones de aplazamiento¶
func processFile(filename: String) throws {
let file = openFile(named: filename)
defer {
closeFile(file)
}
// Work with the file
if someCondition {
return // closeFile(file) is called here
}
if anotherCondition {
throw SomeError.errorCondition // closeFile(file) is called here too
}
// closeFile(file) is called here as well
}
// Multiple defer statements
func deferExample() {
defer { print("First defer") }
defer { print("Second defer") }
defer { print("Third defer") }
print("End of function")
}
// Output:
// End of function
// Third defer
// Second defer
// First defer
Tipo de resultado¶
enum NetworkError: Error {
case badURL
case requestFailed
case unknown
}
func fetchData(from urlString: String) -> Result<Data, NetworkError> {
guard let url = URL(string: urlString) else {
return .failure(.badURL)
}
// Simulate network request
let success = Bool.random()
if success {
return .success(Data())
} else {
return .failure(.requestFailed)
}
}
// Using Result
let result = fetchData(from: "https://example.com")
switch result {
case .success(let data):
print("Received data: \(data)")
case .failure(let error):
print("Error: \(error)")
}
// Result with map and flatMap
let transformedResult = result
.map { data in
return String(data: data, encoding: .utf8) ?? ""
}
.mapError { error in
return "Network error: \(error)"
}
Gestión de memoria¶
Conteo automático de referencia (ARC)¶
class Person {
let name: String
init(name: String) {
self.name = name
print("\(name) is being initialized")
}
deinit {
print("\(name) is being deinitialized")
}
}
var reference1: Person?
var reference2: Person?
var reference3: Person?
reference1 = Person(name: "John Appleseed")
// Prints "John Appleseed is being initialized"
reference2 = reference1
reference3 = reference1
// Strong reference count is now 3
reference1 = nil
reference2 = nil
// Strong reference count is now 1
reference3 = nil
// Strong reference count is now 0
// Prints "John Appleseed is being deinitialized"
Ciclos de referencia fuertes¶
class Person {
let name: String
init(name: String) { self.name = name }
var apartment: Apartment?
deinit { print("\(name) is being deinitialized") }
}
class Apartment {
let unit: String
init(unit: String) { self.unit = unit }
var tenant: Person?
deinit { print("Apartment \(unit) is being deinitialized") }
}
var john: Person?
var unit4A: Apartment?
john = Person(name: "John Appleseed")
unit4A = Apartment(unit: "4A")
john!.apartment = unit4A
unit4A!.tenant = john
john = nil
unit4A = nil
// Neither deinitializer is called - memory leak!
Referencias débiles¶
class Person {
let name: String
init(name: String) { self.name = name }
var apartment: Apartment?
deinit { print("\(name) is being deinitialized") }
}
class Apartment {
let unit: String
init(unit: String) { self.unit = unit }
weak var tenant: Person? // Weak reference
deinit { print("Apartment \(unit) is being deinitialized") }
}
var john: Person?
var unit4A: Apartment?
john = Person(name: "John Appleseed")
unit4A = Apartment(unit: "4A")
john!.apartment = unit4A
unit4A!.tenant = john
john = nil
// Prints "John Appleseed is being deinitialized"
print(unit4A!.tenant) // nil
unit4A = nil
// Prints "Apartment 4A is being deinitialized"
Referencias no propiedad¶
class Customer {
let name: String
var card: CreditCard?
init(name: String) {
self.name = name
}
deinit { print("\(name) is being deinitialized") }
}
class CreditCard {
let number: UInt64
unowned let customer: Customer // Unowned reference
init(number: UInt64, customer: Customer) {
self.number = number
self.customer = customer
}
deinit { print("Card #\(number) is being deinitialized") }
}
var john: Customer?
john = Customer(name: "John Appleseed")
john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)
john = nil
// Prints "John Appleseed is being deinitialized"
// Prints "Card #1234567890123456 is being deinitialized"
Ciclos de cierre y ciclos de referencia fuertes¶
class HTMLElement {
let name: String
let text: String?
lazy var asHTML: () -> String = { [unowned self] in
if let text = self.text {
return "<\(self.name)>\(text)</\(self.name)>"
} else {
return "<\(self.name) />"
}
}
init(name: String, text: String? = nil) {
self.name = name
self.text = text
}
deinit {
print("\(name) is being deinitialized")
}
}
var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world")
print(paragraph!.asHTML())
paragraph = nil
// Prints "p is being deinitialized"
// Capture list with weak reference
class SomeClass {
var value = 0
func doSomething() {
let closure = { [weak self] in
guard let self = self else { return }
print("Value: \(self.value)")
}
closure()
}
}
Concurrencia¶
Async/Await (iOS 15+)¶
// Async function
func fetchUserID(from server: String) async -> Int {
let userID = 501
return userID
}
func fetchUsername(from server: String) async -> String {
let username = "Taylor"
return username
}
// Calling async functions
func connectUser(to server: String) async {
async let userID = fetchUserID(from: server)
async let username = fetchUsername(from: server)
let greeting = await "Hello \(username), user ID \(userID)"
print(greeting)
}
// Async sequence
func fetchData() async throws -> [String] {
// Simulate network delay
try await Task.sleep(nanoseconds: 1_000_000_000)
return ["Item 1", "Item 2", "Item 3"]
}
// Using async in SwiftUI
struct ContentView: View {
@State private var data: [String] = []
var body: some View {
List(data, id: \.self) { item in
Text(item)
}
.task {
do {
data = try await fetchData()
} catch {
print("Failed to fetch data: \(error)")
}
}
}
}
Tareas¶
// Creating tasks
func performWork() async {
let task1 = Task {
return await fetchUserID(from: "server1")
}
let task2 = Task {
return await fetchUsername(from: "server2")
}
let userID = await task1.value
let username = await task2.value
print("User: \(username) (\(userID))")
}
// Task cancellation
func cancellableWork() async {
let task = Task {
for i in 1...10 {
if Task.isCancelled {
print("Task was cancelled")
return
}
print("Working on step \(i)")
try await Task.sleep(nanoseconds: 1_000_000_000)
}
}
// Cancel after 3 seconds
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
task.cancel()
}
await task.value
}
// Task groups
func fetchMultipleUsers() async -> [String] {
await withTaskGroup(of: String.self) { group in
let servers = ["server1", "server2", "server3"]
for server in servers {
group.addTask {
return await fetchUsername(from: server)
}
}
var usernames: [String] = []
for await username in group {
usernames.append(username)
}
return usernames
}
}
```_
### Actores
```swift
actor BankAccount {
private var balance: Double
init(initialBalance: Double) {
balance = initialBalance
}
func deposit(amount: Double) {
balance += amount
}
func withdraw(amount: Double) -> Bool {
if balance >= amount {
balance -= amount
return true
}
return false
}
func getBalance() -> Double {
return balance
}
}
// Using actors
func bankingExample() async {
let account = BankAccount(initialBalance: 1000)
await account.deposit(amount: 500)
let success = await account.withdraw(amount: 200)
let balance = await account.getBalance()
print("Withdrawal successful: \(success), Balance: \(balance)")
}
// MainActor for UI updates
@MainActor
class ViewModel: ObservableObject {
@Published var data: [String] = []
func loadData() async {
let newData = await fetchDataFromNetwork()
// This runs on the main actor automatically
self.data = newData
}
}
func fetchDataFromNetwork() async -> [String] {
// Network operation
return ["Data 1", "Data 2", "Data 3"]
}
AsyncSequence¶
// Custom AsyncSequence
struct Counter: AsyncSequence {
typealias Element = Int
let howHigh: Int
struct AsyncIterator: AsyncIteratorProtocol {
let howHigh: Int
var current = 1
mutating func next() async -> Int? {
guard current <= howHigh else {
return nil
}
let result = current
current += 1
return result
}
}
func makeAsyncIterator() -> AsyncIterator {
return AsyncIterator(howHigh: howHigh)
}
}
// Using AsyncSequence
func useAsyncSequence() async {
for await number in Counter(howHigh: 5) {
print(number)
}
}
// Built-in AsyncSequence operations
func processAsyncData() async {
let numbers = Counter(howHigh: 10)
let evenNumbers = numbers.filter { $0 % 2 == 0 }
let doubled = evenNumbers.map { $0 * 2 }
for await number in doubled {
print("Even doubled: \(number)")
}
}
Colecciones¶
Arrays¶
// Array creation
var someInts: [Int] = []
var threeDoubles = Array(repeating: 0.0, count: 3)
var anotherThreeDoubles = Array(repeating: 2.5, count: 3)
var sixDoubles = threeDoubles + anotherThreeDoubles
// Array literals
var shoppingList: [String] = ["Eggs", "Milk"]
var shoppingList2 = ["Eggs", "Milk"] // Type inferred
// Array operations
shoppingList.append("Flour")
shoppingList += ["Baking Powder"]
shoppingList += ["Chocolate Spread", "Cheese", "Butter"]
let firstItem = shoppingList[0]
shoppingList[0] = "Six eggs"
shoppingList[4...6] = ["Bananas", "Apples"]
shoppingList.insert("Maple Syrup", at: 0)
let mapleSyrup = shoppingList.remove(at: 0)
let apples = shoppingList.removeLast()
// Array iteration
for item in shoppingList {
print(item)
}
for (index, value) in shoppingList.enumerated() {
print("Item \(index + 1): \(value)")
}
// Array methods
let numbers = [1, 2, 3, 4, 5]
let doubled = numbers.map { $0 * 2 }
let evens = numbers.filter { $0 % 2 == 0 }
let sum = numbers.reduce(0, +)
let first = numbers.first
let last = numbers.last
let contains = numbers.contains(3)
Sets¶
// Set creation
var letters = Set<Character>()
var favoriteGenres: Set<String> = ["Rock", "Classical", "Hip hop"]
// Set operations
favoriteGenres.insert("Jazz")
if let removedGenre = favoriteGenres.remove("Rock") {
print("\(removedGenre)? I'm over it.")
} else {
print("I never much cared for that.")
}
if favoriteGenres.contains("Funk") {
print("I get up on the good foot.")
} else {
print("It's too funky in here.")
}
// Set iteration
for genre in favoriteGenres {
print("\(genre)")
}
for genre in favoriteGenres.sorted() {
print("\(genre)")
}
// Set operations
let oddDigits: Set = [1, 3, 5, 7, 9]
let evenDigits: Set = [0, 2, 4, 6, 8]
let singleDigitPrimeNumbers: Set = [2, 3, 5, 7]
let union = oddDigits.union(evenDigits).sorted()
let intersection = oddDigits.intersection(evenDigits).sorted()
let subtracting = oddDigits.subtracting(singleDigitPrimeNumbers).sorted()
let symmetricDifference = oddDigits.symmetricDifference(singleDigitPrimeNumbers).sorted()
// Set membership and equality
let houseAnimals: Set = ["🐶", "🐱"]
let farmAnimals: Set = ["🐮", "🐔", "🐑", "🐶", "🐱"]
let cityAnimals: Set = ["🐦", "🐭"]
houseAnimals.isSubset(of: farmAnimals) // true
farmAnimals.isSuperset(of: houseAnimals) // true
farmAnimals.isDisjoint(with: cityAnimals) // true
Diccionarios¶
// Dictionary creation
var namesOfIntegers: [Int: String] = [:]
var airports: [String: String] = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
var airports2 = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
// Dictionary operations
airports["LHR"] = "London"
airports["LHR"] = "London Heathrow"
if let oldValue = airports.updateValue("Dublin Airport", forKey: "DUB") {
print("The old value for DUB was \(oldValue).")
}
if let airportName = airports["DUB"] {
print("The name of the airport is \(airportName).")
} else {
print("That airport is not in the airports dictionary.")
}
airports["APL"] = "Apple International"
airports["APL"] = nil
if let removedValue = airports.removeValue(forKey: "DUB") {
print("The removed airport's name is \(removedValue).")
} else {
print("The airports dictionary does not contain a value for DUB.")
}
// Dictionary iteration
for (airportCode, airportName) in airports {
print("\(airportCode): \(airportName)")
}
for airportCode in airports.keys {
print("Airport code: \(airportCode)")
}
for airportName in airports.values {
print("Airport name: \(airportName)")
}
let airportCodes = [String](airports.keys)
let airportNames = [String](airports.values)
Facultativos¶
Fundamentos opcionales¶
// Optional declaration
var optionalString: String? = "Hello"
var optionalInt: Int? = nil
// Optional binding
if let actualString = optionalString {
print("The string is \(actualString)")
} else {
print("The string is nil")
}
// Multiple optional binding
if let string = optionalString, let int = optionalInt {
print("Both values exist: \(string), \(int)")
}
// Guard statement
func processOptional(_ value: String?) {
guard let unwrappedValue = value else {
print("Value is nil")
return
}
print("Processing: \(unwrappedValue)")
}
// Nil coalescing operator
let defaultName = "Anonymous"
let username = optionalString ?? defaultName
// Optional chaining
class Person {
var residence: Residence?
}
class Residence {
var numberOfRooms = 1
}
let john = Person()
if let roomCount = john.residence?.numberOfRooms {
print("John's residence has \(roomCount) room(s).")
} else {
print("Unable to retrieve the number of rooms.")
}
john.residence = Residence()
if let roomCount = john.residence?.numberOfRooms {
print("John's residence has \(roomCount) room(s).")
}
Opcionales implícitamente desenfundados¶
let possibleString: String? = "An optional string."
let forcedString: String = possibleString! // Requires an exclamation point
let assumedString: String! = "An implicitly unwrapped optional string."
let implicitString: String = assumedString // No need for an exclamation point
// Still can be treated as optional
if assumedString != nil {
print(assumedString!)
}
if let definiteString = assumedString {
print(definiteString)
}
Mapa opcional y FlatMap¶
let possibleNumber = "123"
let convertedNumber = Int(possibleNumber)
// Optional map
let doubled = convertedNumber.map { $0 * 2 }
print(doubled) // Optional(246)
// Optional flatMap
func doubleIfEven(_ number: Int) -> Int? {
return number % 2 == 0 ? number * 2 : nil
}
let result = convertedNumber.flatMap(doubleIfEven)
print(result) // nil (because 123 is odd)
// Chaining optionals
let numbers = ["1", "2", "three", "4"]
let validNumbers = numbers.compactMap { Int($0) }
print(validNumbers) // [1, 2, 4]
Buenas prácticas¶
Code Style¶
// Use meaningful names
var userAge = 25 // Good
var a = 25 // Bad
func calculateTotalPrice() -> Double // Good
func calc() -> Double // Bad
// Use type inference when possible
let name = "John" // Good
let name: String = "John" // Unnecessary
// Use guard for early returns
func processUser(_ user: User?) {
guard let user = user else { return }
guard user.isActive else { return }
// Process user
}
// Use trailing closures
numbers.map { $0 * 2 } // Good
numbers.map({ $0 * 2 }) // Less preferred
// Use computed properties for simple calculations
struct Circle {
var radius: Double
var area: Double { // Good
return .pi * radius * radius
}
func getArea() -> Double { // Less preferred
return .pi * radius * radius
}
}
Ejecución¶
// Use lazy properties for expensive computations
class DataProcessor {
lazy var expensiveData: [String] = {
// Expensive computation
return processLargeDataSet()
}()
private func processLargeDataSet() -> [String] {
// Implementation
return []
}
}
// Use value types when possible
struct Point { // Good - value type
var x: Double
var y: Double
}
class PointClass { // Use only when reference semantics needed
var x: Double
var y: Double
init(x: Double, y: Double) {
self.x = x
self.y = y
}
}
// Use copy-on-write for large value types
struct LargeDataStructure {
private var _data: NSMutableArray
private var data: NSMutableArray {
mutating get {
if !isKnownUniquelyReferenced(&_data) {
_data = _data.mutableCopy() as! NSMutableArray
}
return _data
}
}
init() {
_data = NSMutableArray()
}
}
Manejo de errores¶
// Use specific error types
enum ValidationError: Error {
case emptyInput
case invalidFormat
case tooShort(minimumLength: Int)
case tooLong(maximumLength: Int)
}
// Provide meaningful error messages
extension ValidationError: LocalizedError {
var errorDescription: String? {
switch self {
case .emptyInput:
return "Input cannot be empty"
case .invalidFormat:
return "Input format is invalid"
case .tooShort(let minimumLength):
return "Input must be at least \(minimumLength) characters"
case .tooLong(let maximumLength):
return "Input cannot exceed \(maximumLength) characters"
}
}
}
// Use Result type for better error handling
func validateInput(_ input: String) -> Result<String, ValidationError> {
guard !input.isEmpty else {
return .failure(.emptyInput)
}
guard input.count >= 3 else {
return .failure(.tooShort(minimumLength: 3))
}
return .success(input)
}
Gestión de memoria¶
// Use weak references to avoid retain cycles
class Parent {
var children: [Child] = []
func addChild(_ child: Child) {
child.parent = self
children.append(child)
}
}
class Child {
weak var parent: Parent?
}
// Use capture lists in closures
class ViewController {
var completion: (() -> Void)?
func setupCompletion() {
completion = { [weak self] in
self?.dismiss()
}
}
func dismiss() {
// Implementation
}
}
// Use unowned when reference will never be nil
class Customer {
let name: String
var card: CreditCard?
init(name: String) {
self.name = name
}
}
class CreditCard {
let number: UInt64
unowned let customer: Customer
init(number: UInt64, customer: Customer) {
self.number = number
self.customer = customer
}
}
-...
Resumen¶
Swift es un lenguaje de programación potente y moderno diseñado para la seguridad, el rendimiento y la expresividad. Las características principales incluyen:
- ** Seguridad del tipo**: El sistema de tipo fuerte previene muchos errores comunes de programación
- ** Seguridad de memoria**: Conteo automático de referencia (ARC) administra la memoria automáticamente
- Performance: Lenguaje compilado con optimizaciones para velocidad
- Expresividad: Sintaxis limpia y legible que es fácil de aprender y mantener
- Interoperabilidad: Integración sin costuras con bibliotecas Objetivo-C y C
- Características modernas: Opcionales, genéricos, cierres y programación orientada al protocolo
- Concurrencia: Modelo integrado de asinc/await y actor para una programación concurrente segura
- Open Source: Disponible en múltiples plataformas más allá del ecosistema de Apple
Swift combina el rendimiento y la eficiencia de los lenguajes compilados con la simplicidad e interactividad de los lenguajes de scripting populares, lo que lo convierte en una excelente opción para iOS, macOS, watchOS, tvOS y desarrollo del lado servidor.
" copia de la funciónToClipboard() {} comandos const = document.querySelectorAll('code'); que todos losCommands = '; comandos. paraCada(cmd = confianza allCommands += cmd.textContent + '\n'); navigator.clipboard.writeText(allCommands); alerta ('Todos los comandos copiados a portapapeles!'); }
función generaPDF() { ventana.print(); } ■/script título