1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
|
---
language: swift
contributors:
- ["Grant Timmerman", "http://github.com/grant"]
- ["Christopher Bess", "http://github.com/cbess"]
- ["Joey Huang", "http://github.com/kamidox"]
- ["Anthony Nguyen", "http://github.com/anthonyn60"]
translators:
- ["David Hsieh", "http://github.com/deivuh"]
lang: es-es
filename: learnswift-es.swift
---
Swift es un lenguaje de programación para el desarrollo en iOS y OS X creado
por Apple. Diseñado para coexistir con Objective-C y ser más resistente contra
el código erroneo, Swift fue introducido en el 2014 en el WWDC, la conferencia
de desarrolladores de Apple.
Véase también la guía oficial de Apple, [getting started guide](https://developer.apple.com/library/prerelease/ios/referencelibrary/GettingStarted/DevelopiOSAppsSwift/), el cual tiene un completo tutorial de Swift.
```swift
// Importar un módulo
import UIKit
//
// MARK: Básicos
//
// XCode soporta referencias para anotar tu código y agregarlos a lista de la
// barra de saltos.
// MARK: Marca de sección
// TODO: Hacer algo pronto
// FIXME: Arreglar este código
// En Swift 2, println y print fueron combinados en un solo método print.
// Print añade una nueva línea automáticamente.
print("Hola, mundo") // println ahora es print
print("Hola, mundo", appendNewLine: false) // print sin agregar nueva línea
// Valores de variables (var) pueden cambiar después de ser asignados
// Valores de constrantes (let) no pueden cambiarse después de ser asignados
var myVariable = 42
let øπΩ = "value" // nombres de variable unicode
let π = 3.1415926
let convenience = "keyword" // nombre de variable contextual
// Las declaraciones pueden ser separadas por punto y coma (;)
let weak = "keyword"; let override = "another keyword"
// Los acentos abiertos (``) permiten utilizar palabras clave como nombres de
// variable
let `class` = "keyword"
let explicitDouble: Double = 70
let intValue = 0007 // 7
let largeIntValue = 77_000 // 77000
let label = "some text " + String(myVariable) // Conversión (casting)
let piText = "Pi = \(π), Pi 2 = \(π * 2)" // Interpolación de string
// Valores específicos de la compilación (build)
// utiliza la configuración -D
#if false
print("No impreso")
let buildValue = 3
#else
let buildValue = 7
#endif
print("Build value: \(buildValue)") // Build value: 7
/*
Las opcionales son un aspecto del lenguaje Swift que permite el
almacenamiento de un valor `Some` (algo) o `None` (nada).
Debido a que Swift requiere que cada propiedad tenga un valor,
hasta un valor 'nil' debe de ser explicitamente almacenado como un
valor opcional.
Optional<T> es un enum.
*/
var someOptionalString: String? = "opcional" // Puede ser nil
// Al igual que lo anterior, pero ? es un operador postfix (sufijo)
var someOptionalString2: Optional<String> = "opcional"
if someOptionalString != nil {
// No soy nil
if someOptionalString!.hasPrefix("opt") {
print("Tiene el prefijo")
}
let empty = someOptionalString?.isEmpty
}
someOptionalString = nil
// Opcional implícitamente desenvuelto
var unwrappedString: String! = "Un valor esperado."
// Al igual que lo anterior, pero ! es un operador postfix (sufijo)
var unwrappedString2: ImplicitlyUnwrappedOptional<String> = "Un valor esperado."
if let someOptionalStringConstant = someOptionalString {
// tiene valor `Some` (algo), no nil
if !someOptionalStringConstant.hasPrefix("ok") {
// No tiene el prefijo
}
}
// Swift tiene soporte de almacenamiento para cualquier tipo de valor.
// AnyObject == id
// A diferencia de Objective-C `id`, AnyObject funciona con cualquier
// valor (Class, Int, struct, etc)
var anyObjectVar: AnyObject = 7
anyObjectVar = "Cambiado a un valor string, no es buena práctica, pero posible."
/*
Comentar aquí
/*
Comentarios anidados también son soportados
*/
*/
//
// MARK: Colecciones
//
/*
Tipos Array (arreglo) y Dictionary (diccionario) son structs (estructuras).
Así que `let` y `var` también indican si son mudables (var) o
inmutables (let) durante la declaración de sus tipos.
*/
// Array (arreglo)
var shoppingList = ["catfish", "water", "lemons"]
shoppingList[1] = "bottle of water"
let emptyArray = [String]() // let == inmutable
let emptyArray2 = Array<String>() // igual que lo anterior
var emptyMutableArray = [String]() // var == mudable
// Dictionary (diccionario)
var occupations = [
"Malcolm": "Captain",
"kaylee": "Mechanic"
]
occupations["Jayne"] = "Public Relations"
let emptyDictionary = [String: Float]() // let == inmutable
let emptyDictionary2 = Dictionary<String, Float>() // igual que lo anterior
var emptyMutableDictionary = [String: Float]() // var == mudable
//
// MARK: Flujo de control
//
// Ciclo for (array)
let myArray = [1, 1, 2, 3, 5]
for value in myArray {
if value == 1 {
print("Uno!")
} else {
print("No es uno!")
}
}
// Ciclo for (dictionary)
var dict = ["uno": 1, "dos": 2]
for (key, value) in dict {
print("\(key): \(value)")
}
// Ciclo for (range)
for i in -1...shoppingList.count {
print(i)
}
shoppingList[1...2] = ["steak", "peacons"]
// Utilizar ..< para excluir el último valor
// Ciclo while
var i = 1
while i < 1000 {
i *= 2
}
// Ciclo do-while
do {
print("Hola")
} while 1 == 2
// Switch
// Muy potente, se puede pensar como declaraciones `if` con _azúcar sintáctico_
// Soportan String, instancias de objetos, y primitivos (Int, Double, etc)
let vegetable = "red pepper"
switch vegetable {
case "celery":
let vegetableComment = "Add some raisins and make ants on a log."
case "cucumber", "watercress":
let vegetableComment = "That would make a good tea sandwich."
case let localScopeValue where localScopeValue.hasSuffix("pepper"):
let vegetableComment = "Is it a spicy \(localScopeValue)?"
default: // obligatorio (se debe cumplir con todos los posibles valores de entrada)
let vegetableComment = "Everything tastes good in soup."
}
//
// MARK: Funciones
//
// Funciones son un tipo de primera-clase, quiere decir que pueden ser anidados
// en funciones y pueden ser pasados como parámetros
// Función en documentación de cabeceras Swift (formato reStructedText)
/**
Una operación de saludo
- Una viñeta en la documentación
- Otra viñeta en la documentación
:param: name Un nombre
:param: day Un día
:returns: Un string que contiene el valor de name y day
*/
func greet(name: String, day: String) -> String {
return "Hola \(name), hoy es \(day)."
}
greet("Bob", "Martes")
// Similar a lo anterior, a excepción del compartamiento de los parámetros
// de la función
func greet2(requiredName: String, externalParamName localParamName: String) -> String {
return "Hola \(requiredName), hoy es el día \(localParamName)"
}
greet2(requiredName:"John", externalParamName: "Domingo")
// Función que devuelve múltiples valores en una tupla
func getGasPrices() -> (Double, Double, Double) {
return (3.59, 3.69, 3.79)
}
let pricesTuple = getGasPrices()
let price = pricesTuple.2 // 3.79
// Ignorar tupla (u otros) valores utilizando _ (guión bajo)
let (_, price1, _) = pricesTuple // price1 == 3.69
print(price1 == pricesTuple.1) // true
print("Gas price: \(price)")
// Cantidad variable de argumentos
func setup(numbers: Int...) {
// Es un arreglo
let number = numbers[0]
let argCount = numbers.count
}
// Pasando y devolviendo funciones
func makeIncrementer() -> (Int -> Int) {
func addOne(number: Int) -> Int {
return 1 + number
}
return addOne
}
var increment = makeIncrementer()
increment(7)
// Pasando como referencia
func swapTwoInts(inout a: Int, inout b: Int) {
let tempA = a
a = b
b = tempA
}
var someIntA = 7
var someIntB = 3
swapTwoInts(&someIntA, &someIntB)
print(someIntB) // 7
//
// MARK: Closures (Clausuras)
//
var numbers = [1, 2, 6]
// Las funciones son un caso especial de closure ({})
// Ejemplo de closure.
// `->` Separa los argumentos del tipo de retorno
// `in` Separa la cabecera del cuerpo del closure
numbers.map({
(number: Int) -> Int in
let result = 3 * number
return result
})
// Cuando se conoce el tipo, como en lo anterior, se puede hacer esto
numbers = numbers.map({ number in 3 * number })
// o esto
//numbers = numbers.map({ $0 * 3 })
print(numbers) // [3, 6, 18]
// Closure restante
numbers = sorted(numbers) { $0 > $1 }
print(numbers) // [18, 6, 3]
// Bastante corto, debido a que el operador < infiere los tipos
numbers = sorted(numbers, < )
print(numbers) // [3, 6, 18]
//
// MARK: Estructuras
//
// Las estructuras y las clases tienen capacidades similares
struct NamesTable {
let names = [String]()
// Subscript personalizado
subscript(index: Int) -> String {
return names[index]
}
}
// Las estructuras tienen un inicializador designado autogenerado (implícitamente)
let namesTable = NamesTable(names: ["Me", "Them"])
let name = namesTable[1]
print("Name is \(name)") // Name is Them
//
// MARK: Clases
//
// Las clases, las estructuras y sus miembros tienen tres niveles de control de acceso
// Éstos son: internal (predeterminado), public, private
public class Shape {
public func getArea() -> Int {
return 0;
}
}
// Todos los métodos y las propiedades de una clase son public (públicas)
// Si solo necesitas almacenar datos en un objecto estructurado,
// debes de utilizar `struct`
internal class Rect: Shape {
var sideLength: Int = 1
// Getter y setter personalizado
private var perimeter: Int {
get {
return 4 * sideLength
}
set {
// `newValue` es una variable implícita disponible para los setters
sideLength = newValue / 4
}
}
// Lazily loading (inicialización bajo demanda) a una propiedad
// subShape queda como nil (sin inicializar) hasta que getter es llamado
lazy var subShape = Rect(sideLength: 4)
// Si no necesitas un getter y setter personalizado
// pero aún quieres ejecutar código antes y después de hacer get o set
// a una propiedad, puedes utilizar `willSet` y `didSet`
var identifier: String = "defaultID" {
// El argumento `willSet` será el nombre de variable para el nuevo valor
willSet(someIdentifier) {
print(someIdentifier)
}
}
init(sideLength: Int) {
self.sideLength = sideLength
// Siempre poner super.init de último al momento de inicializar propiedades
// personalizadas
super.init()
}
func shrink() {
if sideLength > 0 {
sideLength -= 1
}
}
override func getArea() -> Int {
return sideLength * sideLength
}
}
// Una clase simple `Square` que extiende de `Rect`
class Square: Rect {
convenience init() {
self.init(sideLength: 5)
}
}
var mySquare = Square()
print(mySquare.getArea()) // 25
mySquare.shrink()
print(mySquare.sideLength) // 4
// Conversión de tipo de instancia
let aShape = mySquare as Shape
// Comparar instancias, no es igual a == que compara objetos (equal to)
if mySquare === mySquare {
print("Yep, it's mySquare")
}
// Inicialización (init) opcional
class Circle: Shape {
var radius: Int
override func getArea() -> Int {
return 3 * radius * radius
}
// Un signo de interrogación como sufijo después de `init` es un init opcional
// que puede devolver nil
init?(radius: Int) {
self.radius = radius
super.init()
if radius <= 0 {
return nil
}
}
}
var myCircle = Circle(radius: 1)
print(myCircle?.getArea()) // Optional(3)
print(myCircle!.getArea()) // 3
var myEmptyCircle = Circle(radius: -1)
print(myEmptyCircle?.getArea()) // "nil"
if let circle = myEmptyCircle {
// no será ejecutado debido a que myEmptyCircle es nil
print("circle is not nil")
}
//
// MARK: Enums
//
// Los enums pueden ser opcionalmente de un tipo específico o de su propio tipo
// Al igual que las clases, pueden contener métodos
enum Suit {
case Spades, Hearts, Diamonds, Clubs
func getIcon() -> String {
switch self {
case .Spades: return "♤"
case .Hearts: return "♡"
case .Diamonds: return "♢"
case .Clubs: return "♧"
}
}
}
// Los valores de enum permite la sintaxis corta, sin necesidad de poner
// el tipo del enum cuando la variable es declarada de manera explícita
var suitValue: Suit = .Hearts
// Enums de tipo no-entero requiere asignaciones de valores crudas directas
enum BookName: String {
case John = "John"
case Luke = "Luke"
}
print("Name: \(BookName.John.rawValue)")
// Enum con valores asociados
enum Furniture {
// Asociación con Int
case Desk(height: Int)
// Asociación con String e Int
case Chair(String, Int)
func description() -> String {
switch self {
case .Desk(let height):
return "Desk with \(height) cm"
case .Chair(let brand, let height):
return "Chair of \(brand) with \(height) cm"
}
}
}
var desk: Furniture = .Desk(height: 80)
print(desk.description()) // "Desk with 80 cm"
var chair = Furniture.Chair("Foo", 40)
print(chair.description()) // "Chair of Foo with 40 cm"
//
// MARK: Protocolos
//
// `protocol` puede requerir que los tipos tengan propiedades
// de instancia específicas, métodos de instancia, métodos de tipo,
// operadores, y subscripts
protocol ShapeGenerator {
var enabled: Bool { get set }
func buildShape() -> Shape
}
// Protocolos declarados con @objc permiten funciones opcionales,
// que te permite evaluar conformidad
@objc protocol TransformShape {
optional func reshaped()
optional func canReshape() -> Bool
}
class MyShape: Rect {
var delegate: TransformShape?
func grow() {
sideLength += 2
// Pon un signo de interrogación después de la propiedad opcional,
// método, o subscript para ignorar un valor nil y devolver nil
// en lugar de tirar un error de tiempo de ejecución
// ("optional chaining")
if let allow = self.delegate?.canReshape?() {
// test for delegate then for method
self.delegate?.reshaped?()
}
}
}
//
// MARK: Otros
//
// `extension`: Agrega funcionalidades a tipos existentes
// Square ahora se "conforma" al protocolo `Printable`
extension Square: Printable {
var description: String {
return "Area: \(self.getArea()) - ID: \(self.identifier)"
}
}
print("Square: \(mySquare)")
// También puedes hacer extend a tipos prefabricados (built-in)
extension Int {
var customProperty: String {
return "This is \(self)"
}
func multiplyBy(num: Int) -> Int {
return num * self
}
}
print(7.customProperty) // "This is 7"
print(14.multiplyBy(3)) // 42
// Generics: Similar Java y C#. Utiliza la palabra clave `where` para
// especificar los requerimientos de los genéricos.
func findIndex<T: Equatable>(array: [T], valueToFind: T) -> Int? {
for (index, value) in enumerate(array) {
if value == valueToFind {
return index
}
}
return nil
}
let foundAtIndex = findIndex([1, 2, 3, 4], 3)
print(foundAtIndex == 2) // true
// Operadores:
// Operadores personalizados puede empezar con los siguientes caracteres:
// / = - + * % < > ! & | ^ . ~
// o
// Caracteres unicode: math, symbol, arrow, dingbat, y line/box.
prefix operator !!! {}
// Un operador prefix que triplica la longitud del lado cuando es utilizado
prefix func !!! (inout shape: Square) -> Square {
shape.sideLength *= 3
return shape
}
// Valor actual
print(mySquare.sideLength) // 4
// Cambiar la longitud del lado utilizando el operador !!!,
// incrementa el tamaño por 3
!!!mySquare
print(mySquare.sideLength) // 12
```
|