Está en la página 1de 384

Acerca de Swift

NOTA
Para obtener la documentación preliminar de una futura actualización de la lengua
Swift, ver El Swift Lenguaje de Programación .

Swift es un nuevo lenguaje de programación para iOS y OS X aplicaciones que se basa


en la mejor de C y Objective-C, sin las limitaciones de compatibilidad C. Swift adopta
patrones de programación seguras y añade características modernas para hacer la
programación más fácil, más flexible y más divertido. Borrón y cuenta nueva de Swift,
respaldadas por los maduros y los marcos de cacao y cacao Touch muy querida, es una
oportunidad para re-imaginar cómo funciona el desarrollo de software.
Swift ha estado años en la fabricación. Manzana sentó las bases de Swift por el avance
de nuestro compilador, depurador, y la infraestructura marco existente. Hemos
simplificado la gestión de memoria con el recuento de referencias automático
(ARC). Nuestra pila marco, construido sobre la base sólida de la Fundación y el Cacao,
se ha modernizado y estandarizada en todo. Objective-C en sí ha evolucionado para
soportar bloques, literales colección, y los módulos, lo que permite la adopción marco
de las tecnologías lingüísticas modernas sin interrupciones. Gracias a este trabajo
preliminar, ahora podemos introducir un nuevo lenguaje para el futuro del desarrollo de
software de Apple.
Swift se siente familiar para los desarrolladores de Objective-C. Adopta la legibilidad
de los parámetros con nombre de Objective-C y el poder del modelo de objeto dinámico
de Objective-C. Proporciona un acceso transparente a los marcos existentes de cacao y
mezclar y combinar la interoperabilidad con código de Objective-C. La construcción de
esta base común, Swift introduce muchas nuevas características y unifica las partes
procesales y orientados a objetos del lenguaje.
Swift es amigable para los nuevos programadores. Es el primer lenguaje de
programación de sistemas de calidad industrial que es tan expresiva y agradable como
un lenguaje de script. Es compatible con juegos infantiles, una característica innovadora
que permite a los programadores para experimentar con el código Swift y ver los
resultados inmediatamente, sin la sobrecarga de la creación y ejecución de una
aplicación.
Swift combina lo mejor del pensamiento lengua moderna con la sabiduría de la cultura
de ingeniería de Apple en general. El compilador está optimizado para el rendimiento, y
el idioma se ha optimizado para el desarrollo, sin comprometer a ambos. Está diseñado
para escalar de "hola, mundo" a todo un sistema operativo. Todo esto hace que Swift
una inversión de futuro sólido para los desarrolladores y para Apple.
Swift es una fantástica manera de escribir iOS y OS X aplicaciones, y seguirá
evolucionando con nuevas características y capacidades. Nuestras metas para Swift son
ambiciosos. No podemos esperar a ver lo que creas con él.
 

A Swift tour

  1  
La tradición sugiere que el primer programa en un nuevo idioma debe imprimir las
palabras "Hola, mundo!" En la pantalla. En Swift, esto se puede hacer en una sola línea:
• println ( "Hola, mundo!" )  
Si ha escrito código en C o Objective-C, esta sintaxis se parece familiar a usted-en
Swift, esta línea de código es un programa completo. No es necesario importar una
biblioteca independiente para la funcionalidad como de entrada / salida o manejo de
cadenas. El código escrito en el ámbito mundial se utiliza como punto de entrada para el
programa, por lo que no es necesario un principal función. También no es necesario
escribir un punto y coma al final de cada sentencia.
Este tour le da suficiente información para empezar a escribir código en Swift
mostrando cómo lograr una variedad de tareas de programación. No se preocupe si
usted no entiende algo, todo lo presentado en este tour se explica en detalle en el resto
de este libro.
NOTA
Para una mejor experiencia, abra este capítulo como un parque infantil en
Xcode. Parques infantiles permiten editar los listados de código y ver el resultado
inmediatamente.
Descargar juegos
Los valores simples
Utilice dejar de hacer una constante y var para hacer una variable. El valor de una
constante no necesita ser conocido en tiempo de compilación, pero usted debe asignarle
un valor exactamente una vez. Esto significa que puede usar constantes para nombrar un
valor que se determina una vez, pero utiliza en muchos lugares.
• var myVariable = 42
• myVariable = 50
• let myConstant = 42
Una constante o variable deben tener el mismo tipo que el valor que se desea asignar a
la misma. Sin embargo, no siempre se tiene que escribir el tipo
explícitamente. Proporcionar un valor cuando se crea una constante o variable permite
al compilador deducir su tipo. En el ejemplo anterior, el compilador infiere
quemyVariable es un número entero debido a que su valor inicial es un número
entero.
Si el valor inicial no proporciona suficiente información (o si no hay valor inicial),
especificar el tipo de escritura que después de la variable, separados por dos puntos.
• let implicitInteger = 70
• let implicitDouble = 70.0
• let explicitDouble: Double = 70
EXPERIMENTO
Crear una constante con un tipo explícito de flotador y un valor de 4 .
Los valores no se convierten implícitamente a otro tipo. Si usted necesita para convertir
un valor a un tipo diferente, hacer explícita una instancia del tipo deseado.
• let label = "The width is "
• let width = 94

  2  
let widthLabel = label + String(width)

EXPERIMENTO
Trate de no incluir la conversión a la Cadena de la última línea. ¿Qué error Qué se
obtiene?
Hay una manera aún más fácil de incluir valores en cadenas: Escriba el valor entre
paréntesis, y escribir una barra invertida ( \ ) antes del paréntesis. Por ejemplo:
• let apples = 3
• let oranges = 5
• let appleSummary = "I have \(apples) apples."
• let fruitSummary = "I have \(apples + oranges) pieces of fruit."
EXPERIMENTO
Use \ () para incluir un cálculo de punto flotante en una cadena y que incluya el
nombre de alguien en un saludo.
Crear matrices y diccionarios utilizando corchetes ( [] ), y acceder a sus elementos por
escribir el índice o la clave entre corchetes.
• var shoppingList = ["catfish", "water", "tulips", "blue paint"]
• shoppingList[1] = "bottle of water"

• var occupations = [
• "Malcolm": "Captain",
• "Kaylee": "Mechanic",
• ]
• occupations["Jayne"] = "Public Relations"
Para crear una matriz vacía o diccionario, utilice la sintaxis de inicializador.
• let emptyArray = [String]()
• let emptyDictionary = [String: Float]()
Si la información de tipo se puede inferir, puede escribir una matriz vacía como [] y un
diccionario vacío como[:] ; por ejemplo, cuando se establece un nuevo valor para una
variable o pasar un argumento a una función.
• shoppingList = []
• occupations = [:]
Control de flujo
Utilice si y cambiar para hacer los condicionales, y utilizar para -
en , para , mientras , y hacer - mientras quepara hacer bucles. Los
paréntesis alrededor de la variable de condición o bucle son opcionales. Se requieren los
apoyos de todo el cuerpo.
• let individualScores = [75, 43, 103, 87, 12]
• var teamScore = 0
• for score in individualScores {
• if score > 50 {

  3  
• teamScore += 3
• } else {
• teamScore += 1
• }
• }
• teamScore
NOTA
En el código anterior, teamScore se escribe en una línea por sí mismo. Esta es una
manera simple de ver el valor de una variable dentro de un parque infantil.
En un caso de declaración, la condición debe ser una expresión-este Booleano
significa que el código comosi la puntuación {...} es un error, no una
comparación implícita a cero.
Usted puede utilizar si y dejar juntos para trabajar con valores que pudieran
faltar. Estos valores se representan como opcionales. Un valor opcional o bien contiene
un valor o contiene cero para indicar que el valor no está presente. Escriba un signo de
interrogación ( ? ) después de que el tipo de un valor para marcar el valor como
opcional.
• var optionalString: String? = "Hello"
• optionalString == nil

• var optionalName: String? = "John Appleseed"
• var greeting = "Hello!"
• if let name = optionalName {
• greeting = "Hello, \(name)"
• }
EXPERIMENTO
Cambie optionalName a nil . Lo saludo Qué se obtiene? Añadir
una cosa cláusula que establece un saludo diferente si optionalName es nula .
Si el valor opcional es nula , el condicional es falsa y el código entre llaves se
omite. De lo contrario, el valor opcional se desenvuelve y se asigna a la constante
después de let , lo que hace que el valor envolver disponible dentro del bloque de
código.
Switches soportan cualquier tipo de datos y una amplia variedad de operaciones de
comparación-que no se limitan a números enteros y las pruebas para la igualdad.
• 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."

  4  
• case let x where x.hasSuffix("pepper"):
• let vegetableComment = "Is it a spicy \(x)?"
• default:
• let vegetableComment = "Everything tastes good in soup."
• }
EXPERIMENTO
Trate de no incluir el caso por defecto. ¿Qué error Qué se obtiene?
Nótese cómo dejar que se puede utilizar en un patrón para asignar el valor que
coincide con esa parte de un patrón a una constante.
Después de ejecutar el código dentro de la caja del interruptor que hacía juego, el
programa sale de la sentencia switch. Ejecución no continúa al siguiente caso, lo que no
hay necesidad de romper explícitamente del interruptor al final del código de cada caso.
Se utiliza para - en iterar sobre los elementos de un diccionario, proporcionando un
par de nombres a utilizar para cada par clave-valor. Los diccionarios son una colección
desordenada, por lo que sus claves y valores se repiten a lo largo en un orden arbitrario.
• let interestingNumbers = [
• "Prime": [2, 3, 5, 7, 11, 13],
• "Fibonacci": [1, 1, 2, 3, 5, 8],
• "Square": [1, 4, 9, 16, 25],
• ]
• var largest = 0
• for (kind, numbers) in interestingNumbers {
• for number in numbers {
• if number > largest {
• largest = number
• }
• }
• }
• largest
EXPERIMENTO
Añadir otra variable para realizar un seguimiento de qué tipo de número es el más
grande, así como lo que mayor número era.
Utilice mientras que repetir un bloque de código hasta que una condición cambia. El
estado de un bucle puede estar en el extremo en su lugar, asegurando que el bucle se
ejecuta al menos una vez.

  5  
• var n = 2
• while n < 100 {
• n=n*2
• }
• n

• var m = 2
• do {
• m=m*2
• } while m < 100
• m
Usted puede mantener un índice en un bucle, ya sea mediante el uso de .. < para
hacer una serie de índices o escribiendo un explícito inicialización, condición, y el
incremento. Estos dos lazos hacen lo mismo:
• var firstForLoop = 0
• for i in 0..<4 {
• firstForLoop += i
• }
• firstForLoop

• var secondForLoop = 0
• for var i = 0; i < 4; ++i {
• secondForLoop += i
• }
• secondForLoop
Utilice .. < para hacer una serie que omite su valor superior, y usar ... para hacer
una gama que incluye ambos valores.
Funciones y cierres
Utilice func para declarar una función. Llamar a una función siguiendo su nombre con
una lista de argumentos entre paréntesis. Uso -> para separar los nombres de los
parámetros y tipos de tipo de retorno de la función.
• func greet(name: String, day: String) -> String {
• return "Hello \(name), today is \(day)."
• }
• greet("Bob", "Tuesday")

EXPERIMENTO
Retire el día parámetro. Agregar un parámetro para incluir el almuerzo especial de hoy
en el saludo.
  6  
Utilice una tupla para hacer un ejemplo de valor para el compuesto, para devolver
varios valores de una función. Los elementos de una tupla se pueden denominar por su
nombre o por número.
• func calculateStatistics(scores: [Int]) -> (min: Int, max: Int, sum: Int) {
• var min = scores[0]
• var max = scores[0]
• var sum = 0

• for score in scores {
• if score > max {
• max = score
• } else if score < min {
• min = score
• }
• sum += score
• }

• return (min, max, sum)
• }
• let statistics = calculateStatistics([5, 3, 100, 3, 9])
• statistics.sum
• statistics.2
Las funciones también pueden tomar un número variable de argumentos, a su recogida
en una matriz.
• func sumOf(numbers: Int...) -> Int {
• var sum = 0
• for number in numbers {
• sum += number
• }
• return sum
• }
• sumOf()
• sumOf(42, 597, 12)
EXPERIMENTO
Escriba una función que calcula el promedio de sus argumentos.
Las funciones pueden ser anidados. Funciones anidadas tienen acceso a las variables
que fueron declaradas en la función externa. Puede utilizar las funciones anidadas para
organizar el código en una función que es largo o complejo.

  7  
• func returnFifteen() -> Int {
• var y = 10
• func add() {
• y += 5
• }
• add()
• return y
• }
• returnFifteen()
Las funciones son un tipo de primera clase. Esto significa que una función puede
devolver otra función como su valor.
• func makeIncrementer() -> (Int -> Int) {
• func addOne(number: Int) -> Int {
• return 1 + number
• }
• return addOne
• }
• var increment = makeIncrementer()
• increment(7)
Una función puede tener otra función como uno de sus argumentos.
• func hasAnyMatches(list: [Int], condition: Int -> Bool) -> Bool {
• for item in list {
• if condition(item) {
• return true
• }
• }
• return false
• }
• func lessThanTen(number: Int) -> Bool {
• return number < 10
• }
• var numbers = [20, 19, 7, 12]
• hasAnyMatches(numbers, lessThanTen)
Las funciones son en realidad un caso especial de cierres: bloques de código que se
pueden llamar más tarde. El código en un cierre tiene acceso a cosas como las variables
y funciones que estaban disponibles en el ámbito donde se creó el cierre, incluso si el
cierre es en un ámbito diferente cuando se ejecuta-que viste un ejemplo de esto ya con

  8  
funciones anidadas. Usted puede escribir un cierre sin nombre rodeando código con
llaves ( {} ). Utilice en separar los argumentos y el tipo de retorno del cuerpo.
• numbers.map({
• (number: Int) -> Int in
• let result = 3 * number
• return result
• })
EXPERIMENTO
Vuelva a escribir el cierre para volver a cero para todos los números impares.
Usted tiene varias opciones para la escritura de los cierres de forma más
concisa. Cuando el tipo de un cierre que ya se conoce, por ejemplo, la devolución de
llamada de un delegado, se puede omitir el tipo de sus parámetros, el tipo de retorno, o
ambos. Cierres sola instrucción implícitamente devuelven el valor de su única
declaración.
• let mappedNumbers = numbers.map({ number in 3 * number })
• mappedNumbers
Se puede hacer referencia a los parámetros de número en vez de por su nombre-este
enfoque es especialmente útil en los cierres muy cortos. Un cierre pasado como el
último argumento de la función puede aparecer inmediatamente después del paréntesis.
• let sortedNumbers = sorted(numbers) { $0 > $1 }
• sortedNumbers

Objetos y clases
Utilice la clase seguido del nombre de la clase para crear una clase. Una
declaración de propiedad en una clase se escribe de la misma manera como una
declaración de constante o variable, excepto que es en el contexto de una clase. De igual
forma, método y función declaraciones se escriben de la misma manera.
• class Shape {
• var numberOfSides = 0
• func simpleDescription() -> String {
• return "A shape with \(numberOfSides) sides."
• }
• }
EXPERIMENTO
Añadir una propiedad constante con let , y añadir otro método que toma un
argumento.
Crear una instancia de una clase, poniendo entre paréntesis después del nombre de la
clase. Utilice la sintaxis con punto para acceder a las propiedades y métodos de la
instancia.
• var shape = Shape()
• shape.numberOfSides = 7

  9  
• var shapeDescription = shape.simpleDescription()
Esta versión de la Forma clase le falta algo importante: un inicializador para configurar
la clase cuando se crea una instancia. Utilice init para crear una.
• class NamedShape {
• var numberOfSides: Int = 0
• var name: String

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

• func simpleDescription() -> String {
• return "A shape with \(numberOfSides) sides."
• }
• }
Observe cómo auto se utiliza para distinguir el nombre de la propiedad
del nombre de argumento para el inicializador. Los argumentos para el inicializador
se pasan como una llamada a la función cuando se crea una instancia de la clase. Cada
propiedad necesita un valor asignado, ya sea en su declaración (como
connumberOfSides ) o en el inicializador (como con el nombre ).
Utilice deinit para crear un deinitializer si es necesario realizar alguna tarea de
limpieza antes de que se cancela la asignación del objeto.
Las subclases incluyen su nombre después de su superclase nombre de la clase,
separados por dos puntos.No hay ningún requisito para las clases subclase cualquier
clase raíz estándar, por lo que puede incluir u omitir una superclase, según sea
necesario.
Los métodos en una subclase que anulan la implementación de la superclase están
marcados con el override-overriding un método por el accidente, sin anulación ,
es detectado por el compilador como un error. El compilador también detecta con
métodos de anulación que en realidad no anulan cualquier método en la superclase.
• class Square: NamedShape {
• var sideLength: Double

• init(sideLength: Double, name: String) {
• self.sideLength = sideLength
• super.init(name: name)
• numberOfSides = 4
• }

• func area() -> Double {
  10  
• return sideLength * sideLength
• }

• override func simpleDescription() -> String {
• return "A square with sides of length \(sideLength)."
• }
• }
• let test = Square(sideLength: 5.2, name: "my test square")
• test.area()
• test.simpleDescription()
EXPERIMENTO
Haga otra subclase de NamedShape llamado Círculo que tiene un radio y un
nombre como argumentos a su inicializador. Implementar un área y
un simpleDescription método en el Círculo de clase.
Además de las propiedades simples que se almacenan, las propiedades pueden tener un
getter y un setter.
• class EquilateralTriangle: NamedShape {
• var sideLength: Double = 0.0

• init(sideLength: Double, name: String) {
• self.sideLength = sideLength
• super.init(name: name)
• numberOfSides = 3
• }

• var perimeter: Double {
• get {
• return 3.0 * sideLength
• }
• set {
• sideLength = newValue / 3.0
• }
• }

• override func simpleDescription() -> String {
• return "An equilateral triangle with sides of length \(sideLength)."
• }

  11  
• }
• var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle")
• triangle.perimeter
• triangle.perimeter = 9.9
• triangle.sideLength
En la incubadora de perímetro , el nuevo valor tiene el nombre
implícito nuevoValor . Puede proporcionar un nombre explícito entre paréntesis
después de conjunto .
Observe que el inicializador para la EquilateralTriangle clase tiene tres etapas
diferentes:
1. Establecer el valor de las propiedades que la subclase declara.
2. Llamando inicializador de la superclase.
3. Cambiar el valor de las propiedades definidas por la superclase. Cualquier trabajo de
configuración adicional que utiliza métodos getters o setters también se puede hacer
en este momento.
Si no es necesario para calcular la propiedad, pero todavía tiene que proporcionar el
código que se ejecuta antes y después de fijar un nuevo valor,
utilice willSet y didSet . Por ejemplo, la clase a continuación se asegura de que la
longitud del lado de su triángulo es siempre la misma que la longitud del lado de su
cuadrado.
• class TriangleAndSquare {
• var triangle: EquilateralTriangle {
• willSet {
• square.sideLength = newValue.sideLength
• }
• }
• var square: Square {
• willSet {
• triangle.sideLength = newValue.sideLength
• }
• }
• init(size: Double, name: String) {
• square = Square(sideLength: size, name: name)
• triangle = EquilateralTriangle(sideLength: size, name: name)
• }
• }
• var triangleAndSquare = TriangleAndSquare(size: 10, name: "another test shape")
• triangleAndSquare.square.sideLength
• triangleAndSquare.triangle.sideLength

  12  
• triangleAndSquare.square = Square(sideLength: 50, name: "larger square")
• triangleAndSquare.triangle.sideLength
Los métodos de las clases tienen una diferencia importante de funciones. Los nombres
de parámetros en funciones sólo se utilizan dentro de la función, pero los parámetros
nombres en los métodos también se utilizan cuando se llama al método (excepto para el
primer parámetro). Por defecto, un método tiene el mismo nombre para sus parámetros
cuando se llama a ella y dentro del método en sí. Se puede especificar un segundo
nombre, que se utiliza dentro del método.
• class Counter {
• var count: Int = 0
• func incrementBy(amount: Int, numberOfTimes times: Int) {
• count += amount * times
• }
• }
• var counter = Counter()
• counter.incrementBy(2, numberOfTimes: 7)
Cuando se trabaja con valores opcionales, puede escribir ? antes de las operaciones,
como los métodos, propiedades y subíndices. Si el valor antes de la ? es nula , todo
después de la ? se ignora y el valor de toda la expresión es nula . De lo contrario, el
valor es opcional sin envolver, y todo después de la ? actúa sobre el valor de
envolver. En ambos casos, el valor de toda la expresión es un valor opcional.
• let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square")
• let sideLength = optionalSquare?.sideLength
Las enumeraciones y estructuras
Utilice enum para crear una enumeración. Al igual que las clases y todos los demás
tipos con nombre, enumeraciones pueden tener métodos asociados con ellos.
• enum Rank: Int {
• case Ace = 1
• case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten
• case Jack, Queen, King
• func simpleDescription() -> String {
• switch self {
• case .Ace:
• return "ace"
• case .Jack:
• return "jack"
• case .Queen:
• return "queen"
• case .King:

  13  
• return "king"
• default:
• return String(self.toRaw())
• }
• }
• }
• let ace = Rank.Ace
• let aceRawValue = ace.toRaw()
EXPERIMENTO
Escriba una función que compara dos Rank valores mediante la comparación de sus
valores brutos.
En el ejemplo anterior, el tipo de valor bruto de la enumeración es int , por lo que sólo
tiene que especificar el primer valor crudo. El resto de los valores brutos se asignan en
orden. También puede utilizar cadenas o números de punto flotante como el tipo de
prima de una enumeración.
Utilice los toRaw y fromRaw funciones para convertir entre el valor bruto y el valor
de la enumeración.
• if let convertedRank = Rank.fromRaw(3) {
• let threeDescription = convertedRank.simpleDescription()
• }
Los valores de los miembros de una enumeración son valores reales, no sólo otra
manera de escribir sus valores brutos. De hecho, en los casos donde no hay un valor en
bruto significativo, usted no tiene que proporcionar una.
• enum Suit {
• case Spades, Hearts, Diamonds, Clubs
• func simpleDescription() -> String {
• switch self {
• case .Spades:
• return "spades"
• case .Hearts:
• return "hearts"
• case .Diamonds:
• return "diamonds"
• case .Clubs:
• return "clubs"
• }
• }
• }
• let hearts = Suit.Hearts
  14  
• let heartsDescription = hearts.simpleDescription()
EXPERIMENTO
Agregar un color de método para Suit que devuelve "negro" para espadas y palos,
y los retornos "rojos" de corazones y diamantes.
Observe las dos formas en que el Hearts miembro de la enumeración se hace
referencia más arriba: Al asignar un valor a los corazones constantes, los miembros
de enumeración Suit.Hearts se refiere por su nombre completo porque la constante
no tiene un tipo explícito especificado. En el interior del interruptor, la enumeración es
referido por la forma abreviada .Hearts porque el valor del auto que ya se sabe que
es un juego. Usted puede utilizar el formulario abreviado en cualquier momento el tipo
del valor que ya se conoce.
Utilice struct para crear una estructura. Estructuras de soporte para muchas de las
mismas conductas como las clases, incluyendo métodos y inicializadores. Una de las
diferencias más importantes entre las estructuras y las clases es que las estructuras
siempre se copian cuando se pasan alrededor en su código, pero las clases se pasan por
referencia.
• struct Card {
• var rank: Rank
• var suit: Suit
• func simpleDescription() -> String {
• return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
• }
• }
• let threeOfSpades = Card(rank: .Three, suit: .Spades)
• let threeOfSpadesDescription = threeOfSpades.simpleDescription()
EXPERIMENTO
Agregue un método para la tarjeta que crea una baraja completa de tarjetas, con
una carta de cada combinación de rango y palo.
Una instancia de un miembro de la enumeración puede tener valores asociados con la
instancia. Las instancias de la misma miembro de enumeración pueden tener diferentes
valores asociados con ellos. Usted proporciona los valores asociados al crear la
instancia. Valores asociados y valores primas son diferentes: El valor bruto de un
miembro de la enumeración es el mismo para todas sus instancias, y le proporcionará el
valor en bruto cuando se define la enumeración.
Por ejemplo, considere el caso de solicitar el amanecer y el atardecer hora de un
servidor. El servidor o bien responde con la información o responde con un poco de
información de error.
• enum ServerResponse {
• case Result(String, String)
• case Error(String)
• }

  15  
• let success = ServerResponse.Result("6:00 am", "8:09 pm")
• let failure = ServerResponse.Error("Out of cheese.")

• switch success {
• case let .Result(sunrise, sunset):
• let serverResponse = "Sunrise is at \(sunrise) and sunset is at \(sunset)."
• case let .Error(error):
• let serverResponse = "Failure... \(error)"
• }
EXPERIMENTO
Añadir un tercer caso a ServerResponse y para el interruptor.
Observe cómo se extraen las horas de salida y puesta del sol desde
el ServerResponse valor como parte de hacer coincidir el valor contra los casos de
conmutación.
Protocolos y Extensiones
Utilice el protocolo para declarar un protocolo.
• protocol ExampleProtocol {
• var simpleDescription: String { get }
• mutating func adjust()
• }  
Las clases, enumeraciones y estructuras de todo pueden adoptar protocolos.
• class SimpleClass: ExampleProtocol {
• var simpleDescription: String = "A very simple class."
• var anotherProperty: Int = 69105
• func adjust() {
• simpleDescription += " Now 100% adjusted."
• }
• }
• var a = SimpleClass()
• a.adjust()
• let aDescription = a.simpleDescription

• struct SimpleStructure: ExampleProtocol {
• var simpleDescription: String = "A simple structure"
• mutating func adjust() {
• simpleDescription += " (adjusted)"
• }
• }

  16  
• var b = SimpleStructure()
• b.adjust()
• let bDescription = b.simpleDescription
EXPERIMENTO
Escribe una enumeración que se ajusta a este protocolo.
Note el uso de la mutación de la palabra clave en la declaración
de SimpleStructure para marcar un método que modifica la estructura. La
declaración de SimpleClass no necesita ninguno de sus métodos marcados como
mutando debido a los métodos de una clase siempre puede modificar la clase.
Utilice la extensión para agregar funcionalidad a un tipo existente, tales como
nuevos métodos y propiedades calculadas. Puede utilizar una extensión para añadir
conformidad protocolo a un tipo que se declara en otro lugar, o incluso a un tipo que ha
importado de una biblioteca o un marco.
• extension Int: ExampleProtocol {
• var simpleDescription: String {
• return "The number \(self)"
• }
• mutating func adjust() {
• self += 42
• }
• }
• 7.simpleDescription
EXPERIMENTO
Escribe una extensión para el doble tipo, que añade un absoluteValue propiedad.
Puede utilizar un nombre de protocolo al igual que cualquier otro ejemplo de tipo de
llamada, para crear una colección de objetos que tienen diferentes tipos, sino que todos
cumplir con un protocolo único. Cuando se trabaja con valores cuyo tipo es un tipo de
protocolo, los métodos fuera de la definición de protocolo no están disponibles.
• let protocolValue: ExampleProtocol = a
• protocolValue.simpleDescription
• // protocolValue.anotherProperty // Uncomment to see the error
A pesar de que la variable protocolValue tiene un tipo de tiempo de ejecución
de SimpleClass , el compilador lo trata como el tipo dado
de ExampleProtocol . Esto significa que no se puede acceder accidentalmente a los
métodos o propiedades que la clase implementa además de su conformidad protocolo.
Genéricos
Escriba un nombre dentro de paréntesis angulares para hacer una función genérica o
tipo.
• func repeat<ItemType>(item: ItemType, times: Int) -> [ItemType] {
• var result = [ItemType]()
• for i in 0..<times {

  17  
• result.append(item)
• }
• return result
• }
• repeat("knock", 4)
Usted puede hacer las formas genéricas de las funciones y métodos, así como las clases,
enumeraciones y estructuras.
• // Reimplementar tipo opcional de la biblioteca estándar de
Swift  
• enum OptionalValue<T> {
• case None
• case Some(T)
• }
• var possibleInteger: OptionalValue<Int> = .None
• possibleInteger = .Some(100)
Use where after the type name to specify a list of requirements—for example, to require
the type to implement a protocol, to require two types to be the same, or to require a
class to have a particular superclass.
• func anyCommonElements <T, U where T: SequenceType, U: SequenceType,
T.Generator.Element: Equatable, T.Generator.Element == U.Generator.Element> (lhs:
T, rhs: U) -> Bool {
• for lhsItem in lhs {
• for rhsItem in rhs {
• if lhsItem == rhsItem {
• return true
• }
• }
• }
• return false
• }
• anyCommonElements([1, 2, 3], [3])
• anyCommonElements ([ 1 , 2 , 3 ], [ 3 ])  
EXPERIMENTO
Modifique el anyCommonElements función para realizar una función que devuelve
una matriz de los elementos que las dos secuencias tienen en común.
En los casos sencillos, se puede omitir cuando y simplemente escriba el nombre del
protocolo o de clase después de dos puntos. Escribiendo <T: equatable> es lo
mismo que escribir <T donde T: equatable> .

  18  
Los Fundamentos
En esta página
Swift es un nuevo lenguaje de programación para iOS y OS X de desarrollo de
aplicaciones. No obstante, muchas partes de Swift estarán familiarizados desde su
experiencia en el desarrollo en C y Objective-C.
Swift proporciona sus propias versiones de todos los tipos C y Objective-C
fundamentales, incluido Int para enteros, doble y flotador para los valores de
punto flotante, Bool para valores booleanos y de cadena para los datos
textuales. Swift también ofrece versiones potentes de los dos tipos de recolección
primaria, matriz yDiccionario , como se describe en Tipos Collection .
Al igual que C, Swift utiliza variables para almacenar y hacer referencia a los valores
por un nombre de identificación. Swift también hace un amplio uso de variables cuyos
valores no se pueden cambiar. Estos son conocidos como constantes, y son mucho más
poderosos que las constantes en C. Las constantes se utilizan a lo largo Swift para hacer
el código más seguro y más clara en su intención cuando se trabaja con valores que no
tienen que cambiar.
Además de los tipos conocidos, Swift presenta tipos avanzadas que no se encuentran en
Objective-C, como tuplas. Tuples le permiten crear y pasar alrededor de agrupaciones
de valores. Puede usar una tupla para devolver varios valores de una función como un
valor único compuesto.
Swift también introduce tipos opcionales, que se encargan de la ausencia de un
valor. Opcionales dicen bien "no es un valor, y que es igual a x "o" no , no es un valor
en absoluto ". Opcionales son similares al uso de nilcon punteros en Objective-C, pero
trabajan para cualquier tipo, no sólo a las clases. Opcionales son más seguros y más
expresiva que nil punteros en Objective-C y están en el centro de muchas de las
características más poderosas de Swift.
Opcionales son un ejemplo del hecho de que Swift es un seguro de tipo de
idioma. Swift le ayuda a ser claro acerca de los tipos de valores de su código puede
trabajar. Si parte de su código espera una cuerda , la seguridad de tipos le impide
pasándole un Int por error. Esta restricción le permite capturar y corregir los errores lo
antes posible en el proceso de desarrollo.
Constantes y Variables
Constantes y variables asociar un nombre
(como maximumNumberOfLoginAttempts o WelcomeMessage ) con un valor
de un tipo concreto (por ejemplo, el número 10 o la cadena "Hola" ). El valor de
una constante no se puede cambiar una vez que se establece, mientras que una variable
de puede ajustarse a un valor diferente en el futuro.
Declaración de constantes y variables
Constantes y variables deben ser declaradas antes de ser utilizadas. Usted declara
constantes con la let de palabras clave y las variables con la var palabra clave. He
aquí un ejemplo de cómo las constantes y las variables se pueden utilizar para realizar el
seguimiento del número de intentos de inicio de sesión de un usuario ha hecho:
• let maximumNumberOfLoginAttempts = 10
• var currentLoginAttempt = 0
Este código se puede leer como:

  19  
"Declarar una nueva constante llamada maximumNumberOfLoginAttempts , y
darle un valor de 10 . A continuación, declarar una nueva variable
llamada currentLoginAttempt , y darle un valor inicial de 0 ".
En este ejemplo, el número máximo de intentos de inicio de sesión permitidos se
declara como una constante, debido a que el valor máximo nunca cambia. El contador
de inicio de sesión actual intento se declara como una variable, ya que este valor debe
ser incrementado después de cada intento fallido de inicio de sesión.
Se pueden declarar varias constantes o variables múltiples en una misma línea,
separados por comas:
• var x = 0,0 , y = 0,0 , z = 0,0  
NOTA
Si un valor almacenado en el código no va a cambiar, siempre declararemos como una
constante con la letpalabra clave. Utilice variables sólo para almacenar valores que
deben ser capaces de cambiar.
Tipo Anotaciones
Puede proporcionar una anotación de tipo cuando se declara una constante o variable,
para tener claro el tipo de valores de la tienda lata constante o variable. Escribe una
anotación de tipo mediante la colocación de dos puntos después del nombre de la
constante o variable, seguido por un espacio, seguido por el nombre del tipo de usar.
Este ejemplo proporciona una anotación de tipo para una variable
llamada WelcomeMessage , para indicar que la variable puede almacenar de
Cuerda valores:
• var welcomeMessage: String
Los dos puntos en la declaración significa "... el tipo ...", por lo que el código anterior se
puede leer como:
"Declarar una variable llamada WelcomeMessage que es del tipo String. "
La frase "de tipo String "significa" puede almacenar cualquier Cadena de valor.
"Piense en ello como que significa" el tipo de cosas "(o" el tipo de cosa ") que se puede
almacenar.
El WelcomeMessage variables ahora se puede ajustar a cualquier valor de cadena sin
error:
• WelcomeMessage = "Hola"  
Puede definir múltiples variables relacionadas del mismo tipo en una sola línea,
separados por comas, con un solo tipo de anotación después de que el nombre de la
variable definitiva:
• var red, green, blue: Double
NOTA
Es raro que usted necesita para escribir anotaciones de tipo en la práctica. Si
proporciona un valor inicial para una constante o variable en el punto que se define,
Swift casi siempre se puede inferir el tipo que se utilizará para que constante o variable,
como se describe en el tipo de seguridad y la inferencia de tipos . En
la WelcomeMessage ejemplo anterior, no se proporciona ningún valor inicial, por lo
que el tipo de laWelcomeMessage variable se especifica con una anotación de tipo en
lugar de ser inferido a partir de un valor inicial.

  20  
Nombrar constantes y variables
Los nombres de constantes y variables pueden contener casi cualquier carácter,
incluidos los caracteres Unicode:
• let π = 3.14159
• let 你好 = "你好世界"
• let = "dogcow"
Los nombres de constantes y variables no pueden contener espacios en blanco, símbolos
matemáticos, flechas, de uso privado (o no válidos) los puntos de código Unicode o
caracteres de línea y caja de dibujo.Tampoco pueden comenzar con un número, aunque
las cifras pueden ser incluidos en otro lugar dentro del nombre.
Una vez que se ha declarado una constante o variable de un cierto tipo, no se puede
redeclare de nuevo con el mismo nombre, o cambiarlo para almacenar valores de un
tipo diferente. Tampoco se puede cambiar una constante en una variable o una variable
en una constante.
NOTA
Si usted necesita dar una constante o variable el mismo nombre que una palabra clave
reservada Swift, rodear la palabra clave con la espalda garrapatas ( ` ) cuando se utiliza
como un nombre. Sin embargo, evite el uso de palabras clave como nombres a menos
que tenga absolutamente ninguna opción.
Puede cambiar el valor de una variable existente a otro valor de un tipo compatible. En
este ejemplo, el valor de friendlyWelcome se cambia
de "¡Hola!" a "Bonjour!" :
• var friendlyWelcome = "Hello!"
• friendlyWelcome = "Bonjour!"
• // friendlyWelcome is now "Bonjour!"
A diferencia de una variable, el valor de una constante no se puede cambiar una vez que
se establece. Si lo intenta, se reporta como un error cuando se compila el código:
• let languageName = "Swift"
• languageName = "Swift++"
• // Se trata de un error de tiempo de compilación -
languageName no se puede cambiar  
Constantes de impresión y variables
Usted puede imprimir el valor actual de una constante o variable con
el println función:
• println(friendlyWelcome)
• // prints "Bonjour!"
println es una función global que imprime un valor, seguido por un salto de línea, a
una salida apropiada. En Xcode, por ejemplo, println imprime su salida en el panel
de "consola" de Xcode. (Una segunda función, la impresión , realiza la misma
tarea sin anexar un salto de línea al final del valor que se va a imprimir.)
El println función imprime cualquier Cadena de valor se pasa a la misma:
• println("This is a string")

  21  
• // prints "This is a string"
El println función puede imprimir mensajes de registro más complejos, de una
manera similar a la de CocoaNSLog función. Estos mensajes pueden incluir los valores
actuales de constantes y variables.
Swift utiliza interpolación de cadenas para incluir el nombre de una constante o
variable como un marcador de posición en una cadena más larga, ya una pronta Swift
sustituirlo por el valor actual de esa constante o variable. Envuelva el nombre entre
paréntesis y escapar con una barra invertida antes del paréntesis de apertura:
• println("The current value of friendlyWelcome is \(friendlyWelcome)")
• // Impresiones "El valor actual de friendlyWelcome es
Bonjour!"  
NOTA
Todas las opciones que puede utilizar con la interpolación de cadenas se describen en
la Cadena de interpolación .
Comentarios
Utilice los comentarios para incluir texto no ejecutable en su código, como una nota o
un recordatorio a sí mismo. Los comentarios son ignorados por el compilador Swift
cuando se compila el código.
Comentarios en Swift son muy similares a los comentarios en C. sola línea Los
comentarios comienzan con dos barras inclinadas (forward- // ):
• // Esto es un comentario  
Los comentarios multilínea empiezan con una barra inclinada seguida de un asterisco
( / * ) y terminan con un asterisco seguido de una barra diagonal ( * / ):
• / * Este es también un comentario,  
• pero escrito en varias líneas * /  
A diferencia de los comentarios de varias líneas en C, los comentarios de varias líneas
en Swift se pueden anidar dentro de otros comentarios multilínea. Usted escribe
comentarios anidados por iniciar un bloque de varias líneas de comentarios y luego
iniciar un segundo comentario de varias líneas en el primer bloque. El segundo bloque
se cierra a continuación, seguido por el primer bloque:
• / * Este es el comienzo de la primera comentario multilínea  
• / * Esta es la segunda, comentario de varias líneas anidada
* /  
• este es el final de la primera comentario multilínea * /  
Comentarios multilínea anidadas permiten a comentar a cabo grandes bloques de código
de forma rápida y sencilla, incluso si el código contiene ya los comentarios de varias
líneas.
Punto y coma
A diferencia de muchos otros idiomas, Swift no requiere que usted escriba un punto y
coma ( ; ) después de cada sentencia en el código, aunque puede hacerlo si lo
desea. Los puntos y comas se requiere, sin embargo, si desea escribir varias
instrucciones separadas en una sola línea:
• let cat = " "; println(cat)
  22  
• // prints " "
Enteros
Los enteros son números enteros sin componente fraccional, como 42 y -23 . Los
números enteros se seafirmado (positivo, cero o negativo) o sin signo (positivo o cero).
Swift proporciona firmado y enteros sin signo de 8, 16, 32 y 64 forma de bits. Estos
enteros siguen una convención de nomenclatura similar a C, en que un entero sin signo
de 8 bits es de tipo Uint8 , y un entero con signo de 32 bits es de tipo Int32 . Al
igual que todos los tipos de Swift, estos tipos enteros tienen nombres propios.
Entero límites
Usted puede acceder a los valores mínimo y máximo de cada tipo entero con
su min y max propiedades:
• let minValue = UInt8.min // minValue is equal to 0, and is of type UInt8
• let maxValue = UInt8.max // maxValue is equal to 255, and is of type UInt8
Los valores de estas propiedades son del tipo de número de tamaño apropiado (tales
como Uint8 en el ejemplo anterior) y por lo tanto se pueden utilizar en expresiones
junto con otros valores del mismo tipo.
Int
En la mayoría de los casos, usted no tiene que elegir un tamaño específico de número
entero para utilizar en su código. Swift proporciona un tipo entero adicional, Int , que
tiene el mismo tamaño que el tamaño de palabra nativa de la plataforma actual:
• En una plataforma de 32 bits, Int es del mismo tamaño que Int32 .
• En una plataforma de 64 bits, Int es del mismo tamaño que Int64 .
A menos que usted necesita para trabajar con un tamaño específico de número entero,
utilice siempre Intpara valores enteros en el código. Esto ayuda código de coherencia
y la interoperabilidad. Incluso en las plataformas de 32 bits, Int puede almacenar
cualquier valor entre -2147483648 y 2147483647 , y es lo suficientemente grande
para muchos rangos enteros.
UInt
Swift también proporciona un tipo entero sin signo, UInt , que tiene el mismo tamaño
que el tamaño de palabra nativa de la plataforma actual:
• En una plataforma de 32 bits, UInt es del mismo tamaño que UInt32 .
• En una plataforma de 64 bits, UInt es del mismo tamaño que UInt64 .
NOTA
Uso UInt sólo cuando se necesita específicamente un tipo entero sin signo con el
mismo tamaño que el tamaño de palabra nativa de la plataforma. Si este no es el
caso, Int se prefiere, incluso cuando los valores a ser almacenados son conocidos por
ser no negativo. Un uso consistente de Int para el código de ayudas valores enteros
interoperabilidad, evita la necesidad de convertir entre diferentes tipos de números, y
coincide con el tipo entero de inferencia, como se describe en el tipo de seguridad y tipo
de inferencia .
Números de punto flotante
Números de coma flotante son números con un componente fraccional,
como 3.14159 , 0.1 , y -273.15 .
Tipos de punto flotante pueden representar una gama mucho más amplia de valores que
los tipos enteros, y pueden almacenar números que son mucho más grandes o más

  23  
pequeños que se pueden almacenar en unint . Swift proporciona dos tipos de números
de punto flotante firmados:
• Doble representa un número de punto flotante de 64 bits. Úselo cuando los valores
de punto flotante deben ser muy grandes o particularmente precisa.
• Float representa un número de punto flotante de 32 bits. Úselo cuando los valores
de punto flotante no requieren precisión de 64 bits.
NOTA
Doble tiene una precisión de al menos 15 dígitos decimales, mientras que la precisión
de flotador puede ser tan poco como 6 dígitos decimales. El tipo de punto flotante
apropiado utilizar depende de la naturaleza y el rango de valores que necesita para
trabajar en su código.
Escriba Seguridad y tipo de inferencia
Swift es un seguro de tipo de idioma. Un lenguaje de tipo seguro anima a ser claro
acerca de los tipos de valores de su código puede trabajar. Si parte de su código espera
una cuerda , no se puede pasar un int por error.
Debido Swift es un tipo seguro, realiza escribir cheques al compilar el código y
banderas cualesquiera tipos no coincidentes como errores. Esto le permite capturar y
corregir los errores lo antes posible en el proceso de desarrollo.
Tipo de comprobación le ayuda a evitar errores cuando se trabaja con diferentes tipos de
valores. Sin embargo, esto no significa que usted tiene que especificar el tipo de cada
constante y variable que se declara. Si no se especifica el tipo de valor que necesita,
Swift utiliza la inferencia de tipos para calcular el tipo apropiado. La inferencia de tipos
permite un compilador para deducir el tipo de una expresión concreta de forma
automática cuando se compila el código, simplemente mediante el examen de los
valores suministrados por el usuario.
Debido a la inferencia de tipos, Swift requiere muchos menos declaraciones de tipo que
lenguajes como C o Objective-C. Constantes y variables todavía se escriben de forma
explícita, pero gran parte del trabajo de especificar su tipo está hecho para usted.
La inferencia de tipos es particularmente útil cuando se declara una constante o variable
con un valor inicial.Esto se suele hacer mediante la asignación de un valor
literal (o literal ) a la constante o variable en el punto que se declara. (Un valor literal es
un valor que aparece directamente en el código fuente, como 42 y 3,14159en los
ejemplos a continuación.)
Por ejemplo, si se asigna un valor literal de 42 a una nueva constante sin decir de qué
tipo es, Swift infiere que desea que la constante de ser un int , porque usted ha
inicializado con un número que se ve como un entero:
• let meaningOfLife = 42
• // MeaningOfLife se infiere a ser de tipo Int  
Del mismo modo, si no se especifica un tipo de un literal de coma flotante, Swift infiere
que desea crear undoble :
• let pi = 3.14159
• // Pi se infiere a ser de tipo doble  
Swift siempre elige doble (en lugar de Float ) cuando inferir el tipo de números en
coma flotante.

  24  
Si combina enteros y de punto flotante literales en una expresión, un tipo
de doble será inferirse del contexto:
• let anotherPi = 3 + 0.14159
• // AnotherPi también se infiere a ser de tipo doble  
El valor literal de 3 tiene ningún tipo explícito en y de sí mismo, y por lo tanto un tipo
de salida apropiado deDoble se infiere de la presencia de un literal de coma flotante
como parte de la adición.
Los literales numéricos
Literales enteros se pueden escribir como:
• Un decimal número, sin el prefijo
• Un binario número, con un 0b prefijo
• Un octal número, con un 0o prefijo
• A hexadecimal número, con un 0x prefijo
Todos estos literales enteros tienen un valor decimal de 17 :
• let decimalInteger = 17
• let binaryInteger = 0b10001 // 17 in binary notation
• let octalInteger = 0o21 // 17 in octal notation
• let hexadecimalInteger = 0x11 // 17 in hexadecimal notation
Literales de punto flotante pueden ser decimal (sin prefijo) o hexadecimal (con
un 0x prefijo). Ellos siempre deben tener un número (o número hexadecimal) en ambos
lados de la coma decimal. También pueden tener un opcional exponente , indicada por
una mayúscula o minúscula e para carrozas decimales, o una mayúscula o
minúscula p para carrozas hexadecimales.
Para los números decimales con un exponente de exp , el número base se multiplica
por 10 exp :
• 1.25e2 significa 1.25 × 10 2 , o 125,0 .
• 1.25E-2 significa 1,25 × 10 -2 , o 0,0125 .
Para los números hexadecimales con un exponente de exp , el número base se
multiplica por 2 exp :
• 0xFp2 significa 15 × 2 2 , o 60.0 .
• 0xFp-2 significa 15 × 2 -2 , o 3,75 .
Todos estos literales de punto flotante tienen un valor decimal de 12.1875 :
• let decimalDouble = 12.1875
• let exponentDouble = 1.21875e1
• let hexadecimalDouble = 0xC.3p0
 
 
Los literales numéricos pueden contener un formato extra para que sean más fáciles de
leer. Ambos números enteros y flotadores pueden ser rellenados con ceros adicionales y
pueden contener guiones bajos para ayudar con la lectura. Ningún tipo de formato afecta
el valor subyacente de la literal:
• let paddedDouble = 000123.456

  25  
• let oneMillion = 1_000_000
• let justOverOneMillion = 1_000_000.000_000_1
Tipo de conversión numérica
Utilice la Int tipo para todas las constantes de enteros de propósito general y variables
en su código, aunque son conocidos por ser no negativo. Utilizando el tipo de entero por
defecto en situaciones cotidianas significa que constantes enteras y variables son
inmediatamente interoperable en el código y se corresponda con el tipo inferido para
valores enteros literales.
Utilice otros tipos enteros sólo cuando son específicamente necesarios para la tarea en
cuestión, debido a los datos de forma explícita tamaño de una fuente externa, o para el
funcionamiento, uso de memoria, u otro optimización necesaria. El uso de tipos
explícita tamaño en estas situaciones ayuda a detectar cualquier desbordamientos de
valor accidentales y documenta implícitamente la naturaleza de los datos que se utiliza.
Entero Conversión
El rango de números que pueden ser almacenadas en una constante entera o variable es
diferente para cada tipo numérico. Un INT8 constante o variable pueden almacenar
números entre -128 y 127 , mientras que unUint8 constante o variable pueden
almacenar números entre 0 y 255 . Un número que no caben en una constante o
variable de un tipo entero de tamaño se indica como un error cuando se compila el
código:
• let cannotBeNegative: UInt8 = -1
• // Uint8 no puede almacenar números negativos, por lo que
esta informará de un error  
• let tooBig: Int8 = Int8.max + 1
• // INT8 no puede almacenar un número mayor que su valor
máximo,  
• // Y por lo que este también informará de un error  
Debido a que cada tipo numérico puede almacenar una serie diferente de valores, debe
optar por la conversión de tipo numérico sobre una base caso por caso. Este enfoque
opt-in evita errores de conversión ocultos y ayuda a que las intenciones de conversión
de tipo explícita en el código.
Para convertir un tipo determinado número a otro, se inicializa un nuevo número del
tipo deseado con el valor existente. En el siguiente ejemplo, la constante
de twoThousand es de tipo UInt16 , mientras que la constante de uno es de
tipo Uint8 . No se pueden sumar directamente, porque no son del mismo tipo. En
cambio, este ejemplo llama UInt16 (uno) para crear una
nueva UInt16 inicializado con el valor de uno , y utiliza este valor en lugar de la
original:
• let twoThousand: UInt16 = 2_000
• let one: UInt8 = 1
• let twoThousandAndOne = twoThousand + UInt16(one)

  26  
Debido a que ambos lados de la adición son ahora de tipo UInt16 , se permite la
adición. La constante de salida ( twoThousandAndOne ) se infiere a ser de
tipo UInt16 , porque es la suma de dos UINT16 valores.
SomeType (ofInitialValue) es la forma predeterminada para llamar al
inicializador de tipo Swift y pase un valor inicial. Detrás de las escenas, UInt16 tiene
un inicializador que acepta un Uint8 valor, y por lo que este inicializador se utiliza
para hacer un nuevo UInt16 de una existente Uint8 . No se puede pasar
en cualquiertipo aquí, sin embargo, tiene que ser un tipo para el
que UInt16 proporciona un inicializador. La extensión de los tipos existentes para
proporcionar inicializadores que acepten nuevos tipos (incluyendo sus propias
definiciones de tipos) que se cubre en las extensiones .
Entero y en coma flotante Conversión
Las conversiones entre números enteros y de punto flotante tipos numéricos deben
hacerse explícitas:
• let three = 3
• let pointOneFourOneFiveNine = 0.14159
• let pi = Double(three) + pointOneFourOneFiveNine
• // Pi es igual a 3.14159, y se infiere a ser de tipo doble  
Aquí, el valor de la constante de tres se utiliza para crear un nuevo valor de
tipo doble , de modo que ambos lados de la adición son del mismo tipo. Sin esta
conversión en su lugar, la adición no se le permitiría.
De punto flotante de conversión entera también debe hacerse explícito. Un tipo entero
se puede inicializar con un doble o Float valor:
• let integerPi = Int(pi)
• // IntegerPi es igual a 3, y se infiere a ser de tipo Int  
Los valores de coma flotante siempre se truncan cuando se utiliza para inicializar un
nuevo valor de número entero de esta manera. Esto significa que 4,75 se convierte
en 4 , y -3,9 convierte -3 .
NOTA
Las reglas para combinar las constantes numéricas y variables son diferentes de las
reglas para los literales numéricos. El valor literal 3 se puede agregar directamente al
valor literal 0.14159 , porque literales numéricos no tienen un tipo explícito en sí
mismos. Su tipo es inferido sólo en el punto de que son evaluados por el compilador.
Tipo de los nombres
Tipo alias definen un nombre alternativo para un tipo existente. Usted define los alias
de tipo con el typealiaspalabra clave.
Tipo alias son útiles cuando se quiere hacer referencia a un tipo existente por un nombre
que es contextualmente más apropiado, por ejemplo, cuando se trabaja con datos de un
tamaño específico de una fuente externa:
• typealias AudioSample = UInt16
Una vez que se define un alias de tipo, puede utilizar el alias de cualquier lugar que
podría utilizar el nombre original:
• var maxAmplitudeFound = AudioSample.min

  27  
• // MaxAmplitudeFound es ahora 0  
Aquí, AudioSample se define como un alias para UInt16 . Debido a que es un alias,
la llamada aAudioSample.min llama en realidad UInt16.min , que proporciona
un valor inicial de 0 para el maxAmplitudeFoundvariable.
Booleanos
Swift tiene un básico de Boole tipo, llamado Bool . Los valores booleanos se les
conoce como lógica , ya que sólo alguna vez pueden ser verdaderas o falsas. Swift
proporciona dos valores constantes booleanas,verdaderas y falsas :
• let orangesAreOrange = true
• let turnipsAreDelicious = false
Los tipos de orangesAreOrange y turnipsAreDelicious se han deducido
como Bool del hecho de que se inicializan con valores literales booleanos. Al igual que
con Int y doble arriba, usted no tiene que declarar constantes o variables
como Bool Si se ajustan a la verdad o falso tan pronto a medida que los crea. La
inferencia de tipos ayuda a que el código Swift más concisa y fácil de leer cuando se
inicializa las constantes o variables con otros valores cuyo tipo ya se conoce.
Los valores booleanos son particularmente útiles cuando se trabaja con sentencias
condicionales tales como el caso de la declaración:
• if turnipsAreDelicious {
• println("Mmm, tasty turnips!")
• } else {
• println("Eww, turnips are horrible.")
• }
• // prints "Eww, turnips are horrible."
Sentencias condicionales tales como el caso de la declaración se cubren con más
detalle en el control de flujo.
Seguridad de tipos de Swift evita valores no booleanos de ser sustituido por Bool . El
siguiente ejemplo se informa de un error de tiempo de compilación:
• let i = 1
• if i {
• // Este ejemplo no se compilará, y se informará de un error  
• }  
Sin embargo, el ejemplo alternativo a continuación es válido:
• let i = 1
• if i == 1 {
• // Este ejemplo se compilará con éxito  
• }  
El resultado de la i == 1 comparación es de tipo Bool , y por lo que este segundo
ejemplo del tipo pasa-cheque. Las comparaciones como i == 1 se discuten
en Operadores básicos .

  28  
Al igual que con otros ejemplos de tipo de seguridad en Swift, este enfoque evita
errores accidentales y asegura que la intención de una sección particular de código es
siempre clara.
Las tuplas
Las tuplas grupo de valores múltiples en un único valor compuesto. Los valores dentro
de una tupla pueden ser de cualquier tipo y no tienen que ser del mismo tipo que la otra.
En este ejemplo, (404, "Not Found") es una tupla que describe un código de
estado HTTP . Un código de estado HTTP es un valor especial retornado por un
servidor web cada vez que solicita una página web. Un código de estado de 404 Not
Found se devuelve si usted solicita una página web que no existe.
• let http404Error = (404, "Not Found")
• // Http404Error es de tipo (int, String), y es igual a
(404, "Not Found")  
El (404, "Not Found") grupos de tupla juntos un Int y una cadena para dar el
código de estado HTTP dos valores distintos: un número y una descripción
legible. Puede ser descrito como "una tupla de tipo (int, String) ".
Puede crear tuplas de cualquier permutación de tipos, y que puede contener muchos
tipos diferentes como desee. No hay nada que nos impida tener una tupla de
tipo (Int, Int, Int) , o (String, Bool) , o de hecho cualquier otra
permutación usted requiere.
Puede descomponer el contenido de una tupla en constantes o variables independientes,
que luego accede como de costumbre:
• let (statusCode, statusMessage) = http404Error
• println("The status code is \(statusCode)")
• // prints "The status code is 404"
• println("The status message is \(statusMessage)")
• // prints "The status message is Not Found"
Si sólo necesita algunos de los valores de la tupla, ignorar partes de la tupla con un
guión bajo ( _ ) cuando se descompone la tupla:
• let (justTheStatusCode, _) = http404Error
• println("The status code is \(justTheStatusCode)")
• // prints "The status code is 404"
Alternativamente, acceder a los valores de los elementos individuales de una tupla
usando números de índice a partir de cero:
• println("The status code is \(http404Error.0)")
• // prints "The status code is 404"
• println("The status message is \(http404Error.1)")
• // prints "The status message is Not Found"
• // Impresiones "El mensaje de estado no se encuentra"  
Usted puede nombrar a los elementos individuales de una tupla cuando se define la
tupla:

  29  
• dejar http200Status = ( statuscode : 200 , Descripción :
"OK" )  
Si el nombre de los elementos de una tupla, puede utilizar los nombres de los elementos
para tener acceso a los valores de esos elementos:
• println("The status code is \(http200Status.statusCode)")
• // prints "The status code is 200"
• println("The status message is \(http200Status.description)")
• // prints "The status message is OK"
Las tuplas son particularmente útiles como los valores de retorno de las funciones. Una
función que intenta recuperar una página web puede devolver el (Int,
String) Tipo de tupla para describir el éxito o el fracaso de la recuperación de la
página. Al devolver una tupla con dos valores distintos, cada uno de un tipo diferente, la
función proporciona información más útil sobre su resultado que si sólo podía devolver
un solo valor de un solo tipo. Para obtener más información, vea Funciones con
múltiples valores de retorno .
NOTA
Las tuplas son útiles para los grupos temporales de valores relacionados. No son
adecuados para la creación de estructuras de datos complejas. Si es probable que
persistan más allá de un alcance temporal, lo representan como una clase o estructura,
más que como una tupla de su estructura de datos. Para obtener más información,
vea Clases y Estructuras .
Opcionales
Utiliza opcionales en situaciones en que un valor puede estar ausente. Un opcional dice:
• No es un valor, y es igual a x
o
• Allí no es un valor en absoluto
NOTA
El concepto de opcionales no existe en C o Objective-C. Lo más cercano en Objective-
C es la capacidad de volver a cero de un método que de otra manera devolver un
objeto, con nula que significa "la ausencia de un objeto válido." Sin embargo, esto
sólo funciona para los objetos-no funciona para las estructuras , tipos básicos de C, o
valores de enumeración. Para estos tipos, métodos de Objective-C normalmente
devuelven un valor especial (como NSNotFound ) para indicar la ausencia de un
valor. Este enfoque asume que la persona que llama del método sabe que hay un valor
especial para probar en contra y recuerda a comprobar por ello. Opcionales de Swift
permiten indicar la ausencia de un valor de cualquier tipo en absoluto , sin la necesidad
de constantes especiales.
He aquí un ejemplo de cómo opcionales pueden utilizarse para hacer frente a la ausencia
de un valor. De Swift Cadena tipo tiene un método llamado Toint , que trata de
convertir una Cadena de valor en un Int valor.Sin embargo, no todos los cadena se
puede convertir en un entero. La cadena "123" se puede convertir en el valor
numérico 123 , pero la cadena "hola, mundo" no tiene un valor numérico obvio
para convertir.
El ejemplo siguiente utiliza la Toint método para tratar de convertir una cuerda en
un Int :

  30  
• let possibleNumber = "123"
• let convertedNumber = possibleNumber.toInt()
• // ConvertedNumber se infiere a ser de tipo "Int?", O "Int
opcional"  
Debido a que el Toint método puede fallar, devuelve un opcional Int , en lugar de
un int . Un opcional Int se escribe como Int? , no Int . El signo de interrogación
indica que el valor que contiene es opcional, lo que significa que puede
contener algún Int valor, o podría contener ningún valor en absoluto . (No puede
contener cualquier otra cosa, como por ejemplo un Bool valor o una Cadena de valor.
Es o un int , o no es nada en absoluto.)
nil
Se establece una variable opcional a un estado sin valor asignándole el valor
especial nulo :
• var serverResponseCode: Int? = 404
• // ServerResponseCode contiene un valor real Int de 404  
• serverResponseCode = nil  
• // ServerResponseCode ahora no contiene ningún valor  
NOTA
nil no se puede utilizar con constantes y variables no opcional. Si una constante o
variable en el código tiene que trabajar con la ausencia de un valor bajo ciertas
condiciones, siempre declararemos como un valor opcional del tipo apropiado.
Si se define una constante o variable opcional sin proporcionar un valor por defecto, la
constante o variable se ajusta automáticamente a cero para usted:
• var surveyAnswer : Cadena ?  
• // SurveyAnswer se ajusta automáticamente a cero  
NOTA
De Swift nil no es lo mismo que cero en Objective-C. En Objective-C, nil es un
puntero a un objeto inexistente. En Swift, nil no es un puntero-es la ausencia de un
valor de un cierto tipo. Opcionales decualquier tipo se pueden establecer en cero , no
sólo tipos de objetos.
Si Las declaraciones y forzado Unwrapping
Puede utilizar un si declaración para averiguar si un opcional contiene un valor
comparando el opcional contra cero . Se realiza esta comparación con la "igual a"
operador ( == ) o el "no es igual a" operador ( ! = ).
Si una opción tiene un valor, se considera que "no es igual a" cero :
• if convertedNumber != nil {
• println("convertedNumber contains some integer value.")
• }
• // prints "convertedNumber contains some integer value."
Una vez que esté seguro de que la opcional hace contener un valor, puede acceder a su
valor subyacente mediante la adición de un signo de exclamación ( ! ) al final del
nombre de la opción. El signo de exclamación efectivamente dice, "Yo sé que esta

  31  
opción sin duda tiene un valor; por favor use "Esto se conoce como.desenvolver
forzado del valor de la opción:
• if convertedNumber != nil {
• println("convertedNumber has an integer value of \(convertedNumber!).")
• }
• // Impresiones "convertedNumber tiene un valor entero de
123"  
Para más información sobre el caso de la declaración, véase el control de flujo .
NOTA
Tratar de utilizar ! acceder a un valor opcional inexistente provoca un error de
ejecución. Asegúrese siempre de que un opcional contiene una no- nil valor antes de
usar ! forzar-desenvolver su valor.
Opcional Binding
Utiliza unión opcional para averiguar si un opcional contiene un valor, y si es así, haga
que el valor disponible como una constante o variable temporal. Opcional unión se
puede utilizar con si y mientras declaraciones para comprobar un valor dentro de
un opcional, y para extraer ese valor en una constante o variable, como parte de una sola
acción. si y mientras estados se describen con más detalle en el control de flujo .
Escribe enlaces opcionales para el caso de la declaración de la siguiente manera:
• if let constantName = someOptional {
• statements

• }
Puede volver a escribir la possibleNumber ejemplo del Opcionales sección para
utilizar opcional desenvolver vinculante y no forzada:
• if let actualNumber = possibleNumber.toInt() {
• println("\(possibleNumber) has an integer value of \(actualNumber)")
• } else {
• println("\(possibleNumber) could not be converted to an integer")
• }
• // prints "123 has an integer value of 123"
Este código se puede leer como:
"Si el opcional Int devuelve possibleNumber.toInt contiene un valor, establece
una nueva constante llamadaactualNumber al valor contenido en la opcional. "
Si la conversión se realiza correctamente, el actualNumber constante esté disponible
para su uso dentro de la primera rama del si comunicado. Ya se ha inicializado con el
valor contenido dentro de la opcional, y así que no hay necesidad de utilizar el ! sufijo
para acceder a su valor. En este ejemplo, actualNumber se utiliza simplemente para
imprimir el resultado de la conversión.
Puede utilizar ambas constantes y variables con opción de encuadernación. Si quería
manipular el valor deactualNumber dentro de la primera rama del si declaración,

  32  
usted podría escribir si actualNumber var su lugar, y el valor contenido en el
opcional se pondrían a disposición como una variable en lugar de una constante.
Implícitamente Unwrapped Opcionales
Como se describió anteriormente, opcionales indican que se permite una variable
constante o tener "ningún valor". Opcionales pueden ser comprobadas con un caso
de declaración para ver si existe un valor, y puede ser condicionalmente desenvolvió
con opcional de unión para acceder a el valor de la opción, si es que existe.
A veces se desprende de la estructura de un programa que una opción será siempre tener
un valor, después de que el valor se establece en primer lugar. En estos casos, es útil
para eliminar la necesidad de comprobar y desenvolver el valor de la opcional cada vez
que se accede, porque se puede suponer con seguridad a tener un valor todo el tiempo.
Este tipo de opcionales se definen como opcionales implícitamente abierto . Usted
escribe un implícitamente envolver opcional colocando un signo de exclamación
( cuerda! ) en lugar de un signo de interrogación (Cadena? ) después de que el tipo
que desea que sea opcional.
Implícitamente opcionales abierto son útiles cuando el valor de un opcional se confirma
que existe inmediatamente después de la opcional se define primero y definitivamente
se puede suponer que existe en cada punto a partir de entonces. El uso principal de
opcionales implícitamente abierto en Swift es durante la inicialización de clase, como se
describe en las referencias sin propietario e implícitamente Unwrapped propiedades
opcionales .
Un opcional implícitamente envolver es una opción normal de detrás de las escenas,
pero también se puede utilizar como un valor no opcional, sin la necesidad de
desenvolver el valor opcional cada vez que se accede.El siguiente ejemplo muestra la
diferencia de comportamiento entre una cadena opcional y una cadena opcional
implícitamente desenvuelto al acceder a su valor envuelto como un explícito Cadena :
• let possibleString: String? = "An optional string."
• let forcedString: String = possibleString! // requires an exclamation mark

• let assumedString: String! = "An implicitly unwrapped optional string."
• let implicitString: String = assumedString // no need for an exclamation mark
Usted puede pensar en una forma implícita envolver opcional como dar permiso para
que el facultativo de desenvolverse de forma automática cada vez que se utiliza. En
lugar de colocar un signo de exclamación después del nombre de la opción cada vez que
lo use, se coloca un signo de exclamación después de tipo de la opción al declararla.
NOTA
Si intenta acceder a una implícita envolver opcional cuando no contiene un valor, se
activará un error de ejecución. El resultado es exactamente el mismo que si se coloca un
signo de exclamación después de un opcional normal que no contenga un valor.
Todavía se puede tratar una opcional implícitamente sin envolver como un opcional
normal, para comprobar si contiene un valor:
• if assumedString != nil {
• println(assumedString)
• }

  33  
• // imprime "una cadena opcional implícitamente sin
envolver."  
También puede utilizar una forma implícita envolver opcional con opcional de unión,
para comprobar y desenvolver su valor en una sola sentencia:
• if let definiteString = assumedString {
• println(definiteString)
• }
• // imprime "una cadena opcional implícitamente sin
envolver."  
NOTA
No utilice un implícitamente sin envolver opcional cuando hay una posibilidad de
convertirse en una variablenula en un punto posterior. Utilice siempre un tipo opcional
normal si usted necesita para comprobar si hay un nulo valor durante la vida de una
variable.
Aseveraciones
Opcionales te permite comprobar los valores que pueden o no existir, y para escribir
código que hace frente con gracia con la ausencia de un valor. En algunos casos, sin
embargo, simplemente no es posible que el código para continuar la ejecución si el
valor no existe, o si un valor proporcionado no cumple ciertas condiciones. En estas
situaciones, se puede desencadenar una afirmación en su código para poner fin a la
ejecución de código y proporcionar una oportunidad para depurar la causa del valor
ausente o no válido.
Depuración con afirmaciones
Una afirmación es un cheque en tiempo de ejecución que una condición lógica
definitivamente se evalúa como verdadera . Literalmente palabras, una afirmación
"afirma" que una condición es verdadera. Utiliza una afirmación para asegurarse de que
una condición esencial se satisface antes de ejecutar cualquier código adicional. Si la
condición se evalúa como verdadera , la ejecución de código continúa como de
costumbre; si la condición se evalúa como falsa , la ejecución de código termina, y su
aplicación se termina.
Si su código desencadena una afirmación mientras se ejecuta en un entorno de
depuración, tales como cuando se construye y ejecuta una aplicación en Xcode, se
puede ver exactamente dónde se produjo el estado no válido y consultar el estado de su
aplicación en el momento en que la afirmación fue provocado.Una afirmación también
le permite proporcionar un mensaje de depuración adecuado en cuanto a la naturaleza
de la aserción.
Usted escribe una afirmación llamando al mundial afirman función. Se pasa
la aserción función de una expresión que se evalúa como verdadera o falsa y
un mensaje que se debe mostrar si el resultado de la condición es falsa :
• let age = -3
• assert(age >= 0, "A person's age cannot be less than zero")
• // Esto hace que la afirmación para disparar, porque la
edad no es> = 0  

  34  
En este ejemplo, la ejecución de código continuará sólo si la edad> = 0 se evalúa
como verdadera , es decir, si el valor de la edad es no negativo. Si el valor de la
edad es negativo, como en el código anterior, a continuación, la edad> = 0 se
evalúa como falsa , y la afirmación se activa, de terminar la aplicación.
El mensaje afirmación puede omitirse si se desea, como en el siguiente ejemplo:
• afirmar ( edad > = 0 )  
Cuándo utilizar aserciones
Utilice una afirmación cada vez que un estado tiene el potencial de ser falsa, pero
debe sin duda ser verdad para que su código para continuar la ejecución. Escenarios
adecuados para una comprobación de aserción incluyen:
• Un índice subíndice entero se pasa a una aplicación subíndice de encargo, pero el
valor del índice subíndice podría ser demasiado baja o demasiado alta.
• Un valor se pasa a una función, pero un valor no válido significa que la función no
puede cumplir su tarea.
• Un valor opcional es actualmente nula , sino un no- nil de valor es esencial para
el código subsiguiente para ejecutar con éxito.
Ver también subíndices y Funciones .
NOTA
Las afirmaciones hacen que su aplicación para terminar y no son un sustituto para el
diseño de su código de tal manera que las condiciones no válidas es improbable que
surjan. No obstante, en situaciones donde las condiciones no válidas son posibles, una
afirmación es una forma eficaz de garantizar que dichas condiciones se resaltan y se
dieron cuenta durante el desarrollo, antes de la publicación de su aplicación.
A Swift tour
Operadores básicos
 

   

  35  
Operadores básicos
En esta página
Un operador es un símbolo especial o una frase que se utiliza para comprobar, cambiar
o combinar los valores. Por ejemplo, el operador de suma ( + ) suma dos números juntos
(como en let i = 1 + 2 ). Ejemplos más complejos incluyen el operador lógico
AND && (como en el caso de enteredDoorCode && passedRetinaScan)
y el operador de incremento ++ i , que es un acceso directo para aumentar el valor
de i por 1 .
Swift es compatible con los operadores de C más estándar y mejora varias funciones
para eliminar los errores comunes de codificación. El operador de asignación ( = ) no
devuelve un valor, para evitar que sea utilizado por error cuando el operador igual a
( == ) se destina. Los operadores aritméticos ( + , - , * , / , % , etc) y no permiten
detectar desbordamiento valor, para evitar resultados inesperados cuando se trabaja con
los números que se convierten en mayor o menor que el rango de valores permitido del
tipo que los almacena.Usted puede optar por el comportamiento de desbordamiento de
valor mediante el uso de operadores de desbordamiento de Swift, como se describe
en Operadores de desbordamiento .
A diferencia de C, Swift le permite realizar resto ( % ) cálculos sobre números de punto
flotante. Swift también proporciona dos operadores de rango ( un .. <b y a ...
b ) que no se encuentran en C, como un acceso directo para expresar un rango de
valores.
En este capítulo se describen los operadores comunes en Swift. Operadores
avanzados cubre operadores avanzados de Swift, y describe cómo definir sus propios
operadores personalizados e implementar los operadores estándar para sus propios tipos
personalizados.
Terminología
Los operadores son unarios, binarios o ternarios:
• Unarios operadores operan en un solo objetivo (tales como :
una ). Unarios prefijo operadores aparecen inmediatamente antes de su destino
(como ! b ), y unarios postfix operadores aparecen inmediatamente después de su
objetivo (tales como i ++ ).
• Binarias operadores funcionan con dos objetivos (como 2 + 3 ) y
son infijo porque aparecen en entre sus dos objetivos.
• Ternarios operadores operan en tres objetivos. Al igual que C, Swift tiene un solo
operador ternario, el operador condicional ternario ( a b: c ).
Los valores que afectan a los operadores están operando . En la expresión 1 + 2 ,
la + símbolo es un operador binario y sus dos operandos son los valores 1 y 2 .
Operador de asignación
El operador de asignación ( a = b ) inicializa o actualiza el valor de una con el valor
de b :
• let b = 10
• var a = 5
• a=b
• // a is now equal to 10

  36  
Si el lado derecho de la asignación es una tupla con múltiples valores, sus elementos se
pueden descomponer en varias constantes o variables a la vez:
• let (x, y) = (1, 2)
• // x is equal to 1, and y is equal to 2
A diferencia del operador de asignación en C y Objective-C, el operador de asignación
en Swift sí mismo no devuelve ningún valor. La siguiente declaración no es válida:
• if x = y {
• // Esto no es válido, ya que x = y no devuelve un valor  
• }  
Esta función evita que el operador de asignación ( = ) se utilice por accidente cuando el
operador igual a ( == ) se destina en realidad. Al hacer si x = y no válida, Swift le
ayuda a evitar este tipo de errores en el código.
Operadores aritméticos
Swift es compatible con los cuatro estándares operadores aritméticos para todos los
tipos de números:
• Suma ( + )
• Resta ( - )
• Multiplicación ( * )
• División ( / )

• 1 + 2 // equals 3
• 5 - 3 // equals 2
• 2 * 3 // equals 6
•10.0 / 2.5 // equals 4.0
A diferencia de los operadores aritméticos en C y Objective-C, los operadores
aritméticos Swift no permiten valores se desborden por defecto. Usted puede optar por
el comportamiento de desbordamiento de valor mediante el uso de operadores de
desbordamiento de Swift (como a & + b ). Ver Operadores de desbordamiento .
El operador de suma también es apoyado por Cadena concatenación:
• "hello, " + "world" // equals "hello, world"
Dos caracteres valores, o uno de caracteres de valor y uno de cadena de
valor, se pueden sumar para hacer una nueva Cadena de valor:
• let dog: Character = " "
• let cow: Character = " "
• let dogCow = dog + cow
• // dogCow is equal to " "
Ver también concatenar cadenas y caracteres .
Operador resto
El operador de resto ( a% b ) resuelve cuántos múltiplos de b cabrán dentro de una y
devuelve el valor que queda (conocido como el resto ).
NOTA

  37  
El operador resto ( % ) también se conoce como un operador de módulo en otros
idiomas. Sin embargo, su comportamiento en Swift para los números negativos significa
que es, estrictamente hablando, un resto más que una operación de módulo.
He aquí cómo funciona el operador resto. Para calcular el 9% 4 , primero calcular
cuántos 4 s se ajuste dentro de 9 :

Puede  encajar  dos  4  s  interior  9  ,  y  el  resto  es  1  (se  muestra  en  color  naranja).  

En  Swift,  esto  se  escribe  como:  

9 % 4 // equals 1

Para  determinar  la  respuesta  para  a% b  ,  el  %  del  operador  calcula  la  siguiente  ecuación  y  
devuelve  restocomo  salida:  

un  =  (  b  ×  algunos multiplicador  )  +  resto  

donde algunos multiplicador es el mayor número de múltiplos de b que caben


dentro de una .
Inserción de 9 y 4 en esta ecuación se obtiene:
9=(4×2)+1
El mismo método se aplica al calcular el resto para un valor negativo de una :
• - 9 % 4 // es igual a -1  
Inserción de -9 y 4 en los rendimientos ecuación:
-9 = ( 4 × -2 ) + -1
dando un valor resto de -1 .
El signo de b es ignorado por los valores negativos de b . Esto significa que a% b y un
-b% siempre dan la misma respuesta.
Cálculos Resto en coma flotante
A diferencia del operador resto en C y Objective-C, el operador resto de Swift también
puede funcionar con números de punto flotante:
• 8 % 2,5 // es igual a 0,5  
En este ejemplo, 8 dividido por 2,5 es igual a 3 , con un resto de 0,5 , por lo que el
operador devuelve un restoDoble valor de 0,5 .

 
Los operadores de incremento y decremento
Al igual que C, Swift ofrece un operador de incremento ( ++ ) y un operador de
decremento ( - ) como un acceso directo para aumentar o disminuir el valor de una
variable numérica por 1 . Puede utilizar estos operadores con variables de cualquier
número entero o tipo de punto flotante.

  38  
• var i = 0
• ++i // i now equals 1
Cada vez que se llama ++ i , el valor de i se incrementa en 1 . Esencialmente, ++
i es un atajo para decir i = i + 1 Del mismo modo,. --i se puede utilizar como
forma abreviada de i = i - 1 .
El ++ y - símbolos pueden ser utilizados como operadores de prefijo o como
operadores de sufijo. ++ i y i ++son dos formas válidas para aumentar el valor
de i por 1 . Del mismo modo, --i y i-- son dos formas válidas para disminuir el
valor de i por 1 .
Tenga en cuenta que estos operadores modifican i y también devuelven un valor. Si
sólo desea aumentar o disminuir el valor almacenado en i , puede ignorar el valor
devuelto. Sin embargo, si usted no utiliza el valor devuelto, que será diferente en
función de si ha utilizado la versión prefijo o de sufijo del operador, de acuerdo con las
siguientes reglas:
• Si el operador está escrito antes de la variable, se incrementa la variable antes
de devolver su valor.
• Si el operador está escrito después de la variable, se incrementa la variable después
de regresar de su valor.
Por ejemplo:
• var a = 0
• let b = ++a
• // a and b are now both equal to 1
• let c = a++
• // A es igual a 2, pero c se ha establecido en el valor
pre-incremento de 1  
En el ejemplo anterior, sea b = ++ un incrementos de un antes de devolver su
valor. Esta es la razón por tantouna y b son iguales a al nuevo valor de 1 .
Sin embargo, dejó c = a ++ incrementa un después de regresar de su valor. Esto
significa que c recupera el antiguo valor de 1 , y un entonces se actualiza para
igualar 2 .
A menos que necesite el comportamiento específico de i ++ , se recomienda que usted
utilice ++ i y --i en todos los casos, debido a que tienen el comportamiento esperado
típica de modificar i y devolviendo el resultado.
Operador menos unario
El signo de un valor numérico se puede activar mediante un prefijo - , conocido como
el operador menos unario :
• let three = 3
• let minusThree = -three // minusThree equals -3
• let plusThree = -minusThree // plusThree equals 3, or "minus minus three"
El operador unario menos ( - ) se antepone directamente ante el valor que opera en, sin
ningún espacio en blanco.

  39  
Operador unario Plus
El operador unario más ( + ) simplemente devuelve el valor que opera en, sin ningún
cambio:
• let minusSix = -6
• let alsoMinusSix = +minusSix // alsoMinusSix equals -6
Aunque el operador de suma unaria no hace nada, se puede utilizar para proporcionar
simetría en su código para números positivos cuando también mediante el operador
unario menos para los números negativos.
Operadores de Asignación Compuesto
Al igual que C, Swift proporciona operadores de asignación compuestos que combinan
de asignación ( = ) con otra operación. Un ejemplo es el operador de asignación de
suma ( + = ):
• var a = 1
• a += 2
• // a es ahora igual a 3  
La expresión a + = 2 es la abreviatura de a = a + 2 . Efectivamente, la adición y
la asignación se combinan en un operador que realiza ambas tareas al mismo tiempo.
NOTA
Los operadores de asignación compuestos no devuelven un valor. No se puede
escribir al B = a + = 2 , por ejemplo. Este comportamiento es diferente de los
operadores de incremento y decremento mencionados anteriormente.
Una lista completa de operadores de asignación compuestos se puede encontrar en las
expresiones .
Operadores de comparación
Swift es compatible con todos los C estándar operadores de comparación :
• Igual a ( a == b )
• No es igual a ( a! = b )
• Mayor que ( a> b )
• Menos de ( a <b )
• Mayor o igual a ( a> = b )
• Menor o igual a ( a <= b )
NOTA
Swift también proporciona dos operadores de identidad ( === y ! == ), que se utiliza
para probar si dos referencias a objetos tanto se refieren a la misma instancia de
objeto. Para obtener más información, veaClases y Estructuras .
Cada uno de los operadores de comparación devuelve un Bool valor para indicar si la
declaración es verdadera:
• 1 == 1 // cierto, porque 1 es igual a 1  
• 2 ! = 1 // cierto, porque 2 no es igual a 1  
• 2 > 1 // cierto, porque 2 es mayor que 1  
• 1 < 2 // cierto, porque 1 es menor que 2  
• 1 > = 1 // cierto, porque 1 es mayor que o igual a 1  
• 2 <= 1 // falsa, porque 2 no es menor que o igual a 1  

  40  
Los operadores de comparación se utilizan a menudo en las sentencias condicionales,
como el caso de la declaración if:
• let name = "world"
• if name == "world" {
• println("hello, world")
• } else {
• println("I'm sorry \(name), but I don't recognize you")
• }
• // imprime "hola, mundo", porque el nombre es de hecho
igual al "mundo"  
Para más información sobre el caso de la declaración, véase el control de flujo .
Operador condicional ternario
El operador condicional ternario es un operador especial con tres partes, que toma la
forma pregunta?answer1: Respuesta2 . Es un acceso directo para la
evaluación de una de las dos expresiones en función de sipregunta es verdadera o
falsa. Si pregunta es verdadera, evalúa answer1 y devuelve su valor; de lo
contrario, se evalúa Respuesta2 y devuelve su valor.
El operador condicional ternario es una abreviación para el código de abajo:
• if question {
• answer1
• } else {
• answer2
• }
He aquí un ejemplo, que calcula la altura de una fila de tabla. La altura de la fila debe
ser de 50 puntos más alto que la altura del contenido si la fila tiene una cabecera, y 20
puntos más alto si la fila no tiene un encabezado:
• dejar que contentHeight = 40  
• dejar HasHeader = true  
• dejar rowHeight = contentHeight + ( HasHeader ? 50 : 20 )  
• // RowHeight es igual a 90  
El ejemplo anterior es una abreviatura para el código de abajo:
• let contentHeight = 40
• let hasHeader = true
• var rowHeight = contentHeight
• if hasHeader {
• rowHeight = rowHeight + 50
• } else {
• rowHeight = rowHeight + 20
• }

  41  
• // RowHeight es igual a 90  
El primer uso del ejemplo del operador condicional ternario significa
que rowHeight se puede establecer en el valor correcto en una sola línea de
código. Esto es más conciso que el segundo ejemplo, y elimina la necesidad
de rowHeight a una variable, porque su valor no necesita ser modificado dentro de
un sideclaración.
El operador condicional ternario proporciona una taquigrafía eficiente para decidir cuál
de las dos expresiones a considerar. Utilice el operador condicional ternario con
cuidado, sin embargo. Su concisión puede conducir al código difícil de leer si se
abusa. Evite combinar varias instancias del operador condicional ternario en una
sentencia compuesta.
Ninguna Coalescente Operador
El operador de coalescencia nula ( a ?? b ) desenvuelve opcional un si contiene un
valor, o devuelve un valor predeterminado b si una es nula . La
expresión una siempre es de un tipo opcional. La expresión b debe coincidir con el tipo
que se almacena dentro de una .
El operador de coalescencia nil es un atajo para el código de abajo:
• a != nil ? a! : b
El código anterior utiliza el operador condicional ternario y desenvolver forzada
( una! ) para acceder al valor envuelto en una cuando una no es nula , ya
regresar b lo contrario. El operador de coalescencia nil ofrece una forma más elegante
para encapsular esta comprobación condicional y desenvolver de una forma concisa y
fácil de leer.
NOTA
Si el valor de una es no nulo , el valor de b no se evalúa. Esto se conoce
como evaluación de corto-circuito .
El ejemplo siguiente utiliza el operador de coalescencia nil que elegir entre un nombre
de color por defecto y un nombre de color definido por el usuario opcional:
• let defaultColorName = "red"
• var userDefinedColorName: String? // defaults to nil

• var colorNameToUse = userDefinedColorName ?? defaultColorName
• // UserDefinedColorName es nula, por lo colorNameToUse se
establece en el valor predeterminado de "rojo"  
El userDefinedColorName variable se define como un opcional de cuerda ,
con un valor por defecto de cero .Debido userDefinedColorName es de tipo
opcional, puede utilizar el operador de coalescencia nil considerar su valor. En el
ejemplo anterior, el operador se utiliza para determinar un valor inicial para
una cadena variable
llamada colorNameToUse . Debido userDefinedColorName es nula , la
expresión userDefinedColorName ??defaultColorName devuelve el valor
de defaultColorName , o "rojo" .

  42  
Si asigna un no- nil valor a userDefinedColorName y ejecutar la revisión
operador coalescente nula de nuevo, el valor envuelto
dentro userDefinedColorName se utiliza en lugar del predeterminado:
• userDefinedColorName = "green"
• colorNameToUse = userDefinedColorName ?? defaultColorName
• // UserDefinedColorName no es nula, por lo colorNameToUse
se establece en "verde"  

  43  
 
Operadores Range
Swift incluye dos operadores de rango , que son atajos para expresar un rango de
valores.
Cerrado operador Range
El operador de rango cerrado ( un ... b ) define un rango que va desde una a b , e
incluye los valores de una yb . El valor de un no debe ser mayor que b .
El operador de rango cerrado es útil cuando se repite en un intervalo en el que desea que
todos los valores a utilizar, por ejemplo, con un para - en bucle:
• for index in 1...5 {
• println("\(index) times 5 is \(index * 5)")
• }
• // 1 times 5 is 5
• // 2 times 5 is 10
• // 3 times 5 is 15
• // 4 times 5 is 20
• // 5 times 5 is 25
Para más información sobre por - en bucles, consulte Flujo de control .
La mitad-Open Operator Range
El operador entreabierta gama ( un .. <b ) define un rango que va desde una a b ,
pero no incluye b . Se dice que es la mitad-abierta , ya que contiene el primer valor,
pero no su valor final. Como con el operador de rango cerrado, el valor de un no debe
ser mayor que b .
Rangos medio abiertas son particularmente útiles cuando se trabaja con listas de cero-
basado como matrices, en las que es útil para contar hasta (pero sin incluir) la longitud
de la lista:
• let names = ["Anna", "Alex", "Brian", "Jack"]
• let count = names.count
• for i in 0..<count {
• println("Person \(i + 1) is called \(names[i])")
• }
• // Persona 1 se llama Anna  
• // Persona 2 se llama Alex  
• // Persona 3 se llama Brian  
• // Persona 4 se llama Jack  
Tenga en cuenta que la matriz contiene cuatro artículos, pero 0 ..
<cuenta solamente las cuentas en cuanto a3 (el índice del último elemento de la
matriz), porque es un rango medio abierta. Para más información sobre matrices,
vea Matrices .

  44  
Operadores lógicos
Los operadores lógicos modificar o combinar los valores lógicos
booleanos true y false . Swift es compatible con los tres operadores lógicos
estándar que se encuentran en los idiomas basados en C:
• Logical NOT (!a)
• Logical AND (a && b)
• Logical OR (a || b)

Logical NOT Operator

El operador lógico NOT ( ! a) invierte un valor booleano para que verdadera se


convierte en falsa , y falsase convierte en verdadera .
El operador lógico NOT es un operador prefijo, y aparece inmediatamente antes del
valor que opera en, sin ningún espacio en blanco. Se puede leer como "no una ", como
se ve en el siguiente ejemplo:
• let allowedEntry = false
• if !allowedEntry {
• println("ACCESS DENIED")
• }
• // prints "ACCESS DENIED"
La frase ! si allowedEntry se puede leer como "si no se permite la entrada." La
línea posterior sólo se ejecuta si "no entrada permitida" es cierto; es decir,
si allowedEntry es falsa .
Como en este ejemplo, la elección cuidadosa de nombres de constantes y variables
booleanas puede ayudar a mantener el código legible y conciso, evitando dobles
negaciones o afirmaciones lógicas confusas.
Y lógico Operador
El operador lógico Y ( a && b ) crea expresiones lógicas donde ambos valores deben
ser verdad para la expresión general que también sea cierto .
Si alguno de los valores es falso , la expresión general también será falsa . De
hecho, si el primer valor esfalso , el segundo valor de ni siquiera ser evaluada, ya que
no puede hacer la expresión global equivale a laverdad . Esto se conoce
como evaluación de corto-circuito .
En este ejemplo se considera dos Bool valores y sólo permite el acceso si ambos
valores son true :
• let enteredDoorCode = true
• let passedRetinaScan = false
• if enteredDoorCode && passedRetinaScan {
• println("Welcome!")
• } else {
• println("ACCESS DENIED")
• }

  45  
• // prints "ACCESS DENIED"

Operador lógico OR
El operador lógico OR ( a || b ) es un operador infijo hecho a partir de dos
personajes de tuberías adyacentes. Se utiliza para crear expresiones lógicas en las que
sólo uno de los dos valores tiene que serverdadera para la expresión general para
ser verdad .
Al igual que el operador lógico AND anterior, el operador lógico OR utiliza la
evaluación de cortocircuito para considerar sus expresiones. Si el lado izquierdo de una
expresión lógica OR es verdadera , no se evalúa el lado derecho, porque no puede
cambiar el resultado de la expresión general.
En el siguiente ejemplo, la primera Bool valor ( hasDoorKey ) es falsa , pero el
segundo valor (knowsOverridePassword ) es verdadera . Debido a que un
valor es verdadero , la expresión general también se evalúa como verdadera , y
se permite el acceso:
• let hasDoorKey = false
• let knowsOverridePassword = true
• if hasDoorKey || knowsOverridePassword {
• println("Welcome!")
• } else {
• println("ACCESS DENIED")
• }
• // prints "Welcome!"
La combinación de operadores lógicos
Puede combinar múltiples operadores lógicos para crear expresiones compuestas más
largos:
• if enteredDoorCode && passedRetinaScan || hasDoorKey || knowsOverridePassword {
• println("Welcome!")
• } else {
• println("ACCESS DENIED")
• }
• // prints "Welcome!"
Este ejemplo utiliza múltiples && y || operadores para crear una expresión compuesta
por más tiempo. Sin embargo, el && y || operadores siguen funcionando en sólo dos
valores, por lo que este es en realidad tres expresiones más pequeñas encadenadas. El
ejemplo se puede leer como:
Si hemos entrado en el código de la puerta correcta y pasamos el escáner de la retina, o
si tenemos una llave de la puerta válida, o si se conoce la contraseña de anulación de
emergencia y permitir el acceso.
Basado en los valores de enteredDoorCode , passedRetinaScan ,
y hasDoorKey , los primeros dos mini-expresiones son falsas . Sin embargo, la

  46  
contraseña de anulación de emergencia es conocido, por lo que la expresión compuesta
en general todavía se evalúa como verdadera .

Los paréntesis explícitos


A veces es útil incluir paréntesis, cuando no son estrictamente necesarios, para que la
intención de una expresión compleja más fácil de leer. En el ejemplo de puerta de
acceso anteriormente, es útil añadir paréntesis alrededor de la primera parte de la
expresión compuesto para hacer su intención explícita:
• if (enteredDoorCode && passedRetinaScan) || hasDoorKey || knowsOverridePassword
{
• println("Welcome!")
• } else {
• println("ACCESS DENIED")
• }
• // prints "Welcome!"
Los paréntesis, dejan claro que los dos primeros valores son considerados como parte de
un posible estado independiente en la lógica global. La salida de la expresión
compuesto no cambia, pero la intención general es más claro para el lector. La
legibilidad es siempre preferible a la brevedad; utilizar paréntesis, donde ayudan a hacer
que sus intenciones claras.
 
Cuerdas y Personajes

Una cadena es una colección ordenada de caracteres, como "hola,


mundo" o "albatros" . Cuerdas Swift están representados por la Cadena tipo, que
a su vez representa una colección de valores de caracteres de tipo.
De Swift de Cuerda y Carácter tipos proporcionan una manera rápida, compatible
con Unicode para trabajar con el texto en el código. La sintaxis para la creación de la
cadena y la manipulación es ligero y fácil de leer, con una sintaxis literal de cadena que
es similar a C. concatenación de cadenas es tan simple como la suma de dos cuerdas con
el + operador, y la mutabilidad cadena se gestiona mediante la elección entre una
constante o una variables, al igual que cualquier otro valor en Swift.
A pesar de esta simplicidad de la sintaxis, de Swift Cadena tipo es una aplicación de
cadena rápida, moderna.Cada cadena se compone de caracteres Unicode
independientemente de la codificación, y ofrece soporte para acceder a esos personajes
en diversas representaciones Unicode.
También puede utilizar cadenas para insertar constantes, variables, literales y
expresiones en cadenas más largas, en un proceso conocido como interpolación de
cadenas. Esto hace que sea fácil crear valores de cadena personalizada para la
visualización, el almacenamiento y la impresión.
NOTA
De Swift Cadena tipo se tiende un puente a la perfección para la
Fundación NSString clase. Si está trabajando con el marco de la Fundación en Cocoa
o Cocoa Touch, todo el NSString API está disponible para llamar en

  47  
cualquier Cadena de valor se crea, además de los de Cuerda funciones descritas en
este capítulo. También puede utilizar una Cadena de valor con cualquier API que
requiere una NSString instancia.
Para obtener más información sobre el uso de cuerdas con la Fundación y Cocoa,
consulte Uso de Swift con Cocoa y Objective-C .
Literales de cadena
Puede incluir predefinidos de Cuerda valores dentro de su código como literales de
cadena . Un literal de cadena es una secuencia fija de caracteres de texto rodeado por un
par de comillas dobles ( "" ).
Utilice una cadena literal como valor inicial para una variable constante o:
• let someString = "Some string literal value"
Tenga en cuenta que Swift infiere un tipo de cuerda para el someString constante,
ya que se inicializa con un valor literal de cadena.
NOTA
Para obtener información sobre el uso de caracteres especiales en los literales de cadena,
vea caracteres Unicode especial en literales de cadena .
Iniciando una cadena vacía
Para crear un vacío de cadena de valor como punto de partida para la construcción
de una cadena más larga, ya sea asignar una cadena vacía literal a una variable, o
inicializar una nueva cadena con la sintaxis de inicializador ejemplo:
• var emptyString = "" // empty string literal
• var anotherEmptyString = String() // initializer syntax
• // Estas dos cadenas están vacíos, y son equivalentes entre
sí  
Averigüe si una cuerda valor está vacío comprobando su
Boolean estaVacia propiedad:
• if emptyString.isEmpty {
• println("Nothing to see here")
• }
• // prints "Nothing to see here"

La mutabilidad de Cuerdas
Se indica si una determinada cadena se puede modificar (o mutado ) mediante la
asignación a una variable (en cuyo caso puede ser modificado), o a una constante (en
cuyo caso no se puede modificar):
• var variableString = "Horse"
• variableString += " and carriage"
• // variableString is now "Horse and carriage"

• let constantString = "Highlander"
• constantString += " and another Highlander"

  48  
• // this reports a compile-time error - a constant string cannot be modified
NOTA
Este enfoque es diferente de mutación cadena en Objective-C y Cocoa, donde se elige
entre dos clases (NSString y NSMutableString ) para indicar si una cadena se
puede mutar.
Las cadenas son tipos de valor
De Swift Cadena tipo es un tipo de valor . Si crea una nueva Cadena de valor,
que de cuerdas valor se copiancuando se pasa a una función o método, o cuando se
asigna a una constante o variable. En cada caso, una nueva copia de la existente de
cuerdas se crea valor, y se pasa o le asigna la nueva copia, no la versión original. Los
tipos de valor están descritas en estructuras y enumeraciones son tipos de valor .
NOTA
Este comportamiento difiere del de NSString en Cocoa. Cuando se crea
una NSString ejemplo, en Cocoa, y pasarlo a una función o método o la asigna a una
variable, siempre se está de paso o la asignación de unareferencia a la misma
solo NSString . Prohibida la reproducción de la cadena se lleva a cabo, a menos que
usted solicite específicamente.
De Swift copia por defecto Cadena comportamiento asegura que cuando una función o
método que pasa unacuerda valor, está claro que usted es dueño de esa
exacta Cadena de valor, independientemente de dónde vino. Usted puede estar seguro
de que la cadena que se pasan no se modificará a menos que modifique usted mismo.
Detrás de las escenas, el compilador de Swift optimiza el uso de cadena para que la
copia se realiza efectivamente sólo cuando sea absolutamente necesario. Esto significa
que siempre dan un gran rendimiento cuando se trabaja con cadenas como tipos de
valor.
Trabajar con Personajes
De Swift Cadena tipo representa una colección de Carácter valores en un orden
específico. Puede acceder a los individuales de Carácter valores en una cadena por
la iteración en esa cadena con un para - en bucle:
• for character in "Dog! " {
• println(character)
• }
• // D
• // o
• // g
• // !
• //
La for-in bucle se describe en los bucles for .
Como alternativa, crear una independiente de caracteres constante o variable de
una cadena de un solo carácter literal proporcionando un personaje anotación de
tipo:
• let yenSign: Character = "¥"

  49  
La concatenación de cadenas y caracteres
Cuerda valores se pueden sumar (o concatenan ) con el operador de suma ( + ) para
crear una nueva Cadena de valor:
• let string1 = "hello"
• let string2 = " there"
• var welcome = string1 + string2
• // welcome now equals "hello there"
También puede añadir una Cadena de valor a una cuenta existente de
cuerda variable con el operador de asignación de suma ( + = ):
• var instruction = "look over"
• instruction += string2
• // instruction now equals "look over there"
Se puede añadir un personaje valor a una cuerda variable con la cuerda de
tipo append método:
• let exclamationMark: Character = "!"
• welcome.append(exclamationMark)
• // welcome now equals "hello there!"
NOTA
No se puede añadir una cuerda o de caracteres a una cuenta existente de
caracteres variables, porque unpersonaje valor debe contener un único carácter
único.
La interpolación de Cuerdas
Interpolación de cuerda es una manera de construir una nueva Cadena de valor a
partir de una mezcla de constantes, variables, literales y expresiones mediante la
inclusión de sus valores dentro de una cadena literal. Cada elemento que se inserta en la
cadena literal se envuelve en un par de paréntesis, precedido de una barra invertida:
• let multiplier = 3
• let message = "\(multiplier) times 2.5 is \(Double(multiplier) * 2.5)"
• // message is "3 times 2.5 is 7.5"
En el ejemplo anterior, el valor de multiplicador se inserta en una cadena literal
como \ (multiplicador) .Este marcador de posición se sustituye con el valor real
de multiplicador cuando se evalúa la interpolación de cadenas para crear una
cadena real.
El valor de multiplicador es también parte de una expresión mayor más adelante
en la cadena. Esta expresión calcula el valor de doble (multiplicador) *
2,5 e inserta el resultado ( 7.5 ) en la cadena. En este caso, la expresión se escribe
como \ (Doble (multiplicador) * 2,5) cuando se incluye dentro de la
cadena literal.
NOTA
Las expresiones se escriben dentro de paréntesis dentro de una cadena interpolado no
puede contener un doble cita no literal ( " ) ni la barra invertida ( \ ), y no pueden
contener un retorno de carro o salto de línea.

  50  
Unicode
Unicode es un estándar internacional para la codificación, lo que representa, y
procesamiento de textos en diferentes sistemas de escritura. Se le permite representar
casi todos los caracteres de cualquier idioma en una forma estandarizada, y para leer y
escribir los caracteres ay desde una fuente externa, como un archivo de texto o una
página web. De Swift de Cuerda y Carácter tipos son totalmente compatible con
Unicode, como se describe en esta sección.
Unicode escalares
Detrás de las escenas, nativo de Swift Cadena tipo se construye a partir de escalares
Unicode valores. Un escalar Unicode es un número de 21 bits único para un personaje o
modificador, como U + 0061 paraMINÚSCULA A ( "a" ), o U + 1F425 para que
daba al frente POLLUELO DEL BEBÉ ( " " ).
NOTA
Un escalar Unicode Unicode es cualquier punto de código en el rango U + 0000 a U
+ D7FF incluido o U + E000 a U + 10FFFF inclusive. Escalares Unicode no
incluyen los Unicode par suplente puntos de código, que son los puntos de código en el
rango de U + D800 a U + DFFF inclusive.
Tenga en cuenta que no todos los escalares Unicode de 21 bits se asignan a un
personaje-algunos escalares están reservados para la asignación futura. Los escalares
que se han asignado a un carácter típicamente también tienen un nombre,
como MINÚSCULA A y orientados hacia delante POLLUELO DEL
BEBÉ en los ejemplos anteriores.
Caracteres Unicode especiales en literales de cadena
Los literales de cadena pueden incluir los siguientes caracteres especiales Unicode:
• Los caracteres especiales escapados \ 0 (carácter nulo), \\ (barra invertida), \
t (tabulador horizontal),\ n (salto de línea), \ r (retorno de carro), \ " (comillas
dobles) y \ ' (comilla simple )
• Un escalar Unicode arbitraria, escrito como \ u { n } , donde n es entre uno y
ocho dígitos hexadecimales
El código siguiente muestra cuatro ejemplos de estos caracteres
especiales. Los wisewords constantes contiene dos escaparon dos caracteres de
comillas. Los Dollarsign , Blackheart , y sparklingHeart constantes
demuestran el formato escalar Unicode:
• let wiseWords = "\"Imagination is more important than knowledge\" - Einstein"
• // "Imagination is more important than knowledge" - Einstein
• let dollarSign = "\u{24}" // $, Unicode scalar U+0024
• let blackHeart = "\u{2665}" // ♥, Unicode scalar U+2665
• let sparklingHeart = "\u{1F496}" // , Unicode scalar U+1F496
Extended Clusters grafema
Cada instancia de Swift Carácter tipo representa un solo grupo grafema
extendida . Un clúster grafema extendida es una secuencia de uno o más escalares
Unicode (cuando se combina) producen un solo carácter legible.
He aquí un ejemplo. La carta é se puede representar como la única escalar
Unicode é ( E MINÚSCULA CON AGUDA, o U + 00E9 ). Sin embargo, la misma

  51  
carta también se puede representar como un par de escalares-una carta estándar e ( E
MINÚSCULA , o U + 0065 ), seguido de la COMBINACIÓN DE ACENTO
AGUDO escalar ( U + 0301 ).La COMBINACIÓN DE ACENTO AGUDO escalar se
aplica gráficamente al escalar que lo precede, convirtiendo uncorreo en una é cuando
se representa por un sistema de representación de texto Unicode-consciente.
En ambos casos, la carta é se representa como una sola Swift Carácter valor que
representa un clúster grafema extendida. En el primer caso, el clúster contiene un único
escalar; en el segundo caso, es un grupo de dos escalares:
• let precomposed: Character = "\u{D55C}" // 한
• let decomposed: Character = "\u{1112}\u{1161}\u{11AB}" // , ,
• // precomposed is 한, decomposed is
Racimos de grafema ampliada son una forma flexible para representar muchos
caracteres de alfabetos complejos como un solo personaje valor. Por ejemplo, las
sílabas Hangul del alfabeto coreano se pueden representar como una secuencia
cualquiera precomposed o descompuesto. Ambas representaciones califican como un
solo personaje valor en Swift:
• let precomposed: Character = "\u{D55C}" // 한
• let decomposed: Character = "\u{1112}\u{1161}\u{11AB}" // , ,
• // precomposed is 한, decomposed is
• // Precomposed es 한, descompuesto es 한  
Racimos de grafema ampliada permiten escalares para encerrar marcas
(como COMBINAR adjuntando CIRCLE , o U + 20DD ) para encerrar otros
escalares Unicode como parte de una sola Carácter valor:
• let enclosedEAcute: Character = "\u{E9}\u{20DD}"
• // enclosedEAcute is é⃝
Escalares Unicode para los símbolos indicadores regionales se pueden combinar en
parejas para hacer un solo personaje de valor, como esta combinación
de REGIONAL INDICADOR SÍMBOLO LETRA U ( U + 1F1FA ) yREGIONAL
INDICADOR SÍMBOLO LETRA S ( U + 1F1F8 ):
• let regionalIndicatorForUS: Character = "\u{1F1FA}\u{1F1F8}"
• // regionalIndicatorForUS is
Contando Personajes
Para recuperar un recuento de los caracteres en los valores de una cadena, llame al
mundial countElementsfunción y pase una cadena como único parámetro de la
función:
• let unusualMenagerie = "Koala , Snail , Penguin , Dromedary "
• println("unusualMenagerie has \(countElements(unusualMenagerie)) characters")
• // prints "unusualMenagerie has 40 characters"
Tenga en cuenta que el uso de Swift de clusters grafema extendidas
para Carácter valores significa que la concatenación de cadenas y modificación no
siempre puede afectar el número de caracteres de una cadena.

  52  
Por ejemplo, si inicializa una nueva cadena con la palabra de cuatro caracteres café , y
luego añadir unaAGUDA ACCENT COMBINACIÓN ( U + 0301 ) al final de la
cadena, la cadena resultante va a tener un recuento de caracteres de 4 , con una cuarto
carácter de é , no e :
• var word = "cafe"
• println("the number of characters in \(word) is \(countElements(word))")
• // prints "the number of characters in cafe is 4"

• word += "\u{301}" // COMBINING ACUTE ACCENT, U+0301

• println("the number of characters in \(word) is \(countElements(word))")
• // prints "the number of characters in café is 4"
NOTA
Racimos de grafema ampliada pueden estar compuestos de uno o más escalares
Unicode. Esto significa que diferentes personajes y diferentes representaciones del
mismo carácter, pueden requerir diferentes cantidades de memoria para
almacenar. Debido a esto, los personajes de Swift No cada uno tomar la misma cantidad
de memoria dentro de la representación de una cadena. Como resultado, el número de
caracteres de una cadena no puede calcularse sin iteración a través de la cadena para
determinar sus límites de racimo grafema prolongados. Si está trabajando con valores de
cadena especialmente largos, tenga en cuenta que la countElements función debe
iterar sobre los escalares Unicode en toda la cadena con el fin de calcular un recuento de
caracteres exacta para esa cadena.
Tenga en cuenta también que el carácter número devuelto por countElements no
siempre es la misma que lalongitud característica de un NSString que contiene los
mismos caracteres. La longitud de un NSString se basa en el número de unidades de
código de 16 bits dentro de UTF-16 la representación de la cadena y no el número de
grupos de grafema Unicode extenderse dentro de la cadena. Para reflejar este hecho,
lalongitud de la propiedad NSString se llama utf16Count cuando se accede en
un Swift Cadena de valor.
Comparando Cuerdas
Swift proporciona tres maneras de comparar los valores textuales: string y el carácter de
igualdad, de igualdad de prefijo y sufijo de igualdad.
Cadena de caracteres y la Igualdad
Cadena y carácter igualdad se verifica con la "igual a" operador ( == ) y el "no es igual
a" operador ( =! ), como se describe en Operadores de comparación :
• let quotation = "We're a lot alike, you and I."
• let sameQuotation = "We're a lot alike, you and I."
• if quotation == sameQuotation {
• println("These two strings are considered equal")
• }
• // prints "These two strings are considered equal"

  53  
Dos de Cuerda valores (o dos caracteres valores) se consideran iguales si sus
racimos de grafema extendidos son canónicamente equivalentes . Racimos de grafema
ampliada son canónicamente equivalentes si tienen el mismo significado lingüístico y la
apariencia, incluso si están compuestos de diferentes escalares Unicode detrás de las
escenas.
Por ejemplo, E MINÚSCULA CON AGUDA ( U + 00E9 ) es canónicamente
equivalente a E MINÚSCULA ( U + 0065 ), seguido de COMBINAR AGUDA
ACCENT ( U + 0301 ). Ambos grupos de grafema extendidas son formas válidas de
representar el carácter é , y por lo que se consideran equivalentes canónicamente:
• // "Voulez-vous un café?" using LATIN SMALL LETTER E WITH ACUTE
• let eAcuteQuestion = "Voulez-vous un caf\u{E9}?"

• // "Voulez-vous un café?" using LATIN SMALL LETTER E and COMBINING
ACUTE ACCENT
• let combinedEAcuteQuestion = "Voulez-vous un caf\u{65}\u{301}?"

• if eAcuteQuestion == combinedEAcuteQuestion {
• println("These two strings are considered equal")
• }
• // prints "These two strings are considered equal"
Por el contrario, LATIN CAPITAL LETTER A (U+0041, or "A"), tal como se utiliza
en Inglés, es no equivalente aCIRÍLICA MAYÚSCULA A ( U + 0410 , o "А" ), tal
como se utiliza en ruso. Los caracteres son visualmente similares, pero no tienen el
mismo significado lingüístico:
• let latinCapitalLetterA: Character = "\u{41}"

• let cyrillicCapitalLetterA: Character = "\u{0410}"

• if latinCapitalLetterA != cyrillicCapitalLetterA {
• println("These two characters are not equivalent")
• }
• // prints "These two characters are not equivalent"
NOTA
Cuerda y carácter comparaciones en Swift no son sensible a la localidad.
Prefijo y Sufijo Igualdad
Para comprobar si una cadena tiene un prefijo o sufijo cadena en particular, el llamado
de la cadenahasPrefix y hasSuffix métodos, los cuales tienen un solo argumento
de tipo de cadena y devolver un valor booleano.
Los ejemplos a continuación consideran una matriz de cadenas que representan los
lugares de la escena de los dos primeros actos de Shakespeare Romeo y Julieta :

  54  
• let romeoAndJuliet = [
• "Act 1 Scene 1: Verona, A public place",
• "Act 1 Scene 2: Capulet's mansion",
• "Act 1 Scene 3: A room in Capulet's mansion",
• "Act 1 Scene 4: A street outside Capulet's mansion",
• "Act 1 Scene 5: The Great Hall in Capulet's mansion",
• "Act 2 Scene 1: Outside Capulet's mansion",
• "Act 2 Scene 2: Capulet's orchard",
• "Act 2 Scene 3: Outside Friar Lawrence's cell",
• "Act 2 Scene 4: A street in Verona",
• "Act 2 Scene 5: Capulet's mansion",
• "Act 2 Scene 6: Friar Lawrence's cell"
• ]
Usted puede utilizar el hasPrefix método con el romeoAndJuliet matriz para
contar el número de escenas en el acto 1 de la obra:
• var act1SceneCount = 0
• for scene in romeoAndJuliet {
• if scene.hasPrefix("Act 1 ") {
• ++act1SceneCount
• }
• }
• println("There are \(act1SceneCount) scenes in Act 1")
• // prints "There are 5 scenes in Act 1"
Del mismo modo, utilizar el hasSuffix método para contar el número de escenas que
tienen lugar en o alrededor de la mansión de los Capuleto y la celda de Fray Lorenzo:
• var mansionCount = 0
• var cellCount = 0
• for scene in romeoAndJuliet {
• if scene.hasSuffix("Capulet's mansion") {
• ++mansionCount
• } else if scene.hasSuffix("Friar Lawrence's cell") {
• ++cellCount
• }
• }
• println("\(mansionCount) mansion scenes; \(cellCount) cell scenes")
• // prints "6 mansion scenes; 2 cell scenes"
NOTA

  55  
Los hasPrefix y hasSuffix métodos de realizar una comparación equivalencia
canónica carácter por carácter entre los grupos de grafema extendidos en cada cadena,
como se describe en Cadena y Carácter Igualdad .
Unicode Representaciones de Cuerdas
Cuando una cadena Unicode se escribe en un archivo de texto o algún otro tipo de
almacenamiento, los escalares Unicode en esa cadena se codifican en una de varias
definidos Unicode formas de codificación .Cada forma codifica la cadena en trozos
pequeños conocidos como unidades de código . Estos incluyen el UTF-8 forma de
codificación (que codifica una cadena como unidades de código de 8 bits), la forma de
codificación UTF-16 (que codifica una cadena como unidades de código de 16 bits), y
la forma de codificación UTF-32 (que codifica una cadena como unidades de código de
32 bits).
Swift proporciona varias formas de acceder a las representaciones Unicode de
cuerdas. Usted puede recorrer en iteración la cadena con un para - en la declaración,
para acceder a sus particulares caracteres como valores Unicode extendido racimos
grafema. Este proceso se describe en Trabajar con caracteres .
Alternativamente, acceder a una Cadena de valor en una de las otras tres
representaciones Unicode compatibles:
• Una colección de caracteres UTF-8 unidades de código (consultado con la
cadena utf8 propiedad)
• Una colección de 16 caracteres UTF-unidades de código (consultado con la
cadena utf16 propiedad)
• Una colección de valores escalares Unicode de 21 bits, lo que equivale a UTF-32
forma de codificación de la cadena (consultado con la
cadena unicodeScalars propiedad)
Cada ejemplo muestra una representación diferente de la siguiente cadena, que se
compone de los caracteres D , o , g , ! ( EXCLAMATION DOBLE MARCA o Unicode
escalar U + 203C ), y la carácter ( CARA DE PERRO , o Unicode escalar U +
1F436 ):
• dejar dogString = "perro! "  
UTF-8 Representación
Puede acceder a una representación UTF-8 de una cuerda por la iteración en
su utf8 propiedad. Esta propiedad es de tipo String.UTF8View , que es una
colección de 8 bits sin signo ( Uint8 valores), uno para cada byte en UTF-8 la
representación de la cadena:
• for codeUnit in dogString.utf8 {
• print("\(codeUnit) ")
• }
• print("\n")
• // 68 111 103 226 128 188 240 159 144 182
En el ejemplo anterior, los tres primeros decimales codeunit valores
( 68 , 111 , 103 ) representan los caracteres D , o , y g , cuya representación UTF-8 es
el mismo que su representación ASCII. Los próximos tres
decimales codeunit valores ( 226 , 128 , 188 ) son una de tres bytes UTF-8

  56  
representación del DOBLE EXCLAMACIÓN carácter. Los cuatro
últimos codeunit valores ( 240 , 159 , 144 , 182 ) son una de cuatro bytes UTF-8
la representación de la CARA PERRO carácter.
UTF-16 Representación
Puede acceder a una representación UTF-16 de una cuerda por la iteración en
su utf16 propiedad. Esta propiedad es de tipo String.UTF16View , que es una
colección de 16 bits sin signo ( uint16 valores), una para cada unidad de código de 16
bits en UTF-16 la representación de la cadena:
• for codeUnit in dogString.utf16 {
• print("\(codeUnit) ")
• }
• print("\n")
• // 68 111 103 8252 55357 56374
Una vez más, los tres primeros codeunit valores ( 68 , 111 , 103 ) representan los
caracteres D , o , y g , cuya UTF-16 unidades de código tienen los mismos valores que
en UTF-8 la representación de la cadena (porque estos escalares Unicode representan
caracteres ASCII ).
El cuarto codeunit valor ( 8252 ) es un equivalente decimal del valor
hexadecimal 203C , que representa el escalar Unicode U + 203C para el DOBLE
EXCLAMACIÓN carácter. Este carácter se puede representar como una sola unidad de
código UTF-16.
La quinta y sexta codeunit valores ( 55.357 y 56.374 ) son una representación
par suplente UTF-16 de la CARA PERRO carácter. Estos valores son un valor alto
sustituto de U + D83D (valor decimal 55357 ) y un valor bajo sustituta de U +
DC36 (valor decimal 56374 ).
Unicode Scalar Representación
Puede acceder a una representación escalar Unicode de una Cadena de valor de la
iteración en suunicodeScalars propiedad. Esta propiedad es de
tipo UnicodeScalarView , que es una colección de valores de
tipo UnicodeScalar .
Cada UnicodeScalar tiene un valor de propiedad que devuelve el valor de 21
bits del escalar, representada dentro de un UInt32 Valor:
• for scalar in dogString.unicodeScalars {
• print("\(scalar.value) ")
• }
• print("\n")
• // 68 111 103 8252 128054
Los valores para las propiedades de los tres primeros UnicodeScalar valores
( 68 , 111 , 103 ) una vez representan de nuevo los caracteres D , o , y g .
El cuarto codeunit valor ( 8252 ) es de nuevo un equivalente decimal del valor
hexadecimal 203C , que representa el escalar Unicode U + 203C para el DOBLE
EXCLAMACIÓN carácter.

  57  
El valor de la propiedad de la quinta y última UnicodeScalar , 128.054 , es
un equivalente decimal del valor hexadecimal 1F436 , lo que representa el escalar
Unicode U + 1F436 para el CARA DE PERRO carácter.
Como una alternativa a la consulta de sus valor propiedades,
cada UnicodeScalar valor también se puede utilizar para construir una
nueva cadena de valor, tal como con interpolación de cadenas:
• for scalar in dogString.unicodeScalars {
• println("\(scalar) ")
• }
• // D
• // o
• // g
• // ‼
• //
 

Tipos Collection

Swift proporciona dos tipos de colección , conocidas como matrices y diccionarios, para
almacenar colecciones de valores. Matrices tienda ordenó listas de valores del mismo
tipo. Diccionarios almacenar colecciones no ordenadas de valores del mismo tipo, que
puede ser referenciado y miró hacia arriba a través de un identificador único (también
conocido como una clave).
Arrays y diccionarios en Swift son siempre claras sobre los tipos de valores y claves que
pueden almacenar.Esto significa que no se puede insertar un valor de tipo incorrecto en
una matriz o diccionario por error.También significa que usted puede estar seguro
acerca de los tipos de valores que va a recuperar de una matriz o diccionario. Uso de
Swift de colecciones escritas explícitamente garantiza que el código es siempre claro
acerca de los tipos de valores que puede trabajar y le permite capturar cualquier tipo de
desajustes en el desarrollo temprano de su código.
NOTA
Detrás de las escenas, la matriz y Diccionario tipos de Swift se implementan
como colecciones genéricas .Para más información sobre los tipos genéricos y
colecciones, vea Genéricos .
La mutabilidad de las Colecciones
Si crea una matriz o un diccionario y la asigna a una variable, la colección que se crea
será mutable . Esto significa que usted puede cambiar (o mutar ) la colección después
de que se crea al agregar, eliminar o cambiar elementos de la colección. Por el contrario,
si se asigna una matriz o un diccionario a una constante, esa matriz o diccionario
es inmutable , y su tamaño y contenido no se pueden cambiar.
NOTA
Es una buena práctica para crear colecciones inmutables en todos los casos en que la
colección no necesita cambiar. Si lo hace, le permite al compilador Swift para optimizar
el rendimiento de las colecciones que se crean.

  58  
Arrays
Un array almacena varios valores del mismo tipo en una lista ordenada. El mismo valor
puede aparecer en una matriz varias veces en diferentes posiciones.
Arrays Swift son específicas sobre los tipos de valores que pueden almacenar. Se
diferencian de Objective-C de NSArray y NSMutableArray clases, que pueden
almacenar cualquier tipo de objeto y no proporcionan ninguna información sobre la
naturaleza de los objetos que regresan. En Swift, el tipo de valores que una matriz
particular puede almacenar siempre está claro, ya sea a través de un tipo de anotación
explícita, o por medio de la inferencia de tipos, y no tiene que ser un tipo de clase. Si se
crea una matriz de Int valores, por ejemplo, no se puede insertar cualquier valor que
no sea Int valores en la matriz. Arrays Swift son de tipo seguro, y siempre están claros
acerca de lo que pueden contener.
Tipo de matriz Taquigrafía Sintaxis
El tipo de una matriz Swift está escrito en su totalidad como matriz <SomeType> ,
donde SomeType es el tipo que se permite que el conjunto de almacenar. También
puede escribir el tipo de una matriz en forma abreviada como [SomeType] . Aunque
las dos formas son funcionalmente idénticos, se prefiere la forma abreviada, y se utiliza
en toda esta guía para referirse al tipo de una matriz.
Arreglos Literales
Puede inicializar una matriz con un literal de matriz , que es una forma abreviada de
escribir uno o más valores como una colección de matriz. Un literal de matriz se escribe
como una lista de valores separados por comas, rodeado de un par de corchetes:
• [ value 1 , value 2 , value 3 ]


El ejemplo siguiente crea una matriz denominada ShoppingList para almacenar de
Cuerda valores:
• var shoppingList: [String] = ["Eggs", "Milk"]
• // ShoppingList se ha inicializado con dos artículos
iniciales  
El ShoppingList variable se declara como "un conjunto de Cuerda valores ",
escrito como [cadena] . Debido a que esta variedad particular ha especificado un tipo
de valor de la Cadena , se sólo permite almacenar de Cuerda valores. Aquí,
la ShoppingList matriz se inicializa con dos cuerdas valores
( "huevos" y "Milk" ), escritas en un literal de matriz.
NOTA
El ShoppingList matriz se declara como una variable (con la var introductor) y no
una constante (con la letintroductor) porque más elementos se añaden a la lista de la
compra en los siguientes ejemplos.
En este caso, la matriz contiene dos literal de Cuerda valores y nada más. Esto
coincide con el tipo de laShoppingList declaración de variables (una matriz que
sólo puede contener de Cuerda valores), por lo que la asignación de la matriz literal
se permite como una manera de inicializar ShoppingList con dos artículos iniciales.
Gracias a la inferencia de tipos de Swift, usted no tiene que escribir el tipo del array si
está inicializar con un literal de matriz que contiene los valores del mismo tipo. La
  59  
inicialización de ShoppingList podría haber sido escrito en una forma más corta en
su lugar:
• var shoppingList = ["Eggs", "Milk"]
Debido a que todos los valores de la matriz literal son del mismo tipo, Swift se puede
inferir que [cadena] es el tipo correcto a utilizar para la ShoppingList variable.
Acceso y modificación de una matriz
Puede acceder y modificar una matriz a través de sus métodos y propiedades, o
utilizando la sintaxis subíndice.
Para saber el número de elementos de una matriz, compruebe su lectura sólo contar la
propiedad:
• println("The shopping list contains \(shoppingList.count) items.")
• // prints "The shopping list contains 2 items."
• // imprime "La lista de la compra contiene 2 elementos."  
Utilice la Boolean estaVacia propiedad como un acceso directo para comprobar si
el recuento de propiedad es igual a 0 :
• if shoppingList.isEmpty {
• println("The shopping list is empty.")
• } else {
• println("The shopping list is not empty.")
• }
• // prints "The shopping list is not empty."
Puede agregar un nuevo elemento a la final de una matriz llamando a la matriz de
datos anexados método:
• shoppingList.append("Flour")  
// shoppingList now contains 3 items, and someone is making pancakes

Alternativamente, agregue un conjunto de uno o más elementos compatibles con el
operador de asignación de suma ( + = ):
• shoppingList += ["Baking Powder"]
• // shoppingList now contains 4 items
• shoppingList += ["Chocolate Spread", "Cheese", "Butter"]
• // shoppingList now contains 7 items
Recuperar un valor de la matriz utilizando sintaxis subíndice , pasando el índice del
valor que desea recuperar entre corchetes inmediatamente después del nombre de la
matriz:
• var firstItem = shoppingList[0]
• // firstItem is equal to "Eggs"
Tenga en cuenta que el primer elemento de la matriz tiene un índice de 0 , no 1 . Arrays
en Swift son siempre cero-indexada.
Usted puede utilizar la sintaxis subíndice para cambiar un valor existente en un índice
dado:

  60  
• shoppingList[0] = "Six eggs"
• // El primer elemento de la lista es ahora igual a "Seis
huevos" en lugar de "huevos"  
También puede utilizar la sintaxis subíndice para cambiar una serie de valores a la vez,
incluso si el conjunto de reemplazo de los valores tiene una longitud diferente a la gama
que está reemplazando. El ejemplo siguiente reemplaza "Spread
Chocolate" , "queso" , y "Butter" con "Bananas" y "Manzanas" :
• shoppingList[4...6] = ["Bananas", "Apples"]
• // shoppingList now contains 6 items
NOTA
No se puede utilizar la sintaxis subíndice para añadir un nuevo elemento a la final de
una matriz. Si intenta utilizar la sintaxis subíndice para recuperar o establecer un valor
para un índice que está fuera de los límites existentes de una matriz, se activará un error
de ejecución. Sin embargo, se puede comprobar que un índice es válido antes de
utilizarlo, comparándolo con la matriz de conteo propiedad. Excepto cuando el
recuentoes 0 (es decir, la matriz está vacía), el mayor índice válido de una matriz
siempre será count - 1 , porque las matrices se indexan de cero.
Para insertar un elemento en la matriz en un índice especificado, la llamada de la
matriz de inserción (atIndex :) método:
• shoppingList.insert("Maple Syrup", atIndex: 0)
• // shoppingList now contains 7 items
• // "Maple Syrup" is now the first item in the list
Esta llamada a la inserción método inserta un nuevo elemento con un valor
de "jarabe de arce" en el comienzo mismo de la lista de la compra, se indica
mediante un índice de 0 .
Del mismo modo, se elimina un elemento de la matriz con
el removeAtIndex método. Este método elimina el elemento en el índice
especificado y devuelve el elemento eliminado (aunque se puede ignorar el valor
devuelto si no lo necesita):
• let mapleSyrup = shoppingList.removeAtIndex(0)// El elemento que estaba
en el índice 0 sólo se ha eliminado  
• // ShoppingList ahora contiene 6 artículos, y no el jarabe
de arce  
• // La constante Maplesyrup es ahora igual a la cadena
"jarabe de arce" eliminado  
Las lagunas de una matriz se cierran cuando se elimina un elemento, por lo que el valor
en el índice 0 es una vez más igual a "Seis huevos" :
• firstItem = ShoppingList [ 0 ]  
• // FirstItem es ahora igual a "Seis huevos"  
Si desea eliminar el último punto de una matriz, utilice el removeLast método en
lugar de la removeAtIndexmétodo para evitar la necesidad de consultar de la

  61  
matriz recuento propiedad. Al igual que
el removeAtIndexmétodo, removeLast devuelve el elemento eliminado:
• let apples = shoppingList.removeLast()  
• // El último elemento de la matriz sólo se ha eliminado  
• // ShoppingList ahora contiene 5 artículos, y no hay
manzanas  
• // las manzanas constante es ahora igual a las "manzanas"
retirados cadena  
•  
Interactuando sobre una matriz
Puede iterar sobre todo el conjunto de valores en una matriz con el de - en bucle:
• for item in shoppingList {
• println(item)
• }
• // Six eggs
• // Milk
• // Flour
• // Baking Powder
• // Bananas
Si usted necesita el índice entero de cada elemento, así como su valor, utilice el
mundial enumerate función para repetir la matriz en
lugar. La enumeración función devuelve una tupla para cada elemento del conjunto
formado por el índice y el valor de ese elemento. Puede descomponerse en la tupla
constantes o variables temporales como parte de la iteración:
• for (index, value) in enumerate(shoppingList) {
• println("Item \(index + 1): \(value)")
• }
• // Item 1: Six eggs
• // Item 2: Milk
• // Item 3: Flour
• // Item 4: Baking Powder
• // Item 5: Bananas
Para más información sobre la para - en bucle, consulte Para Loops .

Creación e inicialización de una matriz


Puede crear una matriz vacía de un cierto tipo (sin establecer valores iniciales),
utilizando la sintaxis de inicializador:
• var someInts = [Int]()
• println("someInts is of type [Int] with \(someInts.count) items.")

  62  
• // prints "someInts is of type [Int] with 0 items."
Tenga en cuenta que el tipo de la someInts variable se infiere que [Int] , ya que se
ajusta a la salida de un[Int] inicializador.
Alternativamente, si el contexto ya ofrece información de tipo, como un argumento de
función o una variable ya mecanografiado o constante, se puede crear una matriz vacía
con una matriz vacía literal, que se escribe como [] (un par vacío de corchetes):
• someInts.append(3)
• // someInts now contains 1 value of type Int
• someInts = []
• // someInts es ahora un conjunto vacío, pero sigue siendo
de tipo [Int]  
De Swift Matriz tipo también proporciona un inicializador para la creación de una
matriz de un cierto tamaño, con todos sus valores establecidos en un valor
predeterminado proporcionado. Se pasa este inicializador el número de elementos a
añadir a la nueva matriz (denominada cuenta ) y un valor por defecto del tipo
apropiado (denominado repeatedValue ):
• var threeDoubles = [Double](count: 3, repeatedValue: 0.0)
• // threeDoubles is of type [Double], and equals [0.0, 0.0, 0.0]
Puede crear una nueva matriz sumando dos matrices existentes de tipo compatible con
el operador de suma ( + ). Tipo de la nueva matriz se infiere a partir del tipo de las dos
matrices se agregan juntos:
• var anotherThreeDoubles = [Double](count: 3, repeatedValue: 2.5)
• // anotherThreeDoubles is inferred as [Double], and equals [2.5, 2.5, 2.5]

• var sixDoubles = threeDoubles + anotherThreeDoubles
• // sixDoubles is inferred as [Double], and equals [0.0, 0.0, 0.0, 2.5, 2.5, 2.5]

Diccionarios
Un diccionario es un contenedor que almacena varios valores del mismo tipo. Cada
valor se asocia con una única tecla , que actúa como un identificador para ese valor
dentro del diccionario. A diferencia de los elementos de un array, los elementos de un
diccionario no tienen un orden específico. Se utiliza un diccionario cuando necesita
buscar valores en función de su identificador, casi de la misma manera que un
diccionario en el mundo real se utiliza para buscar la definición de una palabra en
particular.
NOTA

  63  
Diccionarios Swift son específicas sobre los tipos de claves y valores que pueden
almacenar. Se diferencian de Objective-C
de NSDictionary y NSMutableDictionary clases, que pueden usar cualquier
tipo de objeto como sus claves y valores y no proporcionan ninguna información sobre
la naturaleza de esos objetos. En Swift, el tipo de claves y valores que un diccionario
particular puede almacenar siempre se pone de manifiesto, ya sea a través de un tipo de
anotación explícita oa través de la inferencia de tipos.

Diccionario Tipo Taquigrafía Sintaxis


El tipo de un diccionario Swift está escrito en su totalidad como Dictionary
<KeyType, ValueType> , dondeKeyType es el tipo de valor que puede ser
utilizado como una clave de diccionario, y ValueType es el tipo de valor que las
tiendas Diccionario para esas llaves.
También puede escribir el tipo de un diccionario en forma abreviada
como [KeyType: ValueType] . Aunque las dos formas son funcionalmente
idénticos, se prefiere la forma abreviada, y se utiliza en toda esta guía para referirse al
tipo de un diccionario.

Los literales Diccionario


Puede inicializar un diccionario con un diccionario literal , que tiene una sintaxis
similar a la matriz literal visto antes. Un literal diccionario es una forma abreviada de
escribir uno o más pares clave-valor como unDiccionario colección.
Un par clave-valor es una combinación de una clave y un valor. En un literal
diccionario, la clave y el valor de cada par clave-valor están separados por dos
puntos. Los pares clave-valor se escriben como una lista, separada por comas, rodeado
de un par de corchetes:
• [ key 1 : value 1 , key 2 : value 2 , key 3 : value 3 ]

El siguiente ejemplo crea un diccionario para almacenar los nombres de los aeropuertos
internacionales. En este diccionario, las claves son códigos de tres letras de la
Asociación Internacional de Transporte Aéreo, y los valores son los nombres de
aeropuertos:
• var airports: [String: String] = ["TYO": "Tokyo", "DUB": "Dublin"]
La aeropuertos diccionario se declara como tener un tipo de [Cadena:
String] , que significa "un diccionariocuyas claves son del tipo de cuerda ,
y cuyos valores son también del tipo de cuerda ".
NOTA
La aeropuertos diccionario se declara como una variable (con la var introductor),
y no una constante (con lalet introductor), debido a que más aeropuertos se añaden al
diccionario en los ejemplos siguientes.
La aeropuertos diccionario se inicializa con un diccionario literal que contiene dos
pares clave-valor. El primer par tiene una clave de "TYO" y un valor de "Tokio" . El
segundo par tiene una clave de "DUB" y un valor de"Dublin" .
Este literal diccionario contiene dos cuerdas: Cuerda pares. Este tipo de clave-
valor coincide con el tipo de losaeropuertos de declaración de variables (un

  64  
diccionario con sólo Cuerda llaves, y sólo de Cuerda valores), por lo que la
asignación del diccionario literal se permite como una manera de inicializar
los aeropuertos diccionario con dos artículos iniciales.
Al igual que con las matrices, usted no tiene que escribir el tipo del diccionario si estás
inicializar con un literal diccionario cuyas claves y valores tienen tipos coherente. La
inicialización de los aeropuertos podría haber sido ser escrito en una forma más
corta en su lugar:
• var airports = ["TYO": "Tokyo", "DUB": "Dublin"]
Debido a que todas las claves en el literal son del mismo tipo que los demás, y del
mismo modo todos los valores son del mismo tipo que los demás, Swift se puede inferir
que [Cadena: Cadena] es el tipo correcto a utilizar para
el aeropuertos diccionario.
Acceso y Modificación de un diccionario
Puede acceder y modificar un diccionario a través de sus métodos y propiedades, o
utilizando la sintaxis subíndice. Al igual que con una matriz, a averiguar el número de
elementos en un Diccionario comprobando su lectura sólo contar la propiedad:
• println("The airports dictionary contains \(airports.count) items.")
• // imprime "El diccionario de los aeropuertos contiene 2
elementos."  
Utilice la Boolean estaVacia propiedad como un acceso directo para comprobar si
el recuento de propiedad es igual a 0 :
• if airports.isEmpty {
• println("The airports dictionary is empty.")
• } else {
• println("The airports dictionary is not empty.")
• }
• // imprime "Diccionario de los aeropuertos no está vacía."  
Puede agregar un nuevo elemento a un diccionario con la sintaxis subíndice. Utilice una
llave del tipo apropiado como el índice de subíndice, y asignar un nuevo valor del tipo
apropiado:
• airports["LHR"] = "London"
• // Diccionario de los aeropuertos ahora contiene 3
artículos  
También puede utilizar la sintaxis subíndice para cambiar el valor asociado a una clave
particular:
• airports["LHR"] = "London Heathrow"
• // El valor de "LHR" se ha cambiado por "Londres Heathrow"  
Como alternativa a subíndices, use un diccionario UpdateValue (forKey
:) método para establecer o actualizar el valor de una clave particular. Al igual que los
ejemplos anteriores subíndice, el UpdateValue (forKey :)método establece un
valor para una clave si no existe ninguno, o actualiza el valor si ya existe esa clave. A
diferencia de un subíndice, sin embargo, el UpdateValue (forKey :) método
  65  
devuelve el viejo valor después de realizar una actualización. Esto le permite comprobar
si una actualización se llevó a cabo.
El UpdateValue (forKey :) método devuelve un valor opcional de valor tipo
del diccionario. Para un diccionario que almacena Cuerda valores, por ejemplo, el
método devuelve un valor de tipo de cadena? , o "opcional Cadena". Este valor
opcional contiene el valor antiguo para esa clave, si es que existía antes de la
actualización, onil si existía ningún valor:
• if let oldValue = airports.updateValue("Dublin International", forKey: "DUB") {
• println("The old value for DUB was \(oldValue).")
• }
• // imprime "El valor antiguo para DUB era Dublín."  
También puede utilizar la sintaxis subíndice para recuperar un valor del diccionario para
una clave particular.Debido a que es posible solicitar una clave para los que no existe
ningún valor, el subíndice de un diccionario devuelve un valor opcional de valor de tipo
del diccionario. Si el diccionario contiene un valor para la clave solicitada, el subíndice
devuelve un valor opcional que contiene el valor existente para esa tecla. De lo
contrario, el subíndice retornos nil :
• if let airportName = airports["DUB"] {
• println("The name of the airport is \(airportName).")
• } else {
• println ( "Ese aeropuerto no está en el diccionario
aeropuertos." )  
• }  
• // imprime "El nombre del aeropuerto es Dublin
International."  
Usted puede utilizar la sintaxis subíndice para quitar un par clave-valor de un
diccionario mediante la asignación de un valor de cero para esa clave:
• airports["APL"] = "Apple International"
• // "Apple Internacional" no es el aeropuerto más real para
APL, por lo que la elimina  
• airports["APL"] = nil
• // APL ha sido eliminado del diccionario  
Alternativamente, quitar un par clave-valor de un diccionario con
el removeValueForKey método. Este método elimina el par clave-valor si existe y
devuelve el valor extraído, o vuelve nulo cuando no existe otro valor:
• if let removedValue = airports.removeValueForKey("DUB") {
• println("The removed airport's name is \(removedValue).")
• } else {
• println("The airports dictionary does not contain a value for DUB.")
• }

  66  
• // imprime "El nombre del aeropuerto es eliminado Dublin
International."  
Iterar sobre un diccionario
Puede iterar sobre los pares de valores clave en un diccionario con un para -
en bucle. Cada elemento en el diccionario se devuelve como una (, valor de la
clave) tupla, y se puede descomponer los miembros de la tupla en constantes o
variables temporales como parte de la iteración:
• for (airportCode, airportName) in airports {
• println("\(airportCode): \(airportName)")
• }
• // LHR: London Heathrow
• // TYO: Tokyo
Para más información sobre la para - en bucle, consulte Para Loops .
También puede recuperar una colección iterable de claves o valores de un diccionario
mediante el acceso a sus claves y valores propiedades:
• for (airportCode, airportName) in airports {
• println("\(airportCode): \(airportName)")
• }
• // LHR: London Heathrow
• // TYO: Tokyo
For more about the for-in loop, see For Loops.
You can also retrieve an iterable collection of a dictionary’s keys or values by accessing
its keys and valuesproperties:
• for airportCode in airports.keys {
• println("Airport code: \(airportCode)")
• }
• // Airport code: LHR
• // Airport code: TYO

• for airportName in airports.values {
• println("Airport name: \(airportName)")
• }
• // Airport name: London Heathrow
• // Airport name: Tokyo
Si usted necesita utilizar claves o valores de un diccionario con una API que toma
una matriz de ejemplo, inicializar un nuevo array con las claves o valores
de la propiedad:
• let airportCodes = [String](airports.keys)
• // airportCodes is ["LHR", "TYO"]

  67  

• let airportNames = [String](airports.values)
• // airportNames is ["London Heathrow", "Tokyo"]
NOTA
De Swift Diccionario tipo es una colección desordenada. No se especifica el orden
en el que las claves, valores y pares clave-valor se recuperan cuando la iteración en un
diccionario.

Creación de un diccionario vacío


Al igual que con las matrices, se puede crear un Diccionario vacío de cierto tipo
utilizando la sintaxis de inicializador:
• var namesOfIntegers = [Int: String]()
• // namesOfIntegers is an empty [Int: String] dictionary
En este ejemplo se crea un diccionario vacío de tipo [Int: String] para almacenar
nombres legibles de valores enteros. Sus teclas son de tipo int , y sus valores son de
tipo Cadena .
Si el contexto ya ofrece información de tipo, puede crear un diccionario vacío con un
diccionario vacío literal, que se escribe como [:] (dos puntos dentro de un par de
corchetes):
• namesOfIntegers [ 16 ] = "dieciséis"  
• // namesOfIntegers ahora contiene 1 par clave-valor  
• namesOfIntegers = [:]  
• // namesOfIntegers es una vez más un diccionario vacío de
tipo [Int: String]  
 
Valores hash para los tipos clave de diccionario
Un tipo debe ser Hashable con el fin de ser utilizado como un diccionario de tipo clave,
es decir, el tipo debe proporcionar una forma de calcular un valor hash por sí
mismo. Un valor hash es un Int valor que es el mismo para todos los objetos que
comparan iguales, tal que si a == b , se deduce que a.hashValue ==
b.hashValue .
Todos los tipos básicos de Swift (tales como cuerdas , Int , doble , y Bool ) son
Hashable por defecto, y todos estos tipos se pueden usar como las teclas de un
diccionario. Valores de los miembros de enumeración sin valores asociados (como se
describe en enumeraciones ) también son Hashable por defecto.
NOTA
Usted puede utilizar sus propios tipos personalizados como tipos clave de diccionario al
hacerlos conformes a la Hashable protocolo de la biblioteca estándar de Swift. Los
tipos que se ajustan a la Hashable protocolo debe proporcionar una
gettable Int propiedad llamada hashValue , y también deben proporcionar una
implementación de la "es igual" operador ( == ). El valor devuelto por un tipo
de hashValue propiedad no está obligado a ser la misma en diferentes ejecuciones del
mismo programa, o en diferentes programas.

  68  
Para obtener más información acerca de conforme a los protocolos,
consulte Protocolos .

Control de flujo

Swift proporciona todos los estados de flujos de control conocidos de idiomas como
C. Estos incluyen for and whileloops para realizar una tarea varias veces; ify switch
sentencias para ejecutar diferentes ramas de código basado en ciertas condiciones; y
declaraciones tales como breaky continue para transferir el flujo de ejecución a
otro punto en el código.
Además de la tradicional de bucle que se encuentra en C, Swift agrega un for- in
bucle que hace que sea fácil de iterar sobre arrays, diccionarios, rangos, cadenas y otras
secuencias.
De Swift switch declaración también es considerablemente más potente que su
homólogo en C. Los casos de un switch de declaración no "caen a través de" al
siguiente caso en Swift, evitando errores C comunes causadas por faltantes de break
declaraciones. Los casos pueden coincidir con muchos modelos diferentes, incluyendo
partidos de rango, tuplas, y arroja a un tipo específico. Valores coincidentes en un
switch de caso se pueden unir a las constantes o variables temporales para su uso
dentro del cuerpo del caso, y las condiciones de juego complejas se pueden expresar con
una cláusula where para cada caso.

Para Loops
Swift proporciona dos tipos de bucle que realizan un conjunto de declaraciones de un
cierto número de veces:
• La for- in bucle realiza una serie de afirmaciones para cada elemento en un
rango, secuencia, recogida, o progresión.
• El for bucle realiza una serie de declaraciones hasta que se cumpla una condición
específica, por lo general mediante el incremento de un contador cada vez que el
bucle termina.
For-In
Se utiliza la for- in bucle para iterar sobre colecciones de objetos, tales como rangos
de números, elementos de un conjunto, o caracteres de una cadena.
Este ejemplo imprime las primeras entradas de la cinco-veces-table:
• for index in 1...5 {
• println("\(index) times 5 is \(index * 5)")
• }
• // 1 times 5 is 5
• // 2 times 5 is 10
• // 3 times 5 is 15
• // 4 times 5 is 20
• // 5 times 5 is 25
La colección de artículos que se iterado es una gama cerrado de números
de 1 a 5 inclusive, como se indica por el uso del operador de rango cerrado ( ... ). El

  69  
valor del índice se establece en el primer número en el rango ( 1 ), y se ejecutan las
sentencias dentro del bucle. En este caso, el bucle contiene sólo una declaración, que
imprime una entrada de la cinco veces-mesa para el valor actual de índice . Después
de que se ejecuta la sentencia, el valor de índice se actualiza para contener el segundo
valor en el intervalo ( 2 ), y elprintln función es llamada nuevamente. Este proceso
continúa hasta que se alcanza el final de la gama.
En el ejemplo anterior, el índice es una constante cuyo valor se establece
automáticamente al inicio de cada iteración del bucle. Como tal, no tiene que ser
declarado antes de ser usado. Se declara implícitamente simplemente por su inclusión
en la declaración del bucle, sin la necesidad de un let declaración palabra clave.
NOTA
El índice constante existe solamente dentro del alcance de la bucle. Si desea
comprobar el valor del índicedespués de completar el bucle, o si usted quiere trabajar
con su valor como una variable en lugar de una constante, debe declararlo a ti mismo
antes de su uso en el circuito.
Si usted no necesita cada valor de la gama, puede ignorar los valores mediante el uso de
un guión en lugar de un nombre de variable:
• let base = 3
• let power = 10
• var answer = 1
• for _ in 1...power {
• answer *= base
• }
• println("\(base) to the power of \(power) is \(answer)")
• // Imprime "3 a la potencia de 10 es 59049"  
En este ejemplo se calcula el valor de un número a la potencia de otro (en este caso, 3 a
la potencia de 10 ).Se multiplica un valor inicial de 1 (es decir, 3 a la potencia de 0 )
por 3 , diez veces, utilizando una gama cerrado que comienza con 1 y termina
con 10 . Este cálculo no tiene por qué conocer los valores de los contadores
individuales en cada iteración del bucle simplemente necesita ejecutar el bucle el
número correcto de veces. El carácter de subrayado _ (en lugar de una variable de
bucle) hace que los valores individuales sean ignorados y no proporciona acceso al
valor actual en cada iteración del bucle.
Use una for- in bucle con un arsenal para repetir sus artículos:
• let names = ["Anna", "Alex", "Brian", "Jack"]
• for name in names {
• println("Hello, \(name)!")
• }
• // Hello, Anna!
• // Hello, Alex!
• // Hello, Brian!
• // Hello, Jack!

  70  
También puede iterar sobre un diccionario para acceder a sus pares clave-valor. Cada
elemento en el diccionario se devuelve como un (clave, valor) tupla cuando se
itera el diccionario, y se puede descomponer el (valor llave) los miembros de la
tupla como constantes nombradas explícitamente para su uso dentro del cuerpo de
la para - en bucle. Aquí, las claves del diccionario se descomponen en una constante
llamadaanimalName , y los valores del diccionario se descomponen en una constante
llamada legCount :
• let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
• for (animalName, legCount) in numberOfLegs {
• println("\(animalName)s have \(legCount) legs")
• }
• // arañas tienen 8 patas  
• // gatos tienen 4 patas  
• // hormigas tienen 6 patas  
Los elementos de un diccionario no necesariamente pueden repetir en el mismo
orden en que se insertaron.El contenido de un diccionario son intrínsecamente
desordenada, y la iteración en ellos no garantiza el orden en el que se recuperarán. Para
más información sobre matrices y diccionarios, vea Tipos Collection .)
Además de las matrices y los diccionarios, también puede utilizar la para - en bucle
para iterar sobre loscaracteres valores en una cadena:
• for character in "Hello" {
• println(character)
• }
• // H
• // e
• // l
• // l
• // o

For
Además de para - en bucles, Swift apoya al estilo de C tradicional para bucles con
una condición y un incrementador:
• for var index = 0; index < 3; ++index {
• println("index is \(index)")
• }
• // index is 0
• // index is 1
• // index is 2
Here’s the general form of this loop format:

  71  
• for initialization ; condition ; increment {
• statements

• }
Los puntos y comas separan las tres partes de la definición del bucle, como en C. Sin
embargo, a diferencia de C, Swift no necesita paréntesis alrededor de toda la
inicialización "; condición; bloque de incremento ".
El bucle se ejecuta de la siguiente manera:
1. La primera vez que se entra en el bucle, la expresión de inicialización se evalúa una
vez, para establecer cualquier constante o variables que se necesitan para el bucle.
2. La expresión de condición es evaluada. Si se evalúa como falsa , el bucle termina,
y la ejecución de código continúa después de la de llave de cierre del bucle ( } ). Si
la expresión se evalúa comoverdadera , la ejecución de código continúa
ejecutando las sentencias entre llaves.
3. Después se ejecutan todas las declaraciones, la expresión de incremento se
evalúa. Puede aumentar o disminuir el valor de un contador, o establecer una de las
variables inicializadas a un nuevo valor basado en el resultado de las
declaraciones. Después de la expresión de incremento ha sido evaluado, la ejecución
vuelve al paso 2, y la expresión de condición se evalúa otra vez.
El proceso de formato de bucle y la ejecución descrita anteriormente es la abreviatura de
(y equivalente a) el siguiente esquema:
• initialization
• while condition {
• statements
• increment

• }
Constantes y variables declaradas dentro de la expresión de inicialización
(como índice var = 0 ) sólo son válidos en el ámbito de la de bucle en sí. Para
recuperar el valor final del índice después de los extremos de bucle, debe declarar el
índice antes de que comience el alcance del bucle:
• var index: Int
• for index = 0; index < 3; ++index {
• println("index is \(index)")
• }
• // index is 0
• // index is 1
• // index is 2
• println ( "Las  sentencias  de  bucle  fueron  ejecutados \ ( index ) veces  " )  

  72  
• // grabados "fueron ejecutados Las sentencias de bucle 3
veces"  
Tenga en cuenta que el valor final del índice después de que se complete este bucle
es 3 , no 2 . La última vez que la declaración de la subasta índice ++ se llama, se
pone índice a 3 , lo que hace que el índice <3equiparar a falso , terminando
el bucle.
Mientras Loops
Un tiempo de bucle realiza un conjunto de declaraciones hasta que una condición se
convierte en falsa . Este tipo de bucles se utilizan mejor cuando no se conoce el
número de iteraciones antes de que comience la primera iteración. Swift proporciona
dos tipos de tiempo de bucle:
• mientras evalúa su estado en el inicio de cada pasada a través del bucle.
• hacer - mientras se evalúa su condición al final de cada paso a través del
bucle.

While (Mientras)
Un while de bucle comienza evaluando un solo estado. Si la condición
es verdadera , un conjunto de estados se repite hasta que la condición se convierte
en falsa .
Aquí está la forma general de un while bucle:
• while condition {
• statements

• }

Este ejemplo tiene un simple juego de Serpientes y Escaleras (también conocido


como Serpientes y Escaleras ):

  73  
 

Las reglas del juego son las siguientes:


• El tablero tiene 25 cuadrados, y el objetivo es aterrizar en o más allá de la plaza 25.
• Cada turno, tirar un dado de seis caras y jugada de ese número de plazas, siguiendo
el camino horizontal que indica la flecha punteada arriba.
• Si su turno termina en la parte inferior de una escalera, que se asciende por la
escalera.
• Si su turno termina a la cabeza de una serpiente, se mueve hacia abajo esa serpiente.
El tablero de juego está representado por una serie de Int valores. Su tamaño se basa
en una constante llamada finalSquare , que se utiliza para inicializar la matriz y
también para comprobar si hay una condición de victoria más adelante en el ejemplo. La
junta se inicializa con cero 26 Int valores, no 25 (uno por cada uno en los índices
de 0 a través de 25 inclusive):
• let finalSquare = 25
• var board = [Int](count: finalSquare + 1, repeatedValue: 0)
Algunas plazas se establecen a continuación, a tener valores más específicos para las
serpientes y escaleras. Cuadrados con una base de la escalera tiene un número positivo a
mover el tablero, mientras que los cuadrados con una cabeza de serpiente tienen un
número negativo para moverte hacia abajo la placa:
• board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
• board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08
Plaza 3 contiene la parte inferior de una escalera que sube a la plaza 11 Para representar
esto, board [03] es igual a 08 , lo que equivale a un valor entero de 8 (la diferencia
entre 3 y 11 ). El operador unario más ( + i ) los saldos con el operador menos unario
( -i ), y los números menores que 10 se rellenan con ceros para que todas las
definiciones de mesa se alinean. (Ni tweak estilística es estrictamente necesario, pero
que conducen a más aseado código.)
Casilla de salida del jugador es "cero plaza", que se encuentra junto a la esquina inferior
izquierda del tablero.La primera tirada de dados siempre se mueve el jugador en el
tablero:

  74  
• var square = 0
• var diceRoll = 0
• while square < finalSquare {
• // roll the dice
• if ++diceRoll == 7 { diceRoll = 1 }
• // move by the rolled amount
• square += diceRoll
• if square < board.count {
• // if we're still on the board, move up or down for a snake or a ladder
• square += board[square]
• }
• }
• println("Game over!")
En este ejemplo se utiliza un enfoque muy simple para tirar los dados. En lugar de un
generador de números aleatorios, que comienza con un diceRoll valor de 0 . Cada
vez que a través del tiempo de bucle, diceRoll se incrementa con el operador de
incremento prefijo ( ++ i ), y luego se comprueba para ver si se ha hecho demasiado
grande. El valor de retorno de ++ diceRoll es igual al valor de diceRoll después
de que se incrementa. Cada vez que este valor de retorno es igual a 7 , la tirada se ha
vuelto demasiado grande, y se pone a un valor de 1 . Esto da una secuencia
de diceRoll valores que siempre es 1 , 2 , 3 , 4 , 5 , 6 , 1 , 2 y así sucesivamente.
Después de tirar los dados, el jugador avanza por diceRoll cuadrados. Es posible que
la tirada de dados pudo haber movido el jugador más allá de la plaza 25, en cuyo caso el
juego ha terminado. Para hacer frente a este escenario, el código comprueba que la
plaza es menor que el consejo de gama recuento propiedad antes de añadir el
valor almacenado en cartón [cuadrados] en la actual plaza de valor para
mover el jugador hacia arriba o hacia abajo las escaleras o las serpientes.
Si este cheque no se ha realizado, a bordo [cuadrado] podrían tratar de acceder a
un valor fuera de los límites de la placa de matriz, que darían lugar a un
error. Si cuadrado es ahora igual a 26 , el código sería tratar de comprobar el valor
de la tabla de [26] , que es más grande que el tamaño de la matriz.
La corriente mientras que la ejecución del bucle finaliza entonces, y la condición
del bucle se comprueba para ver si el bucle debe ejecutarse de nuevo. Si el jugador ha
movido en o más allá de la plaza número 25 , la condición del bucle se evalúa
como falsa , y el juego termina.
Un mientras bucle es apropiado en este caso porque la longitud del juego no está
claro en el comienzo de lamientras bucle. En cambio, el bucle se ejecuta hasta que
una condición particular es satisfecho.
Do-While
La otra variación de la while bucle, conocido como el do – while bucle, realiza
una sola pasada a través del bloque de bucle primero, antes de considerar la condición
del bucle. A continuación, sigue repitiendo el bucle hasta que la condición es falsa .

  75  
Aquí está la forma general de un do – while bucle:

• do {
• statements
• } while condition
Aquí está el juego de la oca ejemplo de nuevo, escrito como un do - mientras bucle
en lugar de una , mientras que bucle. Los valores
de finalSquare , tablero , cuadrados , y diceRoll se inicializan
exactamente de la misma manera que con un tiempo de bucle:
• let finalSquare = 25
• var board = [Int](count: finalSquare + 1, repeatedValue: 0)
• board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
• board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08
• var square = 0
• var diceRoll = 0
En esta versión del juego, la primera acción en el circuito es para comprobar si hay una
escalera o una serpiente. No Escalera en el tablero lleva al jugador directamente a la
plaza 25, por lo que no es posible ganar el juego al subir una escalera. Por lo tanto, es
seguro para comprobar si hay una serpiente o una escalera como la primera acción en el
circuito.
Al comienzo del juego, el jugador está en "cero plaza". tablero [0] siempre es
igual 0 , y no tiene efecto:
• do {
• // move up or down for a snake or ladder
• square += board[square]
• // roll the dice
• if ++diceRoll == 7 { diceRoll = 1 }
• // move by the rolled amount
• square += diceRoll
• } while square < finalSquare
• println("Game over!")
Después de los controles de código para serpientes y escaleras, los dados se rueda, y el
jugador se mueve hacia adelante por diceRoll cuadrados. La ejecución del bucle de
corriente luego termina.
La condición del bucle ( mientras cuadrado <finalSquare ) es el mismo que
antes, pero esta vez no se evalúa hasta que el final de la primera pasada por el bucle. La
estructura de la do - mientras bucle se adapta mejor a este juego que el tiempo de
bucle en el ejemplo anterior. En el do – while bucle de arriba, cuadrado + =
bordo [cuadrado] siempre se ejecuta inmediatamente después del bucle while
la condición confirma que la plaza está todavía en el tablero. Este comportamiento

  76  
elimina la necesidad de la comprobación de límites de la matriz visto en la versión
anterior del juego.

Sentencias condicionales
A menudo es útil para ejecutar diferentes piezas de código basado en ciertas
condiciones. Es posible que desee ejecutar un pedazo de código cuando se produce un
error, o para mostrar un mensaje cuando un valor es demasiado alto o demasiado
bajo. Para hacer esto, usted hace parte de su código condicional .
Swift proporciona dos maneras de agregar saltos condicionales a su código, conocido
como el caso de la declaración y el interruptor comunicado. Normalmente, se
utiliza el caso de declaración para evaluar las condiciones simples con sólo unos
pocos resultados posibles. El interruptor de declaración se adapta mejor a
condiciones más complejas con múltiples permutaciones posibles, y es útil en
situaciones en las que la concordancia de patrones puede ayudar a seleccionar una rama
de código apropiado para ejecutar.

If
En su forma más simple, el if de la declaración tiene un solo caso
de condición. Ejecuta un conjunto de declaraciones sólo si esa condición es true:
• var temperatureInFahrenheit = 30
• if temperatureInFahrenheit <= 32  
• println ( "Hace  mucho  frío.  Considere  usar  una  bufanda." )  
• }  
• // imprime "Es muy frío. Considere usar una bufanda."  
El ejemplo anterior comprueba si la temperatura es inferior o igual a 32 grados
Fahrenheit (el punto de congelación del agua). Si lo es, se imprime un mensaje. De lo
contrario, ningún mensaje se imprime, y la ejecución de código continúa después de que
el caso de llave de cierre de declaración.
El caso de declaración puede proporcionar un conjunto alternativo de los estados,
conocidos como cláusula else , para cuando el si la condición es falsa . Estas
declaraciones se indican con la otra palabra clave:
• temperatureInFahrenheit = 40
• if temperatureInFahrenheit <= 32 {
• println("It's very cold. Consider wearing a scarf.")
• } else {
• println("It's not that cold. Wear a t-shirt.")
• }
• // imprime "¡no está tan fría. Lleve una camiseta".  
Una de estas dos ramas siempre se ejecuta. Debido a que la temperatura ha aumentado
a 40 grados Fahrenheit, ya no es lo suficientemente frío como para aconsejar que
llevaba un pañuelo, y lo que la otrarama se dispara en su lugar.

  77  
Puede múltiple cadena si las declaraciones en conjunto, a tener en cuenta cláusulas
adicionales:
• temperatureInFahrenheit = 90
• if temperatureInFahrenheit <= 32 {
• println("It's very cold. Consider wearing a scarf.")
• } else if temperatureInFahrenheit >= 86 {
• println("It's really warm. Don't forget to wear sunscreen.")
• } else {
• println("It's not that cold. Wear a t-shirt.")
• }
• // imprime "Es muy caliente. No se olvide de usar protector
solar."  
Aquí, un adicional if se añade la declaración para responder a las temperaturas
particularmente cálidos. La última else cláusula se mantiene, e imprime una
respuesta para cualquier temperatura que no son ni demasiado caliente ni demasiado
fría.
La final else cláusula es opcional, sin embargo, y puede ser excluida si el conjunto de
condiciones no necesita ser completa:
• temperatureInFahrenheit = 72
• if temperatureInFahrenheit <= 32 {
• println("It's very cold. Consider wearing a scarf.")
• } else if temperatureInFahrenheit >= 86 {
• println ( "Es  muy  caliente.  No  se  olvide  de  usar  protector  solar." )  
• }  
En este ejemplo, la temperatura no es ni demasiado frío ni demasiado caliente para
activar el si o más si las condiciones, y así se imprime ningún mensaje.

Switch
Un switch declaración considera un valor y lo compara contra varios patrones
coincidentes posibles.A continuación, se ejecuta un bloque de código apropiado, basado
en el primer patrón que coincida con éxito.Un switch declaración proporciona una
alternativa a la if la declaración para responder a múltiples estados posibles.
En su forma más simple, un switch declaración compara un valor con uno o más
valores del mismo tipo:
• switch some value to consider {
• case value 1 :
• respond to value 1
• case value 2 ,

  78  
• value 3 :
• respond to value 2 or 3

• default:
• otherwise, do something else

• }
Cada switch de declaración consiste en múltiples posibles casos , cada uno de los
cuales comienza con el caso de palabras clave. Además de comparar con los valores
específicos, Swift ofrece varias maneras para cada caso para especificar patrones
coincidentes más complejos. Estas opciones se describen más adelante en esta sección.
El cuerpo de cada interruptor de caso es una rama separada de la ejecución de
código, de manera similar a las ramas de un si declaración. El interruptor de la
declaración determina qué rama debe ser seleccionado.Esto se conoce
como conmutación en el valor que se está considerando.
Cada switch de declaración debe ser exhaustiva . Es decir, cada valor posible del
tipo que se está considerado debe ser igualada por uno de los de
conmutación casos. Si no es apropiado para proporcionar un switch de caso para
cada valor posible, se puede definir un cajón de sastre caso por defecto para cubrir
cualquier valor que no se tratan de forma explícita. Este cajón de sastre caso se indica
con la palabra clavepor defecto , y debe aparecer siempre pasado.
En este ejemplo se utiliza un interruptor declaración a considerar un único carácter
en minúscula llamadasomeCharacter :
• let someCharacter: Character = "e"
• switch someCharacter {
• case "a", "e", "i", "o", "u":
• println("\(someCharacter) is a vowel")
• case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m",
• "n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z":
• println("\(someCharacter) is a consonant")
• default:
• println("\(someCharacter) is not a vowel or a consonant")
• }
• // Impresiones "e es una vocal"  
El switch primer caso de declaración coincide con las cinco vocales en minúsculas
en el idioma Inglés.Del mismo modo, su segundo caso coincide con todas las
consonantes en inglés en minúsculas.
No es práctico para escribir el resto de caracteres posibles en el marco de un switch
de caso, y por lo que este switch declaración proporciona un default caso para
que coincida con el resto de personajes que no son vocales o consonantes. Esta
disposición garantiza que el switch de la declaración es exhaustiva.

  79  
No fallthrough Implícito
En contraste con el switch de declaraciones en C y Objective-C, switch
declaraciones en Swift no se pierdan en el fondo de cada caso y en la siguiente de forma
predeterminada. En lugar de ello, todo elconmutador de declaración termina su
ejecución tan pronto como la primera coincidencia interruptor se completa caso,
sin requerir una explícita break comunicado. Esto hace que el interruptor de la
declaración más seguro y más fácil de usar que en C, y evita la ejecución de más de
un interruptor de caso por error.
NOTA
Aunque ruptura no se requiere en Swift, todavía se puede utilizar
un descanso para que coincida con la declaración y pasar por alto un caso particular,
o para salir de un caso emparejado antes de que el caso ha terminado su
ejecución. Ver Rotura en una sentencia switch para más detalles.
El cuerpo de cada caso debe contener al menos una sentencia ejecutable. No es válido
para escribir el siguiente código, debido a que el primer caso está vacía:
• let anotherCharacter: Character = "a"
• switch anotherCharacter {
• case "a":
• case "A":
• println("The letter A")
• default:
• println("Not the letter A")
• }
• // Esto reportará un error en tiempo de compilación  
A diferencia de un interruptor de instrucción en C,
este interruptor declaración no coincide con tanto "a" y"A" . Más bien, se
informa de un error de tiempo de compilación que el caso "a": no contiene
ninguna de las declaraciones ejecutables. Este enfoque evita fallthrough accidental de
un caso a otro, y lo convierte en código más seguro que es más claro en su intención.
Varias coincidencias para un solo interruptor de caso pueden estar separados por
comas, y pueden ser escritas en varias líneas si la lista es larga:
• switch some value to consider {
• case value 1 ,
• value 2 :
• statements

• }
NOTA
Para optar por fallthrough comportamiento para un determinado conmutador caso,
utilice el fallthrough palabra clave, como se describe en fallthrough .

  80  
GAMA A JUEGO
Los valores en los switch de los casos se puede comprobar por su inclusión en un
rango. Este ejemplo utiliza rangos de números para proporcionar un recuento de
lenguaje natural para los números de cualquier tamaño:
• let count = 3_000_000_000_000
• let countedThings = "stars in the Milky Way"
• var naturalCount: String
• switch count {
• case 0:
• naturalCount = "no"
• case 1...3:
• naturalCount = "a few"
• case 4...9:
• naturalCount = "several"
• case 10...99:
• naturalCount = "tens of"
• case 100...999:
• naturalCount = "hundreds of"
• case 1000...999_999:
• naturalCount = "thousands of"
• default:
• naturalCount = "millions and millions of"
• }
• println("There are \(naturalCount) \(countedThings).")
• // imprime "Hay millones y millones de estrellas en la Vía
Láctea."  
 
Tuples
Puede usar tuplas para probar varios valores en el
mismo interruptor comunicado. Cada elemento de la tupla puede ser probado
contra un valor diferente o rango de valores. Como alternativa, utilice el guión bajo
(_ identificador) para adaptarse a cualquier valor posible.
El siguiente ejemplo toma una (x, y) punto, expresado como un simple tupla de
tipo (Int, Int) , y lo clasifica en el gráfico que sigue el ejemplo:
• let somePoint = (1, 1)
• switch somePoint {
• case (0, 0):
• println("(0, 0) is at the origin")

  81  
• case (_, 0):
• println("(\(somePoint.0), 0) is on the x-axis")
• case (0, _):
• println("(0, \(somePoint.1)) is on the y-axis")
• case (-2...2, -2...2):
• println("(\(somePoint.0), \(somePoint.1)) is inside the box")
• default:
• println("(\(somePoint.0), \(somePoint.1)) is outside of the box")
• }
• // imprime "(1, 1) es dentro de la caja"  

 
El switch de declaración determina si el punto está en el origen (0, 0); en el eje x de
color rojo; en el eje y naranja; dentro de la caja azul de 4 por 4 centrada en el origen; o
fuera de la caja.
A diferencia de C, Swift permite múltiples switch casos a considerar el mismo valor
o valores. De hecho, el punto (0, 0) pudo igualar todos cuatro de los casos en este
ejemplo. Sin embargo, si varias coincidencias son posibles, se utiliza siempre el primer
caso a juego. El punto (0, 0) se correspondería con case (0, 0) en primer lugar, y
así todos los demás casos coincidentes sería ignorado.
Vinculaciones Valor
Un switch de caso puede unir el valor o valores de que coincide con constantes o
variables temporales, para su uso en el cuerpo de la caja. Esto se conoce como valor de
unión , ya que los valores son "unido" a las constantes temporales o variables dentro del
cuerpo de la caja.
El siguiente ejemplo toma una (x, y) punto, expresado como una tupla de tipo (Int,
Int) y lo clasifica en el gráfico que sigue:
• let anotherPoint = (2, 0)
• switch anotherPoint {

  82  
• case (let x, 0):
• println("on the x-axis with an x value of \(x)")
• case (0, let y):
• println("on the y-axis with a y value of \(y)")
• case let (x, y):
• println("somewhere else at (\(x), \(y))")
• }
• // Imprime "en el eje x con un valor x de 2"  

 
El switch de declaración determina si el punto está en el eje x de color rojo, en el eje
y naranja, o en otra parte, en ninguno de eje.
Los tres switch casos declaran de marcador de posición constantes x e y , que toman
forma temporal en los valores de una o ambas tuplas de otroPunto . El primer
caso, caso (sea x, 0) , coincide con cualquier punto con una y el valor de 0 y
asigna del punto x valor de la constante temporal x . Del mismo modo, el segundo
caso, el caso (0, dejar y) , coincide con cualquier punto con una x valor
de 0 y asigna del punto yvalor de la constante temporal y .
Una vez que las constantes temporales se declaran, pueden ser utilizados dentro de
bloque de código de la carcasa. Aquí, se utilizan como abreviatura para la impresión de
los valores con el println función.
Tenga en cuenta que este switch de declaración no tiene un valor
predeterminado caso. El último caso,let caso (x, y) , declara una tupla de
dos constantes de marcador de posición que pueden coincidir con cualquier valor. Como
resultado de ello, de que coincide con todos los posibles valores restantes, y
undefecto no es necesario para hacer que el caso del switch declaración
exhaustiva.
En el ejemplo anterior, x y y son declarados como constantes con el let palabra clave,
porque no hay necesidad de modificar sus valores dentro del cuerpo de la caja. Sin
embargo, podrían haber sido declaradas como variables en su lugar, con la var palabra
clave. Si esto se hubiera hecho, se habría creado una variable temporal e inicializado
  83  
con el valor apropiado. Cualquier cambio en esa variable sólo tendrían un efecto en el
cuerpo de la caja.

Where
Un interruptor de caso puede utilizar una donde cláusula para evaluar
afecciones adicionales.
El ejemplo siguiente cataloga un punto en el siguiente gráfico (x, y):
• let yetAnotherPoint = (1, -1)
• switch yetAnotherPoint {
• case let (x, y) where x == y:
• println("(\(x), \(y)) is on the line x == y")
• case let (x, y) where x == -y:
• println("(\(x), \(y)) is on the line x == -y")
• case let (x, y):
• println("(\(x), \(y)) is just some arbitrary point")
• }
• // imprime "(1, -1) está en la línea x == -y"  

 
El switch de la declaración determina si el punto está en la línea diagonal verde
donde x == y , en la línea diagonal púrpura donde x == -y , o ninguno.
Los tres switch casos declaran de marcador de posición constantes x e y , que toman
forma temporal en los dos valores de tupla de yetAnotherPoint . Estas constantes
se utilizan como parte de un donde cláusula, para crear un filtro dinámico. El siwtch
de caso coincide con el valor actual del punto sólo si el que la condición de la
cláusula se evalúa como verdadera para ese valor.
Como en el ejemplo anterior, el último caso coincide con todos los posibles valores
restantes, y por lo que undefecto no es necesario para hacer que el caso del
interruptor declaración exhaustiva.

  84  
Declaraciones de transferencia de control
Enunciados de transferencia de control cambian el orden en que se ejecuta el código,
transfiriendo el control de una sola pieza de código a otro. Swift tiene cuatro enunciados
de transferencia de control:
• continuar
• ruptura
• fallthrough
• retorno
La siguen , descanso , y fallthrough declaraciones se describen a
continuación. El retorno declaración se describe en Funciones .
Continuar
La siguen declaración dice un bucle para detener lo que está haciendo y empezar de
nuevo desde el comienzo de la siguiente iteración a través del bucle. Dice que "he
terminado con la iteración actual del bucle" sin salir del bucle completo.
NOTA
En una de bucle con un estado y incrementador, incrementador del bucle está siendo
evaluada después de llamar al continúan comunicado. El bucle en sí sigue
trabajando como de costumbre; se omite sólo el código dentro del cuerpo del bucle.
El ejemplo siguiente elimina todas las vocales y los espacios de una cadena en
minúsculas para crear una frase críptica rompecabezas:
• let puzzleInput = "great minds think alike"
• var puzzleOutput = ""
• for character in puzzleInput {
• switch character {
• case "a", "e", "i", "o", "u", " ":
• continue
• default:
• puzzleOutput.append(character)
• }
• }
• println(puzzleOutput)
• // prints "grtmndsthnklk"
El código anterior llama al continue palabra clave cada vez que coincide con una
vocal o un espacio, provocando la iteración actual del bucle a fin de inmediato y para
saltar directamente a la comienzo de la siguiente iteración. Este comportamiento
permite que el bloque de interruptores para que coincida (e ignorar) sólo los caracteres
de vocales y espaciales, en lugar de exigir el bloque para que coincida con cada
personaje que debe quedar impreso.

Break
La break declaración finaliza la ejecución de todo un estado de flujo de control
inmediatamente. La break declaración se puede utilizar dentro de un switch o una

  85  
sentencia de bucle cuando se quiere terminar la ejecución del switch de declaración
o bucle antes de lo que sería el caso.

Rotura en una Declaración Loop


Cuando se utiliza dentro de una sentencia de bucle, break termina la ejecución del
bucle inmediato, y transfiere el control a la primera línea de código después de llave de
cierre del bucle ( } ). No se ejecuta el código más lejos de la iteración actual del bucle,
y no habrá más iteraciones del bucle se inician.

Rotura en una sentencia switch


Cuando se utiliza dentro de un switch declaración, break hace que el switch
de declaración para terminar su ejecución de inmediato, y para transferir el control a la
primera línea de código después de que el switch de llave de cierre de declaración
( } ).
Este comportamiento puede ser utilizado para emparejar y pasar por alto uno o más
casos en un switchcase. Porque de Swift swicht declaración es exhaustiva y no
permite que los casos vacíos, a veces es necesario hacer coincidir deliberadamente e
ignorar un caso con el fin de hacer que sus intenciones explícitas. Usted puede hacer
esto escribiendo la ruptura declaración como todo el cuerpo de la caja desea
ignorar. Cuando este caso se corresponde con el switch de la declaración,
la ruptura declaración dentro de la caja termina el switch de la ejecución de la
declaración de inmediato.
NOTA
Un switch de caso que sólo contiene un comentario es reportado como un error en
tiempo de compilación. Los comentarios no son declaraciones y no causan un switch
de caso para ser ignorada.Utilice siempre una ruptura declaración de ignorar
un switch de caso.
El siguiente ejemplo se conecta un Character value y determina si representa un
símbolo número en uno de los cuatro idiomas. Múltiples valores están cubiertos en un
solo switch caso de brevedad:
• let numberSymbol: Character = "三" // Simplified Chinese for the number 3
• var possibleIntegerValue: Int?
• switch numberSymbol {
• case "1", "١۱", "一", " ":
• possibleIntegerValue = 1
• case "2", "٢۲", "二", " ":
• possibleIntegerValue = 2
• case "3", "٣۳", "三", " ":
• possibleIntegerValue = 3
• case "4", "٤", "四", " ":
• possibleIntegerValue = 4
• default:

  86  
• break
• }
• if let integerValue = possibleIntegerValue {
• println("The integer value of \(numberSymbol) is \(integerValue).")
• } else {
• println("An integer value could not be found for \(numberSymbol).")
• }
• // imprime "El valor entero de 三 es 3"  
En este ejemplo se comprueba numberSymbol para determinar si se trata de un,
árabe, chino, tailandés o símbolo latino para los números 1 a 4 . Si se encuentra una
coincidencia, uno de los switch de casos de declaración establece una
opción Int? variable llamada possibleIntegerValue a un valor entero
correspondiente.
Después de la sentencia switch completa su ejecución, el ejemplo se utiliza opcional
vinculante para determinar si se ha encontrado un
valor. El possibleIntegerValue variable tiene un valor inicial implícito
decero en virtud de ser un tipo opcional, por lo que la opción de unión tendrá éxito
sólo si possibleIntegerValuese establece en un valor real por uno de
los interruptor primeros cuatro casos de declaración.
No es práctico enumerar todos los posibles caracteres valor en el ejemplo anterior,
por lo que un default case ofrece un cajón de sastre para cualquier carácter que no
se corresponden. Este default case no tiene que realizar ninguna acción, por lo que
se escribe con una sola ruptura declaración como su cuerpo. Tan pronto como
el valor predeterminado se corresponde caso, la break declaración termina
el switch de ejecución de sentencia, y la ejecución de código continúa desde el if
let comunicado.

Fallthrough
Sentencias switch en Swift no se pierdan en el fondo de cada caso y en la siguiente. En
cambio, toda la instrucción switch completa su ejecución tan pronto como se complete
el primer caso a juego. Por el contrario, C que requiere insertar una
explícita ruptura declaración al final de cada interruptor de caja para prevenir
fallthrough. Evitar fallthrough defecto significa que
Swift interruptor declaraciones son mucho más concisa y predecible que sus
contrapartes en C, y así evitan la ejecución de múltiples interruptores casos por
error.
Si realmente necesita comportamiento fallthrough estilo C, se puede optar por este
comportamiento en una base de caso por caso con el fallthrough palabra clave. El
ejemplo siguiente utiliza fallthrough para crear una descripción textual de un
número:
• let integerToDescribe = 5
• var description = "The number \(integerToDescribe) is"
• switch integerToDescribe {
  87  
• case 2, 3, 5, 7, 11, 13, 17, 19:
• description += " a prime number, and also"
• fallthrough
• default:
• description += " an integer."
• }
• println(description)
• // imprime "El número 5 es un número primo, y también un
número entero."  
En este ejemplo se declara una nueva cuerda variable llamada Descripción y le
asigna un valor inicial. La función se considera el valor
de integerToDescribe utilizando un interruptor comunicado. Si el valor
deintegerToDescribe es uno de los números primos en la lista, la función anexa
texto al final de la descripción , observar que el número es primo. A continuación,
utiliza la fallthrough palabra clave para "caer en" el defaultcaso
también. El valor predeterminado caso añade un poco de texto extra al final de
la descripción, y elinterruptor de declaración es completa.
Si el valor de integerToDescribe es no en la lista de los números primos
conocidos, que no se corresponde con el primer interruptor de caso en
absoluto. No hay otros casos específicos, y así integerToDescribe es igualada por
el cajón de sastre default caso.
Después de que el interruptor de declaración ha finalizado la ejecución, la
descripción que hace el número se imprime utilizando la println función. En este
ejemplo, el número 5 se identifica correctamente como un número primo.
NOTA
El fallthrough palabra clave no comprueba las condiciones del caso para
el interruptor de caso que hace que la ejecución caer. El fallthrough palabra
clave simplemente hace que la ejecución de código para ir a las sentencias dentro del
siguiente caso (o default bloque caso), como en el estándar de
C interruptorcomportamiento comunicado.

Declaraciones Etiquetada
Puede anidar bucles y cambiar estados dentro de otros bucles y cambiar estados en
Swift para crear estructuras de flujo de control complejos. Sin embargo, los lazos
y cambiar los estados pueden utilizar tanto laruptura declaración al finalizar su
ejecución antes de tiempo. Por lo tanto, a veces es útil para ser explícito acerca de qué
lazo o interruptor declaración quieres un descanso declaración para
terminar. Del mismo modo, si usted tiene múltiples bucles anidados, puede ser útil para
ser explícito acerca de lo que el buclecontinuará declaración debería afectar.
Para alcanzar estos objetivos, puede marcar una sentencia de bucle
o cambiar declaración con una etiqueta de declaración , y el uso de esta etiqueta con
la ruptura declaración o continuar declaración para terminar o continuar la
ejecución de la sentencia etiquetada.
  88  
Una declaración de la etiqueta se indica mediante la colocación de una etiqueta en la
misma línea que la palabra clave introductor de la declaración, seguido de dos
puntos. He aquí un ejemplo de esta sintaxis para un tiempo de bucle, aunque el
principio es el mismo para todos los bucles y los interruptores declaraciones:
• label name : while condition {
• statements

• }
El ejemplo siguiente utiliza la ruptura y seguir las declaraciones con la
etiqueta mientras bucle de una versión adaptada de la Serpientes y Escaleras juego
que vimos anteriormente en este capítulo. Esta vez, el juego tiene una regla adicional:
• Para ganar, debes aterrizar exactamente en la plaza 25.
Si una tirada de dados particular, le tomaría más allá de la plaza 25, debe tirar de nuevo
hasta que sacas el número exacto necesario para aterrizar en la plaza 25.
El tablero de juego es el mismo que antes:

 
Los valores de finalSquare , tablero , cuadrados , y diceRoll se
inicializan en la misma forma que antes:
• let finalSquare = 25
• var board = [Int](count: finalSquare + 1, repeatedValue: 0)
• board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
• board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08
• var square = 0
• var diceRoll = 0
Esta versión del juego utiliza un tiempo de bucle y un interruptor
de declaración para implementar la lógica del juego. El tiempo de bucle tiene una
etiqueta llamada declaración gameLoop , para indicar que es el bucle principal del
juego para el juego de Serpientes y Escaleras.

  89  
El while loop que la condición del bucle es mientras cuadrado =
finalSquare! , para reflejar que debe aterrizar exactamente en la plaza 25:
• gameLoop: while square != finalSquare {
• if ++diceRoll == 7 { diceRoll = 1 }
• switch square + diceRoll {
• case finalSquare:
• // diceRoll will move us to the final square, so the game is over
• break gameLoop
• case let newSquare where newSquare > finalSquare:
• // diceRoll will move us beyond the final square, so roll again
• continue gameLoop
• default:
• // this is a valid move, so find out its effect
• square += diceRoll
• square += board[square]
• }
• }
• println("Game over!")
Los dados se enrolla en el inicio de cada bucle. En lugar de mover el reproductor
inmediatamente, uninterruptor de sentencia se utiliza para tener en cuenta el
resultado de la medida, y para trabajar si se permite que el movimiento:
• Si la tirada de dados se moverá el jugador a la plaza final, el juego ha
terminado. Las vacaciones de gameLoop transferencias sentencia de control
a la primera línea de código fuera del tiempo de bucle, que termina el juego.
• Si la tirada de dados se moverá el jugador más allá de la plaza final, el movimiento
no es válida, y el jugador tiene que tirar de nuevo. El continuar
gameLoop declaración termina la actual , mientras que la iteración de bucle
y comienza la siguiente iteración del bucle.
• En todos los demás casos, la tirada es un movimiento válido. El jugador se mueve
hacia adelante pordiceRoll cuadrados y los controles de juego de lógica para
cualquier juego de la oca. El bucle se termina y el control vuelve al mismo
tiempo condición para decidir si se requiere otro turno.
NOTA
Si la break afirmación anterior no utilizó el gameLoop etiqueta, sería romper con
el interruptor de la declaración, no el tiempo comunicado. Usando
el gameLoop etiqueta deja claro que controlar declaración debe ser terminado.
Tenga en cuenta también que no es estrictamente necesario utilizar
el gameLoop etiqueta cuando llame acontinuar gameLoop para saltar a la
siguiente iteración del bucle. Sólo hay un bucle en el juego, y lo que no hay ambigüedad
en cuanto a que el bucle continúan declaración afectará. Sin embargo, no hay ningún
daño en el uso de la gameLoop etiqueta con el continuar comunicado. Si lo hace,

  90  
es consistente con el uso de la etiqueta junto a la ruptura declaración, y ayuda a que
la lógica del juego más claro de leer y entender.
 

Funciones
En esta página
Funciones son trozos independientes de código que realizan una tarea específica. Usted
da una función de un nombre que identifique lo que hace, y este nombre se usa para
"llamar" la función para llevar a cabo su tarea cuando es necesario.
Sintaxis de la función unificada de Swift es lo suficientemente flexible como para
expresar cualquier cosa, desde una función de C-estilo simple, sin nombres de
parámetros a un método-al estilo de Objective C compleja con nombres de parámetros
locales y externos para cada parámetro. Los parámetros se pueden proporcionar valores
predeterminados para simplificar las llamadas a funciones y pueden ser pasados como
in-out parámetros, que modifican una variable pasada una vez que la función ha
terminado su ejecución.
Cada función en Swift tiene un tipo, que consiste en los tipos de parámetros de la
función y el tipo de retorno.Usted puede utilizar este tipo como cualquier otro tipo de
Swift, que hace que sea fácil pasar funciones como parámetros a otras funciones, y para
volver funciones de funciones. Las funciones también pueden ser escritos dentro de
otras funciones para encapsular funcionalidad útil dentro de un ámbito de la función
anidada.

La definición y la Llamada de funciones


Cuando se define una función, puede opcionalmente especificar uno o más nombrado,
valores escritos que la función toma como entrada (conocida como parámetros ), y / o
un tipo de valor que la función va a pasar de nuevo como salida cuando se hace
(conocidos como su tipo de retorno ).
Cada función tiene un nombre de función , que describe la tarea que realiza la
función. Para utilizar una función, "llama" esa función con su nombre y lo pasa valores
de entrada (conocida como argumentos ) que coinciden con los tipos de parámetros de
la función. Los argumentos de una función siempre se deben proporcionar en el mismo
orden que la lista de parámetros de la función.
La función en el ejemplo siguiente se llama sayHello , porque eso es lo que hace-que
toma el nombre de una persona como entrada y devuelve un saludo para esa
persona. Para lograr esto, se define un parámetro de entrada de cadena de valor
llamada PersonName -y un tipo de retorno de la Cadena , que contendrá un saludo
para esa persona:
• func sayHello(personName: String) -> String {
• let greeting = "Hello, " + personName + "!"
• return greeting
• }
Toda esta información se rueda para arriba en función de la definición , que se prefija
con la func palabra clave. Usted indica el tipo de la función de retorno con la flecha de

  91  
retorno -> (un guión seguido de un soporte en ángulo recto), que es seguido por el
nombre del tipo de volver.
La definición describe lo que hace la función, lo que espera recibir, y lo devuelve
cuando se hace. La definición hace que sea fácil para la función a ser llamada sin
ambigüedades de su código en otros lugares:
• println(sayHello("Anna"))
• // prints "Hello, Anna!"
• println(sayHello("Brian"))
• // prints "Hello, Brian!"
Se llama a la sayHello función pasándole una cuerda valor argumento entre
paréntesis, como sayHello ("Anna") . Debido a que la función devuelve
una Cadena de Valor, sayHello se puede envolver en una llamada a
la println función para imprimir esa cadena y ver su valor de retorno, como se
muestra arriba.
El cuerpo de la sayHello función comienza definiendo una nueva Cadena constante
llamada de felicitación y estableciéndola en un mensaje de saludo simple
para PersonName . Este saludo se pasa entonces de nuevo fuera de la función usando
el retorno de palabras clave. Tan pronto como saludo de retorno se llama, la
función termina su ejecución y devuelve el valor actual de saludo .
Usted puede llamar al sayHello función varias veces con diferentes valores de
entrada. El ejemplo anterior muestra lo que sucede si se llama con un valor de entrada
de "Anna" , y un valor de entrada de "Brian" . La función devuelve un saludo a
medida en cada caso.
Para simplificar el cuerpo de esta función, se combinan la creación del mensaje y la
sentencia de retorno en una sola línea:
• func sayHelloAgain(personName: String) -> String {
• return "Hello again, " + personName + "!"
• }
• println(sayHelloAgain("Anna"))
• // prints "Hello again, Anna!"

Parámetros de funciones y valores de retorno
Parámetros de la función y los valores de retorno son extremadamente flexibles en
Swift. Se puede definir cualquier cosa, desde una función de utilidad simple con un solo
parámetro sin nombre de una función compleja con nombres de parámetros expresivos
y diferentes opciones de parámetros.
Parámetros de entrada múltiple
Las funciones pueden tener múltiples parámetros de entrada, que se escriben entre
paréntesis de la función, separados por comas.
Esta función toma un comienzo y un índice final para un rango medio abierta, y trabaja
cuántos elementos de la gama contiene:
• func halfOpenRangeLength(start: Int, end: Int) -> Int {

  92  
• return end - start
• }
• println(halfOpenRangeLength(1, 10))
• // prints "9"

Funciones sin parámetros
Las funciones no son necesarias para definir los parámetros de entrada. He aquí una
función sin parámetros de entrada, que siempre devuelve la misma cuerda mensaje
cada vez que se llama:
• func sayHelloWorld() -> String {
• return "hello, world"
• }
• println(sayHelloWorld())
• // prints "hello, world"
La definición de una función aún necesita paréntesis después del nombre de la función,
a pesar de que no toma ningún parámetro. El nombre de la función también es seguido
por un par de paréntesis vacío cuando se invoca la función.

Funciones Sin Valores devueltos


Las funciones no son necesarias para definir un tipo de retorno. Aquí hay una versión de
la sayHello función, llamada sayGoodbye , que imprime su propia Cadena de
valor en lugar de devolverlo:
• func sayGoodbye(personName: String) {
• println("Goodbye, \(personName)!")
• }
• sayGoodbye("Dave")
• // prints "Goodbye, Dave!"
Debido a que no tiene que devolver un valor, la definición de la función no incluye la
flecha de retorno ( -> ) o un tipo de retorno.
NOTA
En sentido estricto, la sayGoodbye función no todavía devuelve un valor, a pesar de
que hay valor de retorno se define. Funciones sin un tipo de retorno definido devuelven
un valor especial de tipo Vacío . Esto es simplemente una tupla vacía, en efecto, una
tupla con cero elementos, que puede escribirse como () .
El valor de retorno de una función puede ser ignorada cuando se le llama:
• func printAndCount(stringToPrint: String) -> Int {
• println(stringToPrint)
• return countElements(stringToPrint)
• }
• func printWithoutCounting(stringToPrint: String) {

  93  
• printAndCount(stringToPrint)
• }
• printAndCount("hello, world")
• // prints "hello, world" and returns a value of 12
• printWithoutCounting("hello, world")
• // imprime "hola, mundo", pero no devuelve un valor  
La primera función, printAndCount , imprime una cadena y, a continuación,
devuelve su recuento de caracteres como un int . La segunda
función, printWithoutCounting , llama a la primera función, pero no tiene en
cuenta su valor de retorno. Cuando la segunda función es llamada, el mensaje sigue
siendo impreso por la primera función, pero el valor devuelto no se utiliza.
NOTA
Los valores de retorno pueden ser ignorados, pero una función que dice que va a
devolver un valor siempre debe hacerlo. Una función con un tipo de retorno definido no
puede permitir que el control se le caiga de la parte inferior de la función sin devolver
un valor, y tratar de hacerlo resultará en un error en tiempo de compilación.
Funciones con valores de retorno múltiples
Puede utilizar un tipo tupla como el tipo de cambio de una función para devolver varios
valores como parte del valor de retorno de un compuesto.
El ejemplo siguiente define una función llamada MinMax , que encuentra los números
mayor y menor de una gran variedad de Int valores:
• 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)
• }
El MinMax función devuelve una tupla que contiene dos Int valores. Estos valores
están etiquetados min y maxpara que puedan ser accedidos por su nombre cuando se
consulta el valor devuelto por la función.
El cuerpo de la MinMax función inicia estableciendo dos variables de trabajo
llamados currentMin y currentMaxal valor del primer número entero de la
matriz. La función entonces itera sobre los valores restantes de la matriz y comprueba
cada valor para ver si es menor o mayor que los valores

  94  
de currentMin y currentMaxrespectivamente. Por último, los valores mínimos y
máximos generales se devuelven como una tupla de dosInt valores.
Debido a que los valores de miembro de la tupla se nombran como parte de tipo de
retorno de la función, se puede acceder con la sintaxis con punto para recuperar los
valores máximo y mínimo y encontrado:
• let bounds = minMax([8, -6, 2, 109, 3, 71])
• println("min is \(bounds.min) and max is \(bounds.max)")
• // prints "min is -6 and max is 109"
Tenga en cuenta que los miembros de la tupla no necesitan ser identificado en el punto
que la tupla se devuelve desde la función, debido a que sus nombres ya están
especificados como parte del tipo de retorno de la función.
Opcional Tipos Tuple Retorno
Si el tipo de tupla que ser devuelto de una función tiene el potencial de tener "ningún
valor" para toda la tupla, se puede usar un opcional tipo de retorno tupla para reflejar el
hecho de que toda la tupla puede ser nula .Usted escribe un tipo de retorno tupla
opcional colocando un signo de interrogación después del paréntesis de cierre del tipo
tupla, como (Int, Int)? o (String, Int, Bool)? .
NOTA
Un tipo de tupla opcional tal como (Int, Int)? es diferente de una tupla que
contiene tipos opcionales, tales como (Int Int ?,?) . Con un tipo de tupla
opcional, toda la tupla es opcional, no sólo cada valor individual dentro de la tupla.
El MinMax función anterior devuelve una tupla que contiene dos Int valores. Sin
embargo, la función no realiza ninguna comprobación de seguridad en la matriz que se
pasa. Si la matriz argumento contiene una matriz, es decir, una matriz con un
vacío conteo de 0 -el MinMax función, como se ha definido anteriormente, se
activará un error de ejecución cuando se intenta acceder a la matriz [0] .
Para hacer frente a este escenario "vacío matriz" de forma segura, escribir
la MinMax función con un tipo de retorno tupla opcional y devolver un valor
de cero cuando la matriz está vacía:
• func minMax(array: [Int]) -> (min: Int, max: Int)? {
• if array.isEmpty { return nil }
• 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)
• }
  95  
Usted puede utilizar opcional vinculante para comprobar si esta versión
del MinMax función devuelve un valor tupla real o nula :
• if let bounds = minMax([8, -6, 2, 109, 3, 71]) {
• println("min is \(bounds.min) and max is \(bounds.max)")
• }
• // prints "min is -6 and max is 109"

Parámetro Función Nombres
Todas las funciones anteriores definen nombres de los parámetros de sus parámetros:
• func someFunction(externalParameterName localParameterName: Int) {
• // function body goes here, and can use localParameterName
• // to refer to the argument value for that parameter
• }
Sin embargo, estos nombres de parámetros sólo se utilizan dentro del cuerpo de la
función de sí mismo, y no se pueden utilizar cuando se llama a la función. Este tipo de
nombres de los parámetros se conocen comonombres de parámetros locales , ya que
sólo están disponibles para su uso dentro del cuerpo de la función.
Nombres de parámetros externos
A veces es útil para nombrar cada parámetro cuando se llama a una función, para
indicar el propósito de cada argumento se pasa a la función.
Si desea que los usuarios de su función de proporcionar los nombres de parámetros que
llama a su función, definir un nombre de parámetro externo para cada parámetro,
además del nombre del parámetro local. Usted escribe un nombre de parámetro externo
antes del nombre de parámetro local que da soporte, separadas por un espacio:
• func someFunction(externalParameterName localParameterName: Int) {  
• // Cuerpo de la función va aquí, y se puede utilizar
localParameterName  
• // Para referirse al valor del argumento para ese parámetro  
• }  
NOTA
Si proporciona un nombre de parámetro externo para un parámetro, el nombre externo
debe siempre ser utilizada cuando se llama a la función.
Como ejemplo, considere la siguiente función, que se une a dos cadenas mediante la
inserción de un tercer "carpintero" cuerda entre ellos:
• func join(s1: String, s2: String, joiner: String) -> String {
• return s1 + joiner + s2
• }
Cuando se llama a esta función, el propósito de las tres cadenas que se pasa a la función
es clara:
• join("hello", "world", ", ")
• // Devuelve "hola, mundo"  

  96  
Para el propósito de estas Cuerda valores más claros, definir nombres de los
parámetros externos para cadaunen parámetro de la función:
• func join(string s1: String, toString s2: String, withJoiner joiner: String)
• -> String {
• return s1 + joiner + s2
• }
In En esta versión de la join a la función, el primer parámetro tiene un nombre
externo de cadena y un nombre local de s1 ; el segundo parámetro tiene un nombre
externo de toString y un nombre local de s2 ; y el tercer parámetro tiene un nombre
externo de withJoiner y un nombre local de joiner.
Ahora puede utilizar estos nombres de parámetros externos para llamar a la función sin
ambigüedades:
• join(string: "hello", toString: "world", withJoiner: ", ")
• // Devuelve "hola, mundo"  
El uso de nombres de parámetros externos permite a esta segunda versión de
la unirse a la función que se llamará en una frase-como forma expresiva los usuarios
de la función, sin dejar de ofrecer un cuerpo de función que sea legible y clara en su
intención.
NOTA
Considere el uso de nombres de parámetros externos cada vez que el propósito de los
argumentos de una función sería claro para alguien que lee su código por primera
vez. No es necesario especificar los nombres de parámetros externos si el propósito de
cada parámetro es unívoco cuando se invoca la función.
Taquigrafía externos nombres de los parámetros
Si desea proporcionar un nombre de parámetro externo para un parámetro de la función,
y el nombre de parámetro local ya es un nombre apropiado para usar, no es necesario
escribir el mismo nombre dos veces para ese parámetro. En su lugar, escribir el nombre
de una vez, y como prefijo el nombre con un símbolo de almohadilla ( # ). Esto le dice a
Swift a utilizar ese nombre como nombre de parámetro local y el nombre del parámetro
externo.
Este ejemplo define una función llamada containsCharacter , que define los
nombres de parámetros externos para sus dos parámetros mediante la colocación de un
símbolo de hash antes de que sus nombres de parámetros locales:
• func containsCharacter(#string: String, #characterToFind: Character) -> Bool {
• for character in string {
• if character == characterToFind {
• return true
• }
• }
• return false
• }

  97  
Elección de esta función de nombres de parámetros hace que para un cuerpo de la
función de lectura clara, permitiendo al mismo tiempo la función de ser llamado sin
ambigüedad:
• let containsAVee = containsCharacter(string: "aardvark", characterToFind: "v")
• // containsAVee equals true, because "aardvark" contains a "v"

Valores de los parámetros por defecto
Puede definir un valor por defecto para cualquier parámetro como parte de la definición
de una función. Si se define un valor por defecto, se puede omitir este parámetro cuando
se llama a la función.
NOTA
Coloca los parámetros con valores por defecto al final de la lista de parámetros de una
función. Esto garantiza que todas las llamadas a la función utilizan el mismo orden de
sus argumentos no predeterminados, y deja en claro que la misma función se está
llamando en cada caso.
Aquí hay una versión de la unirse función desde antes, lo que proporciona un valor
predeterminado para sucarpintero de parámetro:
• func join(string s1: String, toString s2: String,
• withJoiner joiner: String = " ") -> String {
• return s1 + joiner + s2
• }
Si un valor de cadena para el carpintero se proporciona cuando el unirse a la
función se llama, que valor de cadena se utiliza para unir las dos cadenas juntas, como
antes:
• join(string: "hello", toString: "world", withJoiner: "-")
• // returns "hello-world"
Sin embargo, si no hay ningún valor de carpintero se proporciona cuando se invoca
la función, el valor por defecto de un único espacio ( "" ) se utiliza en su lugar:
• join(string: "hello", toString: "world")
• // returns "hello world"

Nombres externas para parámetros con valores predeterminados
En la mayoría de los casos, es útil para proporcionar (y por lo tanto requieren) un
nombre externo para cualquier parámetro con un valor por defecto. Esto asegura que el
argumento a favor de que el parámetro es claro en su propósito si se proporciona un
valor cuando la función es llamada.
Para hacer este proceso más fácil, Swift proporciona un nombre externo automático
para cualquier parámetro que tiene un valor predeterminado. El nombre externo
automático es el mismo que el nombre local, como si hubiera escrito un símbolo de
hash antes de que el nombre local en el código.
Aquí hay una versión de la unirse a la función de antes, que no proporciona los
nombres externos para cualquiera de sus parámetros, pero todavía proporciona un valor
predeterminado para su carpintero deparámetro:

  98  
• func join(s1: String, s2: String, joiner: String = " ") -> String {
• return s1 + joiner + s2
• }
En este caso, Swift proporciona automáticamente un nombre de parámetro externo para
el carpinteroparámetro. Por tanto, el nombre externo se debe proporcionar al llamar
a la función, por lo que el propósito del parámetro claro e inequívoco:
• join("hello", "world", joiner: "-")
• // returns "hello-world"
NOTA
Usted puede optar por salir de este comportamiento escribiendo un guión bajo ( _ ) en
lugar de un nombre externo explícito al definir el parámetro. Sin embargo, se prefieren
los nombres externos para parámetros con valores por defecto.
Parámetros variadic
Un parámetro variadic acepta cero o más valores de un tipo especificado. Se utiliza un
parámetro variadic para especificar que el parámetro se puede pasar un número variable
de valores de entrada cuando se llama la función. Escribir parámetros variadic
insertando tres personajes de época ( ... ) después del nombre de tipo de parámetro.
Los valores que se pasan a un parámetro variadic se ponen a disposición en el cuerpo de
la función como una matriz del tipo apropiado. Por ejemplo, un parámetro variadic con
un nombre de números y un tipo dedoble ... se pone a disposición dentro del
cuerpo de la función como una matriz constante llama números de tipo [Doble] .
El siguiente ejemplo calcula la media aritmética (también conocida como la media )
para obtener una lista de números de cualquier longitud:
• func arithmeticMean(numbers: Double...) -> Double {
• var total: Double = 0
• for number in numbers {
• total += number
• }
• return total / Double(numbers.count)
• }
• arithmeticMean(1, 2, 3, 4, 5)
• // Devuelve 3.0, que es la media aritmética de estos cinco
números  
• arithmeticMean ( 3 , 8,25 , 18,75 )  
• // Devuelve 10,0, que es la media aritmética de estos tres
números  
NOTA
Una función puede tener como máximo un parámetro variadic, y siempre debe aparecer
último en la lista de parámetros, para evitar la ambigüedad cuando se llama a la función
con varios parámetros.

  99  
Si su función tiene uno o más parámetros con un valor por defecto, y también tiene un
parámetro variadic, coloque el parámetro variadic después de todos los parámetros en
mora al final de la lista.

Parámetros Constante y Variable


Parámetros de la función son constantes por defecto. Tratar de cambiar el valor de un
parámetro de la función desde dentro del cuerpo de que los resultados de la función en
un error en tiempo de compilación.Esto significa que usted no puede cambiar el valor de
un parámetro por error.
Sin embargo, a veces es útil para una función que tiene una variable de copia del valor
de un parámetro para trabajar. Usted puede evitar definir una nueva variable a sí mismo
dentro de la función mediante la especificación de uno o más parámetros
como parámetros variables en lugar. Los parámetros variables están disponibles como
variables y no como constantes, y dan una nueva copia modificable del valor del
parámetro de la función de trabajar.
Definir parámetros variables con el prefijo del nombre del parámetro con la palabra
clave var :
• func alignRight(var string: String, count: Int, pad: Character) -> String {
• let amountToPad = count - countElements(string)
• if amountToPad < 1 {
• return string
• }
• let padString = String(pad)
• for _ in 1...amountToPad {
• string = padString + string
• }
• return string
• }
• let originalString = "hello"
• let paddedString = alignRight(originalString, 10, "-")
• // PaddedString es igual a "----- hola"  
• // OriginalString sigue siendo igual a "hola"  
Este ejemplo define una nueva función llamada alignright , que alinea una cadena
de entrada hasta el borde derecho de una cadena de salida más larga. Cualquier espacio
de la izquierda se llena con un carácter de relleno especificado. En este ejemplo, la
cadena "hello" se convierte en la cadena "----- hola" .
El alignright función define el parámetro de entrada de cadena a ser un
parámetro variable. Esto significa quela cadena ya está disponible como una
variable local, inicializado con el valor de cadena que se pasa-in, y puede ser
manipulado dentro del cuerpo de la función.
La función comienza por la elaboración de cuántos caracteres deben agregarse a la
izquierda de la cadenacon el fin de derecha alinearlo dentro de la cadena

  100  
global. Este valor se almacena en una constante local llamado amountToPad . Si no
se necesita relleno (es decir, si amountToPad es menor que 1 ), la función
simplemente devuelve el valor de entrada de cadena sin ningún relleno.
De lo contrario, la función crea un nuevo temporal de cuerda constante
llamada padString , inicializado con laalmohadilla de carácter, y
añade amountToPad copias de padString a la izquierda de la cadena
existente. (ACadena de valor no se puede añadir a un personaje valor, por lo que
el padString constante se utiliza para asegurarse de que ambos lados de
la + operador son de Cuerda valores.)
NOTA
Los cambios que realice en un parámetro variable no persisten más allá del final de cada
llamada a la función, y no son visibles fuera del cuerpo de la función. El parámetro
variable sólo existe durante toda la vida de esa llamada a la función.
In-Out Parámetros
Los parámetros variables, como se describe anteriormente, sólo pueden ser modificados
dentro de la propia función. Si desea una función para modificar el valor de un
parámetro, y quiere que esos cambios persisten después de la llamada a la función ha
terminado, defina este parámetro como un parámetro in-out en su lugar.
Usted escribe un parámetro en-cabo colocando la inout palabra clave en el inicio de
su definición de parámetros. Un parámetro de entrada-salida tiene un valor que se
pasa en a la función, es modificada por la función, y se pasa de nuevo fuera de la
función para reemplazar el valor original.
Sólo puede pasar una variable como argumento para un parámetro in-out. No se puede
pasar una constante o un valor literal como el argumento, porque las constantes y
literales no pueden ser modificados. Usted coloca un signo ( y ) directamente antes del
nombre de una variable cuando se pasa como argumento a un parámetro inout, para
indicar que se puede modificar con la función.
NOTA
En-hacia fuera parámetros no pueden tener valores por defecto, y los parámetros
variadic no pueden ser marcados como inout . Si marca un parámetro como inout ,
no puede también ser marcado como var odejar .
He aquí un ejemplo de una función llamada swapTwoInts , que tiene dos in-out
parámetros enteros llaman unay b :
• func swapTwoInts(inout a: Int, inout b: Int) {
• let temporaryA = a
• a=b
• b = temporaryA
• }
El swapTwoInts función simplemente intercambia el valor de b en una , y el valor
de una en b . La función realiza este intercambio almacenando el valor de una en una
constante temporal llamada temporaryA , asignando el valor de b a una , y luego
asignar temporaryA a b .
Usted puede llamar al swapTwoInts función con dos variables de tipo int para
intercambiar sus valores. Tenga en cuenta que los nombres

  101  
de someInt y anotherInt son prefijadas con un símbolo de unión cuando se pasan
a la swapTwoInts función:
• var someInt = 3
• var anotherInt = 107
• swapTwoInts(&someInt, &anotherInt)
• println("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
• // Impresiones "someInt es ahora 107, y anotherInt es ahora
3"  
El ejemplo anterior muestra que los valores originales
de someInt y anotherInt son modificados por elswapTwoInts función, a pesar
de que fueron definidos originalmente fuera de la función.
NOTA
En Salida parámetros no son los mismos que devolviendo un valor de una
función. El swapTwoInts ejemplo anterior no define un tipo de retorno o devuelve un
valor, pero todavía modifica los valores de someInt yanotherInt . En-hacia fuera
parámetros son una forma alternativa para una función tenga efecto fuera del alcance de
su cuerpo de la función.
Tipos de funciones
Cada función tiene un determinado tipo de función , integrada por los tipos de
parámetros y el tipo de retorno de la función.
Por ejemplo:
• func addTwoInts(a: Int, b: Int) -> Int {
• return a + b
• }
• func multiplyTwoInts(a: Int, b: Int) -> Int {
• return a * b
• }
Este ejemplo define dos funciones matemáticas simples
llamados addTwoInts y multiplyTwoInts . Estas funciones cada toman
dos Int valores y devuelven un int valor, que es el resultado de realizar una
operación matemática apropiada.
El tipo de ambas de estas funciones es (Int, Int) -> Int . Esto puede leerse
como:
"Un tipo de función que tiene dos parámetros, tanto de tipo int , y que devuelve un
valor de tipo int . "
He aquí otro ejemplo, para una función sin parámetros o valor de retorno:
• func printHelloWorld() {
• println("hello, world")
• }
El tipo de esta función es () -> () , o "una función que no tiene parámetros y
devuelve vacío . "Funciones que no se especifique un valor de retorno siempre
devuelven vacío , lo que equivale a una tupla vacía en Swift, se muestra como () .

  102  
Uso de tipos de función
Utilice tipos de funciones al igual que cualquier otro tipo de Swift. Por ejemplo, puede
definir una constante o variable a ser de un tipo de función y asignar una función
adecuada a esa variable:
• var mathFunction : ( Int , Int ) -> Int = addTwoInts  
Esto puede leerse como:
"Definir una variable llamada mathFunction , que tiene un tipo de 'una función que
toma dos Int valores y devuelve un int valor. ' Establezca esta nueva variable para
hacer referencia a la función llamada addTwoInts".
El addTwoInts función tiene el mismo tipo que el mathFunction variables, por lo
que esta asignación se permite por tipo ortográfico de Swift.
Ahora puede llamar a la función asignada con el nombre mathFunction :
• println("Result: \(mathFunction(2, 3))")
• // Impresiones "Resultado: 5"  
Una función diferente con el mismo tipo de juego puede ser asignado a la misma
variable, de la misma manera como para los tipos de no funcionamiento:
• mathFunction = multiplyTwoInts
• println("Result: \(mathFunction(2, 3))")
• // Impresiones "Resultado: 6"  
Al igual que con cualquier otro tipo, se puede dejar en manos de Swift para inferir el
tipo de función cuando se asigna una función a una constante o variable:
• let anotherMathFunction = addTwoInts
• // AnotherMathFunction se infiere a ser de tipo (Int, Int)
-> Int  
Tipos de funciones como tipos de parámetros
Puede utilizar un tipo de función, tales como (Int, Int) -> Int como un tipo de
parámetro de otra función.Esto le permite dejar algunos aspectos de la aplicación de una
función para la persona que llama de la función de proporcionar, cuando se invoca la
función.
He aquí un ejemplo para imprimir los resultados de las funciones matemáticas desde
arriba:
• func printMathResult(mathFunction: (Int, Int) -> Int, a: Int, b: Int) {
• println("Result: \(mathFunction(a, b))")
• }
• printMathResult(addTwoInts, 3, 5)
• // Impresiones "Resultado: 8"  
Este ejemplo define una función llamada printMathResult , que tiene tres
parámetros. El primer parámetro se llama mathFunction , y es de tipo (Int,
Int) -> Int . Puede pasar cualquier función de ese tipo que el argumento a favor de
este primer parámetro. El segundo y tercer parámetros se llaman una y b , y son ambos
de tipo int . Estos se utilizan como los dos valores de entrada para la función
matemática proporcionado.

  103  
Cuando printMathResult se llama, se le pasa el addTwoInts función, y valora
el número entero 3 y 5 . Se llama a la función, dotándolos de los 3 y 5 , e imprime el
resultado de 8 .
El papel de printMathResult es imprimir el resultado de una llamada a una
función matemática de un tipo apropiado. No importa lo que la aplicación de esa
función en realidad lo-hace sólo importa que la función es del tipo correcto. Esto
permite printMathResult a entregar algunas de sus funciones a la persona que
llama de la función de una manera con seguridad de tipos.
Tipos de funciones como Tipos de valor devueltos
Usted puede utilizar un tipo de función que el tipo de retorno de otra función. Usted
puede hacer esto escribiendo un tipo de función completa inmediatamente después de la
flecha de retorno ( -> ) de retorno de la función.
El siguiente ejemplo define dos funciones simples
llamados StepForward y stepbackward . El StepForwardfunción devuelve un
valor uno más que su valor de entrada, y la stepbackward función devuelve un valor
de un precio inferior a su valor de entrada. Ambas funciones tienen un tipo de (Int)
-> Int :
• func stepForward(input: Int) -> Int {
• return input + 1
• }
• func stepBackward(input: Int) -> Int {
• return input - 1
• }
Aquí hay una función llamada chooseStepFunction , cuyo retorno tipo es "una
función del tipo (Int) -> Int ".chooseStepFunction devuelve
el StepForward función o la stepbackward función basada en un parámetro
Boolean llamada hacia atrás :
• func chooseStepFunction(backwards: Bool) -> (Int) -> Int {
• return backwards ? stepBackward : stepForward
• }
Ahora puede utilizar chooseStepFunction obtener una función que le paso en una
dirección o la otra:
• var currentValue = 3
• let moveNearerToZero = chooseStepFunction(currentValue > 0)
• // MoveNearerToZero ahora se refiere a la stepbackward ()
función  
El ejemplo anterior determina si se necesita un paso positivo o negativo para mover una
variable llamadaCurrentValue progresivamente más cerca de
cero. CurrentValue tiene un valor inicial de 3 , lo que significa
queCurrentValue> 0 vuelve verdadera ,
causando chooseStepFunction para devolver el stepbackward función. Una

  104  
referencia a la función devuelto se almacena en una constante
llamada moveNearerToZero .
Ahora que moveNearerToZero refiere a la función correcta, que puede ser utilizado
para contar a cero:
• println("Counting to zero:")
• // Counting to zero:
• while currentValue != 0 {
• println("\(currentValue)... ")
• currentValue = moveNearerToZero(currentValue)
• }
• println("zero!")
• // 3...
• // 2...
• // 1...
• // zero!
Funciones anidadas
Todas las funciones que ha encontrado hasta ahora en este capítulo han sido ejemplos
de funciones globales, que se definen en un ámbito global. También puede definir
funciones dentro de los cuerpos de otras funciones, conocidas como funciones
anidadas .
Funciones anidadas están ocultos del mundo exterior de forma predeterminada, pero aún
así pueden ser llamados y utilizados por su función envolvente. Una función envolvente
también puede devolver una de sus funciones anidados para permitir la función anidada
para ser utilizado en otro ámbito.
Puede volver a escribir la chooseStepFunction ejemplo anterior de usar y
devolver funciones anidadas:
• println("Counting to zero:")
• // Counting to zero:
• while currentValue != 0 {
• println("\(currentValue)... ")
• currentValue = moveNearerToZero(currentValue)
• }
• println("zero!")
• // 3...
• // 2...
• // 1...
• // zero!
 

  105  
Cierres

Los cierres son bloques autónomos de la funcionalidad que se pueden pasar alrededor y
utilizar en su código.Cierres en Swift son similares a los bloques en C y Objective-C y
para lambdas en otros lenguajes de programación.
Los cierres pueden capturar y almacenar las referencias a todos los constantes y
variables del contexto en el que se definen. Esto se conoce como el cierre de más de
esas constantes y variables, de ahí el nombre "cierres". Swift se encarga de toda la
gestión de memoria de captura para usted.
NOTA
No se preocupe si usted no está familiarizado con el concepto de "captura". Se explica
en detalle a continuación en la captura de Valores .
Funciones globales y anidadas, como introdujo en funciones , en realidad son casos
especiales de cierres.Los cierres tienen una de tres formas:
• Funciones globales son los cierres que tienen un nombre y no captan ningún valor.
• Funciones anidadas son los cierres que tienen un nombre y pueden capturar valores
de su función que encierra.
• Expresiones de cierre son cierres anónimas escritas en una sintaxis ligera que puede
capturar los valores de su contexto circundante.
Expresiones de cierre de Swift tienen un estilo claro limpio, con optimizaciones que
fomenten breve sintaxis, libre de desorden en escenarios comunes. Estas optimizaciones
incluyen:
• Inferir los parámetros y valores de retorno tipos de contexto
• Rendimientos implícitos de los cierres de una sola expresión
• Nombres de los argumentos taquigrafía
• Perdiendo sintaxis cierre
Expresiones de cierre
Funciones anidadas, como introdujo en Funciones anidadas , son un medio conveniente
de nombrar y definir los bloques autónomos de código como parte de una función más
grande. Sin embargo, a veces es útil escribir las versiones más cortas de construcciones
tipo función sin una declaración y nombre completo. Esto es particularmente cierto
cuando se trabaja con funciones que tienen otras funciones como uno o más de sus
argumentos.
Expresiones de cierre son una manera de escribir cierres en línea en una breve, centrado
sintaxis.Expresiones de cierre proporcionan varias optimizaciones de sintaxis para
escribir cierres en forma abreviada y sin pérdida de claridad o la intención. Los
ejemplos a continuación ilustran el cierre de expresión estas optimizaciones mediante el
refinado de un único ejemplo de la ordenada en función de varias iteraciones, cada
una de las cuales expresa la misma funcionalidad de una manera más concisa.
La Función Ordenada
La biblioteca estándar de Swift proporciona una función llamada ordenados , que
ordena una matriz de valores de un tipo conocido, en base a la salida de un cierre de la
clasificación que usted proporcione. Una vez que se completa el proceso de
clasificación, la ordenada función devuelve una nueva matriz del mismo tipo y
tamaño que el anterior, con sus elementos en el orden de clasificación correcto. La
matriz original no es modificado por la ordenada función.

  106  
Los ejemplos de expresión de cierre a continuación utilizan la ordenada función para
ordenar un arreglo decuerdas valores en orden alfabético inverso. Aquí está la matriz
inicial que ser resuelto:
• let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]
• "Barry" , "Daniella" ]  
La ordenada función toma dos argumentos:
• Matriz de valores de un tipo conocido.
• Un cierre que toma dos argumentos del mismo tipo que el contenido de la matriz, y
devuelve un Boolvalor para decir si el primer valor debe aparecer antes o después
de que el segundo valor una vez que se ordenan los valores. El cierre de
clasificación tiene que devolver verdadero si el primer valor debe
aparecer antes del segundo valor, y falso de lo contrario.
Este ejemplo es clasificar un conjunto de Cuerda valores, por lo que el cierre de la
clasificación tiene que ser una función del tipo (String, String) -> Bool .
Una manera de proporcionar el cierre de clasificación es escribir una función normal del
tipo correcto, y para pasarlo adentro como el clasificado segundo parámetro de la
función:
• func backwards(s1: String, s2: String) -> Bool {
• return s1 > s2
• }
• var reversed = sorted(names, backwards)
• // Inversa es igual a ["Ewa", "Daniella", "Chris", "Barry",
"Alex"]  
Si la primera cadena ( s1 ) es mayor que la segunda cadena ( s2 ), el revés función
devolverá verdadero , lo que indica que s1 debe aparecer antes de s2 en la matriz
ordenada. Para caracteres en cadenas, "mayor que" significa "aparece más adelante en el
alfabeto que no sea". Esto significa que la letra "B" es "mayor que" la letra "A" , y la
cadena "Tom" es mayor que la cadena "Tim" . Esto da una especie alfabético inverso,
con"Barry" se coloca antes de "Alex" , y así sucesivamente.
Sin embargo, esta es una forma bastante largo aliento para escribir lo que es
esencialmente una función de una sola expresión ( a> b ). En este ejemplo, sería
preferible para escribir el cierre en línea de clasificación, usando la sintaxis de la
expresión de cierre.
Sintaxis Expresión Clausura
Sintaxis de las expresiones de cierre tiene la siguiente forma general:
• { ( parameters ) -> return type in
• statements

• }
Sintaxis de las expresiones de cierre puede utilizar parámetros constantes, parámetros
variables y inoutparámetros. Los valores por defecto no puede ser
proporcionada. Parámetros variadic se pueden utilizar si el nombre del parámetro

  107  
variadic y coloca última en la lista de parámetros. Las tuplas también se puede utilizar
como tipos de parámetros y tipos de retorno.
El siguiente ejemplo muestra una versión expresión cierre del revés función de antes:
• reversed = sorted(names, { (s1: String, s2: String) -> Bool in
• return s1 > s2
• })
Tenga en cuenta que la declaración de parámetros y el tipo de retorno para este cierre en
línea es idéntica a la declaración del revés función. En ambos casos, se escribe
como (s1: String, s2: String) -> Bool . Sin embargo, para la expresión
de cierre en línea, los parámetros y el tipo de retorno se escriben dentro de las llaves, y
no fuera de ellas.
El comienzo del cuerpo del cierre se introduce por el en la palabra clave. Esta palabra
clave indica que la definición de parámetros y devuelve un tipo del cierre ha terminado,
y el cuerpo del cierre está por comenzar.
Debido a que el cuerpo del cierre es tan corto, que incluso se puede escribir en una sola
línea:
• reversed = sorted(names, { (s1: String, s2: String) -> Bool in return s1 > s2 } )

Esto ilustra que la llamada general a la sorted función se ha mantenido la misma. Un
par de paréntesis, todavía envuelve todo el conjunto de argumentos de la función. Sin
embargo, uno de esos argumentos es ahora un cierre inline.
Inferir Tipo De Contexto
Debido a que el cierre de la clasificación se pasa como un argumento a una función,
Swift puede inferir los tipos de sus parámetros y el tipo de valor que devuelve el tipo de
la ordenada segundo parámetro de la función. Este parámetro está esperando una
función del tipo (String, String) -> Bool . Esto significa que el(String,
String) y Bool tipos no necesitan ser escritas como parte de la definición de la
expresión de cierre.Debido a que todos los tipos se puede inferir, la flecha de retorno ( -
> ) y los paréntesis alrededor de los nombres de los parámetros también se pueden
omitir:
• reversed = sorted(names, { s1, s2 in return s1 > s2 } )
Siempre es posible inferir los tipos de parámetros y el tipo de retorno al pasar un cierre
a una función como una expresión de cierre en línea. Como resultado, usted nunca tiene
que escribir un cierre en línea en su forma más completa cuando el cierre se utiliza un
argumento de función.
Sin embargo, usted todavía puede hacer los tipos explícita si lo desea, y lo hace, es
alentado si se evita la ambigüedad para los lectores de su código. En el caso de
la ordenada función, el propósito de la clausura se desprende del hecho de que la
clasificación está teniendo lugar, y es seguro para que el lector asume que el cierre es
probable que sea el trabajo con Cuerda valores, ya que está ayudando con la
clasificación de una matriz de cadenas.

  108  
Devoluciones implícitas de cierres sola expresión
Cierres sola expresión pueden regresar de forma implícita el resultado de su expresión
única omitiendo elretorno de palabras clave de su declaración, como en esta versión
del ejemplo anterior:
• reversed = sorted(names, { s1, s2 in s1 > s2 } )
En este caso, el tipo de función de la ordenada El segundo argumento de la función
deja claro que un Boolvalor debe ser devuelto por el cierre. Debido a que el cuerpo del
cierre contiene una sola expresión ( s1> s2 ) que devuelve un Bool valor, no hay
ambigüedad, y el retorno de la palabra clave puede ser omitida.
Nombres de argumentos taquigrafía
Swift proporciona automáticamente nombres de los argumentos de la taquigrafía para
inline cierres, que se pueden utilizar para hacer referencia a los valores de los
argumentos del cierre por los nombres $ 0 , $ 1 , $ 2, y así sucesivamente.
Si utiliza estos nombres de los argumentos de la taquigrafía en su expresión de cierre, se
puede omitir la lista de argumentos de la clausura de su definición, y el número y tipo
de los nombres de los argumentos de la taquigrafía se desprenderán de el tipo de
función esperada. El de palabras clave también se puede omitir, porque la expresión de
cierre se compone en su totalidad de su cuerpo:
• reversed = sorted(names, { $0 > $1 } )
Aquí, $ 0 y $ 1 se refieren al primero y segundo del cierre de Cuerda argumentos.
Funciones del operador
De hecho, hay una aún más breve manera de escribir la expresión de cierre anterior. De
Swift Cadena tipo define su implementación-cadena específica de la mayor-que el
operador ( > ) como una función que tiene dos parámetros de tipo de cadena , y
devuelve un valor de tipo Bool . Esto coincide exactamente con el tipo de función
necesaria para el clasificado segundo parámetro de la función. Por lo tanto, usted
puede simplemente pasar en el operador mayor que, y Swift se infiere que desea utilizar
su implementación-cadena específica:
• reversed = sorted(names, >)
Para más información sobre las funciones del operador, consulte Funciones del
operador .
Trailing Cierres
Si usted necesita para pasar una expresión de cierre a una función como argumento final
de la función y la expresión de cierre es largo, puede ser útil para escribir como
un cierre posterior en su lugar. A cierre de arrastre es una expresión de cierre que se
escribe fuera de (y después ) de los paréntesis de la función de llamada que soporta:
• func someFunctionThatTakesAClosure(closure: () -> ()) {
• // function body goes here
• }
•  
• // Así es como se llama a esta función sin necesidad de
utilizar un cierre de arrastre:  
•  
  109  
• someFunctionThatTakesAClosure({
• // Cuerpo de cierre va aquí  
• })  
•  
• // Así es como se llama a esta función con un cierre
posterior en su lugar:  
•  
• someFunctionThatTakesAClosure() {
• // Cuerpo detrás del cierre va aquí  
• }  
NOTA
Si una expresión de cierre se proporciona como único argumento de la función y le
proporcionará esa expresión como un cierre trasero, que no es necesario escribir un par
de paréntesis () después del nombre de la función cuando se llama a la función.
El cierre de cadena de clasificación de la sintaxis de la expresión Cierre sección anterior
se puede escribir fuera de la ordenada paréntesis de funcionar como un cierre de
salida:
• reversed = sorted(names) { $0 > $1 }
Cierres trailing son más útiles cuando el cierre es suficientemente largo que no es
posible escribir en línea en una sola línea. Como un ejemplo, de Swift matriz tipo
tiene un mapa método que toma una expresión de cierre como su argumento único. El
cierre se llama una vez para cada elemento de la matriz, y devuelve un valor asignado
alternativo (posiblemente de algún otro tipo) para dicho elemento. La naturaleza de la
cartografía y el tipo del valor devuelto se deja hasta el cierre de especificar.
Después de aplicar el cierre proporcionada a cada elemento de la matriz,
el mapa método devuelve una nueva matriz que contiene todos los nuevos valores
mapeadas, en el mismo orden que los valores correspondientes en la matriz original.
He aquí cómo usted puede utilizar el mapa método con un cierre posterior para
convertir una serie de Intvalores en una matriz de Cuerda valores. La matriz [16,
58, 510] se utiliza para crear la nueva matriz["OneSix", "FiveEight",
"FiveOneZero"] :
• let digitNames = [
• 0: "Zero", 1: "One", 2: "Two", 3: "Three", 4: "Four",
• 5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"
• ]
• let numbers = [16, 58, 510]
El código anterior crea un diccionario de asignaciones entre los dígitos enteros y
versiones en idioma Inglés de sus nombres. También define una matriz de enteros, listo
para ser convertido en cuerdas.
Ahora puede utilizar el número de serie para crear una matriz de Cuerda valores,
pasando una expresión de cierre a la matriz de mapa método como cierre final. Tenga
en cuenta que la llamada a numbers.map no necesita incluir ningún paréntesis

  110  
después de mapa , porque el mapa método tiene sólo un parámetro, y ese parámetro se
proporciona como un cierre de arrastre:
• let strings = numbers.map {
• (var number) -> String in
• var output = ""
• while number > 0 {
• output = digitNames[number % 10]! + output
• number /= 10
• }
• return output
• }
• // cuerdas se infiere a ser de tipo [cadena]  
• // Su valor es ["OneSix", "FiveEight", "FiveOneZero"]  
El mapa método llama a la expresión de cierre una vez para cada elemento de la
matriz. No es necesario especificar el tipo de parámetro de entrada de la clausura, el
número , porque el tipo se puede deducir de los valores de la matriz para ser asignada.
En este ejemplo, el cierre de número de parámetro se define como un parámetro
variable , como se describe en parámetros constantes y variables , de manera que el
valor del parámetro puede ser modificada dentro del cuerpo de cierre, en lugar de
declarar una nueva variable local y asignando el pasado número de valor a ella.La
expresión de cierre también especifica el tipo de devolución de cuerdas , para
indicar el tipo que se almacena en la matriz de salida asignada.
La expresión de cierre genera una cadena llamada de salida cada vez que se
llama. Calcula el último dígito del número mediante el operador resto ( % número
10 ), y utiliza este dígito para buscar una cadena apropiada en
el digitNames diccionario. El cierre se puede utilizar para crear una representación
de cadena de cualquier número entero mayor que cero.
NOTA
La llamada a la digitNames subíndice del diccionario es seguido por un signo de
exclamación ( ! ), porque subíndices Diccionario devuelven un valor opcional para
indicar que la consulta de diccionarios puede fallar si no existe la clave. En el ejemplo
anterior, se garantiza que el número de 10% será siempre una clave subíndice
válido para la digitNames diccionario, y por lo tanto un signo de exclamación se usa
para forzar-desenvolver la Cadena de valor almacenado en valor de retorno opcional
del subíndice.
La cadena recuperada de la digitNames diccionario se añade a la parte
delantera de la salida , para aprovechar efectivamente una versión de cadena del
número en sentido inverso. (La expresión número 10% da un valor
de 6 a 16 , 8 por 58 , y 0 por 510 .)
El número variable se divide por 10 . Debido a que es un número entero, se
redondeará a la baja durante la división, por lo que 16 se convierte en 1 , 58 se
convierte en 5 , y 510 se convierte en 51 .

  111  
El proceso se repite hasta que el número / = 10 es igual a 0 , en cuyo punto
la salida de cadena se devuelve por el cierre, y se añade a la matriz de salida por
el mapa de función.
El uso de la sintaxis de cierre de salida en el ejemplo anterior encapsula perfectamente
la funcionalidad del cierre inmediatamente después de la función que soporta el cierre,
sin necesidad de envolver todo el cierre dentro del mapa paréntesis exteriores de
función.

La captura de Valores
Un cierre puede capturar las constantes y variables del contexto que rodean en la que se
define. El cierre entonces puede referirse y modificar los valores de esas constantes y
variables desde el interior de su cuerpo, incluso si el alcance original que define las
constantes y variables ya no existe.
La forma más simple de un cierre en Swift es una función anidada, escrito dentro del
cuerpo de otra función.Una función anidada puede capturar cualquiera de los
argumentos de la función externa y también puede capturar cualquier constantes y
variables definidas dentro de la función externa.
He aquí un ejemplo de una función llamada makeIncrementor , que contiene una
función anidada denominadaincrementor . El anidado incrementor función
captura dos valores, RunningTotal y cantidad , de su contexto
circundante. Después de la captura de estos valores, incrementor es devuelto
por makeIncrementor como un cierre que se
incrementa RunningTotal por importe cada vez que se llama.
• func makeIncrementor(forIncrement amount: Int) -> () -> Int {
• var runningTotal = 0
• func incrementor() -> Int {
• runningTotal += amount
• return runningTotal
• }
• return incrementor
• }
El tipo de retorno de makeIncrementor es () -> Int . Esto significa que
devuelve una función , en lugar de un valor simple. La función devuelve no tiene
parámetros y devuelve un int valor cada vez que se llama. Para aprender las funciones
pueden devolver otras funciones, consulte Tipos de función como tipo de retorno .
El makeIncrementor función define una variable entera llamada RunningTotal ,
para almacenar el total de ejecución actual del incrementor que será devuelto. Esta
variable se inicializa con un valor de 0 .
El makeIncrementor función tiene un único int parámetro con un nombre externo
de forIncrement , y un nombre local de cantidad . El valor del argumento
pasado a este parámetro especifica cuánto RunningTotaldebe ser incrementado por
cada vez que la función de volver incrementor se llama.

  112  
makeIncrementor define una función denominada anidada incrementor , que
realiza la incremental real. Esta función no hace sino aumentar la
cantidad de RunningTotal , y devuelve el resultado.
Cuando se considera en forma aislada, el anidado incrementor función podría
parecer inusual:
• func incrementor() -> Int {
• runningTotal += amount
• return runningTotal
• }
El incrementor función no tiene parámetros, y sin embargo, se refiere
a RunningTotal y cantidad de dentro de su cuerpo de la función. Lo hace
mediante la captura de los existentes valores de RunningTotal y cantidad de su
función alrededores y utilizarlos dentro de su propio cuerpo de la función.
Debido a que no modifica la cantidad , incrementor realmente capta y
almacena una copia del valor almacenado en cantidad . Este valor se almacena junto
con el nuevo incrementor función.
Sin embargo, ya que modifica la RunningTotal variable cada vez que se
llama, incrementor captura unareferencia a la actual RunningTotal variables, y
no sólo una copia de su valor inicial. Captura de una referencia asegura
que RunningTotal no desaparece cuando la llamada
a makeIncrementor termina y asegura queRunningTotal seguirá siendo
disponible la próxima vez que la función incrementor se llama.
NOTA
Swift determina lo que debe ser capturado por referencia y lo que debería ser copiada
por valor. No es necesario anotar la cantidad o RunningTotal decir que se
pueden utilizar dentro del anidado incrementorfunción. Swift también se encarga de
toda la gestión de memoria que supone la colocación de RunningTotalcuando ya no
es necesaria por la función incrementor.
He aquí un ejemplo de makeIncrementor en acción:
• let incrementByTen = makeIncrementor(forIncrement: 10)
En este ejemplo se establece una constante llamada incrementByTen para referirse a
una función incrementor que añade 10 a su RunningTotal variable cada vez que se
llama. Llamar a la función varias veces muestra este comportamiento en la acción:
• incrementByTen()
• // returns a value of 10
• incrementByTen()
• // returns a value of 20
• incrementByTen()
• // Devuelve un valor de 30  
Si se crea una segunda incrementor, tendrá su propia referencia almacenado a una
nueva, separadaRunningTotal variables:
• let incrementBySeven = makeIncrementor(forIncrement: 7)

  113  
• incrementBySeven()
• // Devuelve un valor de 7  
Llamar a la incrementor originales ( incrementByTen ) de nuevo continúa para
incrementar su propiaRunningTotal variables, y no afecta a la variable capturada
por incrementBySeven :
• incrementByTen()
• // Devuelve un valor de 40  
NOTA
Si asigna un cierre a una propiedad de una instancia de clase, y el cierre captura ese
ejemplo haciendo referencia a la instancia o de sus miembros, creará un fuerte ciclo de
referencia entre el cierre y la instancia.Swift utiliza listas de captura para romper estos
ciclos de referencia fuertes. Para obtener más información, consulte Ciclos de referencia
fuertes para cierres .
Los cierres son tipos de referencia
En el ejemplo anterior, incrementBySeven y incrementByTen son constantes,
pero los cierres de estas constantes se refieren a son todavía capaces de incrementar
los RunningTotal variables que se han capturado. Esto se debe a que las funciones y
los cierres son los tipos de referencia .
Cada vez que se asigna una función o un cierre a una constante o una variable, en
realidad se está configurando esa constante o variable para ser una referencia a la
función o el cierre. En el ejemplo anterior, es la elección de cierre
que incrementByTen se refiere a que es constante, y no los contenidos del propio
cierre.
Esto también significa que si asigna un cierre de dos constantes o variables diferentes,
tanto de esas constantes o variables se refieren a la misma de cierre:
• let alsoIncrementByTen = incrementByTen
• alsoIncrementByTen()
• // Devuelve un valor de 50  
Funciones
Las enumeraciones

Las enumeraciones
Una enumeración define un tipo común de un grupo de valores relacionados y le
permite trabajar con los valores de una manera con seguridad de tipos dentro de su
código.
Si está familiarizado con C, sabrás que C enumeraciones asignan nombres relacionados
a un conjunto de valores enteros. Las enumeraciones de Swift son mucho más flexibles,
y no tienen que proporcionar un valor para cada miembro de la enumeración. Si un
valor (conocido como valor de "prima") se proporciona para cada miembro de la
enumeración, el valor puede ser una cadena, un carácter o un valor de número entero o
tipo de punto flotante.
Alternativamente, los miembros de enumeración pueden especificar valores asociados
de cualquier tipo para ser almacenados junto con cada valor de miembro diferente, tanto
como los sindicatos o variantes hacen en otras lenguas. Puede definir un conjunto

  114  
común de miembros relacionados como parte de una enumeración, cada uno de los
cuales tiene un conjunto diferente de valores de tipos apropiados asociados.
Las enumeraciones de Swift son tipos de primera clase en su propio derecho. Adoptan
muchas características que tradicionalmente sólo compatibles con las clases, como las
propiedades calculadas para proporcionar información adicional sobre el valor actual de
la enumeración, y los métodos de instancia para proporcionar funcionalidad relacionada
con los valores de la enumeración representa. Las enumeraciones pueden definir
también inicializadores para proporcionar un valor inicial miembro; se puede extender
para ampliar su funcionalidad más allá de su aplicación original; y puede ajustarse a los
protocolos para proporcionar una funcionalidad estándar.
Para más información sobre estas funciones,
consulte Properties, Methods, Initialization, Extensions, and Protocols.

Sintaxis Enumeración
Introduces enumeraciones con la enumeración de palabras clave y colocar toda su
definición dentro de un par de llaves:
• enum SomeEnumeration {
• // Definición enumeración va aquí  
• }  
He aquí un ejemplo de los cuatro puntos principales de una brújula:
• enum CompassPoint {
• case North
• case South
• case East
• case West
• }
Los valores definidos en la enumeración (como Norte , Sur , Este y Oeste ) son
los valores de los miembros(o miembros ) de esa enumeración. El caso de palabras
clave indica que una nueva línea de valores de los miembros está por ser definido.
NOTA
A diferencia de C y Objective-C, miembros de la enumeración Swift no se les asigna un
valor entero por defecto cuando se crean. En el CompassPoint ejemplo
anterior, Norte , Sur , Este y Oeste no lo hacen implícitamente
igual 0 , 1 , 2 y 3 . En su lugar, los diferentes miembros de la enumeración son valores
de pleno derecho en su propio derecho, con un tipo definido de forma explícita-
de CompassPoint .
Valores de los miembros múltiples pueden aparecer en una sola línea, separados por
comas:
• enum Planet {
• case Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune
• }
Each enumeration definition defines a brand new type. Like other types in Swift, their
Cada definición de enumeración define un nuevo tipo de marca. Al igual que otros tipos

  115  
de Swift, sus nombres (como CompassPoint y Planeta ) deben comenzar con una
letra mayúscula. Dale tipos de enumeración singulares en lugar de nombres en plural,
para que se lean como evidente:
• var directionToHead = CompassPoint.West
El tipo de directionToHead se infiere cuando se inicializa con uno de los valores
posibles de CompassPoint .Una vez directionToHead se declara como
un CompassPoint , se puede establecer en un diferenteCompassPoint valor
utilizando una sintaxis con punto más corto:
• directionToHead =. Oriente  
El tipo de directionToHead ya se conoce, y por lo que puede bajar el tipo al
establecer su valor. Esto lo convierte en código muy legible cuando se trabaja con
valores de enumeración explícita mecanografiadas-.
Coincidencia de Valores de enumeración con una sentencia switch
Puede coincidir con los valores de enumeración individuales con un interruptor
de declaración:
• directionToHead = .South
• switch directionToHead {
• case .North:
• println("Lots of planets have a north")
• case .South:
• println("Watch out for penguins")
• case .East:
• println("Where the sun rises")
• case .West:
• println("Where the skies are blue")
• }
• // prints "Watch out for penguins"
• // imprime "Ten cuidado con los pingüinos"  
Usted puede leer este código como:
"Considere el valor de directionToHead . En el caso en el que es igual .North ,
impresión "Un montón de planetas tienen un norte" . En el caso en el
que es equals.South , imprimir "Cuidado con los pingüinos"".
... Etcétera.
Como se describe en el control de flujo , un switch de declaración debe ser
exhaustiva cuando se considera miembros de una enumeración. Si el for.West se
omite, el código no se compila, porque no tiene en cuenta la lista completa
de CompassPoint miembros. Exigir exhaustividad garantiza que los miembros de
enumeración no se incluyeron, accidentalmente.
Cuando no es conveniente establecer un caso para cada miembro de la enumeración,
puede proporcionar un default case para cubrir los miembros que no se tratan de
forma explícita:

  116  
• let somePlanet = Planet.Earth
• switch somePlanet {
• case .Earth:
• println("Mostly harmless")
• default:
• println("Not a safe place for humans")
• }
• // imprime "Sobre todo inofensivo"  
Valores asociados
Los ejemplos de la sección anterior muestran cómo los miembros de una enumeración
son un valor definido (y escrito) por derecho propio. Puede definir una constante o
variable a Planet.Earth , y comprobar si este valor más adelante. Sin embargo, a
veces es útil poder almacenar valores asociados de otros tipos junto a estos valores de
miembro. Esto le permite almacenar información personalizada adicional junto con el
valor de miembro, y permite que esta información para variar cada vez que utilice ese
miembro en el código.
Puede definir enumeraciones Swift para almacenar valores asociados de cualquier tipo
dado, y los tipos de valor puede ser diferente para cada miembro de la enumeración, si
es necesario. Las enumeraciones similares a éstos se conocen como uniones
discriminadas , etiquetados sindicatos , o variantes en otros lenguajes de programación.
Por ejemplo, supongamos que un sistema de seguimiento de inventario necesita para
rastrear productos por dos tipos diferentes de código de barras. Algunos productos están
etiquetados con códigos de barras 1D en UPC-A formato, que utiliza los números
de 0 a 9 . Cada código de barras tiene un dígito "sistema de numeración", seguida de
cinco "código de fabricante" dígitos y cinco "código de producto" dígitos. Estos son
seguidos por un dígito "check" para verificar que el código ha sido escaneado
correctamente:

Otros productos que están etiquetados con códigos de barras 2D en forma de códigos
QR, que pueden usar cualquiera de caracteres ISO 8859-1 y puede codificar una cadena
de hasta 2.953 caracteres de longitud:

  117  
 

Sería conveniente para un sistema de seguimiento de inventario para poder almacenar


los códigos de barras UPC-A como una tupla de cuatro enteros, y los códigos de barras
de códigos QR como una cadena de cualquier longitud.
En Swift, una enumeración para definir los códigos de barras de productos de cualquier
tipo podría tener este aspecto:
• enum Barcode {
• case UPCA(Int, Int, Int, Int)
• case QRCode(String)
• }
Esto puede leerse como:
"Definir un tipo de enumeración llamado código de barras , el cual puede tomar
un valor de UPCA con un valor asociado de tipo ( Int , Int , Int , Int ), o un valor
de QRCode con un valor asociado de tipo Cadena . "
Esta definición no ofrece reales Int o de Cuerda valores-que sólo define el tipo de
valores asociados que de código de barras constantes y variables se almacenan
cuando son iguales a Barcode.UPCA oBarcode.QRCode .
Nuevos códigos de barras a continuación, se pueden crear utilizando cualquier tipo:
• var productBarcode = código de barras . UPCA ( 8 , 85909 ,
51226 , 3 )  
En este ejemplo se crea una nueva variable llamada productBarcode y le asigna un
valor de Barcode.UPCAcon un valor asociado de tupla (8, 85909, 51226,
3) .
El mismo producto se puede asignar un tipo diferente de código de barras:
• productBarcode = .QRCode("ABCDEFGHIJKLMNOP")
En este punto, el original Barcode.UPCA sus valores enteros y se sustituyen por el
nuevo Barcode.QRCode y su valor de cadena. Constantes y variables de tipo de
código de barras se pueden almacenar ya sea un .UPCAo una .QRCode (junto
con sus valores asociados), pero sólo pueden almacenar uno de ellos en un momento
dado.
Los diferentes tipos de códigos de barras se pueden verificar utilizando una sentencia
switch, como antes.Esta vez, sin embargo, los valores asociados puede ser extraída
como parte de la instrucción switch. Extraer cada valor asociado como una constante

  118  
(con la let prefijo) o una variable (con la var prefijo) para su uso en
el interruptor del cuerpo de caso:
• switch productBarcode {
• case .UPCA(let numberSystem, let manufacturer, let product, let check):
• println("UPC-A: \(numberSystem), \(manufacturer), \(product), \(check).")
• case .QRCode(let productCode):
• println("QR code: \(productCode).")
• }
• // prints "QR code: ABCDEFGHIJKLMNOP."
Si todos los valores asociados para un miembro de la enumeración se extraen como
constantes, o si todo se extraen como variables, se puede colocar una
sola var o dejar de anotación antes de que el nombre de miembro, por razones de
brevedad:
• switch productBarcode {
• case let .UPCA(numberSystem, manufacturer, product, check):
• println("UPC-A: \(numberSystem), \(manufacturer), \(product), \(check).")
• case let .QRCode(productCode):
• println("QR code: \(productCode).")
• }
• // imprime "código QR: ABCDEFGHIJKLMNOP".  
Valores primas
El ejemplo de código de barras en valores asociados muestra cómo los miembros de una
enumeración pueden declarar que almacenan valores asociados de diferentes
tipos. Como una alternativa a los valores asociados, los miembros de enumeración
pueden venir rellena previamente con valores predeterminados (denominados valores en
bruto ), que son todos del mismo tipo.
He aquí un ejemplo que almacena valores ASCII prima junto a los miembros de la
enumeración designados:
• enum ASCIIControlCharacter: Character {
• case Tab = "\t"
• case LineFeed = "\n"
• case CarriageReturn = "\r"
• }
En este caso, los valores de primas para una enumeración
denominada ASCIIControlCharacter se definen como de tipo de
caracteres , y se ponen a algunos de los personajes más comunes de control
ASCII.Carácter valores se describen en Cuerdas y Personajes .
Tenga en cuenta que los valores de primas son no lo mismo que los valores
asociados. Valores primas se ajustan a los valores rellenados previamente cuando defina
primero la enumeración en el código, como los tres códigos ASCII anteriores. El valor

  119  
en bruto para un miembro de la enumeración particular es siempre la misma. Valores
asociados se establecen cuando se crea una nueva constante o variable en función de
uno de los miembros de la enumeración, y puede ser diferente cada vez que lo haga.
Valores crudos pueden ser cadenas, caracteres o cualquiera de los números enteros o de
punto flotante tipos de números. Cada valor en bruto debe ser único en su declaración
de la enumeración. Cuando se utilizan números enteros para los valores de primas, que
de incremento automático si no se especifica ningún valor para algunos de los miembros
de la enumeración.
La enumeración a continuación es un refinamiento de la anterior Planet enumeración,
con valores enteros primas para representar el fin de cada planeta del sistema solar:
• enum Planet: Int {
• case Mercury = 1, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune
• }
Auto-incrementación significa que Planet.Venus tiene un valor en bruto de 2 , y así
sucesivamente.
Acceder al valor bruto de un miembro de la enumeración con su toRaw método:
• let earthsOrder = Planet.Earth.toRaw()
• // earthsOrder is 3
Utilizar de una enumeración fromRaw método para tratar de encontrar un miembro de
la enumeración con un valor bruto particular. En este ejemplo se identifica Urano de su
valor bruto de 7 :
• let possiblePlanet = Planet.fromRaw(7)
• // possiblePlanet is of type Planet? and equals Planet.Uranus
No todos los posibles Int valores encontrarán un planeta a juego, sin embargo. Debido
a esto, la fromRawmétodo devuelve un opcional miembro de enumeración. En el
ejemplo anterior, possiblePlanet es de tipoPlanet? , o "opcional Planet . "
Si usted trata de encontrar un planeta con una posición de 9 , el opcional Planet valor
devuelto por fromRawserá nula :
• let positionToFind = 9
• if let somePlanet = Planet.fromRaw(positionToFind) {
• switch somePlanet {
• case .Earth:
• println("Mostly harmless")
• default:
• println("Not a safe place for humans")
• }
• } else {
• println("There isn't a planet at position \(positionToFind)")
• }
• // imprime "No hay un planeta en la posición 9"  

  120  
En este ejemplo se utiliza opcional vinculante para tratar de acceder a un planeta con un
valor bruto de 9 . La declaración si dejar somePlanet = Planet.fromRaw
(9) recupera un opcional Planet , y establecesomePlanet al contenido de ese
opcional Planet si puede ser recuperada. En este caso, no es posible recuperar un
planeta con una posición de 9 , por lo que la otra rama se ejecuta en su lugar.
 

Clases y estructuras

Las clases y las estructuras son de uso general, construcciones flexibles que se
convierten en los componentes básicos del código de su programa. Usted define las
propiedades y métodos para agregar funcionalidad a sus clases y estructuras utilizando
exactamente la misma sintaxis que para las constantes, variables y funciones.
A diferencia de otros lenguajes de programación, Swift no le requiere para crear
archivos de interfaz y de aplicación única para las clases y estructuras
personalizadas. En Swift, se define una clase o una estructura en un solo archivo, y la
interfaz externa a esa clase o estructura se hace automáticamente disponible para otro
código a utilizar.
NOTA
Una instancia de una clase se conoce tradicionalmente como un objeto . Sin embargo,
las clases y las estructuras de Swift están mucho más cerca en la funcionalidad que en
otros idiomas, y gran parte de este capítulo se describe la funcionalidad que se puede
aplicar a instancias de cualquiera de una clase o un tipo de estructura. Debido a esto, el
término más general de ejemplo se utiliza.
La comparación de clases y estructuras
Clases y estructuras en Swift tienen muchas cosas en común. Ambos pueden:
• Definir propiedades para almacenar valores
• Definir los métodos para proporcionar funcionalidad
• Definir subíndices para dar acceso a sus valores usando la sintaxis subíndice
• Definir inicializadores para establecer su estado inicial
• Se ampliará para ampliar su funcionalidad más allá de una implementación por
defecto
• Conformarse a protocolos para proporcionar una funcionalidad estándar de un cierto
tipo
Para obtener más información,
vea Propiedades , Métodos , subíndices , inicialización , extensiones , yProtocolos .
Las clases tienen capacidades adicionales que las estructuras no hacen:
• La herencia permite a una clase a heredar las características de otro.
• Tipo de fundición permite comprobar e interpretar el tipo de una instancia de clase
en tiempo de ejecución.
• Deinitializers permiten una instancia de una clase para liberar todos los recursos que
tiene asignados.
• El conteo de referencias permite más de una referencia a una instancia de clase.
Para obtener más información, vea Herencia , la conversión de
tipos , deinicialización y conteo automático de referencia .
NOTA

  121  
Estructuras siempre se copian cuando se pasan alrededor de su código, y no utilizan el
recuento de referencias.
Sintaxis Definición
Clases y estructuras tienen una sintaxis definición similar. Introduces clases con
la clase de palabras clave y las estructuras con la estructura de palabras
clave. Tanto colocar toda su definición dentro de un par de llaves:
• class SomeClass {
• // Definición de clase va aquí  
• }  
• struct SomeStructure {
• // Estructura de definición va aquí  
• }  
NOTA
Cada vez que se define una nueva clase o estructura, se definen de manera efectiva un
nuevo tipo Swift marca. Dale tipos UpperCamelCase nombres
(como AlgunaClase y SomeStructure aquí) para que coincida con la
capitalización de los tipos Swift estándar (tales como cuerdas , Int , y Bool ). Por
el contrario, siempre dan propiedades y métodos lowerCamelCase nombres
(como frameRate y incrementCount ) para diferenciarlos de los nombres de los
tipos.
He aquí un ejemplo de una definición de la estructura y una definición de clase:
• struct Resolution {
• var width = 0
• var height = 0
• }
• class VideoMode {
• var resolution = Resolution()
• var interlaced = false
• var frameRate = 0.0
• var name: String?
• }
El ejemplo anterior define una nueva estructura llamada Resolución , para describir
una resolución de pantalla basado en píxeles. Esta estructura tiene dos propiedades
almacenado llamado anchura y altura .Propiedades almacenados son constantes o
variables que se empaquetan y almacenan como parte de la clase o estructura. Estas dos
propiedades se infieren a ser de tipo Int estableciendo su valor a un valor entero inicial
de 0 .
El ejemplo anterior también define una nueva clase llamada VideoMode , para
describir un modo de vídeo específico para la visualización de vídeo. Esta clase tiene
cuatro propiedades almacenadas variables. La primera, la resolución , se
inicializa con una nueva Resolución instancia de estructura, lo que infiere un tipo de
propiedad de la Resolución . Para las otras tres propiedades,

  122  
nuevas Videomode casos se pueden inicializar con un entrelazado de
ajuste falsa (que significa "de vídeo no entrelazado"), una velocidad de fotogramas
de reproducción de 0.0 opcional, y Cadena valor llamado nombre . El nombre
de la propiedad se le asigna automáticamente un valor por defecto de cero , o
"no nombre de valor ", ya que es de un tipo opcional.
Instancias de clase y estructura
La Resolución definición de la estructura y la VideoMode definición de clase sólo
describen lo que unaresolución o VideoMode se verá así. Ellos mismos no
describen una resolución específica o en el modo de vídeo. Para ello, es necesario crear
una instancia de la estructura o clase.
La sintaxis para la creación de instancias es muy similar para ambas estructuras y
clases:
• let someResolution = Resolution()
• let someVideoMode = VideoMode()
Estructuras y clases tanto usan la sintaxis de inicializador de nuevos casos. La forma
más simple de la sintaxis de inicializador utiliza el nombre del tipo de la clase o
estructura seguida de paréntesis vacíos, como la Resolución () o VideoMode
() . Esto crea una nueva instancia de la clase o estructura, con propiedades
inicializados a sus valores predeterminados. Inicialización de la clase y la estructura se
describe con más detalle en la inicialización .
Acceso a las propiedades
Puede acceder a las propiedades de una instancia utilizando la sintaxis con punto . En la
sintaxis con punto, se escribe el nombre de la propiedad inmediatamente después de que
el nombre de la instancia, separados por un punto ( . , sin espacios):
• println("The width of someResolution is \(someResolution.width)")
• // imprime "El ancho de someResolution es 0"  
En este ejemplo, someResolution.width se refiere a la anchura de la
propiedad de someResolution , y devuelve su valor inicial por defecto de 0 .
Puede profundizar en sub-propiedades, como el ancho de la propiedad en
la resolución de la propiedad de unVideoMode :
• println("The width of someVideoMode is \(someVideoMode.resolution.width)")
• // imprime "El ancho de someVideoMode es 0"  
También puede utilizar la sintaxis con punto para asignar un nuevo valor a una
propiedad de variable:
• someVideoMode.resolution.width = 1280
• println("The width of someVideoMode is
now\(someVideoMode.resolution.width)")
• // imprime "El ancho de someVideoMode es ahora 1280"  
NOTA
A diferencia de Objective-C, Swift le permite establecer directamente sub-propiedades
de una estructura de propiedad. En el último ejemplo de arriba, la anchura de la
propiedad de la resolución de la propiedad desomeVideoMode se establece

  123  
directamente, sin la necesidad de configurar toda la resolución de la propiedad a
un nuevo valor.
Miembro por miembro Inicializadores de Estructura Tipos
Todas las estructuras tienen una generada automáticamente inicializador miembro por
miembro , que se puede utilizar para inicializar las propiedades de los miembros de las
nuevas instancias de estructura. Los valores iniciales de las propiedades de la nueva
instancia se pueden pasar a la inicializador miembro por miembro por su nombre:
• let vga = Resolution(width: 640, height: 480)
A diferencia de las estructuras, instancias de clase no reciben un inicializador de
miembro por miembro por defecto. Inicializadores se describen con más detalle en la
inicialización .
Estructuras y enumeraciones son tipos de valor
Un tipo de valor es un tipo cuyo valor es copiado cuando se asigna a una variable o
constante, o cuando se pasa a una función.
En realidad se ha estado utilizando los tipos de valor extensivamente a través de los
capítulos anteriores. De hecho, todos los tipos básicos en Swift-números enteros,
números de punto flotante, booleanos, cadenas, matrices y diccionarios-son tipos de
valor, y se implementan como estructuras detrás de las escenas.
Todas las estructuras y enumeraciones son tipos de valor en Swift. Esto significa que
todas las instancias de la estructura y la enumeración que crear-y de cualquier tipo de
valor que tienen, como siempre, son propiedades-copian cuando se pasan alrededor de
su código.
Considere este ejemplo, que utiliza la Resolución estructura del ejemplo anterior:
• let hd = Resolution(width: 1920, height: 1080)
• var cinema = hd
En este ejemplo se declara una llamada constante hd y lo establece en
un Resolución instancia inicializada con el ancho y la altura de vídeo Full HD
( 1920 píxeles de ancho por 1080 píxeles de alto).
A continuación, declara una variable de llamada del cine y lo establece en el valor
actual de hd . DebidoResolución es una estructura, una copia está hecha de la
instancia existente, y esta nueva copia se asigna acine . Aunque hd y el
cine tienen ahora la misma anchura y altura, son dos casos completamente diferentes
entre bastidores.
A continuación, el ancho de la propiedad del cine se modifica para ser el ancho de
la 2K estándar ligeramente más amplio utilizado para la proyección de cine digital
( 2048 píxeles de ancho por 1080 píxeles de alto):
• cine . ancho = 2048  
Comprobación de la anchura de la propiedad de cine muestra que ha cambiado de
hecho a ser 2048 :
• println("cinema is now \(cinema.width) pixels wide")
• // Imprime "el cine es ahora 2.048 píxeles de ancho"  
Sin embargo, la anchura de la propiedad del original hd ejemplo todavía tiene el
valor antiguo de 1920 :
• println("hd is still \(hd.width) pixels wide")
  124  
• // Impresiones "hd es todavía 1920 píxeles de ancho"  
Cuando cinema se le dio el valor actual del hd , los valores almacenados en hd se
copian en el nuevo cinemainstancia. El resultado final es dos instancias
completamente separados, que acaba de pasar a contener los mismos valores
numéricos. Debido a que son instancias separadas, establecer el ancho
de cine a 2048 no afecta a la anchura almacenada en HD .
El mismo comportamiento se aplica a las enumeraciones:
• enum CompassPoint {
• case North, South, East, West
• }
• var currentDirection = CompassPoint.West
• let rememberedDirection = currentDirection
• currentDirection = .East
• if rememberedDirection == .West {
• println("The remembered direction is still .West")
• }
• // imprime "La dirección es recordado todavía .West"  
Cuando rememberedDirection se le asigna el valor de currentDirection ,
en realidad está ajustado a una copia de ese valor. Cambiar el valor
de currentDirection a partir de entonces no afecta a la copia del valor original
que se guarda en rememberedDirection .

Las clases son tipos de referencia


A diferencia de los tipos de valor, los tipos de referencia no son copiados cuando se les
asigna a una variable o constante, o cuando se pasan a una función. En lugar de una
copia, una referencia a la misma instancia existente se utiliza en su lugar.
He aquí un ejemplo, usando el VideoMode clase definido anteriormente:
• let tenEighty = VideoMode()
• tenEighty.resolution = hd
• tenEighty.interlaced = true
• tenEighty.name = "1080i"
• tenEighty.frameRate = 25.0
En este ejemplo se declara una nueva constante llamada Teneighty y establece que
para referirse a una nueva instancia de la VideoMode clase. El modo de vídeo se le
asigna una copia de la resolución HD de 1.920por 1.080 de antes. Se fija para ser
entrelazadas, y se le da un nombre de "1080i" . Finalmente, se establece a una
velocidad de 25,0 fotogramas por segundo.
A continuación, Teneighty se asigna a una nueva constante,
llamado alsoTenEighty , y la velocidad de fotogramas de alsoTenEighty se
modifica:
• let alsoTenEighty = tenEighty

  125  
• alsoTenEighty.frameRate = 30.0
Debido a que las clases son tipos de
referencia, Teneighty y alsoTenEighty realidad ambos se refieren a
lamisma VideoMode instancia. Efectivamente, son sólo dos nombres diferentes para la
misma instancia única.
Comprobación del frameRate propiedad de Teneighty muestra que informa
correctamente la nueva velocidad de fotogramas de 30,0 desde el
subyacente VideoMode ejemplo:
• println("The frameRate property of tenEighty is now \(tenEighty.frameRate)")
• // imprime "La propiedad frameRate de Teneighty es ahora
30.0"  
Tenga en cuenta que Teneighty y alsoTenEighty se declaran como constantes ,
en lugar de variables. Sin embargo, todavía puede
cambiar tenEighty.frameRate y alsoTenEighty.frameRate debido a que
los valores de la Teneighty y alsoTenEighty constantes de sí mismos en
realidad no cambian. Teneighty y alsoTenEightymismos no "tienda"
del VideoMode ejemplo-en vez, ambos se refieren a un VideoMode instancia detrás
de las escenas. Es la frameRate propiedad del subyacente VideoMode que se
cambia, no los valores de las constantes referencias a que VideoMode .
Operadores de identidad
Debido a que las clases son tipos de referencia, es posible que varias constantes y
variables que se refieren a la misma instancia única de una clase detrás de las
escenas. (Lo mismo no es cierto para las estructuras y enumeraciones, porque se copian
siempre cuando se les asigna a una constante o variable, o se pasan a una función.)
A veces puede ser útil para averiguar si dos constantes o variables se refieren a
exactamente la misma instancia de una clase. Para permitir esto, Swift proporciona dos
operadores de identidad:
• Idéntico al ( === )
• No idéntica a ( ! == )
Utilice estos operadores para comprobar si dos constantes o variables se refieren a la
misma instancia única:
• if tenEighty === alsoTenEighty {
• println("tenEighty and alsoTenEighty refer to the same VideoMode instance.")
• }
• // Impresiones "Teneighty y alsoTenEighty se refieren a la
misma instancia VideoMode."  
Tenga en cuenta que "idéntico a" (representado por tres signos de igual, o === ) no
significa lo mismo que "igual" (representado por dos signos de igual, o == ):
• "Igual que" significa que dos constantes o variables de tipo de clase se refieren
exactamente a la misma instancia de clase.
• "Igual a" significa que dos casos son considerados "iguales" o "equivalente" en el
valor, por algún significado apropiado de "iguales", como se define por el diseñador
del tipo.

  126  
Al definir sus propias clases y estructuras personalizadas, es su responsabilidad de
decidir lo que califica como dos casos de ser "igual". El proceso de definición de sus
propias implementaciones de la "igual a" y "no es igual a" operadores se describe
en Operadores de equivalencia .

Punteros
Si usted tiene experiencia con C, C ++ o Objective-C, usted puede saber que estos
idiomas utilizan punterospara hacer referencia a direcciones en la memoria. Una
constante Swift o variable que hace referencia a una instancia de un tipo de referencia es
similar a un puntero en C, pero no es un puntero directo a una dirección en la memoria,
y no requiere que usted escriba un asterisco ( * ) para indicar que están creando una
referencia. En lugar de ello, estas referencias se definen como cualquier otra constante o
variable en Swift.

Elegir entre clases y estructuras


Puede utilizar ambas clases y estructuras para definir tipos de datos personalizados para
su uso como los bloques de construcción de código de su programa.
Sin embargo, las instancias de la estructura siempre se pasan por valor , y las instancias
de clase siempre se pasan por referencia . Esto significa que son adecuados para
diferentes tipos de tareas. Al considerar las construcciones de datos y funcionalidad que
usted necesita para un proyecto, decidir si cada construcción de datos debe ser definido
como una clase o como una estructura.
Como pauta general, considerar la creación de una estructura cuando una o más de estas
condiciones:
• El propósito principal de la estructura es encapsular unos valores de datos
relativamente simples.
• Es razonable esperar que los valores encapsulados se copiarán en lugar de referencia
cuando se asigna o pasar alrededor de una instancia de esa estructura.
• Todas las propiedades almacenados por la estructura son ellos mismos tipos de
valores, que también se esperaría que se va a copiar en lugar de referencia.
• La estructura no necesita heredar propiedades o comportamiento de otro tipo
existente.
Ejemplos de buenos candidatos para estructuras incluyen:
• El tamaño de una forma geométrica, tal vez la encapsulación de una anchura
de propiedad y una altura de la propiedad, tanto de tipo doble .
• Una forma para referirse a rangos dentro de una serie, tal vez encapsula
un inicio la propiedad y unalongitud de la propiedad, tanto de tipo int .
• Un punto en un sistema de 3D, tal vez encapsulación de
coordenadas x , Y y Z propiedades, cada uno de tipo doble .
En todos los demás casos, definir una clase, y crear instancias de esa clase se gestionen
y se pasan por referencia. En la práctica, esto significa que la mayoría de las
construcciones de datos personalizados deben ser clases, no a estructuras.

  127  
Asignación y Copiar Comportamiento de cadenas, matrices, y Diccionarios
De Swift de Cuerda , de matriz , y Diccionario tipos se implementan como
estructuras. Esto significa que se copian cadenas, matrices y diccionarios cuando son
asignados a una nueva constante o variable, o cuando se pasan a una función o método.
Este comportamiento es diferente de NSString , NSArray y NSDictionary en
Fundación, que se implementan como clases, no
estructuras. NSString , NSArray y NSDictionary casos siempre se asignan y se
pasa alrededor como una referencia a una instancia existente, en lugar de como una
copia.
NOTA
La descripción anterior se refiere a la "copia" de las cadenas, matrices y diccionarios. El
comportamiento que se observa en el código siempre será como si una copia se llevó a
cabo. Sin embargo, Swift sólo realiza unaverdadera copia en segundo plano cuando es
absolutamente necesario hacerlo. Swift gestiona toda la copia de valores para garantizar
un rendimiento óptimo, y usted no debe evitar la asignación para tratar de anticiparse a
esta optimización.
 

Propiedades
Propiedades asocian valores con una clase, estructura o enumeración
particular. Propiedades almacenados almacenar valores constantes y variables como
parte de una instancia, mientras que las propiedades calculadas calculan (en lugar de la
tienda) un valor. Propiedades calculadas son proporcionados por las clases, estructuras y
enumeraciones. Propiedades almacenados se proporcionan sólo por las clases y
estructuras.
Propiedades almacenadas y calculadas se asocian generalmente a instancias de un tipo
particular. Sin embargo, las propiedades también pueden estar asociados con el propio
tipo. Dichas propiedades se conocen como propiedades de tipo.
Además, puede definir la propiedad observadores para monitorear los cambios en el
valor de una propiedad, que se puede responder con acciones
personalizadas. Observadores de propiedad pueden ser añadidos a las propiedades
almacenados definidas por usted, y también a las propiedades que una subclase hereda
de su superclase.
Propiedades guardadas
En su forma más simple, una propiedad almacenada es una constante o una variable que
se almacena como parte de una instancia de una clase o estructura
particular. Propiedades almacenados pueden ser opropiedades de las variables
almacenadas (introducidas por la var palabra clave) o propiedades almacenadas
constantes (introducidos por el let palabra clave).
Puede proporcionar un valor predeterminado para una propiedad almacenada como
parte de su definición, como se describe en los valores de propiedad
predeterminados . También puede establecer y modificar el valor inicial de una
propiedad almacenada durante la inicialización. Esto es cierto incluso para constantes
propiedades almacenadas, como se describe en Modificación de las propiedades
constantes durante la inicialización .

  128  
El ejemplo siguiente define una estructura llamada FixedLengthRange , que
describe un rango de enteros cuya longitud rango no se puede cambiar una vez que se
crea:
• struct FixedLengthRange {
• var firstValue: Int
• let length: Int
• }
• var rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3)
• // the range represents integer values 0, 1, and 2
• rangeOfThreeItems.firstValue = 6
• // La gama ahora representa valores enteros 6, 7, y 8  
Las instancias de FixedLengthRange tienen una propiedad de variable almacenado
llamado firstValue y una propiedad almacenada constante
llamada longitud . En el ejemplo anterior, la longitud se inicializa cuando se
crea la nueva gama y no puede ser cambiado a partir de entonces, debido a que es una
propiedad constante.
Propiedades almacenados de Estructura instancias constantes
Si crea una instancia de una estructura y asigna esa instancia a una constante, no puede
modificar las propiedades de la instancia, aunque hayan sido declarados como
propiedades de las variables:
• let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4)
• // this range represents integer values 0, 1, 2, and 3
• rangeOfFourItems.firstValue = 6
• // Esto reportará un error, a pesar de que firstValue es
una propiedad de variable  
Debido rangeOfFourItems se declara como una constante (con la let palabra
clave), no es posible cambiar sufirstValue propiedad, a pesar de
que firstValue es una propiedad variable.
Este comportamiento se debe a que las estructuras son tipos de valor . Cuando una
instancia de un tipo de valor está marcado como una constante, por lo que son todas sus
propiedades.
Lo mismo no es cierto para las clases, que son los tipos de referencia . Si asigna una
instancia de un tipo de referencia a una constante, siempre será posible modificar
propiedades de las variables de esa instancia.
Propiedades almacenados Lazy
Una propiedad almacenado perezoso es una propiedad cuyo valor inicial no se calcula
hasta que la primera vez que se utiliza. Usted indica un perezoso propiedad almacenada
escribiendo el perezoso modificador antes de su declaración.
NOTA
Siempre hay que declarar una propiedad perezoso como una variable (con
la var palabra clave), ya que su valor inicial no podría ser recuperada hasta después de
que finalice inicialización de instancia. Propiedades constantes siempre deben tener un

  129  
valor antes de la inicialización completa, y por lo tanto no pueden ser declarados como
perezoso.
Lazy propiedades son útiles cuando el valor inicial de una propiedad depende de
factores externos, cuyos valores no se conocen hasta después de la inicialización de una
instancia se ha completado. Lazy propiedades también son útiles cuando el valor inicial
de una propiedad requiere configuración compleja o costosa computacionalmente que
no debe realizarse a menos que o hasta que se necesite.
El ejemplo siguiente utiliza una propiedad almacenada perezosa para evitar la
inicialización innecesaria de una clase compleja. Este ejemplo define dos clases
llamadas DataImporter y DataManager , ninguno de los cuales se muestra en su
totalidad:
• class DataImporter {
• / *  
• DataImporter es una clase para importar datos de un archivo
externo.  
• La clase se supone que tomar una cantidad no trivial de
tiempo para inicializar.  
• * /  
• var fileName = "data.txt"
• // La clase DataImporter proporcionaría datos importadores
funcionalidad aquí  
• }  
•  
• class DataManager {
• lazy var importer = DataImporter()
• var data = [String]()
• // La clase DataManager proporcionaría la funcionalidad de
gestión de datos aquí  
• }  
•  
• let manager = DataManager()
• manager.data.append("Some data")
• manager.data.append("Some more data")
• // Aún no se ha creado la instancia DataImporter para la
propiedad importador  
El DataManager clase tiene una propiedad almacenado llamado de datos , que se
inicia con una nueva matriz, vacío de Cuerda valores. Aunque no se muestra el resto
de su funcionalidad, el propósito de este DataManagerclase es gestionar y facilitar el
acceso a esta matriz de cadena de datos.

  130  
Parte de la funcionalidad del DataManager clase es la capacidad de importar datos de
un archivo. Esta funcionalidad es proporcionada por el DataImporter clase, que se
supone que tomar una cantidad no trivial de tiempo para inicializar. Esto podría ser
debido a un DataImporter instancia tiene que abrir un archivo y leer su contenido
en la memoria cuando el DataImporter se inicializa la instancia.
Es posible que un DataManager ejemplo para administrar sus datos sin importar
datos de un archivo, lo que no hay necesidad de crear un
nuevo DataImporter ejemplo, cuando el DataManager se crea en sí. En cambio,
tiene más sentido para crear la DataImporter ejemplo, si y cuando se utilizó por
primera vez.
Debido a que está marcado con el perezoso modificador,
el DataImporter instancia para el importador sólo se crea la propiedad cuando
el importador de propiedad se accede por primera vez, como cuando
su nomArchivopropiedad se consulta:
• println(manager.importer.fileName)
• // Ahora se ha creado la instancia DataImporter para la
propiedad importador  
• // Impresiones "data.txt"  
•  
Propiedades almacenados y variables de instancia
Si usted tiene experiencia con Objective-C, usted puede saber que ofrece dos formas de
almacenar los valores y las referencias como parte de una instancia de clase. Además de
las propiedades, puede utilizar las variables de instancia como un almacén de respaldo
para los valores almacenados en una propiedad.
Swift unifica estos conceptos en una única declaración de propiedad. Una propiedad
Swift no tiene una variable de instancia correspondiente, y el almacén de respaldo para
una propiedad no se accede directamente. Este enfoque evita la confusión acerca de
cómo se accede al valor en diferentes contextos y simplifica la declaración de la
propiedad en una sola sentencia, definitiva. Toda la información sobre la propiedad-
incluyendo su nombre, características-es el tipo y la gestión de memoria definen en un
solo lugar, como parte de la definición del tipo.
Propiedades calculadas
Además de las propiedades almacenados, clases, estructuras y enumeraciones pueden
definir propiedades calculadas , que en realidad no almacenan un valor. En su lugar,
proporcionan un getter y un setter opcional para recuperar y establecer otras
propiedades y valores de manera indirecta.
• struct Point {
• var x = 0.0, y = 0.0
• }
• struct Size {
• var width = 0.0, height = 0.0
• }

  131  
• struct Rect {
• var origin = Point()
• var size = Size()
• var center: Point {
• get {
• let centerX = origin.x + (size.width / 2)
• let centerY = origin.y + (size.height / 2)
• return Point(x: centerX, y: centerY)
• }
• set(newCenter) {
• origin.x = newCenter.x - (size.width / 2)
• origin.y = newCenter.y - (size.height / 2)
• }
• }
• }
• var square = Rect(origin: Point(x: 0.0, y: 0.0),
• size: Size(width: 10.0, height: 10.0))
• let initialSquareCenter = square.center
• square.center = Point(x: 15.0, y: 15.0)
• println("square.origin is now at (\(square.origin.x), \(square.origin.y))")
• // Impresiones "square.origin se encuentra ahora en (10.0,
10.0)"  
Este ejemplo define tres estructuras para trabajar con formas geométricas:
• Punto encapsula una (x, y) de coordenadas.
• Tamaño encapsula una anchura y una altura .
• Rect define un rectángulo por un punto de origen y un tamaño.
El Rect estructura también proporciona una propiedad calculada llamado centro . La
posición central actual de un Rect siempre se puede determinar a partir de
su origen y tamaño , y por lo que no es necesario almacenar el punto central como
un explícito Point valor. En su lugar, Rect define un captador de encargo y setter
para una variable de llamada computarizada centro , para que pueda trabajar con el
rectángulo del centro como si fuera una propiedad real almacenado.
El ejemplo anterior crea una nueva Rect variable
llamada plaza . El cuadrado variable se inicializa con un punto de origen de (0,
0) , y una anchura y una altura de 10 . Esta plaza está representado por el cuadrado
azul en el diagrama a continuación.
La plaza de la variable centro propiedad se accede luego a través de la sintaxis con
punto ( square.center ), lo que hace que el captador de centro para ser llamado,
para recuperar el valor actual de la propiedad. En lugar de devolver un valor existente,
el comprador realmente calcula y devuelve un nuevo punto para representar el centro

  132  
de la plaza. Como se puede ver arriba, el getter devuelve correctamente un punto central
de (5, 5) .
El centro de la propiedad se establece a continuación, a un nuevo valor de (15,
15) , que se mueve a la plaza arriba y hacia la derecha, a la nueva posición mostrada
por el cuadrado de color naranja en el siguiente diagrama. Ajuste del centro de la
propiedad llama al colocador de centro , que modifica la x y Y los valores de la
almacenada origen propiedad, y se mueve hacia la plaza a su nueva posición.

 
 

Taquigrafía Declaración Setter


Si seleccionador de propiedades computarizada no define un nombre para el nuevo
valor que se determine, el nombre predeterminado nuevoValor se utiliza. Aquí hay
una versión alternativa de la Rect estructura, que se aprovecha de esta notación
abreviada:
• struct AlternativeRect {
• var origin = Point()
• var size = Size()
• var center: Point {
• get {
• let centerX = origin.x + (size.width / 2)
• let centerY = origin.y + (size.height / 2)
• return Point(x: centerX, y: centerY)
• }

  133  
• set {
• origin.x = newValue.x - (size.width / 2)
• origin.y = newValue.y - (size.height / 2)
• }
• }
• }

Sólo lectura Propiedades calculadas


Una propiedad calculada con un captador pero ningún organismo que se conoce como
una propiedad calculada de sólo lectura . Una propiedad de sólo lectura computarizada
siempre devuelve un valor, y se puede acceder a través de la sintaxis con punto, pero no
se puede ajustar a un valor diferente.
NOTA
Debe declarar propiedades-incluyendo calculados propiedades de sólo lectura-como
propiedades de las variables calculadas con la var palabra clave, porque su valor no es
fijo. El let palabra clave sólo se utiliza para propiedades constantes, para indicar que
sus valores no se pueden cambiar una vez que se establecen como parte de inicialización
de instancia.
Se puede simplificar la declaración de un solo lectura propiedad calculada mediante la
eliminación de la getpalabra clave y sus apoyos:
• struct Cuboid {
• var width = 0.0, height = 0.0, depth = 0.0
• var volume: Double {
• return width * height * depth
• }
• }
• let fourByFiveByTwo = Cuboid(width: 4.0, height: 5.0, depth: 2.0)
• println("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)")
• // imprime "el volumen de fourByFiveByTwo es 40.0"  
En este ejemplo se define una nueva estructura llamada Cuboide , lo que representa
una caja rectangular 3D con anchura , altura y profundidad propiedades. Esta
estructura también tiene una propiedad de sólo lectura computarizada
llamado volumen , que calcula y devuelve el volumen actual del cuboides. No tiene
sentido queel volumen sea configurable, porque sería ambiguo en cuanto a qué
valores de anchura , altura y profundidadse debe utilizar para un
determinado volumen de valor. Sin embargo, es útil para un cuboide para
proporcionar una propiedad de sólo lectura computarizada para permitir a los usuarios
externos para descubrir su volumen calculado actual.
Los observadores de la propiedad
Observadores de Propiedad observan y responden a los cambios en el valor de una
propiedad.Observadores de propiedad son llamados cada vez que el valor de una

  134  
propiedad se establece, incluso si el nuevo valor es el mismo que el valor actual de la
propiedad.
Puede agregar observadores de propiedad a ninguna propiedad en que se definen,
además de propiedades almacenadas perezosos. También puede agregar los
observadores de propiedad a cualquier propiedad heredada (si almacena o calcula) por
razones imperiosas de la propiedad dentro de una subclase. Primordial de la propiedad
se describe en Overriding .
NOTA
No es necesario definir los observadores de propiedad para propiedades calculadas no
anulado, ya que se puede observar y responder a los cambios de su valor directamente
desde setter de la propiedad calculada.
Usted tiene la opción de definir uno o ambos de estos observadores a una propiedad:
• willSet se llama justo antes de que el valor se almacena.
• didSet se llama inmediatamente después de que el nuevo valor se almacena.
Si implementa un willSet observador, se pasa el nuevo valor de la propiedad como
un parámetro constante.Puede especificar un nombre para este parámetro como parte de
su willSet aplicación. Si decide no escribir el nombre del parámetro y los paréntesis
dentro de su aplicación, el parámetro todavía estará disponible con un nombre de
parámetro por defecto de nuevoValor .
Del mismo modo, si implementa un didSet observador, se le pasará un parámetro
constante que contiene el valor de la propiedad antigua. Puede nombrar el parámetro si
lo desea, o utilizar el nombre del parámetro por defecto de oldValue .
NOTA
willSet y didSet observadores no son llamados cuando una propiedad se inicializa
primero. Ellos sólo son llamados cuando el valor de la propiedad se establece fuera de
un contexto de inicialización.
He aquí un ejemplo de willSet y didSet en acción. El ejemplo siguiente define una
nueva clase llamadastepcounter , que rastrea el número total de pasos que una
persona toma al caminar. Esta clase puede utilizarse con datos de entrada de un
podómetro u otro contador de pasos para realizar un seguimiento del ejercicio de una
persona durante su rutina diaria.
• class StepCounter {
• var totalSteps: Int = 0 {
• willSet(newTotalSteps) {
• println("About to set totalSteps to \(newTotalSteps)")
• }
• didSet {
• if totalSteps > oldValue {
• println("Added \(totalSteps - oldValue) steps")
• }
• }
• }
• }

  135  
• let stepCounter = StepCounter()
• stepCounter.totalSteps = 200
• // Acerca establecer totalSteps a 200  
• // Añadido 200 pasos  
• stepCounter.totalSteps = 360
• // Acerca establecer totalSteps al 360  
• // Añadido 160 escalones  
• stepCounter.totalSteps = 896
• // Acerca establecer totalSteps al 896  
• // Añadido 536 pasos  
El stepcounter clase declara un totalSteps propiedad de tipo int . Esta es una
propiedad almacenada conwillSet y didSet observadores.
Los willSet y didSet observadores de totalSteps son llamados cada vez que la
propiedad se le asigna un nuevo valor. Esto es cierto incluso si el nuevo valor es el
mismo que el valor actual.
De este ejemplo willSet observador utiliza un nombre de parámetro personalizado
de newTotalSteps para el próximo valor nuevo. En este ejemplo, simplemente
imprime el valor que se va a establecer.
El didSet observador se llama después de que el valor de totalSteps se
actualiza. Se compara el nuevo valor de totalSteps contra el valor antiguo. Si el
número total de pasos se ha incrementado, se imprime un mensaje para indicar la
cantidad de pasos nuevos se han tomado. El didSet observador no proporciona un
nombre de parámetro personalizado para el valor anterior, y el nombre predeterminado
de oldValue se utiliza en su lugar.
NOTA
Si se asigna un valor a una propiedad dentro de su propio didSet observador, el nuevo
valor que asigne sustituirá a la que se acaba de establecer.

Variables globales y locales


Las capacidades descritas anteriormente para la informática y las propiedades de
observación también están disponibles para las variables globales y las variables
locales . Las variables globales son variables que se definen fuera de cualquier función,
método de cierre, o contexto de tipo. Las variables locales son variables que se definen
dentro de una función, método, o el contexto de cierre.
Las variables globales y locales que pueda haber tenido en los capítulos anteriores,
todos se hanalmacenado las variables . Variables almacenadas, como propiedades
almacenadas, proporcionan almacenamiento para un valor de un determinado tipo y
permiten que el valor que se fijará y se recupera.
Sin embargo, también se pueden definir variables calculadas y definir observadores
para las variables almacenadas, ya sea en un ámbito global o local. Las variables
calculadas calculan en lugar de almacenar un valor, y se escriben de la misma manera
como las propiedades calculadas.
NOTA

  136  
Constantes y variables globales se calculan siempre con pereza, de una manera similar
a to Lazy Stored Properties. A diferencia de las propiedades almacenados perezosos,
constantes y variables globales no necesitan ser marcados con el lazy modificador.
Constantes y variables locales no se calculan perezosamente.

Tipo de Propiedades
Propiedades de instancia son las propiedades que pertenecen a una instancia de un tipo
particular. Cada vez que se crea una nueva instancia de ese tipo, tiene su propio
conjunto de valores de la propiedad, separada de cualquier otra instancia.
También puede definir propiedades que pertenecen al tipo de sí mismo, no a cualquier
instancia de ese tipo.Sólo habrá alguna vez una copia de estas propiedades, no importa
cuántas instancias de ese tipo que crean.Estos tipos de propiedades se
denominan propiedades de tipo .
Propiedades de tipo son útiles para definir los valores que son universales para todas
las instancias de un tipo particular, tal como una propiedad constante que todas las
instancias pueden utilizar (como una constante estática en C), o una propiedad variable
que almacena un valor que es global para todos los instancias de ese tipo (como una
variable estática en C).
Para los tipos de valor (es decir, estructuras y enumeraciones), puede definir
almacenado y calculado propiedades de tipo. Para las clases, puede definir sólo
propiedades de tipo computados.
Propiedades de tipo almacenados para los tipos de valor pueden ser variables o
constantes. Propiedades de tipo calculadas siempre se declaran como propiedades de las
variables, en la misma forma que las propiedades de instancia computados.
NOTA
A diferencia de propiedades de la instancia almacenados, siempre hay que dar
propiedades de tipo almacenado un valor por defecto. Esto es porque el tipo en sí no
tiene un inicializador que puede asignar un valor a una propiedad de tipo almacenado en
tiempo de inicialización.
Escriba Propiedad Sintaxis
En C y Objective-C, se define constantes estáticas y variables asociadas a un tipo
como globales variables estáticas. En Swift, sin embargo, las propiedades del tipo se
escriben como parte de la definición del tipo, entre llaves exteriores del tipo, y cada
propiedad tiene el ámbito de tipo explícitamente al tipo que soporta.
Usted define las propiedades del tipo para los tipos de valor con la estática de
palabras clave y propiedades de tipo para los tipos de clase con la clase de palabras
clave. El siguiente ejemplo muestra la sintaxis de propiedades de tipo almacenados y
calculados:
• struct SomeStructure {
• static var storedTypeProperty = "Some value."
• static var computedTypeProperty: Int {
• // return an Int value here
• }
• }

  137  
• enum SomeEnumeration {
• static var storedTypeProperty = "Some value."
• static var computedTypeProperty: Int {
• // Devuelve un valor int aquí  
• }
• }
• class SomeClass {
• class var computedTypeProperty: Int {
• // Devuelve un valor int aquí  
• }
•}
NOTA
Los ejemplos calculados tipo de propiedad anteriores son para propiedades de tipo de
sólo lectura computados, pero también es posible definir propiedades de estilo
calculados con la misma sintaxis que para las propiedades de instancia calculados de
lectura-escritura.
Consulta y ajuste del tipo de Propiedades
Tipo propiedades se consultan y establecen con la sintaxis con punto, al igual que las
propiedades de instancia. Sin embargo, las propiedades del tipo se consultan y
establecen en el tipo , no en una instancia de ese tipo. Por ejemplo:
• println(SomeClass.computedTypeProperty)
• // imprime "42"  
•  
• println(SomeStructure.storedTypeProperty)
• // imprime "algún valor."  
• SomeStructure.storedTypeProperty = "Another value."
• println(SomeStructure.storedTypeProperty)
• // imprime "otro valor."  
Los ejemplos que siguen utilizan dos propiedades de tipo almacenados como parte de
una estructura que los modelos de un metro de nivel de audio para un número de canales
de audio. Cada canal tiene un nivel de audio de número entero entre 0 y 10 inclusive.
La siguiente figura ilustra cómo dos de estos canales de audio se pueden combinar para
modelar un medidor de nivel de audio estéreo. Cuando el nivel de audio de un canal
es 0 , ninguna de las luces de ese canal están encendidos Cuando el nivel de audio
es 10 , todas las luces de ese canal son lit. En esta figura, el canal de la izquierda tiene
un nivel de corriente de 9 , y el canal derecho tiene un nivel actual de 7 :

  138  
 

Los canales de audio descritos anteriormente están representados por instancias de


la AudioChannelestructura:
• struct AudioChannel {
• static let thresholdLevel = 10
• static var maxInputLevelForAllChannels = 0
• var currentLevel: Int = 0 {
• didSet {
• if currentLevel > AudioChannel.thresholdLevel {
• // cap the new audio level to the threshold level
• currentLevel = AudioChannel.thresholdLevel
• }
• if currentLevel > AudioChannel.maxInputLevelForAllChannels {
• // store this as the new overall maximum input level
• AudioChannel.maxInputLevelForAllChannels = currentLevel
• }
• }
• }
• }
El AudioChannel estructura define dos propiedades de tipo almacenados en apoyo
de su funcionalidad. El primero, thresholdLevel , define el valor de umbral
máximo un nivel de audio puede tomar. Este es un valor constante de 10 para todos
los AudioChannel casos. Si una señal de audio llega con un valor superior a 10 , que
se limitará a este valor de umbral (como se describe a continuación).

  139  
La segunda propiedad type es una variable almacenada propiedad
llamada maxInputLevelForAllChannels .Esto hace un seguimiento del valor de
entrada máximo que haya sido recibida por cualquier AudioChannelinstancia. Se
inicia con un valor inicial de 0 .
El AudioChannel estructura también define una propiedad de instancia almacenado
llamado CurrentLevel , que representa el nivel de audio actual del canal en una
escala de 0 a 10 .
El CurrentLevel propiedad tiene un didSet observador propiedad para comprobar
el valor de CurrentLevelcada vez que se establece. Este observador realiza dos
comprobaciones:
• Si el nuevo valor de CurrentLevel es mayor que el
permitido thresholdLevel , las tapas de observadores
propiedad CurrentLevel a thresholdLevel .
• Si el nuevo valor de CurrentLevel (después de cualquier nivelación) es mayor
que cualquier valor previamente recibida por cualquier AudioChannel ejemplo,
el observador propiedad almacena el nuevoCurrentLevel valor en
los maxInputLevelForAllChannels propiedad estática.
NOTA
En el primero de estos dos controles, los didSet conjuntos de
observación CurrentLevel a un valor diferente.Esto no significa, sin embargo,
hacen que el observador que se llamará de nuevo.
Usted puede utilizar el AudioChannel estructura para crear dos nuevos canales de
audio llamados leftChannely rightChannel , para representar los niveles de
audio de un sistema de sonido estéreo:
• var leftChannel = AudioChannel()
• var rightChannel = AudioChannel()
If you set the currentLevel of the left channel to 7, you can see that
the maxInputLevelForAllChannels type property is updated to equal 7:
• leftChannel.currentLevel = 7
• println(leftChannel.currentLevel)
• // prints "7"
• println(AudioChannel.maxInputLevelForAllChannels)
• // imprime "7"  
Si se intenta establecer la CurrentLevel de la derecha del canal a 11 , se puede ver
que el canal derechoCurrentLevel propiedad está limitado al valor máximo de 10 ,
y el maxInputLevelForAllChannels tipo de propiedad se ha actualizado a la
igualdad 10 :
• rightChannel.currentLevel = 11
• println(rightChannel.currentLevel)
• // imprime "10"  
• println(AudioChannel.maxInputLevelForAllChannels)
• // imprime "10"  
 

  140  
Métodos
En esta página
Métodos son funciones que están asociadas con un tipo particular. Las clases,
estructuras y enumeraciones todos pueden definir métodos de instancia, que encapsulan
tareas y funciones específicas para trabajar con una instancia de un tipo dado. Las
clases, estructuras y enumeraciones también pueden definir métodos de tipo, que se
asocian con el propio tipo. Tipo métodos son similares a los métodos de clase en
Objective-C.
El hecho de que las estructuras y enumeraciones pueden definir métodos en Swift es
una gran diferencia con C y Objective-C. En Objective-C, las clases son los únicos tipos
que pueden definir métodos. En Swift, puede elegir si desea definir una clase, estructura
o enumeración, y aún así tener la flexibilidad de definir métodos en el tipo que cree.
Métodos de instancia
Los métodos de instancia son funciones que pertenecen a instancias de una clase,
estructura o enumeración particular. Apoyan a la funcionalidad de los casos, ya sea
proporcionando formas de acceder y modificar las propiedades de instancia, o
proporcionando una funcionalidad relacionada con el propósito de la instancia.Los
métodos de instancia tienen exactamente la misma sintaxis que las funciones, como se
describe enFunciones .
Usted escribe un método de instancia dentro de las llaves de apertura y cierre del tipo al
que pertenece. Un método de instancia tiene acceso implícito a todos los demás
métodos de instancia y las propiedades de ese tipo. Un método de instancia sólo se
puede llamar a una instancia específica del tipo al que pertenece. No se puede llamar de
forma aislada, sin una instancia existente.
He aquí un ejemplo que define un sencillo contador de la clase, que se puede
utilizar para contar el número de veces que se produce una acción:
• class Counter {
• var count = 0
• func increment() {
• count++
• }
• func incrementBy(amount: Int) {
• count += amount
• }
• func reset() {
• count = 0
• }
• }
El contador de clase define tres métodos de instancia:
• Valor mínimo incrementa el contador por 1 .
• incrementBy (cantidad: Int) incrementa el contador por un importe
entero especificado.

  141  
• restablecer restablece el contador a cero.
El contador de la clase también declara una propiedad de variable, cuenta , para
no perder de vista el valor actual del contador.
Usted llama a los métodos de instancia con el mismo sintaxis con punto como
propiedades:
• let counter = Counter()
• // the initial counter value is 0
• counter.increment()
• // the counter's value is now 1
• counter.incrementBy(5)
• // the counter's value is now 6
• counter.reset()
• // the counter's value is now 0

Nombres locales y parámetros externos para los métodos


Parámetros de la función pueden tener tanto un nombre local (para el uso en el cuerpo
de la función) y un nombre externo (para su uso cuando se llama a la función), como se
describe en el parámetro External Nombres . Lo mismo es cierto para los parámetros del
método, porque los métodos son sólo funciones que están asociadas con un tipo. Sin
embargo, el comportamiento predeterminado de los nombres locales y nombres
externos es diferente para las funciones y métodos.
Métodos de Swift son muy similares a sus contrapartes en Objective-C. Como en
Objective-C, el nombre de un método en el Swift se refiere típicamente a primer
parámetro del método que utiliza una preposición comocon , para , o por , como se
ve en la incrementBy método de la anterior Contador ejemplo de la clase. El uso
de una preposición permite el método para ser leído como una sentencia cuando se le
llama. Swift hace que esta convención de nombres método establecido fácil escribir
utilizando un enfoque predeterminado diferente para los parámetros del método que se
utiliza para los parámetros de función.
En concreto, Swift da la primera nombre de parámetro en un método un nombre de
parámetro local de forma predeterminada, y da los nombres de los parámetros segundo
y siguientes ambos locales y nombres de los parámetros externos de manera
predeterminada. Esta convención coincide con la denominación típica y el convenio de
llamada que usted estará familiarizado con los métodos de escritura de Objective-C, y lo
convierte en método expresivo llamadas sin la necesidad de calificar los nombres de los
parámetros.
Considere esta versión alternativa del contador de clase, que define una forma más
compleja de laincrementBy método:
• class Counter {
• var count: Int = 0
• func incrementBy(amount: Int, numberOfTimes: Int) {
• count += amount * numberOfTimes

  142  
• }
• }
Esta incrementBy método tiene dos parámetros-
cantidad y numberOfTimes . De forma predeterminada, Swift
trata cantidad tan sólo un nombre local, pero trata numberOfTimes como tanto
local y un nombre externo.Llamar al método de la siguiente manera:
• let counter = Counter()
• counter.incrementBy(5, numberOfTimes: 3)
• // Valor del contador es ahora de 15 años  
No es necesario definir un nombre de parámetro externo para el primer valor del
argumento, porque su propósito es claro desde el nombre de la
función incrementBy . El segundo argumento, sin embargo, es calificado por un
nombre de parámetro externo para realizar su propósito claro cuando se llama al
método.
Este comportamiento predeterminado trata con eficacia el método como si hubiera
escrito un símbolo de almohadilla ( # ) antes de la numberOfTimes parámetro:
• func incrementBy(amount: Int, #numberOfTimes: Int) {
• count += amount * numberOfTimes
• }
El comportamiento predeterminado descrito anteriormente significa que las definiciones
de método en Swift se escriben con el mismo estilo gramatical como Objective-C, y se
llaman de una manera natural, expresiva.
Modificación de parámetros externos Comportamiento Nombre de Métodos
A veces es útil para proporcionar un nombre de parámetro externo para el primer
parámetro de un método, a pesar de que este no es el comportamiento
predeterminado. Usted puede añadir un nombre externo explícito a ti mismo, o puede
anteponer el nombre del primer parámetro con un símbolo de hash para utilizar el
nombre local como un nombre externo también.
Por el contrario, si usted no desea proporcionar un nombre externo para el segundo o
subsiguiente parámetro de un método, reemplazar el comportamiento predeterminado
mediante un carácter de subrayado ( _ ) como un nombre de parámetro externo explícito
para ese parámetro.
El auto de la propiedad
Cada instancia de un tipo tiene una propiedad llamada implícita auto , que es
exactamente equivalente a la propia instancia. Se utiliza el auto propiedad para hacer
referencia a la instancia actual dentro de sus propios métodos de instancia.
El incremento de método en el ejemplo anterior se podría haber escrito así:
• func increment() {
• self.count++
• }
En la práctica, no es necesario escribir uno mismo en su código muy a menudo. Si
usted no escribe explícitamente auto , Swift asume que se está haciendo referencia a

  143  
una propiedad o método de la instancia actual cada vez que utilice una propiedad
conocida o nombre de método dentro de un método. Esta suposición se demostró
mediante el uso de recuento (en lugar de self.count ) dentro de los tres métodos
de instancia para Contador .
La principal excepción a esta regla se produce cuando un nombre de parámetro para un
método de instancia tiene el mismo nombre que una propiedad de esa instancia. En esta
situación, el nombre del parámetro tiene prioridad, y se hace necesario hacer referencia
a la propiedad de forma más cualificada. Se utiliza el autopropiedad de distinguir entre
el nombre del parámetro y el nombre de la propiedad.
Aquí, por cuenta de ambigüedad entre un parámetro de método llamado x y una
propiedad de instancia que también se llama x :
• struct Point {
• var x = 0.0, y = 0.0
• func isToTheRightOfX(x: Double) -> Bool {
• return self.x > x
• }
• }
• let somePoint = Point(x: 4.0, y: 5.0)
• if somePoint.isToTheRightOfX(1.0) {
• println("This point is to the right of the line where x == 1.0")
• }
• // Impresiones "Este punto está a la derecha de la línea en
la que x == 1.0"  
Sin el auto prefijo, Swift sería asumir que ambos usos de x hace referencia al
parámetro de método llamado x.
Modificación de tipos de valor desde dentro de los métodos de instancia
Estructuras y enumeraciones son tipos de valor . De forma predeterminada, las
propiedades de un tipo de valor no se puede modificar desde dentro de sus métodos de
instancia.
Sin embargo, si tiene que modificar las propiedades de su estructura o enumeración
dentro de un método en particular, se puede optar por la mutación de comportamiento
para ese método. El método puede entonces mutar (es decir, cambiar) sus propiedades
desde dentro del método, y cualquier cambio que haga en se escriben de nuevo a la
estructura original cuando el método termina. El método también se puede asignar una
nueva instancia a su implícita auto propiedad, y esta nueva instancia reemplazará a la
existente cuando el método termina.
Usted puede optar por este comportamiento mediante la colocación de la mutación
de la palabra clave antes de la func palabra clave para ese método:
• struct Point {
• var x = 0.0, y = 0.0
• mutating func moveByX(deltaX: Double, y deltaY: Double) {

  144  
• x += deltaX
• y += deltaY
• }
• }
• var somePoint = Point(x: 1.0, y: 1.0)
• somePoint.moveByX(2.0, y: 3.0)
• println("The point is now at (\(somePoint.x), \(somePoint.y))")
• // imprime "El punto es ahora en (3.0, 4.0)"  
El Punto estructura anterior define una mutación moveByX método, que mueve
un Punto de ejemplo, por una cierta cantidad. En lugar de devolver un nuevo punto,
este método en realidad modifica el punto en el que se llama. La mutación de la
palabra clave se añade a su definición para que pueda modificar sus propiedades.
Tenga en cuenta que usted no puede llamar a un método mutando en una constante del
tipo de estructura, ya que sus propiedades no se pueden cambiar, incluso si son
propiedades de las variables, como se describe enPropiedades almacenados de
Estructura instancias constantes :
• let fixedPoint = Point(x: 3.0, y: 3.0)
• fixedPoint.moveByX(2.0, y: 3.0)
• // Esta informará de un error  
Asignar a la libre dentro de un método Mutating
Métodos mutantes pueden asignar una instancia completamente nueva de lo
implícito auto propiedad. ElPunto ejemplo anterior podría haber sido escrito de la
siguiente manera en su lugar:
• struct Point {
• var x = 0.0, y = 0.0
• mutating func moveByX(deltaX: Double, y deltaY: Double) {
• self = Point(x: x + deltaX, y: y + deltaY)
• }
• }
This version of the mutating moveByX method creates a brand new structure Esta
versión de la mutación moveByX método crea una nueva estructura de marcas
cuya x y Y los valores se establecen en la ubicación de destino. El resultado final de
llamar a esta versión alternativa del método será exactamente la misma que para llamar
a la versión anterior.
La mutación de los métodos para enumeraciones puede establecer el
implícito auto parámetro que ser miembro diferente de la misma enumeración:
• enum TriStateSwitch {
• case Off, Low, High
• mutating func next() {
• switch self {

  145  
• case Off:
• self = Low
• case Low:
• self = High
• case High:
• self = Off
• }
• }
• }
• var ovenLight = TriStateSwitch.Low
• ovenLight.next()
• // OvenLight es ahora igual a .high  
• ovenLight.next()
• // OvenLight es ahora igual a .OFF  
Este ejemplo define una enumeración para un interruptor de tres estados. Los ciclos de
conmutación entre los tres estados de energía diferentes ( Off , Bajo y Alto ) cada
vez que su siguiente método se llama.
Tipo Métodos
Los métodos de instancia, como se describe más arriba, son los que se denominan en
una instancia de un tipo particular. También puede definir los métodos que se llaman en
el propio tipo. Estos tipos de métodos son llamados métodos de tipo . Usted indica
métodos de tipo para las clases escribiendo la palabra clave de clase antes del
método func palabra clave, y escribe métodos para estructuras y enumeraciones
escribiendo la palabra clave static antes del método func palabra clave.
NOTA
En Objective-C, se pueden definir métodos de nivel de tipo sólo para las clases de
Objective-C. En Swift, se pueden definir métodos de nivel de tipo para todas las clases,
estructuras y enumeraciones. Cada método tiene el ámbito de tipo explícitamente al tipo
que soporta.
Tipo métodos se denominan con la sintaxis con punto, al igual que los métodos de
instancia. Sin embargo, se llama a métodos de tipo del tipo, no en una instancia de ese
tipo. He aquí cómo se llama a un método de tipo en una clase llamada AlgunaClase :
• class SomeClass {
• class func someTypeMethod() {
• // type method implementation goes here
• }
• }
• SomeClass.someTypeMethod()
Dentro del cuerpo de un método de tipo, lo implícito auto propiedad se refiere al tipo
en sí, en lugar de una instancia de ese tipo. Para las estructuras y enumeraciones, esto
significa que usted puede utilizar auto para eliminar la ambigüedad entre las

  146  
propiedades estáticas y parámetros del método estático, tal como lo hace para las
propiedades de instancia y los parámetros del método de instancia.
Más en general, cualquier método y propiedad nombres no calificados que se utilizan
dentro del cuerpo de un método tipo se referirán a otros métodos y propiedades de nivel
de tipo. Un método de tipo puede llamar a otro método de tipo con el nombre del otro
método, sin necesidad de un prefijo con el nombre del tipo. Del mismo modo, los
métodos de tipo de estructuras y enumeraciones pueden tener acceso a las propiedades
estáticas utilizando el nombre de la propiedad estática sin un prefijo de nombre de tipo.
El ejemplo siguiente define una estructura llamada LevelTracker , que rastrea el
progreso del jugador a través de los diferentes niveles o etapas de un juego. Es un juego
para un solo jugador, pero puede almacenar información para múltiples jugadores en un
solo dispositivo.
Todos los niveles del juego (aparte de nivel uno) están bloqueadas cuando el partido se
jugó por primera vez.Cada vez que un jugador termina un nivel, ese nivel está
desbloqueado para todos los jugadores en el dispositivo. El LevelTracker estructura
utiliza propiedades y métodos estáticos para no perder de vista que los niveles del juego
han sido desbloqueados. También realiza un seguimiento del nivel actual para un
jugador individual.
• struct LevelTracker {
• static var highestUnlockedLevel = 1
• static func unlockLevel(level: Int) {
• if level > highestUnlockedLevel { highestUnlockedLevel = level }
• }
• static func levelIsUnlocked(level: Int) -> Bool {
• return level <= highestUnlockedLevel
• }
• var currentLevel = 1
• mutating func advanceToLevel(level: Int) -> Bool {
• if LevelTracker.levelIsUnlocked(level) {
• currentLevel = level
• return true
• } else {
• return false
• }
• }
• }
El LevelTracker estructura no pierde de vista el nivel más alto que cualquier
jugador ha desbloqueado. Este valor se almacena en una propiedad estática
llamada highestUnlockedLevel .
LevelTracker también define dos funciones de tipo para trabajar con
el highestUnlockedLevel propiedad. La primera es una función de tipo de

  147  
llamada unlockLevel , que actualiza el valor de highestUnlockedLevel cada
vez que un nuevo nivel está desbloqueado. La segunda es una función de tipo de
conveniencia denominadalevelIsUnlocked , que devuelve verdadero si un
número determinado nivel es ya desbloqueado. (Tenga en cuenta que estos métodos de
tipo pueden acceder al highestUnlockedLevel propiedad estática sin necesidad
de que escribirlo como LevelTracker.highestUnlockedLevel .)
Además de sus métodos de propiedad y de tipo estático, LevelTracker un
seguimiento del progreso de un jugador individual a través del juego. Utiliza una
propiedad de instancia denominada CurrentLevel para seguir el nivel de un jugador
que está jugando.
Para ayudar a administrar el CurrentLevel propiedad, LevelTracker define un
método de instancia denominadoadvanceToLevel . Antes de
actualizar CurrentLevel , este método comprueba si el nuevo nivel solicitado está
ya desbloqueados. El advanceToLevel método devuelve un valor booleano para
indicar si es o no en realidad era capaz de establecer CurrentLevel .
El LevelTracker estructura se utiliza con el jugador de clase, se muestra a
continuación, realizar un seguimiento y actualizar el progreso de un jugador individual:
• class Player {
• var tracker = LevelTracker()
• let playerName: String
• func completedLevel(level: Int) {
• LevelTracker.unlockLevel(level + 1)
• tracker.advanceToLevel(level + 1)
• }
• init(name: String) {
• playerName = name
• }
• }
El player de la clase crea una nueva instancia de LevelTracker para seguir el
progreso de ese jugador.También proporciona un método
llamado completedLevel , que se llama cada vez que un jugador completa un nivel
particular. Este método desbloquea el siguiente nivel para todos los jugadores y
actualiza el progreso del jugador para moverse al siguiente nivel. (El valor de retorno
booleano de advanceToLevel se ignora, ya que el nivel es conocido por haber sido
desbloqueado por la llamada a LevelTracker.unlockLevel en el rubro anterior.)
Puede crear una instancia del player de clase para un nuevo jugador, y ver lo que
sucede cuando el jugador completa el nivel uno:
• var player = Player(name: "Argyrios")
• player.completedLevel(1)
• println("highest unlocked level is now \(LevelTracker.highestUnlockedLevel)")
• // imprime "más alto nivel desbloqueado es ahora 2"  

  148  
Si crea un segundo jugador, quien intenta mover a un nivel que todavía no está
desbloqueado por cualquier jugador en el juego, el intento de establecer el nivel actual
del jugador falla:
• player = Player(name: "Beto")
• if player.tracker.advanceToLevel(6) {
• println("player is now on level 6")
• } else {
• println("level 6 has not yet been unlocked")
• }
• // Impresiones "nivel 6 no ha sido desbloqueado"  
 

Los subíndices
Las clases, estructuras y enumeraciones pueden definir subíndices , que son accesos
directos para acceder a los elementos de miembros de una colección, una lista o
secuencia. Se utiliza subíndices para establecer y recuperar valores de índice sin
necesidad de métodos diferentes para configuración y recuperación. Por ejemplo, puede
acceder a los elementos de una Array instancia como someArray [Index] y
elementos en un Dictionary ejemplo como someDictionary [key] .
Se pueden definir varios subíndices para un solo tipo, y la sobrecarga subíndice
adecuado para su uso se selecciona en función del tipo de valor índice que se pasa al
subíndice. Los subíndices no se limitan a una sola dimensión, y se pueden definir
subíndices con múltiples parámetros de entrada para satisfacer las necesidades de su
tipo de encargo.

Sintaxis Subíndice
Los subíndices le permiten consultar instancias de un tipo escribiendo uno o más
valores entre corchetes después del nombre de la instancia. Su sintaxis es similar a las
sintaxis del método de instancia y sintaxis de la propiedad calculada. Usted escribe
definiciones subíndice con el subíndice de palabras clave, y especificar uno o más
parámetros de entrada y un tipo de retorno, en la misma forma que los métodos de
instancia. A diferencia de los métodos de instancia, los subíndices pueden ser de lectura
y escritura o sólo lectura. Este comportamiento se comunica por un get y set de la
misma manera que para las propiedades calculadas:
• subscript(index: Int) -> Int {
• get {
• // return an appropriate subscript value here
• }
• set(newValue) {
• // perform a suitable setting action here
• }
• }

  149  
El tipo de newValue es el mismo que el valor de retorno de la subíndice. Al igual que
con las propiedades calculadas, usted puede optar por no especificar del
setter (newValue ) parámetro. Un parámetro por defecto llamada newValue se
proporciona a su organismo si no se proporciona una tú mismo.
Al igual que con las propiedades calculada de sólo lectura, se puede eliminar
el get palabra clave para subíndices de sólo lectura:
• subscript(index: Int) -> Int {
• // Devolver un valor apropiado en este subíndice  
• }  
He aquí un ejemplo de una aplicación de sólo lectura subíndice, que define
un TimesTable estructura para representar un n -veces-tabla de enteros:
• struct TimesTable {
• let multiplier: Int
• subscript(index: Int) -> Int {
• return multiplier * index
• }
• }
• let threeTimesTable = TimesTable(multiplier: 3)
• println("six times three is \(threeTimesTable[6])")
• // grabados "seis veces tres es de 18"  
En este ejemplo, una nueva instancia de TimesTable se creó para representar el tres
veces a la mesa. Esto se indica mediante el paso de un valor de 3 a de la
estructura inicializador como el valor a usar para la instancia
de multiplicador de parámetros.
Puede consultar el threeTimesTable instancia llamando su subíndice, como se
muestra en la llamada athreeTimesTable [6] . Esto pide la sexta entrada en el
tres veces a la mesa, que devuelve un valor de 18 , o 3veces 6 .
NOTA
Un n -veces-tabla se basa en una regla matemática fija. No es adecuado
fijar threeTimesTable [someIndex]a un nuevo valor, por lo que el subíndice
de TimesTable se define como una de sólo lectura subíndice.

Uso Subíndice
El significado exacto de "subíndice" depende del contexto en el que se utiliza. Los
subíndices se utilizan típicamente como un acceso directo para acceder a los elementos
de miembro en una colección, una lista o secuencia. Usted es libre de aplicar los
subíndices de la manera más apropiada para su clase o la funcionalidad de la estructura.
Por ejemplo, de Swift Diccionario tipo implementa un subíndice para establecer y
recuperar los valores almacenados en un Diccionario ejemplo. Puede establecer un
valor en un diccionario, proporcionando una clave de tipo de clave del diccionario entre
llaves subíndice, y la asignación de un valor de valor de tipo de diccionario para el
subíndice:

  150  
• var numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
• numberOfLegs["bird"] = 2
El ejemplo anterior define una variable llamada numberOfLegs y lo inicializa con un
diccionario literal que contiene tres pares clave-valor. El tipo de
la numberOfLegs diccionario se infiere que [Cadena: Int] . Después de crear el
diccionario, este ejemplo utiliza la asignación subíndice añadir una cuerda clave
de "pájaro" y unInt valor de 2 al diccionario.
Para obtener más información acerca de Diccionario subíndices, consulte Acceso y
Modificación de un diccionario .

NOTA
El Dictionary tipo de Swift implementa su subscripting clave-valor como un
subíndice que toma y recibe unaopcional tipo. Para los numberOfLegs diccionario de
más arriba, el subíndice de clave y valor toma y devuelve un valor de tipo int? , o "int
opcional". El Diccionario de tipo utiliza un tipo subíndice opcional para modelar el
hecho de que no todas las teclas tendrá un valor, y para dar una forma de eliminar un
valor de una clave mediante la asignación de un nulo valor para esa llave.

Opciones Subíndice
Los subíndices pueden tomar cualquier número de parámetros de entrada, y estos
parámetros de entrada pueden ser de cualquier tipo. Los subíndices también pueden
devolver cualquier tipo. Los subíndices se pueden utilizar parámetros variables y
parámetros variadic, pero no pueden utilizar in-out parámetros o proporcionar valores
de los parámetros por defecto.
Una clase o estructura puede proporcionar tantas implementaciones subíndice ya que
necesita, y el subíndice adecuado para ser utilizado se infiere sobre la base de los tipos
de valor o los valores que se encuentran dentro de las llaves de subíndice en el punto
que se utiliza el subíndice. Esta definición de múltiples subíndices se conoce
como sobrecarga subíndice .
Si bien es más común para un subíndice para tomar un solo parámetro, también puede
definir un subíndice con múltiples parámetros si es apropiado para su tipo. El ejemplo
siguiente define una matriz de estructura, lo que representa una matriz
bidimensional de dobles valores. El Matrix subíndice de estructura toma dos
parámetros enteros:
• struct Matrix {
• let rows: Int, columns: Int
• var grid: [Double]
• init(rows: Int, columns: Int) {
• self.rows = rows
• self.columns = columns
• grid = Array(count: rows * columns, repeatedValue: 0.0)
• }
• func indexIsValidForRow(row: Int, column: Int) -> Bool {

  151  
• return row >= 0 && row < rows && column >= 0 && column < columns
• }
• subscript(row: Int, column: Int) -> Double {
• get {
• assert(indexIsValidForRow(row, column: column), "Index out of range")
• return grid[(row * columns) + column]
• }
• set {
• assert(indexIsValidForRow(row, column: column), "Index out of range")
• grid[(row * columns) + column] = newValue
• }
• }
• }
Matrix proporciona un inicializador que toma dos parámetros
denominados filas y columnas , y crea una matriz que es lo suficientemente grande
para almacenar filas * columnas valores de tipo doble . Cada posición en la
matriz se le da un valor inicial de 0,0 . Para lograr esto, el tamaño de la matriz, y un
valor de la celda inicial de 0.0 , se pasan a un inicializador de matriz que crea e
inicializa una nueva matriz del tamaño correcto. Este inicializador se describe con más
detalle en la creación e inicialización de una matriz .
Usted puede construir una nueva matriz de ejemplo haciendo pasar una fila
adecuada y el recuento de la columna a su inicializador:
• var matrix = Matrix(rows: 2, columns: 2)
El ejemplo anterior crea una nueva matriz de ejemplo con dos filas y dos
columnas. La rejilla de matriz para este Matrix ejemplo es efectivamente una
versión aplanada de la matriz, como se lee desde la parte superior izquierda a la inferior
derecha:

Los valores en la matriz pueden ser establecidas pasando los valores de fila y columna
en el subíndice, separados por una coma:
• matrix[0, 1] = 1.5
• matrix[1, 0] = 3.2

  152  
Estas dos afirmaciones llaman setter del subíndice para establecer un valor de 1,5 en la
posición superior derecha de la matriz (donde fila es 0 y la columna es 1 ),
y 3,2 en la posición inferior izquierda (donde fila es1 y la columna es 0 ):

 
El Matrix get y set de subíndice ambos contienen una afirmación para comprobar que
el subíndice de fila ycolumna valores son válidos. Para ayudar con estas
afirmaciones, Matrix incluye un método de conveniencia
denominada indexIsValidForRow (_: :) columna , que comprueba si el
solicitado fila y columna están dentro de los límites de la matriz:
• func indexIsValidForRow(row: Int, column: Int) -> Bool {
• return row >= 0 && row < rows && column >= 0 && column < columns
• }
Una afirmación se activa si se intenta acceder a un subíndice que se encuentra fuera de
los límites de la matriz:
• let someValue = matrix[2, 2]
• // Esto desencadena una aserción, porque [2, 2] se
encuentra fuera de los límites de la matriz  

Herencia
Una clase puede heredar métodos, propiedades y otras características de otra
clase. Cuando una clase hereda de otra, la clase que hereda se conoce como
una subclase , y la clase que hereda de que se conoce como su superclase . La herencia
es un comportamiento fundamental que diferencia a las clases de otros tipos en Swift.
Clases en Swift pueden llamar y acceso métodos, las propiedades y los subíndices que
pertenecen a su superclase y pueden proporcionar sus propias versiones primordiales de
esos métodos, propiedades y subíndices para refinar o modificar su
comportamiento. Swift ayuda a asegurar las sustituciones son correctos mediante la
comprobación de que la definición de anulación tiene una definición de superclase a
juego.
Las clases también pueden agregar observadores de propiedad de las propiedades
heredadas a fin de ser notificados cuando el valor de una propiedad
cambia. Observadores de propiedad se pueden agregar a cualquier propiedad,
independientemente de si se definió originalmente como una propiedad almacenada o
calculado.

Definición de una base de la Clase


Cualquier clase que no hereda de otra clase se conoce como una clase base .
NOTA
Clases Swift no heredan de una clase base universal. Las clases se definen sin
especificar una superclase automáticamente convertido clases base para que usted pueda
aprovechar.
  153  
El ejemplo siguiente define una clase base llamada Vehículo . Esta clase base define
una propiedad almacenado llamado currentspeed , con un valor por defecto
de 0.0 (inferir un tipo de propiedad de doble ). Elcurrentspeed valor de la
propiedad es utilizada por una de sólo lectura computarizada Cadena propiedad
llamada descripción para crear una descripción del vehículo.
El vehículo de la clase base también define un método llamado makeNoise . Este
método no hace nada para una base de vehículo instancia, pero será personalizado
por subclases de vehículos más adelante:
• class Vehicle {
• var currentSpeed = 0.0
• var description: String {
• return "traveling at \(currentSpeed) miles per hour"
• }
• func makeNoise() {
• // Hacer nada - un vehículo arbitraria no necesariamente
hace un ruido  
• }  
• }  
Se crea una nueva instancia de vehículo con la sintaxis de inicializador , que se
escribe como un TypeNameseguida de paréntesis vacíos:
• let someVehicle = Vehicle()
Después de haber creado un nuevo vehículo instancia, puede acceder a
su descripción inmueble para imprimir una descripción legible de la velocidad
actual del vehículo:
• println("Vehicle: \(someVehicle.description)")
• // Vehículo: viaja a 0.0 kilómetros por hora  
El vehículo clase define las características comunes de un vehículo arbitraria, pero
no sirve de mucho en sí mismo. Para que sea más útil, es necesario refinarlo para
describir tipos más específicos de vehículo.
Subclassing
Subclassing es el acto de fundar una nueva clase en una clase existente. La subclase
hereda las características de la clase existente, que luego se puede refinar. También
puede añadir nuevas características a la subclase.
Para indicar que una subclase tiene una superclase, escribir el nombre de subclase antes
del nombre de superclase, separados por dos puntos:
• class SomeSubclass: SomeSuperclass {
• // Definición subclase va aquí  
• }  
El ejemplo siguiente define una subclase llamada de bicicletas , con una
superclase de vehículo :
• class Bicycle: Vehicle {

  154  
• var hasBasket = false
• }
La nueva bicicleta de clase gana automáticamente todas las características
del vehículo , tales como suscurrentspeed y descripción propiedades y
su makeNoise método.
Además de las características que hereda, la bicicleta clase define una nueva
propiedad almacenada,hasBasket , con un valor predeterminado de false (inferir
un tipo de Bool para la propiedad).
Por defecto, cualquier nueva bicicleta instancia se crea no tendrá una cesta. Puede
configurar el hasBasketpropiedad a true para un
particular, bicicletas instancia después de crear esa instancia:
• let bicycle = Bicycle()
• bicycle.hasBasket = true
También puede modificar el heredado currentspeed propiedad de
una bicicleta de instancia y consultar heredado de la instancia descripción de
propiedad:
• bicycle.currentSpeed = 15.0
• println("Bicycle: \(bicycle.description)")
• // Bicicletas: viaje de 15,0 kilómetros por hora  
Las subclases pueden estar a su vez subclases. El siguiente ejemplo crea una subclase
de bicicletas para una bicicleta de dos asientos conocido como un "tándem":
• class Tandem: Bicycle {
• var currentNumberOfPassengers = 0
• }
Tandem hereda todas las propiedades y métodos de bicicletas , que a su vez
hereda todas las propiedades y métodos de vehículo . El Tandem subclase también
añade una nueva propiedad almacenado llamadocurrentNumberOfPassengers ,
con un valor por defecto de 0 .
Si crea una instancia de Tandem , se puede trabajar con cualquiera de sus propiedades
nuevas y heredadas, y consultar el de sólo lectura Descripción propiedad se hereda
de vehículo :
• let tandem = Tandem()
• tandem.hasBasket = true
• tandem.currentNumberOfPassengers = 2
• tandem.currentSpeed = 22.0
• println("Tandem: \(tandem.description)")
• // Tandem: viaja a 22,0 millas por hora  
•  

  155  
Anulación
Una subclase puede proporcionar su propia implementación personalizada de un método
de instancia, método de clase, propiedad de instancia, propiedad de clase, o subíndice
que de otro modo heredar de una superclase. Esto se conoce como primordial .
Para anular una característica que de otro modo se hereda, escribir antes de la definición
primordial con la override keyword. Si lo hace, aclara que tiene la intención de
proporcionar una anulación y no se ha proporcionado una definición coincidente por
error. Anulación por accidente puede provocar un comportamiento inesperado, y los
reemplazos sin la anulación de palabras clave son diagnosticados como un error
cuando se compila el código.
La anulación de palabras clave también solicita al compilador Swift para comprobar
que la superclase de la clase predominante (o uno de sus padres) tiene una declaración
que coincide con la que nos indicó en el aumento al presupuesto. Esta comprobación
asegura que su definición primordial es correcta.

Acceso a métodos de superclase, propiedades y subíndices


Cuando usted proporciona un método, propiedad o anulación subíndice para una
subclase, a veces es útil usar la aplicación superclase existentes como parte de su
anulación. Por ejemplo, se puede refinar el comportamiento de que la aplicación
existente o almacenar un valor modificado en una variable heredada existente.
Cuando resulte oportuno, se accede a la versión de la superclase de un método, una
propiedad o subíndice utilizando el súper prefijo:
• Un método reemplazado llamado algunMetodo puede llamar a la versión de la
superclase de algunMetodollamando super.someMethod () dentro de la
implementación del método de primer orden.
• Una propiedad anulado llamado UnaPropiedad puede acceder a la versión de la
superclase deUnaPropiedad como super.someProperty dentro del
captador primordial o aplicación setter.
• Un subíndice reemplazado por someIndex puede acceder a la versión de la
superclase del mismo subíndice como súper [someIndex] desde dentro de la
aplicación subíndice primordial.

Sustitución de métodos
Puede anular un método de instancia o clase heredada para proporcionar una aplicación
a medida o alternativa del procedimiento dentro de la subclase.
El ejemplo siguiente define una nueva subclase de vehículo llamado tren , lo que
anula el makeNoise método que Train hereda de vehículo :
• class Train: Vehicle {
• override func makeNoise() {
• println("Choo Choo")
• }
• }
Si crea una nueva instancia de tren y llamar su makeNoise método, se puede ver
que el tren versión subclase del método se llama:

  156  
• let train = Train()
• train.makeNoise()
• // Impresiones "Choo Choo"  
•  
Propiedades Anulación
Puede reemplazar una instancia o una clase de bienes heredados para proporcionar su
propio getter y setter personalizado para esa propiedad, o para añadir observadores de
propiedad para permitir la propiedad primordial observar cuando los cambios
subyacentes valor de la propiedad.

Anulación de la propiedad get y set


Puede proporcionar un captador de encargo (y setter, en su caso) para
anular cualquier propiedad heredada, sin importar si la propiedad heredada se
implementa como una propiedad almacenada o calculado en la fuente. La naturaleza
almacenado o calculado de una propiedad heredada no es conocido por una subclase-
sólo sabe que la propiedad heredada tiene un cierto nombre y tipo. Siempre se debe
indicar el nombre y el tipo de la propiedad está sustituyendo, para permitir que el
compilador para comprobar que su anulación coincide con una propiedad superclase
con el mismo nombre y tipo.
Usted puede presentar una propiedad de sólo lectura hereda como una propiedad de
lectura-escritura, proporcionando tanto un getter y un setter en su propiedad subclase de
anulación. No puede, sin embargo, presentar una propiedad de lectura y escritura
heredado como una propiedad de sólo lectura.

NOTA
Si usted proporciona un setter como parte de una anulación de la propiedad, también
debe proporcionar un captador para que override. Si no desea modificar el valor de la
propiedad heredada dentro del captador primordial, sólo tiene que pasar por el valor
heredado devolviendo super.someProperty del captador,
dondeUnaPropiedad es el nombre de la propiedad que está sustituyendo.
El ejemplo siguiente define una nueva clase llamada de coches , que es una subclase
de vehículo . El cocheclase introduce una nueva propiedad almacenado
llamado artes , con un valor entero por defecto de 1 . Elcoche clase también anula
la descripción de propiedad que hereda de vehículo , para proporcionar una
descripción personalizada que incluye la marcha actual:
• class Car: Vehicle {
• var gear = 1
• override var description: String {
• return super.description + " in gear \(gear)"
• }
• }

  157  
La anulación de la descripción de propiedad comienza
llamando super.description , que devuelve el vehículode
clase Descripción propiedad. El coche la versión de la clase de descripción a
continuación, añade un poco de texto adicional al final de esta descripción para
proporcionar información sobre la marcha actual.
Si crea una instancia de la Car clase y configura
su engranaje y currentspeed propiedades, se puede ver que
su descripción propiedad devuelve la descripción adaptada definida dentro
del coche de clase:
• let car = Car()
• car.currentSpeed = 25.0
• car.gear = 3
• println("Car: \(car.description)")
• // Coche: viajando a 25,0 millas por hora en la marcha 3  
•  
Los observadores de Propiedad Anulación
Puede utilizar la propiedad primordial para agregar observadores de propiedad a una
propiedad heredada.Esto permite que se le notifique cuando el valor de un cambio de
propiedad heredadas, independientemente de cómo se implementó originalmente esa
propiedad. Para obtener más información sobre los observadores de propiedades,
consulte Observadores de propiedad .
NOTA
No se puede agregar observadores de propiedad de propiedades constantes almacenado
heredadas o propiedades de sólo lectura computados heredados. El valor de estas
propiedades no se puede ajustar, por lo que no es apropiada para proporcionar
una willSet o didSet aplicación como parte de una anulación.
Tenga en cuenta también que no se puede proporcionar tanto un pionero de primer
orden y un observador propiedad primordial de la misma propiedad. Si desea observar
los cambios en el valor de una propiedad, y que ya está proporcionando un setter
personalizado para esa propiedad, sólo tiene que observar los cambios de valor del
interior del setter personalizado.
El ejemplo siguiente define una nueva clase llamada AutomaticCar , que es una
subclase de coches . ElAutomaticCar clase representa un coche con cambio
automático, que selecciona automáticamente una velocidad adecuada a utilizar en
función de la velocidad actual:
• class AutomaticCar: Car {
• override var currentSpeed: Double {
• didSet {
• gear = Int(currentSpeed / 10.0) + 1
• }
• }
• }

  158  
Siempre que sitúe el currentspeed propiedad de un AutomaticCar ejemplo, el
alojamiento didSet observador fija de la instancia de engranajes propiedad a
una elección apropiada de engranaje para la nueva velocidad. En concreto, el
observador propiedad elige un engranaje que es el nuevo currentspeed valor
dividido por 10 , redondea hacia abajo al entero más cercano, más 1 . Una velocidad
de 10,0 produce un engranaje de 1 , y una velocidad de 35,0 produce un engranaje
de 4 :
• let automatic = AutomaticCar()
• automatic.currentSpeed = 35.0
• println("AutomaticCar: \(automatic.description)")
• // AutomaticCar: viaja a 35,0 millas por hora en la marcha
4  
 
Prevención Anulaciones
Usted puede evitar que un método, una propiedad o subíndice se cambie marcándolo
como definitiva . Para ello, escribir el último modificador antes de la palabra clave
introductor del método, la propiedad o de subíndice (como final var,final func, final
class func, and final subscript).
Cualquier intento de anular una final método, propiedad o subíndice en una subclase se
reporta como un error en tiempo de compilación. Métodos, propiedades o subíndices
que agregue a una clase en una extensión también se pueden marcar como final dentro
de la definición de la extensión.
Puede marcar toda una clase como final por escribir el final modificador antes de
la class de palabras clave en su definición de clase ( final class). Cualquier intento de
crear una subclase de una clase final se reporta como un error en tiempo de
compilación.
 

Inicialización
Inicialización es el proceso de preparación de una instancia de una clase, estructura o
enumeración para su uso. Este proceso consiste en fijar un valor inicial para cada
propiedad almacenada en esa instancia y realizar cualquier otra configuración o
inicialización que se requiere antes de la nueva instancia está listo para su uso.
Implemente este proceso de inicialización definiendo inicializadores , que son como los
métodos especiales que pueden ser llamados para crear una nueva instancia de un tipo
particular. A diferencia de los inicializadores de Objective-C, inicializadores Swift no
devuelven un valor. Su función principal es asegurar que las nuevas instancias de un
tipo se inicializan correctamente antes de que se utilizan por primera vez.
Las instancias de tipos de clase también pueden implementar una deinitializer , que
realiza cualquier limpieza a medida solo antes de que se cancela la asignación de una
instancia de esa clase. Para obtener más información acerca de deinitializers,
ver deinicialización .

  159  
Establecimiento de valores iniciales para las propiedades almacenados
Clases y estructuras deben establecer todas sus propiedades almacenadas en un valor
inicial adecuado para el momento en que se crea una instancia de esa clase o
estructura. Propiedades almacenados no se pueden dejar en un estado indeterminado.
Puede establecer un valor inicial para una propiedad almacenada dentro de un
inicializador, o mediante la asignación de un valor de propiedad predeterminado como
parte de la definición de la propiedad. Estas acciones se describen en las siguientes
secciones.
NOTA
Al asignar un valor predeterminado a una propiedad almacenada, o establecer su valor
inicial dentro de un inicializador, el valor de esa propiedad se establece directamente,
sin tener que llamar todos los observadores de propiedad.
Inicializadores
Inicializadores están llamados a crear una nueva instancia de un tipo particular. En su
forma más simple, un inicializador es como un método de instancia sin parámetros,
escrito usando el init palabra clave:
• init() {
• // perform some initialization here
• }
El ejemplo siguiente define una nueva estructura llamada Fahrenheit para
almacenar las temperaturas expresadas en la escala
Fahrenheit. El Fahrenheit estructura tiene una propiedad almacenada, la
temperatura , que es de tipo doble :
• struct Fahrenheit {
• var temperature: Double
• init() {
• temperature = 32.0
• }
• }
• var f = Fahrenheit()
• println("The default temperature is \(f.temperature)° Fahrenheit")
• // imprime "La temperatura predeterminada es 32,0 °
Fahrenheit"  
La estructura define un único inicializador, init , sin parámetros, que inicializa la
temperatura almacenado con un valor de 32,0 (el punto de congelación del agua
cuando se expresa en la escala Fahrenheit).
Defecto Valores de la propiedad
Puede establecer el valor inicial de una propiedad almacenado desde dentro un
inicializador, como se muestra arriba. Como alternativa, especifique un valor de la
propiedad por defecto como parte de la declaración de la propiedad. Se especifica un
valor de propiedad predeterminado mediante la asignación de un valor inicial de la
propiedad cuando se define.

  160  
NOTA
Si una propiedad tiene siempre el mismo valor inicial, proporcionar un valor por defecto
en lugar de establecer un valor dentro de un inicializador. El resultado final es el mismo,
pero el valor predeterminado ata inicialización de la propiedad más de cerca a su
declaración. Se convierte en más cortos, inicializadores más claras y le permite inferir el
tipo de la propiedad de su valor original. El valor por defecto también hace que sea más
fácil para que usted tome ventaja de inicializadores por defecto y la herencia de
inicialización, como se describe más adelante en este capítulo.
Usted puede escribir la Fahrenheit estructura desde arriba en una forma más simple,
proporcionando un valor predeterminado para su temperatura de propiedad en el
punto de que la propiedad se declara:
• struct Fahrenheit {
• var temperature = 32.0
• }

Personalización de inicialización
Usted puede personalizar el proceso de inicialización de parámetros de entrada y tipos
de propiedad opcionales, o mediante la modificación de las propiedades constantes
durante la inicialización, como se describe en las siguientes secciones.
Parámetros de inicialización
Usted puede proporcionar los parámetros de inicialización , como parte de la definición
de un inicializador, para definir los tipos y los nombres de los valores que personalizan
el proceso de inicialización. Parámetros de inicialización tienen las mismas capacidades
y la sintaxis como parámetros de funciones y métodos.
El ejemplo siguiente define una estructura llamada Celsius , que almacena las
temperaturas expresadas en la escala Celsius. El Celsius estructura implementa dos
inicializadores personalizados denominados init (fromFahrenheit :) y init
(fromKelvin :) , que inicializar una nueva instancia de la estructura con un valor
de una escala de temperatura diferente:
• struct Celsius {
• var temperatureInCelsius: Double
• init(fromFahrenheit fahrenheit: Double) {
• temperatureInCelsius = (fahrenheit - 32.0) / 1.8
• }
• init(fromKelvin kelvin: Double) {
• temperatureInCelsius = kelvin - 273.15
• }
• }
• let boilingPointOfWater = Celsius(fromFahrenheit: 212.0)
• // boilingPointOfWater.temperatureInCelsius is 100.0
• let freezingPointOfWater = Celsius(fromKelvin: 273.15)
• // freezingPointOfWater.temperatureInCelsius is 0.0
  161  
La primera inicializador tiene un solo parámetro de inicialización con un nombre
externo de fromFahrenheit y un nombre local de fahrenheit . El segundo
inicializador tiene un solo parámetro de inicialización con un nombre externo
de fromKelvin y un nombre local de kelvin . Ambos inicializadores convertir su
único argumento en un valor en la escala Celsius y almacenar este valor en una
propiedad llamadatemperatureInCelsius .

Los nombres de parámetros locales y externos


Al igual que con los parámetros de las funciones y métodos, parámetros de
inicialización pueden tener tanto un nombre local para el uso dentro del cuerpo del
inicializador y un nombre externo para su uso cuando se llama al inicializador.
Sin embargo, los inicializadores no tienen un nombre de la función de identificación
antes de que sus paréntesis en la forma en que las funciones y los métodos de hacer. Por
lo tanto, los nombres y tipos de parámetros de un inicializador desempeñan un papel
particularmente importante en la identificación que inicializador debe ser
llamado. Debido a esto, Swift proporciona un nombre externo automático
para cadaparámetro en un inicializador si no se proporciona un nombre externo a ti
mismo. Este nombre externo automático es el mismo que el nombre local, como si
hubiera escrito un símbolo de hash antes de cada parámetro de inicialización.
El ejemplo siguiente define una estructura llamada en color , con tres propiedades
constantes llamados rojo ,verde , y azul . Estas propiedades almacenan un valor
entre 0.0 y 1.0 para indicar la cantidad de rojo, verde y azul en el color.
Color proporciona un inicializador con tres parámetros con nombres correspondientes
de tipo doble para sus componentes rojo, verde y azul. color también proporciona
un segundo inicializador con un único blancoparámetro, que se utiliza para
proporcionar el mismo valor para todos los tres componentes de color.
• struct Color {
• let red, green, blue: Double
• init(red: Double, green: Double, blue: Double) {
• self.red = red
• self.green = green
• self.blue = blue
• }
• init(white: Double) {
• red = white
• green = white
• blue = white
• }
• }
Ambos inicializadores se pueden utilizar para crear un nuevo color de ejemplo,
proporcionando valores con nombre para cada parámetro de inicialización:
• let magenta = Color(red: 1.0, green: 0.0, blue: 1.0)

  162  
• let halfGray = Color(white: 0.5)
Tenga en cuenta que no es posible llamar a estos inicializadores sin usar nombres de los
parámetros externos. Nombres externos siempre se deben utilizar en un inicializador si
están definidos, y la omisión de ellos es un error en tiempo de compilación:
• let veryGreen = Color(0.0, 1.0, 0.0)
• // Esta informa de un error de tiempo de compilación - Se
requieren nombres externos  
Parámetros inicializador sin nombres externos
Si no desea utilizar un nombre externo para un parámetro de inicialización, escribir un
guión bajo ( _ ) en lugar de un nombre externo explícito para ese parámetro para alterar
temporalmente el comportamiento por defecto.
He aquí una versión ampliada de la Celsius ejemplo de antes, con un inicializador
adicional para crear una nueva Celsius ejemplo de un doble valor que ya está en la
escala Celsius:
• struct Celsius {
• var temperatureInCelsius: Double
• init(fromFahrenheit fahrenheit: Double) {
• temperatureInCelsius = (fahrenheit - 32.0) / 1.8
• }
• init(fromKelvin kelvin: Double) {
• temperatureInCelsius = kelvin - 273.15
• }
• init(_ celsius: Double) {
• temperatureInCelsius = celsius
• }
• }
• let bodyTemperature = Celsius(37.0)
• // BodyTemperature.temperatureInCelsius es 37.0  
La llamada inicializador Celsius (37.0) es clara en su intención, sin la necesidad
de un nombre de parámetro externo. Por tanto, es conveniente escribir este inicializador
como init (_ celsius: Doble) por lo que se puede llamar al proporcionar un
anónimo doble valor.
Tipos de Propiedad opcionales
Si su tipo personalizado tiene una propiedad almacenado que se permite lógicamente
tener "ningún valor" -quizás porque su valor no se puede ajustar durante la
inicialización, o porque se le permite tener "ningún valor" en algún punto más adelante-
declarar la propiedad con un opcional tipo. Inmuebles del tipo opcional se inicializan
automáticamente con un valor de cero , lo que indica que la propiedad está destinado
deliberadamente a tener "ningún valor todavía" durante la inicialización.
El ejemplo siguiente define una clase denominada SurveyQuestion , con un
opcional de cuerda llamada propiedad respuesta :

  163  
• class SurveyQuestion {
• var text: String
• var response: String?
• init(text: String) {
• self.text = text
• }
• func ask() {
• println(text)
• }
• }
• let cheeseQuestion = SurveyQuestion(text: "Do you like cheese?")
• cheeseQuestion.ask()
• // prints "Do you like cheese?"
• cheeseQuestion.response = "Yes, I do like cheese."
La respuesta a una pregunta de la encuesta no se puede saber hasta que se le pide, por lo
que la respuesta de la propiedad se declara con un tipo de cuerda? , o
"opcional Cadena ". Se asigna automáticamente un valor por defecto de cero , que
significa "ninguna cadena todavía", cuando una nueva instancia
de SurveyQuestionse inicializa.
Modificación de las propiedades constantes durante la inicialización
Puede modificar el valor de una propiedad constante en cualquier punto durante la
inicialización, siempre y cuando se establece en un valor definido por los acabados de
inicialización de tiempo.
NOTA
Para las instancias de clase, una propiedad constante sólo puede ser modificado durante
la inicialización de la clase que lo introduce. No puede ser modificado por una subclase.
Usted puede revisar el SurveyQuestion ejemplo desde arriba para utilizar una
propiedad constante en lugar de una propiedad de variable para el texto propiedad de
la cuestión, para indicar que la cuestión no cambia una vez que una instancia
de SurveyQuestion se crea. A pesar de que el texto de la propiedad es ahora
una constante, todavía puede ajustarse dentro de inicializador de la clase:
• class SurveyQuestion {
• let text: String
• var response: String?
• init(text: String) {
• self.text = text
• }
• func ask() {
• println(text)
• }

  164  
• }
• let beetsQuestion = SurveyQuestion(text: "How about beets?")
• beetsQuestion.ask()
• // prints "How about beets?"
• beetsQuestion.response = "I also like beets. (But not with cheese.)"

Inicializadores defecto
Swift proporciona un inicializador por defecto para cualquier estructura o base clase
que proporciona valores predeterminados para todas sus propiedades y no proporciona
al menos un inicializador de sí mismo. El inicializador por defecto simplemente crea
una nueva instancia con todos sus propiedades configuradas con los valores
predeterminados.
En este ejemplo se define una clase llamada ShoppingListItem , que encapsula el
nombre, cantidad y estado de compra de un artículo en una lista de la compra:
• class ShoppingListItem {
• var name: String?
• var quantity = 1
• var purchased = false
• }
• var item = ShoppingListItem()
Debido a que todas las propiedades de la ShoppingListItem clase tienen valores
por defecto, y porque es una clase base sin superclase, ShoppingListItem gana
automáticamente una aplicación inicializador por defecto que crea una nueva instancia
con todos sus propiedades configuradas con los valores predeterminados. (Elnombre
de la propiedad es una opción de cadena de propiedad, y por lo que recibe
automáticamente un valor por defecto de cero , a pesar de que este valor no está
escrito en el código.) El ejemplo anterior utiliza el inicializador por defecto para
el ShoppingListItem clase para crear una nueva instancia de la clase con la
sintaxis de inicializador, escrito como ShoppingListItem () , y asigna esta nueva
instancia a una variable llamada elemento .

Miembro por miembro Inicializadores de Estructura Tipos


Tipos de estructura reciben automáticamente un inicializador de miembro por
miembro , si no definen ninguna de sus propias inicializadores personalizados. Esto es
cierto incluso si las propiedades almacenados de la estructura no tienen valores por
defecto.
El inicializador de miembro por miembro es una forma abreviada para inicializar las
propiedades de los miembros de las nuevas instancias de estructura. Los valores
iniciales de las propiedades de la nueva instancia se pueden pasar a la inicializador
miembro por miembro por su nombre.

  165  
El ejemplo siguiente define una estructura llamada Tamaño con dos propiedades
denominadas anchura y altura. Ambas propiedades se infieren a ser de
tipo doble mediante la asignación de un valor por defecto de 0.0 .
El Tamaño estructura recibe automáticamente una init (ancho: alto
:) inicializador miembro por miembro, que se puede utilizar para inicializar un
nuevo Tamaño ejemplo:
• struct Size {
• var width = 0.0, height = 0.0
• }
• let twoByTwo = Size(width: 2.0, height: 2.0)

Delegación inicializador para tipos de valor


Inicializadores pueden llamar a otros inicializadores para realizar parte de la
inicialización de una instancia.Este proceso, conocido como delegación inicializador ,
evita duplicación de código en varios inicializadores.
Las reglas de cómo funciona la delegación inicializador, y para qué formas de
delegación se permiten, son diferentes para los tipos de valor y tipos de clase. Valor
tipos (estructuras y enumeraciones) no admiten la herencia, por lo que su proceso de
delegación inicializador es relativamente simple, ya que sólo pueden delegar en otro
inicializador que proporcionan a sí mismos. Las clases, sin embargo, se pueden heredar
de otras clases, como se describe en la herencia . Esto significa que las clases tienen
responsabilidades adicionales para asegurar que todas las propiedades almacenadas que
heredan se les asigna un valor adecuado durante la inicialización. Estas
responsabilidades se describen en la clase de herencia e inicialización de abajo.
Para los tipos de valor, se utiliza self.init para referirse a otros inicializadores del
mismo tipo de valor al escribir sus propios inicializadores personalizados. Sólo puede
llamar self.init desde un inicializador.
Tenga en cuenta que si se define un inicializador personalizado para un tipo de valor, ya
no tendrá acceso a la inicializador por defecto (o el inicializador de miembro por
miembro, si se trata de una estructura) para ese tipo. Esta limitación impide una
situación en la que la configuración esencial adicional proporcionada en un inicializador
más compleja se elude por alguien usando accidentalmente uno de los inicializadores
automáticos lugar.
NOTA
Si usted quiere que su tipo de valor a medida que sea initializable con el inicializador
por defecto y inicializador miembro por miembro, y también con sus propias
inicializadores personalizados, escriba sus inicializadores personalizados en una
extensión más que como parte de la implementación original del tipo de valor. Para
obtener más información, vea Extensiones .
El ejemplo siguiente define una costumbre Rect estructura para representar un
rectángulo geométrico. El ejemplo requiere dos estructuras de apoyo
llamada Tamaño y Point , los cuales proporcionan valores por defecto de 0,0 para
todas sus propiedades:
• struct Size {

  166  
• var width = 0.0, height = 0.0
• }
• struct Point {
• var x = 0.0, y = 0.0
• }
Puede inicializar el Rect estructura por debajo de una de tres maneras: mediante el uso
de sus defecto cero inicializado- origen y tamaño valores de la propiedad,
proporcionando un punto y el tamaño de origen específico, o proporcionando un punto
central específico y tamaño. Estas opciones de inicialización están representados por
tres inicializadores personalizadas que forman parte de la Rect definición de la
estructura:
• struct Rect {
• var origin = Point()
• var size = Size()
• init() {}
• init(origin: Point, size: Size) {
• self.origin = origin
• self.size = size
• }
• 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)
• }
• }
La primera Rect inicializador, init () , es funcionalmente lo mismo que el
inicializador por defecto que la estructura habría recibido si no tuviese una fisonomía
propia inicializadores personalizados. Este inicializador tiene un cuerpo vacío,
representado por un par vacío de llaves {} , y no perfom cualquier inicialización. Al
llamar a este inicializador devuelve un Rect instancia cuyo origen y tamaño
de las propiedades se inicializan con los valores por defecto de punto (x: 0.0,
y: 0.0) y Tamaño (anchura: 0.0, Altura: 0.0) de sus definiciones de
propiedad:
• let basicRect = Rect()
• // Origen de basicRect es (0.0, 0.0) y su tamaño es (0.0,
0.0)  
El segundo Rect inicializador, init (origen: tamaño :) , es funcionalmente
lo mismo que el inicializador de miembro por miembro que la estructura habría recibido
si no tuviese una fisonomía propia inicializadores personalizados. Este inicializador

  167  
simplemente asigna los de origen y tamaño valores de los argumentos de las
propiedades adecuadas almacenado:
• let originRect = Rect(origin: Point(x: 2.0, y: 2.0),
• size: Size(width: 5.0, height: 5.0))
• // Origen de originRect es (2.0, 2.0) y su tamaño es (5.0,
5.0)  
La tercera Rect inicializador, init (centro: tamaño :) , es un poco más
compleja. Se inicia mediante el cálculo de un punto de origen apropiado basado en
un centro de punto y un tamaño valor. A continuación, llama (odelegados )
al init (origen: tamaño :) inicializador, que almacena los nuevos valores de
origen y tamaño en las propiedades adecuadas:
• let centerRect = Rect(center: Point(x: 4.0, y: 4.0),
• size: Size(width: 3.0, height: 3.0))
• // Origen de centerRect es (2.5, 2.5) y su tamaño es (3.0,
3.0)  
El init (centro: tamaño :) inicializador podría haber asignado los nuevos
valores de origen y el tamaño de las propias propiedades adecuadas. Sin embargo,
es más conveniente (y más claro en la intención) para elinit (centro: tamaño
:) inicializador para tomar ventaja de un inicializador existente que ya proporciona
exactamente esa funcionalidad.
NOTA
Para una forma alternativa de escribir este ejemplo sin definir el init () y init
(origen: tamaño :)inicializadores ti mismo, ver las extensiones .
Clase herencia e inicialización
Todas las propiedades-incluyendo almacenados de una clase propiedades de la clase
hereda de su superclass- debe ser asignado un valor inicial durante la inicialización.
Swift define dos tipos de inicializadores para tipos de clase para ayudar a asegurar todas
las propiedades almacenadas reciben un valor inicial. Estos son conocidos como
inicializadores designados y los inicializadores de conveniencia.
Inicializadores Designados y Conveniencia Inicializadores
Inicializadores designados son los inicializadores primarios para una clase. Un
inicializador designado inicializa totalmente todas las propiedades introducidas por esa
clase y llama a un inicializador superclase apropiado continuar el proceso de
inicialización en la cadena de superclase.
Las clases suelen tener muy pocos inicializadores designadas, y es muy común que una
clase tenga sólo uno. Inicializadores mencionadas son puntos "embudo" a través del
cual tiene lugar la inicialización, ya través del cual el proceso de inicialización continúa
en la cadena de superclase.
Cada clase debe tener al menos un inicializador designado. En algunos casos, este
requisito se satisface con la herencia de uno o varios designado inicializadores de una
superclase, como se describe en automático Inicializador Herencia continuación.
Inicializadores de conveniencia son, inicializadores de apoyo secundarias para una
clase. Puede definir un inicializador conveniencia de llamar a un inicializador designado

  168  
de la misma clase que el inicializador de conveniencia con algunos de los parámetros
del inicializador designado establecidos a sus valores predeterminados. También puede
definir un inicializador conveniencia de crear una instancia de esa clase para un caso de
uso o valor de entrada tipo específico.
Usted no tiene que proporcionar inicializadores de conveniencia si su clase no los
requiere. Crear inicializadores de conveniencia cada vez que un acceso directo a un
patrón de iniciación común ahorrará tiempo o hacer que la inicialización de la clase más
clara en su intención.
Sintaxis para Designados y Inicializadores de Conveniencia
Inicializadores designados para las clases se escriben de la misma manera como
inicializadores simples para los tipos de valor:
• init( parameters ) {
• statements

• }
Inicializadores de Conveniencia están escritos en el mismo estilo, pero con
la comodidad modificador colocado antes del inicio de palabras clave, separadas
por un espacio:
• convenience init( parameters ) {
• statements

• }
Inicializador encadenamiento
Para simplificar las relaciones entre los inicializadores designados y de conveniencia,
Swift se aplica las siguientes tres reglas para la delegación de llamadas entre
inicializadores:
Regla  1  

Un inicializador designado debe llamar a un inicializador designado de su


superclase inmediata.
Regla  2  

Un inicializador de conveniencia debe llamar a otro inicializador de


la misma clase.
Regla  3  

Un inicializador de conveniencia debe en última instancia, llamar a un


inicializador designado.
Una forma sencilla de recordar esto es:
• Inicializadores designados siempre deben delegar para arriba .
• Inicializadores de Conveniencia siempre deben delegar en todo .
Estas reglas se ilustran en la siguiente figura:

  169  
 

Aquí, la superclase tiene un único inicializador designado y dos inicializadores de


conveniencia. Un inicializador conveniencia llama a otro inicializador conveniencia,
que a su vez llama a la única inicializador designado. Esto satisface las reglas 2 y 3 de
arriba. La superclase no en sí tiene otros superclase, y lo que la regla 1 no se aplica.
La subclase de esta figura tiene dos inicializadores designados y un inicializador
conveniencia. El inicializador de conveniencia debe llamar a uno de los dos
inicializadores designados, ya que sólo puede llamar a otro inicializador de la misma
clase. Esto satisface las reglas 2 y 3 de arriba. Ambos inicializadores designados deben
llamar a la única inicializador designado de la superclase, para satisfacer a la regla 1
desde arriba.
NOTA
Estas normas no afectan a cómo los usuarios de sus clases crean instancias de cada
clase. Cualquier inicializador en el diagrama anterior se puede utilizar para crear una
instancia de inicializado completamente de la clase al que pertenecen. Las reglas sólo
afectan a la forma de escribir la implementación de la clase.
La siguiente figura muestra una jerarquía de clases más complejo para cuatro
clases. Ilustra cómo los inicializadores designados en este acto jerarquía como puntos de
"embudo" para la inicialización de clase, lo que simplifica las relaciones entre las clases
de la cadena:

  170  
 

Two-Phase inicialización
Clase de inicialización en Swift es un proceso de dos fases. En la primera fase, cada
propiedad almacenado se le asigna un valor inicial de la clase que lo introdujo. Una vez
que el estado inicial de cada propiedad almacenado ha sido determinada, la segunda fase
comienza, y cada clase se le da la oportunidad de personalizar sus propiedades
almacenadas más antes de considerar la nueva instancia de lista para su uso.
El uso de un proceso de inicialización de dos fases hace segura la inicialización,
mientras que todavía da flexibilidad completa a cada clase en una jerarquía de
clases. Inicialización de dos fases impide valores de la propiedad de ser visitada antes
de que se inicializan, y evita los valores de propiedad de ser ajustado a un valor
diferente por otro inicializador inesperadamente.
NOTA
Proceso de inicialización de dos fases de Swift es similar a la inicialización en
Objective-C. La principal diferencia es que en la fase 1, Objective-C asigna cero o nulos
valores (como 0 o nulo ) a cada propiedad.Flujo de inicialización de Swift es más
flexible ya que permite establecer los valores iniciales de encargo, y puede hacer frente
a tipos a los que 0 o nulo no es un valor predeterminado válido.
Compilador de Swift realiza cuatro controles de seguridad útiles para asegurarse de que
la inicialización de dos fases se completa sin errores:
Comprobación  de  seguridad  1  

Un inicializador designado debe asegurar que todas las propiedades introducidas


por su clase se inicializan antes de que los delegados hasta un inicializador
superclase.
  171  
Como se mencionó anteriormente, la memoria de un objeto sólo se considera
inicializado completamente una vez que se conoce el estado inicial de todas sus
propiedades almacenados. Para que esta regla para estar satisfechos, un inicializador
designado debe asegurarse de que todas sus propiedades se inicializan antes de que las
manos fuera de la cadena.
Comprobación  de  seguridad  2  

Un inicializador designado debe delegar a un inicializador superclase antes de


asignar un valor a una propiedad heredada. Si no es así, el nuevo valor de los
cesionarios de inicializador designado será sobrescrita por la superclase como
parte de su propia inicialización.
Comprobación  de  seguridad  3  

Un inicializador de conveniencia debe delegar en otro inicializador antes de


asignar un valor a cualquierpropiedad (incluidas las propiedades definidas por la
misma clase). Si no es así, el nuevo valor de los cesionarios de inicializador de
conveniencia será sobrescrita por inicializador designado de su propia clase.
Comprobación  de  seguridad  4  

Un inicializador no puede llamar a cualquier método de instancia, leer los


valores de las propiedades de la instancia, o se refieren a uno mismo como un
valor de hasta una vez finalizada la primera fase de inicialización.
La instancia de la clase no es totalmente válida hasta que termine la primera
fase. Propiedades sólo se puede acceder, y métodos sólo pueden ser convocadas, una
vez conocida la instancia de clase sea válido al final de la primera fase.
Así es como la inicialización de dos fases se desarrolla, en base a los cuatro controles de
seguridad por encima de:
Fase 1
• Un inicializador designado o conveniencia se llama en una clase.
• Memoria de una nueva instancia de esa clase se asigna. La memoria aún no se
inicializa.
• Un inicializador designado para esa clase confirma que todas las propiedades
almacenadas introducidas por esa clase tienen un valor. La memoria de estas
propiedades almacenadas ahora inicializa.
• Los inicializadores manos designadas fuera a un inicializador superclase para
realizar la misma tarea por sus propias propiedades almacenadas.
• Esto continúa en la cadena de herencia de clases hasta que se alcance la parte
superior de la cadena.
• Una vez que se alcanza la cima de la cadena, y la clase final de la cadena se ha
asegurado de que todas sus propiedades almacenadas tienen un valor, la memoria de
la instancia se considera que está totalmente inicializado, y la fase 1 se ha
completado.
Fase 2
• Trabajando hacia abajo desde la parte superior de la cadena, cada inicializador
designado de la cadena tiene la opción de personalizar la instancia
más. Inicializadores ahora son capaces de acceder a uno mismo y puede modificar
sus propiedades, llamar a sus métodos de instancia, y así sucesivamente.
  172  
• Por último, cualquier inicializadores de conveniencia de la cadena tienen la opción
de personalizar el ejemplo y trabajar con uno mismo .
Así es como se ve la fase 1 para una llamada de inicialización para una subclase y
superclase hipotética:

En este ejemplo, la inicialización comienza con una llamada a un inicializador de


conveniencia en la subclase.Este inicializador conveniencia aún no puede modificar las
propiedades. Delegados a través a un inicializador designado de la misma clase.
El inicializador designado se asegura de que todas las propiedades de la subclase tienen
un valor, según comprobación de seguridad 1. A continuación, llama un inicializador
designado en su superclase para continuar con la inicialización de la cadena.
Inicializador designado de la superclase se asegura de que todas las propiedades de la
superclase tiene un valor. No hay más superclases para inicializar, y así no se necesita
una mayor delegación.
Tan pronto como todas las propiedades de la superclase tienen un valor inicial, su
memoria se considera totalmente inicializado, y la Fase 1 se ha completado.
Así es como la fase 2 se ve por la misma llamada de inicialización:

Inicializador designado de la superclase tiene ahora la oportunidad de personalizar la


instancia más (aunque no tiene por qué).
Una vez inicializador designado de la superclase se terminó, inicializador designado de
la subclase puede realizar una personalización adicional (aunque, de nuevo, que no tiene
por qué).

  173  
Por último, una vez finalizado inicializador designado de la subclase, el inicializador de
conveniencia que originalmente fue llamado puede realizar una personalización
adicional.
Inicializador Sucesiones y Anulación
A diferencia de las subclases en Objective-C, subclases Swift no heredan sus
inicializadores superclase de forma predeterminada. El enfoque de Swift evita una
situación en la que un inicializador simple a partir de una superclase es heredado por
una subclase más especializada y se utiliza para crear una nueva instancia de la subclase
que no está inicializado completamente o correctamente.
NOTA
Inicializadores superclase se heredan en ciertas circunstancias, pero sólo cuando sea
seguro y apropiado para ello. Para obtener más información, consulte automática
Inicializador Herencia continuación.
Si quieres una subclase personalizada de presentar uno o más de los mismos
inicializadores como su superclase, puede proporcionar una implementación
personalizada de los inicializadores dentro de la subclase.
Cuando se escribe un inicializador subclase que coincide con una
superclase designado inicializador, usted está proporcionando efectivamente un
aumento al presupuesto de ese inicializador designado. Por lo tanto, debe escribir
la anulación modificador antes de la definición de inicialización de la subclase. Esto
es cierto incluso si está sustituyendo un inicializador por defecto proporcionado de
forma automática, como se describe en Inicializadores predeterminados .
Al igual que con una propiedad, método o subíndice anulado, la presencia de
la anulación modificador solicita Swift para comprobar que la superclase tiene un
inicializador de juego designado para ser anulado, y valida que se han especificado los
parámetros para su inicializador primordial como es debido.
NOTA
Siempre escribe la anulación modificador cuando anulando una superclase
designado inicializador, incluso si la aplicación de la subclase del inicializador es un
inicializador de conveniencia.
Por el contrario, si usted escribe un inicializador subclase que coincide con una
superclase convenienciainicializador, que inicializador conveniencia superclase nunca
puede ser llamado directamente por su subclase, de acuerdo con las reglas descritas
anteriormente en el inicializador de encadenamiento . Por lo tanto, la subclase no está
(en sentido estricto) proporcionar una sustitución de la inicializador superclase.Como
resultado, usted no escribe la anulación modificador cuando se proporciona una
aplicación coincidente de un inicializador conveniencia superclase.
El ejemplo siguiente define una clase base llamada Vehículo . Esta clase base declara
una propiedad almacenado llamado numberOfWheels y su valor
predeterminado Int valor de 0 . El numberOfWheels propiedad es utilizada por una
propiedad llamada computarizada descripción para crear una Cadena
de descripción de las características del vehículo:
• class Vehicle {
• var numberOfWheels = 0
• var description: String {

  174  
• return "\(numberOfWheels) wheel(s)"
• }
• }
El vehículo clase proporciona un valor predeterminado para su propiedad sólo
almacenado, y no proporciona ningún sí inicializadores personalizados. Como
resultado, recibe automáticamente un inicializador por defecto, como se describe
en Inicializadores predeterminados . El inicializador por defecto (si está disponible) es
siempre un inicializador designado para una clase, y se puede utilizar para crear un
nuevo vehículoejemplo con un numberOfWheels de 0 :
• let vehicle = Vehicle()
• println("Vehicle: \(vehicle.description)")
• // Vehículo: 0 rueda (s)  
El siguiente ejemplo define una subclase de vehículo llamado de bicicletas :
• class Bicycle: Vehicle {
• override init() {
• super.init()
• numberOfWheels = 2
• }
• }
La bicycle subclase define un inicializador designado costumbre, init () . Este
inicializador designado coincide con un inicializador designado de la superclase
de bicicletas , por lo que la bicicleta versión de este inicializador está
marcado con el override modificador.
El init () inicializador para bicicletas comienza llamando super.init () ,
que llama al inicializador por defecto para la bicicleta superclase de la
clase, vehículo . Esto asegura que el numberOfWheels propiedad heredada es
inicializado por el vehículo antes de bicicletas tiene la oportunidad de
modificar la propiedad.Después de llamar a super.init () , el valor original
de numberOfWheels se sustituye con un nuevo valor de 2 .
Si crea una instancia de la bicicleta , puede llamar a su
heredada Descripción computarizada propiedad para ver cómo
su numberOfWheels propiedad ha sido actualizada:
• let bicycle = Bicycle()
• println("Bicycle: \(bicycle.description)")
• // Bicicletas: 2 ruedas (s)  
NOTA
Las subclases sólo se les permite modificar variables propiedades superclase durante la
inicialización. Las subclases no pueden modificar heredado propiedades constantes.
Automatic Inicializador Herencia
Como se mencionó anteriormente, las subclases no heredan sus inicializadores
superclase de forma predeterminada. Sin embargo, los inicializadores
superclase son heredados automáticamente si se cumplen ciertas condiciones. En la

  175  
práctica, esto significa que no es necesario escribir las anulaciones de inicializador en
muchos escenarios comunes, y pueden heredar sus inicializadores superclase con el
mínimo esfuerzo, siempre que sea seguro hacerlo.
Suponiendo que usted proporciona valores predeterminados para las nuevas propiedades
usted introduce en una subclase, se aplican las siguientes reglas:
Regla  1  

Si su subclase no define ningún inicializadores designados, hereda


automáticamente todos sus superclase designado inicializadores.
Regla  2  

Si su subclase proporciona una implementación de todos los de su superclase


designado inicializadores-ya sea heredando ellos según la regla 1, o
proporcionando una implementación personalizada como parte de su definición-
entonces hereda automáticamente todos los inicializadores de conveniencia
superclase.
Estas normas se aplican incluso si su subclase añade nuevos inicializadores de
conveniencia.
NOTA
Una subclase puede aplicar una superclase inicializador designado como inicializador
conveniencia subclase como parte de la satisfacción de la regla 2.
Designado y Conveniencia Inicializadores en Acción
El siguiente ejemplo muestra inicializadores designados, inicializadores de
conveniencia, y la herencia de inicialización automática en acción. En este ejemplo se
define una jerarquía de tres clases
llamadas Alimentos, recipeIngredient y ShoppingListItem , y
demuestra cómo sus inicializadores interactúan.
La clase base de la jerarquía se llama la Alimentación , que es una clase simple
para encapsular el nombre de un producto alimenticio. La Food clase introduce una
sola cuerda propiedad llamada nombre y ofrece dos inicializadores para la creación
de Alimentos casos:
• class Food {
• var name: String
• init(name: String) {
• self.name = name
• }
• convenience init() {
• self.init(name: "[Unnamed]")
• }
• }
La siguiente figura muestra la cadena de inicialización para la Alimentación de
clase:

  176  
 

Las clases no tienen un miembro por miembro inicializador por defecto, por lo que
la Food clase proporciona un inicializador designado que toma un solo argumento
llamado nombre . Este inicializador puede ser utilizado para crear un
nuevo Alimentación instancia con un nombre específico:
• let namedMeat = Food(name: "Bacon")
• // Nombre de namedMeat es "tocino"  
El init (name: String) inicializador de la Food clase se proporciona como
un designado inicializador, ya que asegura que todas las propiedades almacenadas de un
nuevo Alimentación instancia están completamente iniciados. La Food clase no
tiene una superclase, por lo que el init (name: String) inicializador no necesita
llamar super.init () para completar su inicialización.
La Food clase también proporciona una mayor comodidad inicializador, init () ,
sin argumentos. El init ()inicializador proporciona un nombre de marcador de
posición por defecto para un nuevo alimento mediante la delegación a través de
la Alimentación de la clase init (name: String) con un nombre de valor
de [nombre] :
• let mysteryMeat = Food()
• // Nombre de mysteryMeat es "[nombre]"  
La segunda clase en la jerarquía es una subclase de la
Alimentación llamado recipeIngredient . LosrecipeIngredient model
os de clase un ingrediente en una receta de cocina. Se introduce un Int propiedad
llamada cantidad (además del nombre de la propiedad se hereda de la
Alimentación ) y define dos inicializadores para
crear recipeIngredient casos:
• class RecipeIngredient: Food {
• var quantity: Int
• init(name: String, quantity: Int) {
• self.quantity = quantity
• super.init(name: name)
• }
• override convenience init(name: String) {
• self.init(name: name, quantity: 1)
• }
• }

  177  
 
La siguiente figura muestra la cadena de inicialización para
el recipeIngredient clase:

 
El recipeIngredient clase tiene un único inicializador designado, init
(name: String, cantidad: Int) , que se puede utilizar para rellenar todas las
propiedades de un nuevo recipeIngredient ejemplo. Este inicializador comienza
asignando el pasado cantidad argumento a la cantidad de propiedad, que es la
única propiedad nueva introducida por recipeIngredient . Después de hacerlo,
los delegados de inicializador hasta el init (name: String) inicializador de
la Alimentación de clase. Este proceso satisface control de seguridad 1 deTwo-
Phase inicialización anteriormente.
RecipeIngredient también define un inicializador conveniencia, init (name:
String) , que se utiliza para crear un recipeIngredient ejemplo por su nombre
solo. Este inicializador conveniencia asume una cantidad de 1 por
cualquier recipeIngredient instancia que se crea sin una cantidad explícito. La
definición de este inicializador conveniencia hace recipeIngredient casos más
rápido y más conveniente para crear, y evita la duplicación de código al crear varios de
una sola cantidad recipeIngredient casos. Este inicializador conveniencia
simplemente delegados de todo a inicializador designado de la clase, que pasan en
una cantidad de valor de1 .
El init (name: String) inicializador comodidad proporcionada
por recipeIngredient toma los mismos parámetros que el init (name:
String) designado inicializador de Alimentos . Debido a que este inicializador
conveniencia anula un inicializador designado de su superclase, que debe estar marcado
con la anulación de modificación (como se describe en Inicializador Sucesiones y
Anulación ).
Aunque recipeIngredient ofrece el init (name: String) inicializador
como inicializador conveniencia,recipeIngredient ha proporcionado, sin
embargo, una implementación de todos los inicializadores designados de su

  178  
superclase. Por lo tanto, recipeIngredient hereda automáticamente todos los
inicializadores de conveniencia de su superclase también.
En este ejemplo, la superclase para recipeIngredient es Alimentación , que
tiene una sola inicializador conveniencia llamado init () . Por tanto, este
inicializador es heredado por recipeIngredient . La versión heredada de init
() funciona de la misma manera como la Food versión, salvo que los delegados a
larecipeIngredient versión de init (name: String) en lugar de
la Alimentación versión.
Los tres de estos inicializadores se puede utilizar para crear
nuevos recipeIngredient casos:
• let oneMysteryItem = RecipeIngredient()
• let oneBacon = RecipeIngredient(name: "Bacon")
• let sixEggs = RecipeIngredient(name: "Eggs", quantity: 6)
La tercera y última clase en la jerarquía es una subclase
de recipeIngredient llamado ShoppingListItem . LosShoppingListIte
m modelos de clase un ingrediente receta tal como aparece en una lista de compras.
Cada elemento de la lista de compras comienza como "unpurchased". Para representar
este hecho,ShoppingListItem introduce una propiedad booleana
denominada comprado , con un valor predeterminado
defalse . ShoppingListItem también añade un
computarizada Descripción propiedad, que ofrece una descripción textual de
un ShoppingListItem ejemplo:
• class ShoppingListItem: RecipeIngredient {
• var purchased = false
• var description: String {
• var output = "\(quantity) x \(name)"
• output += purchased ? " ✔" : " ✘"
• return output
• }
• }
NOTA
ShoppingListItem no define un inicializador para proporcionar un valor inicial
para comprar , porque los elementos de una lista de la compra (como modelados aquí)
siempre comienzan unpurchased.
Debido a que proporciona un valor predeterminado para todas las propiedades que
presenta y no define ningún inicializadores sí, ShoppingListItem hereda
automáticamente todos los inicializadores de conveniencia designados y de su
superclase.
La siguiente figura muestra la cadena global de inicialización para las tres clases:

  179  
 

Puede utilizar los tres de los inicializadores heredados para crear un


nuevo ShoppingListItem ejemplo:
• var breakfastList = [
• ShoppingListItem(),
• ShoppingListItem(name: "Bacon"),
• ShoppingListItem(name: "Eggs", quantity: 6),
• ]
• breakfastList[0].name = "Orange juice"
• breakfastList[0].purchased = true
• for item in breakfastList {
• println(item.description)
• }
• // 1 x Orange juice ✔
• // 1 x Bacon ✘
• // 6 x Eggs ✘
Aquí, una nueva matriz llamada breakfastList se crea a partir de una matriz que
contiene literal tres nuevosShoppingListItem casos. El tipo de la matriz se deduce
que [ShoppingListItem] . Una vez creada la matriz, el nombre de
la ShoppingListItem al inicio de la matriz se cambia
de "[nombre]" para "Zumo de naranja" y se marca como comprado. Impresión

  180  
de la descripción de cada elemento de la matriz muestra que sus estados
predeterminados se han fijado como se esperaba.
Inicializadores Requeridos
Escriba el requerido modificador antes de la definición de un inicializador de clase
para indicar que cada subclase de la clase debe implementar que inicializador:
• class SomeClass {
• required init() {
• // Aplicación inicializador va aquí  
• }
•}
También debe escribir el requerido modificador antes de cada aplicación subclase
de un inicializador necesario, para indicar que el requisito de inicialización se aplica a
otras subclases de la cadena. No escribes la anulación modificador cuando anulando
un inicializador designado requerida:
• class SomeSubclass: SomeClass {
• required init() {
• // Aplicación subclase del inicializador requerida va aquí  
• }
•}
NOTA
Usted no tiene que proporcionar una implementación explícita de un inicializador
necesaria si se puede cumplir con el requisito con un inicializador heredado.
El establecimiento de un defecto Valor de la propiedad con un cierre o la
Función
Si el valor predeterminado de una propiedad almacenado requiere algún tipo de
personalización o configuración, puede utilizar un cierre o función global para
proporcionar un valor por defecto a medida para esa propiedad. Siempre que una nueva
instancia del tipo que la propiedad pertenece a se inicializa, el cierre o la función se
llama, y su valor de retorno se asigna como valor predeterminado de la propiedad.
Este tipo de cierres o funciones suelen crear un valor temporal del mismo tipo que la
propiedad, a medida que valoran para representar el estado inicial deseado, y luego
regresan ese valor temporal que se utilizará como valor predeterminado de la propiedad.
He aquí un esbozo de cómo un esqueleto de cierre puede ser utilizado para proporcionar
un valor de propiedad predeterminado:
• class SomeClass {
• let someProperty: SomeType = {
• // Crear un valor predeterminado para UnaPropiedad dentro
de este cierre  
• // SomeValue debe ser del mismo tipo que SomeType  
• return someValue
• }()

  181  
• }
Tenga en cuenta que extremo de la llave de cierre es seguido por un par de paréntesis
vacío. Esto le dice a Swift para ejecutar el cierre inmediato. Si omite estos paréntesis,
usted está tratando de asignar el propio cierre a la propiedad, y no el valor de retorno de
la clausura.
NOTA
Si utiliza un cierre para inicializar una propiedad, recuerde que el resto de la instancia
aún no se ha inicializado en el punto que se ejecuta el cierre. Esto significa que no se
puede acceder a cualquier otro valor de las propiedades dentro de su cierre, incluso si
esas propiedades tienen valores por defecto. Tampoco se puede utilizar la
implícita auto propiedad, o llamar a cualquiera de los métodos de la instancia.
El ejemplo siguiente define una estructura llamada de tablero de ajedrez , que
los modelos de un tablero para el juego de Checkers (también conocido como Damas ):

El juego de las Damas se juega en un tablero de diez por diez, con cuadrados blancos y
negros alternados.Para representar este tablero de juego, el tablero de
ajedrez estructura tiene una sola propiedad denominada boardColors , que es una
matriz de 100 Bool valores. Un valor de verdad de la matriz representa un cuadrado
negro y un valor de falso representa un cuadrado blanco. El primer elemento de la
matriz representa el cuadrado superior izquierda en el tablero y el último elemento de la
matriz representa el cuadrado inferior derecha en el tablero.
El boardColors matriz se inicializa con un cierre para establecer sus valores de
color:
• struct Checkerboard {
• let boardColors: [Bool] = {
• var temporaryBoard = [Bool]()
• var isBlack = false
• for i in 1...10 {
• for j in 1...10 {
• temporaryBoard.append(isBlack)

  182  
• isBlack = !isBlack
• }
• isBlack = !isBlack
• }
• return temporaryBoard
• }()
• func squareIsBlackAtRow(row: Int, column: Int) -> Bool {
• return boardColors[(row * 10) + column]
• }
• }
Cada vez que un nuevo tablero de ajedrez se crea una instancia, el cierre se
ejecuta, y el valor por defecto de boardColors se calcula y se volvió. El cierre en el
ejemplo anterior calcula y establece el color apropiado para cada casilla del tablero en
una matriz temporal llamado temporaryBoard , y devuelve esta matriz temporal
como valor de retorno de la clausura una vez que su configuración se ha completado. El
valor de la matriz devuelta se almacena en boardColors y se puede consultar con
el squareIsBlackAtRow función de utilidad:
• let board = Checkerboard()
• println(board.squareIsBlackAtRow(0, column: 1))
• // imprime "verdadera"  
• println(board.squareIsBlackAtRow(9, column: 9))
• // imprime "falsa"  
 

Deinicialización
En esta página
A deinitializer se llama inmediatamente antes de que se cancela la asignación de una
instancia de clase.Usted escribe deinitializers con la deinit palabra clave, similar a
cómo intializers se escriben con el initpalabra clave. Deinitializers sólo están
disponibles en los tipos de clase.
Cómo deinicialización Obras
Swift desasigna automáticamente los casos en los que ya no son necesarios, para liberar
recursos. Swift se encarga de la gestión de memoria de casos a través de la cuenta de
referencias automático ( ARC ), como se describe en la cuenta automática de
referencia . Normalmente no es necesario para llevar a cabo manual de limpieza cuando
se desasignan las instancias. Sin embargo, cuando se está trabajando con sus propios
recursos, es posible que deba realizar alguna limpieza adicional a ti mismo. Por
ejemplo, si crea una clase personalizada para abrir un archivo y escribir algunos datos
en él, es posible que tenga que cerrar el archivo antes de que se cancela la asignación de
la instancia de clase.
Definiciones de clase pueden tener como máximo un deinitializer por clase. El
deinitializer no toma ningún parámetro y se escribe sin paréntesis:

  183  
• deinit {
• // Realizar la deinicialización  
•}
Deinitializers se denominan de forma automática, justo antes de desasignación ejemplo
se lleva a cabo. No se le permite llamar a un deinitializer ti mismo. Deinitializers
superclase son heredados por sus subclases, y la deinitializer superclase se llama
automáticamente al final de una aplicación deinitializer subclase.Deinitializers
superclase siempre se llaman, incluso si una subclase no proporciona su propio
deinitializer.
Debido a que una instancia no se cancela la asignación hasta después de su deinitializer
se llama, un deinitializer puede acceder a todas las propiedades de la instancia que se
llama en y puede modificar su comportamiento sobre la base de esas propiedades (tales
como buscar el nombre de un archivo que necesita ser cerrado ).
Deinitializers en Acción
He aquí un ejemplo de un deinitializer en acción. Este ejemplo define dos nuevos
tipos, el Banco y el jugador , para un juego simple. El Banco estructura gestiona
una moneda inventada, que nunca puede tener más de 10.000 monedas en
circulación. No puede ser más que un Banco en el juego, por lo que el Banco se
implementa como una estructura con propiedades y métodos para almacenar y
administrar su estado actual estáticas:
• struct Bank {
• static var coinsInBank = 10_000
• static func vendCoins(var numberOfCoinsToVend: Int) -> Int {
• numberOfCoinsToVend = min(numberOfCoinsToVend, coinsInBank)
• coinsInBank -= numberOfCoinsToVend
• return numberOfCoinsToVend
• }
• static func receiveCoins(coins: Int) {
• coinsInBank += coins
• }
• }
Bank realiza un seguimiento del número actual de monedas que tiene con
su coinsInBank propiedad. También ofrece dos métodos-
vendCoins y receiveCoins : para manejar la distribución y recogida de
monedas.
vendCoins comprueba que hay suficientes monedas en el banco antes de
distribuirlos. Si no hay suficientes monedas, Banco devuelve un número menor que el
número que se solicitó (y devuelve cero si no hay monedas se dejan en el
banco). vendCoins declara numberOfCoinsToVend como un parámetro variable,
de modo que el número puede ser modificado dentro del método de cuerpo sin la
necesidad de declarar una nueva variable. Devuelve un valor entero que indique el
número real de las monedas que se proporcionaron.

  184  
El receiveCoins método no hace sino aumentar el número recibido de las monedas
de nuevo en la tienda de la moneda del banco.
El jugador clase describe un jugador en el juego. Cada jugador tiene un cierto
número de monedas almacenadas en su bolso en cualquier momento. Esto está
representado por el jugador coinsInPursepropiedad:
• class Player {
• var coinsInPurse: Int
• init(coins: Int) {
• coinsInPurse = Bank.vendCoins(coins)
• }
• func winCoins(coins: Int) {
• coinsInPurse += Bank.vendCoins(coins)
• }
• deinit {
• Bank.receiveCoins(coinsInPurse)
• }
• }
Cada Player instancia se inicializa con un subsidio inicial de un determinado número
de monedas del banco durante la inicialización, aunque un Player instancia puede
recibir menos de ese número, si no hay suficientes monedas están disponibles.
El player de clase define un winCoins método, que recupera un cierto número de
monedas del banco y los agrega a la bolsa del jugador. El player de clase también
implementa un deinitializer, que se llama justo antes de un player se desasigna
instancia. Aquí, la deinitializer simplemente devuelve todo de monedas de los jugadores
a la orilla:
• var playerOne: Player? = Player(coins: 100)
• println("A new player has joined the game with \(playerOne!.coinsInPurse)
coins")
• // imprime "Un nuevo jugador se ha unido a la partida con
100 monedas"  
• println("There are now \(Bank.coinsInBank) coins left in the bank")
• // imprime "En la actualidad hay 9.900 monedas que quedan
en el banco"  
Un nuevo jugador se crea una instancia, con una solicitud de 100 monedas si están
disponibles. Este jugadorinstancia se almacena en una opción del
jugador variable llamada Playerone . Una variable opcional se utiliza aquí, porque
los jugadores pueden abandonar el juego en cualquier momento. El opcional permite
realizar un seguimiento de si actualmente hay un jugador en el juego.

  185  
Debido Playerone es opcional, es calificado con un signo de exclamación ( ! cuando
su) coinsInPurse se accede a la propiedad a imprimir su número predeterminado de
monedas, y siempre que su winCoins se llama al método:
• playerOne!.winCoins(2_000)
• println("PlayerOne won 2000 coins & now has \(playerOne!.coinsInPurse)
coins")
• // Impresiones "Playerone ganado 2000 monedas y ahora tiene
2.100 monedas"  
• println("The bank now only has \(Bank.coinsInBank) coins left")
• // imprime "El banco ahora sólo ha 7900 monedas de la
izquierda"  
Aquí, el jugador ha ganado 2.000 monedas. Bolso del jugador ahora contiene 2.100
monedas, y el banco tiene sólo 7.900 monedas fueron.
• playerOne = nil
• println("PlayerOne has left the game")
• // Impresiones "Playerone ha dejado el juego"  
• println("The bank now has \(Bank.coinsInBank) coins")
• // Impresiones "El banco ahora tiene 10.000 monedas"  
El jugador ya ha dejado el juego. Esto se indica mediante el establecimiento de la
opcional Playerone variablenula , lo que significa "no jugador instancia. "En el
momento que esto sucede, el Playerone referencia de variable al jugador instancia
está roto. No hay otras propiedades o variables siguen refiriendo al jugadorinstancia,
y por lo que se desasignan con el fin de liberar su memoria. Justo antes de que esto
sucede, su deinitializer se llama de forma automática, y sus monedas se devuelven al
banco.

Conteo automático de Referencia

Swift utiliza el recuento de referencias automático (ARC) para rastrear y administrar el


uso de la memoria de su aplicación. En la mayoría de los casos, esto significa que la
gestión de la memoria "simplemente funciona" en Swift, y usted no tiene que pensar en
la gestión de memoria usted mismo. ARC libera automáticamente la memoria utilizada
por las instancias de clase cuando esos casos ya no son necesarios.
Sin embargo, en unos pocos casos ARC requiere más información acerca de las
relaciones entre las partes de su código con el fin de gestionar la memoria para
usted. En este capítulo se describen las situaciones y muestra cómo se habilita ARC
para gestionar toda la memoria de su aplicación.
NOTA
El conteo de referencias sólo se aplica a las instancias de clases. Estructuras y
enumeraciones son tipos de valor, no hacen referencia a tipos, y no se almacenan y se
pasan por referencia.

  186  
Cómo ARC Obras
Cada vez que se crea una nueva instancia de una clase, ARC asigna un trozo de
memoria para almacenar información sobre esa instancia. Esta memoria contiene
información sobre el tipo de la instancia, junto con los valores de propiedades
almacenados asociados con esa instancia.
Además, cuando ya no se necesita una instancia, ARC libera la memoria utilizada por la
instancia para que la memoria puede ser utilizado para otros fines en lugar. Esto
garantiza que las instancias de clase no ocupan espacio en la memoria cuando ya no son
necesarios.
Sin embargo, si ARC eran desasignar una instancia que todavía estaba en uso, que ya no
sería posible acceder a las propiedades de esa instancia, o llamar a los métodos de esa
instancia. De hecho, si se trató de acceder a la instancia, su aplicación lo más probable
accidente.
Para asegurarse de que los casos no desaparecen, mientras que todavía se necesitan,
ARC rastrea cuántos propiedades, constantes y variables se refieren actualmente a cada
instancia de clase. ARC no desasignar una instancia, siempre y cuando todavía existe al
menos una referencia activa a esa instancia.
Para que esto sea posible, cada vez que se asigna una instancia de clase a una propiedad,
constante o variable, propiedad, constante o variable hace una fuerte referencia a la
instancia. La referencia se llama una referencia "fuerte", ya que mantiene un firme
control sobre esa instancia, y no permitir que se cancela la asignación durante el tiempo
que sigue siendo tan fuerte como referencia.
ARC en Acción
He aquí un ejemplo de cómo funciona automáticas de referencia de conteo. Este
ejemplo comienza con una clase simple llamada persona , que define una propiedad
denominada constante almacenado nombre :
• class Person {
• let name: String
• init(name: String) {
• self.name = name
• println("\(name) is being initialized")
• }
• deinit {
• println("\(name) is being deinitialized")
• }
• }
La person de clase tiene un inicializador que establece la instancia de name de
propiedad e imprime un mensaje para indicar que la inicialización está en
marcha. La person de clase también tiene un deinitializer que imprime un mensaje
cuando se cancela la asignación de una instancia de la clase.
El siguiente fragmento de código define tres variables de tipo person? , que se
utilizan para configurar varias referencias a una nueva person instancia en fragmentos
de código siguientes. Debido a que estas variables son de tipo opcional ( person? ,

  187  
no person ), que se inicializa automáticamente con un valor de cero , y actualmente
no hace referencia a una persona instancia.
• var reference1: Person?
• var reference2: Person?
• var reference3: Person?
Ahora puede crear una nueva persona instancia y asignarlo a una de estas tres
variables:
• reference1 = Person(name: "John Appleseed")
• // Impresiones "John Appleseed se inicializa"  
Tenga en cuenta que el mensaje de "John Appleseed se inicializa" se
imprime en el punto que se llama a lapersona inicializador de clase. Esto confirma
que la inicialización ha tenido lugar.
Debido a la nueva persona instancia se ha asignado a la referencia1 variables,
ahora hay una fuerte referencia de referencia1 a la
nueva persona instancia. Debido a que existe al menos una referencia fuerte, ARC se
asegura de que esta persona se mantiene en la memoria y no se cancela la asignación.
Si asigna la misma persona instancia a dos variables más, dos más fuertes referencias
a esa instancia se establecen:
• reference2 = reference1
• reference3 = reference1
En la actualidad hay tres referencias fuertes a esta única persona instancia.
Si se rompe dos de estas referencias fuertes (incluyendo la referencia original)
asignando cero a dos de las variables, una sola fuertes vestigios de referencia, y
la persona instancia no se cancela la asignación:
• reference1 = nil
• reference2 = nil
ARC no desasigna la persona instancia hasta que se rompe la tercera y última
referencia fuerte, momento en el que es evidente que ya no estás usando
la Person ejemplo:
• reference3 = nil
• // Impresiones "John Appleseed está siendo deinitialized"  
 
Ciclos de referencia fuertes entre instancias de clase
En los ejemplos anteriores, ARC es capaz de rastrear el número de referencias a la
nueva persona instancia crear y desasignar que persona instancia cuando ya no se
necesita.
Sin embargo, es posible escribir código en el que una instancia de una clase nunca llega
a un punto donde tiene cero referencias fuertes. Esto puede suceder si dos instancias de
la clase tienen una fuerte referencia el uno al otro, de tal manera que cada instancia
mantiene el otro vivo. Esto se conoce como un ciclo de referencia fuerte .
A resolver los ciclos de referencia fuertes mediante la definición de algunas de las
relaciones entre las clases como referencias débiles o sin dueño en lugar de referencias

  188  
tan fuertes. Este proceso se describe en laResolución de Ciclos de referencia fuertes
entre instancias de clase . Sin embargo, antes de aprender cómo resolver un ciclo de
referencia fuerte, es útil para entender cómo se produce tal ciclo.
He aquí un ejemplo de cómo un ciclo de referencia fuerte se puede crear por
accidente. Este ejemplo define dos clases llamadas Persona y Apartamento , cuál
es el modelo de un bloque de apartamentos y sus residentes:
• class Person {
• let name: String
• init(name: String) { self.name = name }
• var apartment: Apartment?
• deinit { println("\(name) is being deinitialized") }
• }

• class Apartment {
• let number: Int
• init(number: Int) { self.number = number }
• var tenant: Person?
• deinit { println("Apartment #\(number) is being deinitialized") }
• }
Cada person instancia tiene un nombre de propiedad de tipo Cadena y un
opcional apartament propiedad que es
inicialmente cero . El apartament propiedad es opcional, porque una persona no
siempre puede tener un apartamento.
Del mismo modo, cada apartament instancia tiene un number property de
tipo int y tiene un opcionalinquilino propiedad que es inicialmente cero . La
propiedad es opcional porque el inquilino de un apartamento no siempre puede tener un
inquilino.
Ambas clases también definen un deinitializer, que imprime el hecho de que se está
deinitialized una instancia de esa clase. Esto le permite ver si las instancias
de Persona y Apartamento se desasignan como se esperaba.
Este siguiente fragmento de código define dos variables de tipo opcional
llamado juan y number73 , que se establece en un
determinado Apartamento y Persona ejemplo a continuación. Ambas variables
tienen un valor inicial de cero , en virtud de ser opcional:
• var john: Person?
• var number73: Apartment?
Ahora puede crear una específica persona instancia y Apartamento instancia y
asignar estas nuevas instancias a las juan y number73 variables:
• john = Person(name: "John Appleseed")
• number73 = Apartment(number: 73)

  189  
He aquí cómo las referencias fuertes cuidan de creación y asignación de estas dos
instancias. El johnvariable de ahora tiene una fuerte referencia a la
nueva persona instancia, y el number73 variables tiene una fuerte referencia a la
nueva Apartamento ejemplo:

Ahora puede enlazar los dos casos juntos para que la persona tiene un apartamento, y el
apartamento tiene un inquilino. Tenga en cuenta que un signo de exclamación ( ! se
utiliza para desenvolver y acceder a las instancias almacenadas en el interior
del) john y number73 las variables opcionales, por lo que las propiedades de esos
casos se pueden establecer:
• john !. apartamento = number73  
• number73 !. inquilino = john  
Así es como las referencias fuertes cuidan de vincular los dos casos juntos:

Desafortunadamente, uniendo estos dos casos crea un fuerte ciclo de referencia entre
ellos. La Personaejemplo ahora tiene una fuerte referencia
al Apartamento ejemplo, y el Apartamento instancia tiene una fuerte referencia a
la persona de instancia. Por lo tanto, cuando se rompen las referencias fuertes en
poder de losjohn y number73 las variables, los recuentos de referencias no bajan a
cero, y los casos no se desasignan por ARC:
• john = nil  
• number73 = nil  
Tenga en cuenta que ni deinitializer fue llamado al configurar estas dos variables
a cero . El ciclo de referencia fuerte impide que la persona y Apartamento casos
que alguna vez se cancela la asignación, causando una pérdida de memoria en su
aplicación.

  190  
Así es como las referencias fuertes se ven después de establecer
los john y number73 las variables a cero :

 
Las fuertes referencias entre la persona y la instancia Apartamento instancia
permanecen y no se pueden romper.
Resolver Ciclos de referencia fuertes entre instancias de clase
Swift proporciona dos formas de resolver los ciclos de referencia fuertes cuando se
trabaja con las propiedades de tipo de clase: referencias débiles y referencias sin dueño.
Referencias débiles y sin dueño permiten una instancia en un ciclo de referencia para
referirse a la otra instancia y sin mantener un fuerte control sobre el mismo. Los casos
pueden entonces referirse unos a otros sin crear un ciclo de referencia fuerte.
Utilice una referencia débil siempre que sea válida para que se convierta en
referencia nula en algún momento durante su vida útil. Por el contrario, utilice una
referencia sin dueño cuando se sabe que la referencia nunca será nula una vez que se
ha establecido durante la inicialización.

Referencias débiles
Una referencia débil es una referencia que no mantiene una fuerte influencia en la
instancia que se refiere, por lo que no deja de ARC de la eliminación de la instancia de
referencia. Este comportamiento impide que la referencia se conviertan en parte de un
ciclo de referencia fuerte. Usted indica una referencia débil mediante la colocación de
la débil palabra clave antes de una propiedad o declaración de variables.
Utilice una referencia débil para evitar los ciclos de referencia, siempre que sea posible
para que la referencia a tener "ningún valor" en algún momento de su vida. Si la
referencia será siempre tener un valor, utilizar una referencia sin dueño en su lugar,
como se describe en las referencias sin propietario . En el Apartamentoejemplo
anterior, es apropiado para un apartamento para poder tener "ningún inquilino" en algún
momento de su vida útil, por lo que una referencia débil es una forma adecuada para
romper el ciclo de referencia en este caso.
NOTA
Referencias débiles deben ser declaradas como variables, para indicar que su valor
puede cambiar en tiempo de ejecución. Una referencia débil no puede ser declarada
como una constante.
Debido a las referencias débiles se les permite tener "ningún valor", debe declarar cada
referencia débil como tener un tipo opcional. Tipos opcionales son la mejor forma de
representar la posibilidad de que "ningún valor" en Swift.

  191  
Debido a una referencia débil no mantiene una fuerte influencia en la instancia que se
refiere, es posible que esa instancia para cancelar la asignación, mientras que la
referencia débil todavía se está refiriendo a la misma. Por lo tanto, ARC establece
automáticamente una referencia débil a cero cuando la instancia que se refiere a que se
cancela la asignación. Usted puede comprobar la existencia de un valor en la referencia
débil, al igual que cualquier otro valor opcional, y que nunca va a terminar con una
referencia a una instancia válida de que ya no existe.
El siguiente ejemplo es idéntico al de la persona y Apartamento ejemplo desde
arriba, con una diferencia importante. Esta vez, el Apartamento de
tipo inquilino propiedad se declara como una referencia débil:
• class Person {
• let name: String
• init(name: String) { self.name = name }
• var apartment: Apartment?
• deinit { println("\(name) is being deinitialized") }
• }

• class Apartment {
• let number: Int
• init(number: Int) { self.number = number }
• weak var tenant: Person?
• deinit { println("Apartment #\(number) is being deinitialized") }
• }
Las fuertes referencias de las dos variables ( juan y number73 ) y los vínculos entre
las dos instancias se crean como antes:
• var john: Person?
• var number73: Apartment?

• john = Person(name: "John Appleseed")
• number73 = Apartment(number: 73)

• john!.apartment = number73
• number73!.tenant = john
Así es como las referencias se ven ahora que usted ha enlazado las dos instancias a la
vez:

  192  
 
La persona instancia todavía tiene una fuerte referencia al Apartamento instancia,
pero el Apartamento ejemplo ahora tiene una débil referencia a la persona de
instancia. Esto significa que cuando se rompe la referencia fuerte en poder de
los john las variables, no hay referencias más fuertes a la persona ejemplo:

 
Debido a que no existen referencias más fuertes a la Persona ejemplo, se cancela la
asignación:
• john = nil
• // Impresiones "John Appleseed está siendo deinitialized"  
La fuerte referencia solamente restante al Apartamento instancia es
del number73 variable. Si usted rompe esareferencia fuerte, no hay más fuertes
referencias al Apartamento ejemplo:

 
Debido a que no hay más fuertes referencias al Apartamento ejemplo, también lo es
desasignada:

  193  
• number73 = nil
• // Impresiones "Apartamento # 73 está siendo deinitialized"  
Los dos fragmentos de código finales anteriores muestran que los deinitializers para
la persona instancia yApartamento instancia imprimen sus mensajes
"deinitialized" después de las juan y number73 variables se ponen a cero . Esto
demuestra que el ciclo de referencia se ha roto.

Referencias sin propietario


Como referencias débiles, una referencia sin dueño no mantiene una fuerte influencia
en la instancia que se refiere. A diferencia de una referencia débil, sin embargo, se
supone que una referencia sin dueño parasiempre tener un valor. Debido a esto, una
referencia sin dueño siempre se define como un tipo no opcional.Usted indica una
referencia sin dueño colocando el unowned palabra clave antes de una propiedad o
declaración de variables.
Porque una referencia sin dueño no es opcional, no es necesario para desenvolver la
referencia sin dueño cada vez que se utiliza. Una referencia sin dueño siempre se puede
acceder directamente. Sin embargo, ARC no puede establecer la referencia
a cero cuando la instancia se refiere a que se cancela la asignación, ya que las
variables de un tipo no opcional, no se pueden establecer en cero .
NOTA
Si intenta acceder a una referencia sin dueño tras la instancia que hace referencia se
cancela la asignación, se activará un error de ejecución. Utilice referencias sin dueño
sólo cuando esté seguro de que la referencia será siempre referirse a una instancia.
Tenga en cuenta también que Swift garantiza su aplicación se bloqueará si se intenta
acceder a una referencia sin dueño tras la instancia que hace referencia se cancela la
asignación. Usted nunca va a encontrar un comportamiento inesperado en esta
situación. Su aplicación siempre se bloqueará de forma fiable, aunque debe, por
supuesto, evitar que lo hagan.
El ejemplo siguiente define dos clases, los clientes y la tarjeta de
crédito , cuál es el modelo de un cliente de un banco y de una posible tarjeta de
crédito para ese cliente. Estas dos clases de cada tienda una instancia de la otra clase
como una propiedad. Esta relación tiene el potencial de crear un ciclo de referencia
fuerte.
La relación entre el cliente y la tarjeta de crédito es un poco diferente de
la relación entre la Casa y lapersona se ve en el ejemplo de referencia por encima
débil. En este modelo de datos, un cliente puede o no puede tener una tarjeta de crédito,
una tarjeta de crédito pero será siempre estar asociada con un cliente.Para representar
esto, el cliente de clase tiene una opcional tarjeta de propiedad, pero el la
tarjeta de crédito tiene una clase no opcional cliente propiedad.
Por otra parte, un nuevo la tarjeta de crédito instancia puede sólo ser creado
al pasar un número de valor y un cliente de instancia a un encargo la tarjeta
de crédito inicializador. Esto asegura que una la tarjeta de
crédito instancia siempre tiene un cliente de instancia asociado con él cuando
el la tarjeta de crédito se crea una instancia.
Debido a que una tarjeta de crédito tendrá siempre un cliente, definir su cliente la
propiedad como una referencia sin dueño, para evitar un ciclo de referencia fuerte:

  194  
• class Customer {
• let name: String
• var card: CreditCard?
• init(name: String) {
• self.name = name
• }
• deinit { println("\(name) is being deinitialized") }
• }

• class CreditCard {
• let number: UInt64
• unowned let customer: Customer
• init(number: UInt64, customer: Customer) {
• self.number = number
• self.customer = customer
• }
• deinit { println("Card #\(number) is being deinitialized") }
• }
NOTA
El número de propiedad del la tarjeta de crédito de clase se define con un
tipo de UInt64 lugar de Int , para asegurar que el número de la capacidad de la
propiedad es lo suficientemente grande como para guardar un número de tarjeta de 16
dígitos en ambos sistemas de 32 bits y 64 bits.
Este siguiente fragmento de código define una opcional Cliente variable
llamada John , que se utiliza para almacenar una referencia a un cliente
específico. Esta variable tiene un valor inicial de cero, en virtud de ser opcional:
• var john: Customer?
Ahora puede crear un cliente de ejemplo, y lo utilizan para inicializar y asignar un
nuevo la tarjeta de crédito como ejemplo de ese cliente la tarjeta
de propiedad:
• john = Customer(name: "John Appleseed")
• john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)

  195  
Así es como se ven las referencias, ahora que usted ha enlazado las dos instancias:

 
El cliente de ejemplo ahora tiene una fuerte referencia a la la tarjeta de
crédito instancia, y el la tarjeta de crédito instancia tiene una referencia
sin dueño al Cliente instancia.
Debido a la unowned cliente de referencia, cuando se rompe la referencia fuerte en
poder del john variables, no hay más fuertes referencias al Cliente ejemplo:

 
Debido a que no existen referencias más fuertes al Cliente ejemplo, se cancela la
asignación. Después de esto, no hay más fuertes referencias al creditcard ejemplo,
y también lo es desasignada:
• john = nil
• // Impresiones "John Appleseed está siendo deinitialized"  
• // Impresiones "Tarjeta # 1234567890123456 está siendo
deinitialized"  
El fragmento de código final anterior muestra que los deinitializers para el cliente
de la instancia y la tarjeta de crédito instancia tanto imprimir sus mensajes
de "deinitialized" después de la john variable se establece en cero .

Referencias sin propietario y propiedades opcionales Implícitamente


Unwrapped
Los ejemplos de referencias débiles y sin dueño por encima de la cubierta de dos de los
escenarios más comunes en las que es necesario romper un ciclo de referencia fuerte.

  196  
La persona y Apartamento ejemplo muestra una situación en la que dos
propiedades, los cuales se les permite ser nulo , tienen el potencial de causar un ciclo
de referencia fuerte. Este escenario se resuelve mejor con una referencia débil.
El cliente y la tarjeta de crédito ejemplo muestra una situación en la que
una propiedad que se le permite ser nulo y otra propiedad que no puede
ser nula tienen el potencial de causar un ciclo de referencia fuerte.Este escenario se
resuelve mejor con una referencia sin dueño.
Sin embargo, hay un tercer escenario, en el que ambas propiedades deben tener siempre
un valor, y ni propiedad debe nunca ser nil una vez se completa la inicialización. En
este escenario, es útil combinar una propiedad sin dueño en una clase con una propiedad
opcional implícitamente sin envolver en la otra clase.
Esto permite a ambas propiedades para acceder directamente (sin desenvolver opcional)
una vez completada la inicialización, evitando al mismo tiempo un ciclo de
referencia. En esta sección se muestra cómo configurar una relación de este tipo.
El ejemplo siguiente define dos clases, País y ciudad , cada una de ellas con una
instancia de la otra clase como una propiedad. En este modelo de datos, cada país debe
tener siempre una ciudad capital, y cada ciudad siempre debe pertenecer a un país. Para
representar esto, el país tiene una clase capitalCitypropiedad, y la Ciudad
de la clase tiene un país de propiedad:
• class Country {
• let name: String
• let capitalCity: City!
• init(name: String, capitalName: String) {
• self.name = name
• self.capitalCity = City(name: capitalName, country: self)
• }
• }

• class City {
• let name: String
• unowned let country: Country
• init(name: String, country: Country) {
• self.name = name
• self.country = country
• }
• }
Para configurar la interdependencia entre las dos clases, el inicializador para la
ciudad toma un Paísinstancia, y almacena esta instancia en su país la propiedad.
El inicializador para la ciudad se llama desde dentro del inicializador de País . Sin
embargo, el inicializador dePaís no puede pasar a uno mismo a la Ciudad de

  197  
inicialización hasta que un nuevo País instancia está totalmente inicializado, como se
describe en dos fase de inicialización .
Para hacer frente a este requisito, se declara la capitalCity propiedad
del país como una propiedad opcional implícitamente sin envolver, indicado por el
signo de exclamación al final de su tipo de anotación ( Ciudad! ).Esto significa que
el capitalCity propiedad tiene un valor por defecto de cero , como cualquier otro
opcional, pero se puede acceder sin necesidad de desenvolver su valor como se describe
en forma implícita Unwrapped Opcionales .
Debido capitalCity tiene un valor predeterminado cero valor, un
nuevo País instancia se considera totalmente inicializado tan pronto como
el País instancia establece su nombre de la propiedad dentro de su
inicializador.Esto significa que el País inicializador puede empezar a referenciar y
pasar alrededor de la implícita autopropiedad tan pronto como el nombre de la
propiedad se establece. El País , por lo tanto inicializador puede pasar a uno
mismo como uno de los parámetros para la Ciudad de inicialización cuando
el País inicializador está estableciendo su propio capitalCity propiedad.
Todo esto significa que usted puede crear los País y Ciudad casos en una sola
sentencia, sin crear un ciclo de referencia fuerte, y el capitalCity propiedad se
puede acceder directamente, sin necesidad de utilizar un signo de exclamación a
desenvolver su valor opcional:
• var country = Country(name: "Canada", capitalName: "Ottawa")
• println("\(country.name)'s capital city is called \(country.capitalCity.name)")
• // Imprime "la capital de Canadá es Ottawa llama"  
En el ejemplo anterior, el uso de un opcional envolver implícitamente significa que
todos los requisitos inicializador de la clase de dos fases son
satisfechos. El capitalCity propiedad se puede utilizar y se accede como un valor
no opcional una vez completada la inicialización, mientras que todavía evitando un
ciclo de referencia fuerte.

Ciclos de referencia fuertes para cierres


Usted vio anteriormente cómo un ciclo de referencia fuerte se puede crear cuando dos
propiedades de la instancia de clase tienen una fuerte referencia a la otra. También
hemos visto cómo utilizar referencias débiles y sin dueño para romper estos ciclos de
referencia fuertes.
Un ciclo de referencia fuerte también puede ocurrir si asigna un cierre a una propiedad
de una instancia de clase, y el cuerpo de que el cierre capta la instancia. Esta captura
puede ocurrir porque el cuerpo del cierre de acceso a una propiedad de la instancia,
como self.someProperty , o porque el cierre llama a un método en la instancia,
como self.someMethod () . En cualquiera de los casos, estos accesos causan el
cierre de la "captura" de auto , la creación de un ciclo de referencia fuerte.
Este ciclo de referencia fuerte se produce porque los cierres, como las clases, son tipos
de referencia .Cuando se asigna un cierre a una propiedad, usted está asignando
una referencia a que el cierre. En esencia, es el mismo problema que el anterior de dos
referencias fuertes mantienen vivos unos a otros. Sin embargo, en lugar de dos

  198  
instancias de clase, esta vez se trata de una instancia de clase y un cierre que se
mantenía vivos unos a otros.
Swift ofrece una solución elegante a este problema, conocido como una lista de captura
de cierre . Sin embargo, antes de aprender cómo romper un ciclo de referencia fuerte
con una lista de captura de cierre, es útil para entender cómo un ciclo de este tipo puede
ser causado.
El siguiente ejemplo muestra cómo se puede crear un ciclo de referencia fuerte cuando
se utiliza un cierre que hace referencia a sí mismo . Este ejemplo define una clase
llamada HTMLElement , que proporciona un modelo simple para un elemento
individual dentro de un documento HTML:
• class HTMLElement {

• let name: String
• let text: String?

• lazy var asHTML: () -> String = {
• 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 {
• println("\(name) is being deinitialized")
• }

• }
El HTMLElement clase define un nombre de propiedad, lo que indica el nombre del
elemento, como "p" para un elemento de párrafo, o "br" para un elemento de salto de
línea. HTMLElement también define una opción de texto propiedad, la cual se
puede establecer a un cadena que representa el texto que se dictará dentro de ese
elemento HTML.
Además de estas dos propiedades simples, la HTMLElement clase define una
propiedad perezoso llamadoasHTML . Esta propiedad hace referencia a un cierre que
  199  
combina el nombre y el texto en un fragmento de cadena
HTML. El asHTML propiedad es de tipo () -> Cadena , o "una función que no
toma parámetros y devuelve una Cadena de Valor ".
Por defecto, el asHTML propiedad se le asigna un cierre que devuelve una
representación de cadena de una etiqueta HTML. Esta etiqueta contiene la opción de
texto de valor si existe, o si no el contenido de texto de texto no existe. Para un
elemento de párrafo, el cierre volvería "<p> texto </ p>" o "<p />" ,
dependiendo de si el texto propiedad es igual a "algún texto" o nula .
El asHTML propiedad se llama y usa un poco como un método de instancia. Sin
embargo, debido asHTML es una propiedad de cierre en lugar de un método de
instancia, puede reemplazar el valor predeterminado de laasHTML propiedad con un
cierre de encargo, si usted desea cambiar la representación HTML para un elemento
HTML en particular.
NOTA
El asHTML propiedad se declara como una propiedad perezoso, ya que sólo es
necesario si y cuando el elemento realmente necesita ser traducido como un valor de
cadena por algún objetivo de salida HTML. El hecho de que asHTML es una propiedad
perezoso significa que usted puede referirse a sí mismo dentro del cierre por defecto,
ya que no se accede a la propiedad perezoso hasta después de la inicialización se ha
completado y sí se sabe que existen.
El HTMLElement clase proporciona un único inicializador, que tiene un nombre
de argumento y (si lo desea) untexto argumento para inicializar un nuevo
elemento. La clase también define un deinitializer, que imprime un mensaje para
mostrar cuando un HTMLElement se desasigna instancia.
He aquí cómo se utiliza el HTMLElement clase para crear e imprimir una nueva
instancia:
• var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello,
world")
• println(paragraph!.asHTML())
• // imprime "<p> hola, mundo </ p>"  
NOTA
El paragraph variable de arriba se define como un opcional HTMLElement , de
modo que se puede ajustar a nuloa continuación para demostrar la presencia de un
ciclo de referencia fuerte.
Por desgracia, la HTMLElement clase, como está escrito más arriba, crea un fuerte
ciclo de referencia entre unHTMLElement instancia y el cierre empleado para su
defecto asHTML valor. Así es como se ve el ciclo:

  200  
 
Del ejemplo asHTML propiedad se mantiene una fuerte referencia a su cierre. Sin
embargo, debido a que el cierre se refiere a la auto dentro de su cuerpo (como una
forma de referencia self.name y self.text ), el cierre captura auto, lo que
significa que contiene una referencia de nuevo a la fuerte HTMLElement ejemplo. Se
crea un ciclo de referencia fuerte entre los dos. (Para obtener más información acerca de
la captura de los valores en un cierre, consulte Captura de valores .)
NOTA
A pesar de que el cierre se refiere a sí mismo varias veces, sólo capta una fuerte
referencia a la HTMLElementinstancia.
Si establece el párrafo variable nula y romper su fuerte referencia a
la HTMLElement ejemplo, ni el HTMLElementinstancia ni su cierre se desasignan,
debido al ciclo de referencia fuerte:
• párrafo = nil  
Tenga en cuenta que el mensaje en el HTMLElement deinitializer no se imprime, lo
que demuestra que laHTMLElement instancia no se cancela la asignación.

Resolver Ciclos de referencia fuertes para cierres


A resolver un fuerte ciclo de referencia entre un cierre y una instancia de clase
definiendo una lista de capturacomo parte de la definición de la clausura. Una lista de
captura define las reglas para usar en la captura de uno o más tipos de referencia dentro
del cuerpo del cierre. Al igual que con fuertes ciclos de referencia entre dos instancias
de la clase, se declara cada referencia capturado para ser una referencia débil o sin
dueño en lugar de una referencia fuerte. La elección adecuada de débil o sin dueño
depende de las relaciones entre las diferentes partes de su código.
NOTA
Swift requiere que usted escriba self.someProperty o self.someMethod (en
lugar de sólo UnaPropiedad oalgunMetodo ) siempre hace referencia a un
miembro del auto dentro de un cierre. Esto le ayudará a recordar que es posible
capturar auto por accidente.
Definición de una lista de captura
Cada elemento de una lista de captura es un acoplamiento entre el débil o sin
dueño palabra clave con una referencia a una instancia de clase (por
ejemplo, auto o someInstance ). Estos emparejamientos se escriben dentro de un
par de corchetes, separados por comas.

  201  
Coloque la lista de captura antes de la lista de parámetros de un cierre y tipo de retorno
si se les proporciona:
• lazy var someClosure: (Int, String) -> String = {
• [unowned self] (index: Int, stringToProcess: String) -> String in
• // Cuerpo de cierre va aquí  
• }  
Si un cierre no especifica una lista de parámetros o tipo de retorno, ya que pueden ser
inferidos a partir del contexto, coloque la lista de captura en el comienzo del cierre,
seguido por el de palabra clave:
• lazy var someClosure: () -> String = {
• [unowned self] in
• // Cuerpo de cierre va aquí  
• }  
Referencias débiles y sin propietario
Definir una captura en un cierre como una referencia sin dueño cuando el cierre y la
instancia de captura siempre referirse unos a otros, y siempre se desasigna al mismo
tiempo.
Por el contrario, definir una captura como una referencia débil cuando la referencia
capturado puede llegar a ser nula en algún momento en el futuro. Referencias débiles
son siempre de tipo opcional, y se convierten automáticamente a cero cuando se
desasigna la instancia que hacen referencia. Esto le permite comprobar su existencia
dentro del cuerpo del cierre.
NOTA
Si la referencia capturado nunca llegará a ser nula , siempre debe ser capturado como
una referencia sin dueño, en lugar de una referencia débil.
Una referencia sin dueño es el método de captura apropiado utilizar para resolver el
ciclo de referencia fuerte en el HTMLElement ejemplo de antes. He aquí cómo usted
escribe el HTMLElement clase para evitar el ciclo:
• 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) />"
• }

  202  
• }

• init(name: String, text: String? = nil) {
• self.name = name
• self.text = text
• }

• deinit {
• println("\(name) is being deinitialized")
• }

• }
la adición de una lista de captura dentro de la asHTML cierre. En este caso, la lista de
captura es [auto sin dueño] , que significa "auto captura como una referencia sin
dueño en lugar de una referencia fuerte".
Puede crear e imprimir un HTMLElement ejemplo de antes:
• var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello,
world")
• println(paragraph!.asHTML())
• // imprime "<p> hola, mundo </ p>"  
He aquí cómo las referencias se ven con la lista de captura en su lugar:

 
Esta vez, la captura de uno mismo por el cierre es una referencia sin dueño, y no
mantiene una fuerte influencia en la HTMLElement instancia que ha capturado. Si
establece la fuerte referencia del párrafo variable en nil , la HTMLElement se
desasigna ejemplo, como se puede ver desde la impresión de su mensaje deinitializer en
el siguiente ejemplo:
• paragraph = nil
• // Impresiones "p está siendo deinitialized"  
 

  203  
Encadenamiento Opcional

Encadenamiento opcional es un proceso para consultar y llamar a las propiedades,


métodos y subíndices en una opción que en la actualidad podría ser nula . Si la opción
contiene un valor, la propiedad, método o llamada subíndice tiene éxito; si la opción
es nula , la propiedad, método o llamada subíndice retornos nil .Múltiples consultas
pueden ser encadenados juntos, y toda la cadena falla con gracia si cualquier eslabón de
la cadena es nula .
NOTA
Encadenamiento Opcional en Swift es similar a la mensajería nula en Objective-C,
pero de una manera que funcione para cualquier tipo, y que se puede comprobar por el
éxito o el fracaso.
El encadenamiento opcional como alternativa a forzado Unwrapping
Se especifica el encadenamiento opcional mediante la colocación de un signo de
interrogación ( ? ) tras el valor opcional en la que desea llamar a una propiedad, método
o subíndice si el opcional es no nula . Esto es muy similar a la colocación de un signo
de exclamación ( ! ) después de un valor opcional para forzar el desembalaje de su
valor. La principal diferencia es que el encadenamiento opcional falla con gracia cuando
la opción es nula , mientras que desenvolver forzada provoca un error de ejecución
cuando el opcional es nula .
Para reflejar el hecho de que el encadenamiento opcional se puede llamar en
un nulo valor, el resultado de una llamada de encadenamiento opcional es siempre un
valor opcional, incluso si la propiedad, método o subíndice que está consultando
devuelve un valor que no sea opcional. Puede utilizar este valor de retorno opcional
para comprobar si la llamada encadenamiento opcional fue exitosa (opcional regresado
contiene un valor), o no tuvo éxito debido a una nula valor en la cadena (el valor
opcional devuelto es nulo ).
Específicamente, el resultado de una llamada de encadenamiento opcional es del mismo
tipo que el valor de retorno esperado, pero envuelto en una opcional. Una propiedad que
normalmente devuelve un Int devuelve un int? cuando se accede a través de
encadenamiento opcional.
Los próximos fragmentos de código muestran cómo opcional encadenamiento difiere de
desenvolver forzada y le permite comprobar si hay éxito.
En primer lugar, dos clases llamadas Persona y Residencia se definen:
• class Person {
• var residence: Residence?
• }

• class Residence {
• var numberOfRooms = 1
• }
Residence casos tener un único int propiedad llamada numberOfRooms , con un
valor predeterminado de 1 .Person casos tienen un opcional residence propiedad
de tipo Residence? .

  204  
Si crea una nueva persona instancia, su residencia propiedad está
predeterminado inicializa a cero , en virtud de ser opcional. En el siguiente
código, john tiene una residencia valor de la propiedad de nil :
• let john = Person()
Si intenta acceder a la numberOfRooms propiedad de esta persona residencia ,
mediante la colocación de un signo de exclamación después de la residencia para
forzar el desembalaje de su valor, que se activa un error de ejecución, porque no hay
una residencia de valor para desenvolver:
• let roomCount = john.residence!.numberOfRooms
• // Esto provoca un error de ejecución  
El código anterior tiene éxito cuando john.residence tiene un no- nil de valor y
establecerá roomCount a un Intvalor que contiene el número apropiado de
habitaciones. Sin embargo, este código siempre provoca un error de ejecución
cuando la residencia es nula , como se ilustra arriba.
Encadenamiento opcional proporciona una forma alternativa para acceder al valor
de numberOfRooms . Para utilizar el encadenamiento opcional, utilice un signo de
interrogación en lugar del signo de exclamación:
• if let roomCount = john.residence?.numberOfRooms {
• println("John's residence has \(roomCount) room(s).")
• } else {
• println("Unable to retrieve the number of rooms.")
• }
• // imprime "No se puede recuperar el número de
habitaciones."  
Esto le dice Swift para "cadena" en la opción de residencia y la propiedad para
recuperar el valor denumberOfRooms si residencia existe.
Debido a que el intento de acceso numberOfRooms tiene el potencial de fallar, el
intento de encadenamiento opcional devuelve un valor de tipo int? , o
"opcional Int ". Cuando residencia es cero , como en el ejemplo anterior, esto
opcional Int también será nula , para reflejar el hecho de que no fue posible acceder
anumberOfRooms .
Tenga en cuenta que esto es cierto a pesar de que numberOfRooms es un no
opcional Int . El hecho de que se realiza una consulta a través de una cadena opcional
significa que la llamada a numberOfRooms devolverá siempre un int? en lugar de
un int .
Puede asignar una Residencia instancia a john.residence , por lo que ya no
tiene un nulo valor:
• john.residence = Residence()
john.residence ahora contiene un real Residence ejemplo, en lugar
de cero . Si intenta acceder a numberOfRoomscon el mismo encadenamiento
opcional como antes, será ahora devolver un int? que contiene el
defectonumberOfRooms valor de 1 :

  205  
• if let roomCount = john.residence?.numberOfRooms {
• println("John's residence has \(roomCount) room(s).")
• } else {
• println("Unable to retrieve the number of rooms.")
• }
• // Impresiones "residencia de John posee 1 dormitorio (s)."  
Definición de clases de modelos para opcional encadenamiento
Usted puede utilizar el encadenamiento opcional con llamadas a las propiedades,
métodos y subíndices que son más de un nivel de profundidad. Esto le permite desglosar
subpropiedades en modelos complejos de tipos interrelacionados, y para comprobar si
es posible acceder a las propiedades, métodos y subíndices en esas subpropiedades.
Los fragmentos de código a continuación definen cuatro clases de modelo para su uso
en varios ejemplos posteriores, incluyendo ejemplos de encadenamiento opcional
multinivel. Estas clases se expanden sobre lapersona y la Residencia modelo
desde arriba mediante la adición de una habitación y Dirección de clase, con
propiedades asociadas, métodos y subíndices.
La persona clase se define de la misma manera que antes:
• class Person {
• var residence: Residence?
• }
La Residencia de clase es más complejo que antes. Esta vez, la Residencia clase
define una propiedad variable llamada habitaciones , que se inicia con una matriz
vacía de tipo [Sala] :
• class Residence {
• var rooms = [Room]()
• var numberOfRooms: Int {
• return rooms.count
• }
• subscript(i: Int) -> Room {
• get {
• return rooms[i]
• }
• set {
• rooms[i] = newValue
• }
• }
• func printNumberOfRooms() {
• println("The number of rooms is \(numberOfRooms)")
• }

  206  
• var address: Address?
• }
Debido a que esta versión de Residencia almacena una matriz de la
habitación de los casos, sunumberOfRooms propiedad se implementa como una
propiedad calculada, no una propiedad almacenada. El
computarizada numberOfRooms propiedad simplemente devuelve el valor de
la cuenta de la propiedad de lahabitaciones matriz.
Como un atajo para acceder a su habitaciones matriz, esta versión
de Residencia ofrece un subíndice de lectura y escritura que da acceso a la
habitación en el índice se solicita en la salas de matriz.
Esta versión de Residencia también proporciona un método
llamado printNumberOfRooms , que simplemente imprime el número de
habitaciones en la residencia.
Por último, Residencia define una propiedad opcional llamado dirección , con
un tipo de dirección? . LaDirección tipo de clase de esta propiedad se define a
continuación.
La Sala de clase utilizada para la salas de matriz es una clase simple con una
propiedad llamada nombre , y un inicializador para establecer esa propiedad a un
nombre local adecuado:
• class Room {
• let name: String
• init(name: String) { self.name = name }
• }
La última clase en este modelo se llama Dirección . Esta clase tiene tres propiedades
opcionales del tipo de cuerda? . Las dos primeras
propiedades, buildingName y buildingNumber , son formas alternativas para
identificar a un edificio en particular como parte de una dirección. La tercera
propiedad, calle , se utiliza para nombrar la calle para esa dirección:
• class Address {
• var buildingName: String?
• var buildingNumber: String?
• var street: String?
• func buildingIdentifier() -> String? {
• if buildingName != nil {
• return buildingName
• } else if buildingNumber != nil {
• return buildingNumber
• } else {
• return nil
• }
• }
  207  
• }
La Dirección de clase también proporciona un método
llamado buildingIdentifier , que tiene un tipo de retorno de la Cadena? . Este
método comprueba las buildingName y buildingNumber propiedades y
devuelvebuildingName si tiene un valor, o buildingNumber si tiene un valor,
o nil si ni la propiedad tiene un valor.
Acceso a las propiedades A través Opcional encadenamiento
Como se demuestra en Optional Chaining as an Alternative to Forced Unwrapping,
puede utilizar encadenamiento opcional para acceder a una propiedad en un valor
opcional, y para asegurarse de que ese acceso a la propiedad es un éxito.
Utilice las clases definidas anteriormente para crear una nueva persona instancia, y
tratar de acceder a sunumberOfRooms propiedad como antes:
• let john = Person()
• if let roomCount = john.residence?.numberOfRooms {
• println("John's residence has \(roomCount) room(s).")
• } else {
• println("Unable to retrieve the number of rooms.")
• }
• // imprime "No se puede recuperar el número de
habitaciones."  
Debido john.residence es nula , esta llamada de encadenamiento opcional falla
en la misma manera que antes.
También puede tratar de establecer el valor de una propiedad a través de
encadenamiento opcional:
• let someAddress = Address()
• someAddress.buildingNumber = "29"
• someAddress.street = "Acacia Road"
• john.residence?.address = someAddress
En este ejemplo, el intento de establecer la dirección de la propiedad
de john.residence fallará, porquejohn.residence es actualmente nula .
Métodos A través de encadenamiento opcional Calling
Usted puede utilizar el encadenamiento opcional para llamar a un método en un valor
opcional, y para comprobar si ese llamado método es exitoso. Usted puede hacer esto
incluso si ese método no define un valor de retorno.
El printNumberOfRooms método en la Residencia de clase imprime el valor
actual de numberOfRooms . Así es como se ve el método:
• func printNumberOfRooms() {
• println("The number of rooms is \(numberOfRooms)")
• }
Este método no especifica un tipo de retorno. Sin embargo, las funciones y los métodos
con ningún tipo de retorno tienen un tipo de retorno implícita de vacío , como se

  208  
describe en Funciones Sin Valores retornados .Esto significa que devuelven un valor
de () , o una tupla vacía.
Si se llama a este método en un valor opcional con el encadenamiento opcional, tipo de
retorno del método será Vacío? , no vacío , porque los valores de retorno son
siempre de tipo opcional cuando se invocan mediante el encadenamiento opcional. Esto
le permite utilizar un si declaración para comprobar si era posible llamar a
la printNumberOfRooms método, a pesar de que el método no define un valor de
retorno. Compare el valor de retorno de las printNumberOfRooms llaman
contra cero para ver si la llamada al método se ha realizado correctamente:
• if john.residence?.printNumberOfRooms() != nil {
• println("It was possible to print the number of rooms.")
• } else {
• println("It was not possible to print the number of rooms.")
• }
• // imprime "No fue posible imprimir el número de
habitaciones."  
Lo mismo ocurre si se intenta establecer una propiedad a través de encadenamiento
opcional. El ejemplo anterior de Acceso a las propiedades A través Opcional
encadenamiento intenta establecer una dirección devalor
para john.residence , a pesar de que la residencia propiedad
es nula . Cualquier intento de establecer una propiedad a través de encadenamiento
opcional devuelve un valor de tipo Vacío? , lo que le permite comparar
contra cero para ver si la propiedad se ha establecido con éxito:
• if (john.residence?.address = someAddress) != nil {
• println("It was possible to set the address.")
• } else {
• println("It was not possible to set the address.")
• }
• // imprime "No fue posible establecer la dirección."  
•  
Acceso subíndices A través Opcional encadenamiento
Usted puede utilizar el encadenamiento opcional para tratar de recuperar y establecer un
valor de un subíndice en un valor opcional, y para comprobar si esa llamada subíndice
tiene éxito.
NOTA
Cuando acceda a un subíndice en un valor opcional a través de encadenamiento
opcional, se coloca el signo de interrogación antes de los apoyos del subíndice, no
después. El signo de interrogación encadenamiento opcional siempre sigue
inmediatamente después de la parte de la expresión que es opcional.
El siguiente ejemplo intenta recuperar el nombre de la primera habitación en la salas
de gama de lajohn.residence establecimiento mediante el subíndice definida en

  209  
la Residencia de clase. Debidojohn.residence es actualmente nula , la
llamada falla subíndice:
• if let firstRoomName = john.residence?[0].name {
• println("The first room name is \(firstRoomName).")
• } else {
• println("Unable to retrieve the first room name.")
• }
• // imprime "No se puede recuperar el primer nombre de la
sala."  
El signo de interrogación encadenamiento opcional en la presente convocatoria
subíndice se coloca inmediatamente después john.residence , antes de que los
soportes de subíndice, porque john.residence es el valor opcional en el que se está
intentando encadenamiento opcional.
Del mismo modo, se puede tratar de establecer un nuevo valor a través de un subíndice
con el encadenamiento opcional:
• john.residence?[0] = Room(name: "Bathroom")
Este intento de ajuste subíndice también falla, porque la residencia es
actualmente nula .
Si crea y asigna una real Residence instancia a john.residence , con uno o
más Habitación casos en su salas de matriz, puede utilizar
la Residencia subíndice para acceder a los elementos reales de
la habitaciones matriz a través de encadenamiento opcional:
• let johnsHouse = Residence()
• johnsHouse.rooms.append(Room(name: "Living Room"))
• johnsHouse.rooms.append(Room(name: "Kitchen"))
• john.residence = johnsHouse

• if let firstRoomName = john.residence?[0].name {
• println("The first room name is \(firstRoomName).")
• } else {
• println("Unable to retrieve the first room name.")
• }
• // imprime "El primer nombre de la sala es la sala."  
Acceso a los subíndices de Tipo Opcional
Si un subíndice devuelve un valor de tipo opcional, tales como el subíndice clave de
Swift Diccionario tipo-lugar un signo de interrogación después del paréntesis de
cierre del subíndice de la cadena en su valor de retorno opcional:
• var testScores = ["Dave": [86, 82, 84], "Bev": [79, 94, 81]]
• testScores["Dave"]?[0] = 91
• testScores["Bev"]?[0]++

  210  
• testScores["Brian"]?[0] = 72
• // La matriz "Dave" es ahora [91, 82, 84] y la matriz "Bev"
es ahora [80, 94, 81]  
El ejemplo anterior define un diccionario llamado testScores , que contiene dos
pares clave-valor que asignan una cuerda clave para una gran variedad
de Int valores. El ejemplo utiliza el encadenamiento opcional para establecer el primer
elemento de la "Dave" matriz a 91 ; para incrementar el primer elemento de
la "Bev" matriz por 1 ; y para tratar de establecer el primer elemento de una matriz
para una clave de "Brian" . Las dos primeras llamadas a tener éxito, porque
el testScores diccionario contiene las claves para "Dave" y "Bev" . La tercera
llamada falla, porque el testScores diccionario no contiene una clave
para "Brian" .
La vinculación de Múltiples Niveles de encadenamiento
Puede vincular múltiples niveles de encadenamiento opcional para profundizar en las
propiedades, métodos y subíndices más profundo dentro de un modelo. Sin embargo,
múltiples niveles de encadenamiento opcional no añaden más niveles de opcionalidad al
valor devuelto.
Para decirlo de otra manera:
• Si el tipo que está tratando de recuperar no es opcional, se convertirá opcional
debido al encadenamiento opcional.
• Si el tipo que está tratando de recuperar es ya opcional, no se convertirá
en más opcional debido al encadenamiento.
Por lo tanto:
• Si intenta recuperar un Int valor a través de encadenamiento opcional,
un int? siempre se devuelve, no importa cómo se utilizan muchos niveles de
encadenamiento.
• Del mismo modo, si usted trata de recuperar un Int? valor a través de
encadenamiento opcional, unint? siempre se devuelve, no importa cómo se
utilizan muchos niveles de encadenamiento.
El siguiente ejemplo intenta acceder a la calle de la propiedad de la dirección
de la propiedad de laresidencia propiedad de john . Hay dos niveles de
encadenamiento opcional en uso aquí, a través de la cadena de los de
residencia y dirección de las propiedades, las cuales son de tipo opcional:
• if let johnsStreet = john.residence?.address?.street {
• println("John's street name is \(johnsStreet).")
• } else {
• println("Unable to retrieve the address.")
• }
• // imprime "No se puede recuperar la dirección."  
El valor de john.residence actualmente contiene una
válida Residencia instancia. Sin embargo, el valor
dejohn.residence.address es actualmente nula . Debido a esto, la llamada
a john.residence? .Address? .streetfalla.

  211  
Tenga en cuenta que en el ejemplo anterior, usted está tratando de recuperar el valor de
la calle de la propiedad. El tipo de esta propiedad es de cuerda? . El valor de
retorno de john.residence? .Address? .streetes, por tanto, también de
cuerda? , a pesar de que dos niveles de encadenamiento opcional se aplican además
del tipo opcional subyacente de la propiedad.
Si establece un real Dirección instancia como valor
para john.residence.address , y establecer un valor real para los de la
dirección de la calle propiedad, se puede acceder al valor de la calle de la
propiedad a través de encadenamiento opcional multinivel:
• let johnsAddress = Address()
• johnsAddress.buildingName = "The Larches"
• johnsAddress.street = "Laurel Street"
• john.residence!.address = johnsAddress

• if let johnsStreet = john.residence?.address?.street {
• println("John's street name is \(johnsStreet).")
• } else {
• println("Unable to retrieve the address.")
• }
• // Impresiones "nombre de la calle de Juan es la calle
Laurel."  
Tenga en cuenta el uso de un signo de exclamación en la asignación de una instancia de
dirección ajohn.residence.address . El john.residence propiedad tiene
un tipo opcional, y por lo que necesita para desenvolver su valor real con un signo de
exclamación antes de acceder a la residencia de dirección de propiedad.
Encadenar sobre Métodos de Valores de retorno opcionales
El ejemplo anterior muestra cómo recuperar el valor de una propiedad de tipo opcional
mediante el encadenamiento opcional. También puede utilizar el encadenamiento
opcional para llamar a un método que devuelve un valor de tipo opcional, y para la
cadena de valor de retorno de dicho método, si es necesario.
El ejemplo siguiente llama a la Dirección de la
clase buildingIdentifier método a través del encadenamiento opcional. Este
método devuelve un valor del tipo de cuerda? . Como se describió anteriormente, el
tipo de retorno final de este método de llamada después de encadenamiento es también
opcional Cadena? :
• if let buildingIdentifier = john.residence?.address?.buildingIdentifier() {
• println("John's building identifier is \(buildingIdentifier).")
• }
• // Impresiones "identificador edificio de Juan es Los
Alerces."  

  212  
Si desea realizar más de encadenamiento opcional en el valor devuelto por este método,
coloque el signo de interrogación de encadenamiento opcional después paréntesis del
método:
• if let beginsWithThe =
• john.residence?.address?.buildingIdentifier()?.hasPrefix("The") {
• if beginsWithThe {
• println("John's building identifier begins with \"The\".")
• } else {
• println("John's building identifier does not begin with \"The\".")
• }
• }
• // Impresiones "identificador edificio de Juan comienza
con" El "."  
NOTA
En el ejemplo anterior, se coloca el signo de interrogación de encadenamiento
opcional después de los paréntesis, ya que el valor opcional está encadenando en es
el buildingIdentifier valor de retorno del método, y no
el buildingIdentifier método en sí.
 

Tipo de casting

Tipo de casting es una manera de comprobar el tipo de un ejemplo, y / o para tratar esa
instancia como si es una superclase o subclase diferente de algún otro lugar en su propia
jerarquía de clases.
Tipo de calidad en Swift se implementa con el is y as operadores. Estos dos
operadores proporcionan una forma simple y expresiva para comprobar el tipo de un
valor o convertir un valor a un tipo diferente.
También puede utilizar la conversión de tipos para comprobar si un tipo es conforme a
un protocolo, como se describe en Comprobación de Protocolo de Conformidad .

Definir una jerarquía de las clases para la conversión de tipos


Usted puede utilizar la conversión de tipos con una jerarquía de clases y subclases para
comprobar el tipo de una instancia de clase en particular y emita esa instancia a otra
clase dentro de la misma jerarquía. Los tres fragmentos de código siguientes definen
una jerarquía de clases y una matriz que contiene las instancias de esas clases, para su
uso en un ejemplo de la conversión de tipos.
El primer fragmento de código define una nueva clase base llamada MediaItem . Esta
clase proporciona la funcionalidad básica para cualquier tipo de elemento que aparece
en una biblioteca de medios digitales. En concreto, se declara un nombre
de propiedad de tipo Cadena , y un nombre de inicio de inicialización. (Se
supone que todos los elementos multimedia, incluyendo todas las películas y canciones,
tendrán un nombre.)

  213  
• class MediaItem {
• var name: String
• init(name: String) {
• self.name = name
• }
• }
El siguiente fragmento de código define dos subclases de MediaItem . La primera
subclase, Película , encapsula información adicional acerca de una película o una
película. Se añade un director propiedad en la parte superior de la
base MediaItem clase, con un inicializador correspondiente. La segunda
subclase, Canción, añade un artista propiedad y inicializador en la parte superior
de la clase base:
• class Movie: MediaItem {
• var director: String
• init(name: String, director: String) {
• self.director = director
• super.init(name: name)
• }
• }

• class Song: MediaItem {
• var artist: String
• init(name: String, artist: String) {
• self.artist = artist
• super.init(name: name)
• }
• }
El fragmento final, crea una matriz constante llamada biblioteca , que contiene
dos películas instancias y tres canciones casos. El tipo de
la biblioteca matriz se infiere por la inicialización con el contenido de un literal de
matriz. Tipo ortográfico de Swift es capaz de deducir que la película y la
canción tiene una superclase común de MediaItem , y por lo que infiere un tipo
de [MediaItem] para la biblioteca de matriz:
• let library = [
• Movie(name: "Casablanca", director: "Michael Curtiz"),
• Song(name: "Blue Suede Shoes", artist: "Elvis Presley"),
• Movie(name: "Citizen Kane", director: "Orson Welles"),
• Song(name: "The One And Only", artist: "Chesney Hawkes"),

  214  
• Song(name: "Never Gonna Give You Up", artist: "Rick Astley")
• ]
• // Del tipo de "biblioteca" se infiere que [MediaItem]  
Los elementos almacenados en la biblioteca son
todavía Película y Canción casos detrás de las escenas.Sin embargo, si usted iterar
sobre el contenido de esta matriz, los elementos que reciba de vuelta se escriben
como MediaItem , y no como la película o canción . Con el fin de trabajar
con ellos como su tipo nativo, es necesario comprobar su tipo, o abatido a un tipo
diferente, tal como se describe a continuación.
Comprobación Tipo
Utilice el operador de control de tipo ( es ) para comprobar si una instancia es de un
cierto tipo de subclase. El operador de verificación tipo devuelve verdadero si la
instancia es de ese tipo de subclase y falsa si no lo es.
El siguiente ejemplo define dos variables, movieCount y songCount , que cuentan
el número de películas y de canciones casos en la biblioteca de matriz:
• var movieCount = 0
• var songCount = 0

• for item in library {
• if item is Movie {
• ++movieCount
• } else if item is Song {
• ++songCount
• }
• }

• println("Media library contains \(movieCount) movies and \(songCount) songs")
• // Impresiones "Mediateca contiene 2 películas y 3
canciones"  
Este ejemplo recorre en iteración todos los elementos de la biblioteca
de matriz. En cada paso, el para - enbucle establece el elemento constante a la
siguiente MediaItem en la matriz.
Articulo Movie devuelve verdadero si la corriente MediaItem es
una película instancia y falsa si no lo es. Del mismo modo, el artículo es
Canción comprueba si el elemento es una canción instancia. Al final de la para -
en bucle, los valores de movieCount y songCount contienen una cuenta de
cuántas MediaItem se encontraron casos de cada tipo.

Downcasting
Una constante o variable de un cierto tipo de clase pueden referirse en realidad a una
instancia de una subclase detrás de las escenas. ¿Dónde crees que este es el caso, usted

  215  
puede tratar de abatido al tipo subclase con el operador de conversión de
tipos ( como ).
Debido downcasting puede fallar, el operador de conversión de tipos se presenta en dos
formas diferentes.La forma opcional, como? , devuelve un valor opcional del tipo que
está intentando abatido a. La forma forzada, como , intenta los abatidos y fuerza
desenvuelve el resultado como una sola acción compuesto.
Utilice el formulario opcional del operador tipo elenco ( como? ) cuando no está seguro
de si el abatido tendrá éxito. Esta forma de la operadora siempre devolverá un valor
opcional, y el valor será nulo si el abatido no era posible. Esto le permite comprobar
de un abatido éxito.
Utilice la forma forzosa del operador tipo elenco ( como ) sólo cuando esté seguro de
que el abatido siempre tendrá éxito. Esta forma de operador activará un error de
ejecución si se intenta abatido a un tipo de clase incorrecta.
El siguiente ejemplo itera sobre cada MediaItem en la biblioteca , e imprime
una descripción apropiada para cada elemento. Para ello, es necesario acceder a cada
elemento como una verdadera película o canción , y no sólo como
un MediaItem . Esto es necesario a fin de que sea capaz de acceder
al director o artistapropiedad de una película o canción para uso en la
descripción.
En este ejemplo, cada elemento de la matriz puede ser una película , o podría ser
una canción . Usted no sabe de antemano qué clase real a utilizar para cada elemento,
y por lo que es adecuado utilizar el formulario opcional del operador de conversión de
tipos ( como? para comprobar los abatidos cada vez en el bucle):
• for item in library {
• if let movie = item as? Movie {
• println("Movie: '\(movie.name)', dir. \(movie.director)")
• } else if let song = item as? Song {
• println("Song: '\(song.name)', by \(song.artist)")
• }
•  
• // Película: 'Casablanca', dir. Michael Curtiz  
• // Song: "Blue Suede Shoes", de Elvis Presley  
• // Película: 'Ciudadano Kane', dir. Orson Welles  
• // Canción: 'El One And Only', por Chesney Hawkes  
• // Canción: 'Nunca Gonna Give You Up', de Rick Astley  
El ejemplo empieza por intentar abatido el actual artículo como la
película . Debido a que el punto es unMediaItem ejemplo, es posible
que podría ser una película ; igualmente, también es posible que podría ser
una canción , o incluso sólo una base MediaItem . Debido a esta incertidumbre,
el como? forma del operador de conversión de tipo devuelve un opcional valor al
intentar abatido a un tipo de subclase. El resultado de lapartida como
película es del tipo de películas? , o "opcional Movie ".

  216  
Downcasting a Movie falla cuando se aplica a las dos canciones instancias del array
biblioteca. Para hacer frente a esto, el ejemplo anterior utiliza opcional de unión para
comprobar si la opción Movie realidad contiene un valor (es decir, para saber si los
abatidos sucedió.) Esta unión se escribe "opcional artículo si dejar que la
película = as? Película ", que se puede leer como:
"Trate de acceder tema como Película . Si esto tiene éxito, establecer una nueva
constante temporal denominada película con el valor almacenado en la opción de
regresar Movie ".
Si el downcasting tiene éxito, las propiedades de la película se utilizan para
imprimir una descripción de eseMovie ejemplo, incluyendo el nombre de
su director . Un principio similar se utiliza para comprobar si haycanción de los
casos, y para imprimir una descripción apropiada (incluyendo artista nombre)
siempre que una canción se encuentra en la biblioteca.
NOTA
Fundición en realidad no modificar la instancia o cambiar sus valores. La instancia
subyacente sigue siendo el mismo; simplemente se trata y se accede como una instancia
del tipo al que se ha fundido.
Escriba Casting para Todas y AnyObject
Swift proporciona dos alias de tipo especial para trabajar con tipos no específicos:
• AnyObject puede representar una instancia de cualquier tipo de clase.
• Cualquier puede representar una instancia de cualquier tipo en absoluto, aparte
de los tipos de función.
NOTA
Utilice Cualquier y AnyObject sólo cuando se necesita explícitamente el
comportamiento y las capacidades que proporcionan. Siempre es mejor ser específico
acerca de los tipos que se pueden esperar para trabajar con en el código.
AnyObject
Al trabajar con las API de cacao, es común recibir una matriz con un tipo
de [AnyObject] , o "una matriz de valores de cualquier tipo de objeto". Esto se debe
a Objective-C no tiene matrices con tipo de forma explícita.Sin embargo, a menudo se
puede estar seguro sobre el tipo de los objetos contenidos en una gama tan sólo de la
información que tiene sobre la API que proporciona la matriz.
En estas situaciones, puede utilizar la versión forzada del operador de conversión de
tipos ( como ) al abatido cada elemento de la matriz a un tipo de clase más específica
que AnyObject , sin la necesidad de desenvolver opcional.
El ejemplo siguiente define una matriz de tipo [AnyObject] y rellena esta matriz con
tres instancias de lapelícula de clase:
• let someObjects: [AnyObject] = [
• Movie(name: "2001: A Space Odyssey", director: "Stanley Kubrick"),
• Movie(name: "Moon", director: "Duncan Jones"),
• Movie(name: "Alien", director: "Ridley Scott")
• ]
Debido a que esta variedad se sabe que contiene sólo la película de los casos,
usted puede abatido y desenvolver directamente a un no opcional Película con la
versión forzada del operador de conversión de tipos ( como ):

  217  
• for object in someObjects {
• let movie = object as Movie
• println("Movie: '\(movie.name)', dir. \(movie.director)")
• }
• // Película: "2001: Una odisea del espacio ', dir. Stanley
Kubrick  
• // Película: 'Luna', dir. Duncan Jones  
• // Película: 'Alien', dir. Ridley Scott  
Para una forma aún más breve de este bucle, abatido el someObjects matriz a un tipo
de [Vídeo] en lugar de downcasting cada elemento:
• for movie in someObjects as [Movie] {
• println("Movie: '\(movie.name)', dir. \(movie.director)")
• }
• // Película: "2001: Una odisea del espacio ', dir. Stanley
Kubrick  
• // Película: 'Luna', dir. Duncan Jones  
• // Película: 'Alien', dir. Ridley Scott  
 
Cualquier (Any)
He aquí un ejemplo del uso de Cualquier trabajar con una mezcla de diferentes tipos,
incluyendo los tipos no-clase. El ejemplo crea una matriz denominada cosas , que
puede almacenar valores de tipo Cualquier :
• var things = [Any]()

• things.append(0)
• things.append(0.0)
• things.append(42)
• things.append(3.14159)
• things.append("hello")
• things.append((3.0, 5.0))
• things.append(Movie(name: "Ghostbusters", director: "Ivan Reitman"))
La things matriz contiene dos Int valores, dos dobles valores, una Cadena de
valor, una tupla de tipo (Doble, doble) , y la película "Los Cazafantasmas",
dirigida por Ivan Reitman.
Puede utilizar los is y as operadores en un switch de casos de declaración para
descubrir el tipo específico de una constante o variable que sólo es conocida como de
tipo Any o AnyObject . El siguiente ejemplo itera sobre los elementos de
la things array y consulta el tipo de cada elemento con un switch

  218  
comunicado. Varios de los switch de los casos de declaración de unir su valor
coincidente con una constante del tipo especificado para permitir su valor a imprimir:
• for thing in things {
• switch thing {
• case 0 as Int:
• println("zero as an Int")
• case 0 as Double:
• println("zero as a Double")
• case let someInt as Int:
• println("an integer value of \(someInt)")
• case let someDouble as Double where someDouble > 0:
• println("a positive double value of \(someDouble)")
• case is Double:
• println("some other double value that I don't want to print")
• case let someString as String:
• println("a string value of \"\(someString)\"")
• case let (x, y) as (Double, Double):
• println("an (x, y) point at \(x), \(y)")
• case let movie as Movie:
• println("a movie called '\(movie.name)', dir. \(movie.director)")
• default:
• println("something else")
• }
• }
•  
• // Cero como Int  
• // Cero como un doble  
• // Un valor entero de 42  
• // Un doble valor positivo de 3.14159  
• // Un valor de cadena de "hola"  
• // Una (x, y) en el punto 3.0, 5.0  
• // Una película llamada 'Ghostbusters', dir. Ivan Reitman  
NOTA
Los casos de un interruptor de uso Declaración de la versión forzada del
operador de conversión de tipos (como , no como? ) para comprobar y fundido a un
tipo específico. Esta comprobación es siempre seguro dentro del contexto de
un interruptor de declaración de caso.

  219  
Tipos anidados

Las enumeraciones son creadas a menudo para apoyar a una clase específica o la
funcionalidad de la estructura. Del mismo modo, puede ser conveniente definir clases y
estructuras de utilidad puramente para su uso en el contexto de un tipo más
complejo. Para lograr esto, Swift le permite definir tipos anidados , por el que usted
nido apoyar las enumeraciones, las clases y las estructuras dentro de la definición del
tipo que soportan.
Para anidar un tipo dentro de otro tipo, escribir su definición dentro de las llaves
externas del tipo que soporta.Los tipos pueden ser anidados a tantos niveles como son
obligatorios.
Tipos anidados en Acción
El ejemplo siguiente define una estructura llamada BlackjackCard , que modela una
tarjeta de juego tal como se utiliza en el juego de Blackjack. El BlackJack estructura
contiene dos tipos de enumeración anidados llamados Traje y Rango .
En el Blackjack, las cartas Ace tienen un valor de uno u once. Esta característica está
representada por una estructura llamada Valores , que está anidado dentro
del rango de enumeración:
• struct BlackjackCard {
•  
• //  Enumeración  Traje  anidada  
• enum Suit: Character {
• case Spades = "♠", Hearts = "♡", Diamonds = "♢", Clubs = "♣"
• }

• //  Anidada  Rango  enumeración  
• enum Rank: Int {
• case Two = 2, Three, Four, Five, Six, Seven, Eight, Nine, Ten
• case Jack, Queen, King, Ace
• struct Values {
• let first: Int, second: Int?
• }
• var values: Values {
• switch self {
• case .Ace:
• return Values(first: 1, second: 11)
• case .Jack, .Queen, .King:
• return Values(first: 10, second: nil)
• default:
• return Values(first: self.toRaw(), second: nil)

  220  
• }
• }
• }
•  
• //  BlackjackCard  propiedades  y  métodos  
• let rank: Rank, suit: Suit
• var description: String {
• var output = "suit is \(suit.toRaw()),"
• output += " value is \(rank.values.first)"
• if let second = rank.values.second {
• output += " or \(second)"
• }
• return output
• }
• }
El suit enumeración describe los cuatro juegos de la tarjeta de juego comunes, junto
con una prima de caracteres valor para representar a su símbolo.
El rango de enumeración describe las trece posibles filas de tarjetas de juego, junto
con una prima Int valor para representar a su valor nominal. (Esta prima Int valor no
se utiliza para la Jota, Reina, Rey y As de tarjetas.)
Como se mencionó anteriormente, el rango de enumeración define una estructura
anidada adicional de sus propios, llamados valores . Esta estructura encapsula el
hecho de que la mayoría de las tarjetas tienen un valor, pero la tarjeta Ace tiene dos
valores. El Valores estructura define dos propiedades para representar esto:
• primero , de tipo Int
• segundo , de tipo Int? , o "opcional Int "
Rango también define una propiedad calculada, valores , que devuelve una
instancia de la Valores estructura.Esta propiedad computarizada considera el rango
de la tarjeta y se inicializa un nuevo Valores instancia con los valores adecuados en
función de su rango. Utiliza valores especiales para Jack , Reina , Rey y As . Para
las tarjetas numéricas, utiliza prima del rango Int valor.
El BlackjackCard estructura en sí tiene dos propiedades- rango y suit. También
define una propiedad calculada denominada descripción , que utiliza los valores
almacenados en rango y suit para construir una descripción del nombre y el valor
de la tarjeta. La descripción de propiedad utiliza opcional vinculante para
comprobar si hay un segundo valor a mostrar, y si es así, inserta descripción adicional
detallada para ese segundo valor.
Debido BlackjackCard es una estructura sin inicializadores personalizados, tiene un
inicializador implícito miembro por miembro, como se describe en miembro por
miembro Inicializadores de Estructura Tipos . Usted puede utilizar este inicializador
para inicializar una nueva constante llamados theAceOfSpades :

  221  
• let theAceOfSpades = BlackjackCard(rank: .Ace, suit: .Spades)
• println("theAceOfSpades: \(theAceOfSpades.description)")
• //  imprime  "theAceOfSpades:  traje  está  ♠,  el  valor  es  1  o  11"  
A pesar de Rango y Suit se anidan dentro BlackjackCard , su tipo se puede
inferir a partir del contexto, por lo que la inicialización de esta instancia es capaz de
referirse a los miembros de la enumeración de sus nombres de los miembros
( .ace y .Spades ) solos. En el ejemplo anterior, la descripción de la
propiedad informa correctamente que el as de espadas tiene un valor de 1 o 11 .
En referencia a los tipos anidados
Para utilizar un tipo anidado fuera de su contexto definición, preceda su nombre con el
nombre del tipo que está anidado dentro:
• let heartsSymbol = BlackjackCard.Suit.Hearts.toRaw()
• //  HeartsSymbol  es  "♡"  
Para el ejemplo anterior, esto permite que los nombres
de Traje , Rango y valores que se mantiene deliberadamente corto, porque sus
nombres son, naturalmente, calificados por el contexto en el que se definen.
 

Extensiones

Extensiones de añadir nueva funcionalidad a una clase, estructura o tipo de enumeración


existente. Esto incluye la capacidad de ampliar los tipos para los que no tiene acceso al
código fuente original (conocido como el modelado retroactiva ). Las extensiones son
similares a categorías en Objective-C. (A diferencia de las categorías de Objective-C,
extensiones Swift no tienen nombres.)
Extensiones en Swift puede:
• Agregar propiedades calculadas y propiedades estáticas calculadas
• Definir los métodos de instancia y métodos de tipo
• Proporcionar nuevos inicializadores
• Definir subíndices
• Definir y utilizar nuevos tipos anidados
• Haz un tipo existente se ajusta a un protocolo
NOTA
Las extensiones pueden añadir nuevas funcionalidades a un tipo, pero no pueden
reemplazar la funcionalidad existente.
Sintaxis Extensión
Declarar extensiones con la extensión de la palabra clave:
• extension SomeType {
• // Nueva funcionalidad para añadir a SomeType va aquí  
• }  
Una extensión puede extender un tipo existente para que adopte uno o más
protocolos. Cuando este es el caso, los nombres de protocolo se escriben exactamente
de la misma manera que para una clase o estructura:
• extension SomeType: SomeProtocol, AnotherProtocol {
  222  
• // Implementación de los requisitos del protocolo va aquí  
• }  
Adición de conformidad protocolo de esta manera se describe en Añadiendo Protocolo
de Conformidad con una extensión .
NOTA
Si se define una extensión para agregar nueva funcionalidad a un tipo existente, la
nueva funcionalidad estará disponible en todas las instancias existentes de ese tipo,
incluso si se hubieran creado antes se definió la extensión.
Propiedades calculadas
Las extensiones pueden añadir propiedades de instancia calculados y propiedades de
tipo calculados a los tipos existentes. Este ejemplo añade cinco propiedades de la
instancia computarizada para incorporado de Swift doble tipo, para proporcionar
soporte básico para trabajar con unidades de distancia:
• 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
• println("One inch is \(oneInch) meters")
• // Impresiones "Una pulgada es 0.0254 metros"  
• let threeFeet = 3.ft
• println("Three feet is \(threeFeet) meters")
• // grabados "Tres pies es ,914399970739201 metros"  
Estas propiedades calculadas que expresan un doble valor debe ser considerado como
una cierta unidad de longitud. A pesar de que se implementan como propiedades
calculadas, los nombres de estas propiedades se pueden adjuntar a un valor literal de
coma flotante con la sintaxis con punto, como una manera de utilizar ese valor literal
para realizar las conversiones de distancia.
En este ejemplo, un doble valor de 1,0 se considera que representa ", uno
meter". Esta es la razón por la mpropiedad calculada vuelve auto expresión -el 1.m se
considera para calcular un doble valor de 1.0 .
Otras unidades requieren alguna conversión para ser expresado como un valor medido
en metros. Un kilómetro es el mismo que 1.000 metros, por lo que el km propiedad
calculado multiplica el valor por 1_000.00para convertir en un número expresado en
metros. Del mismo modo, hay 3,28024 pies de un metro, y así elft propiedad
computarizada divide el subyacente doble valor por 3.28024 , para convertirlo de
pies a metros.

  223  
Estas propiedades se calcula las propiedades de sólo lectura, por lo que se expresan sin
el get palabra clave, por razones de brevedad. Su valor de retorno es de tipo doble , y
se puede utilizar en cálculos matemáticos, cuando ese doble se acepta:
• let aMarathon = 42.km + 195.m
• println("A marathon is \(aMarathon) meters long")
• // imprime "Un maratón es 42,195.0 metros de largo"  
NOTA
Las extensiones pueden añadir nuevas propiedades calculadas, pero no pueden agregar
propiedades almacenadas, o añadir observadores de propiedad de las propiedades
existentes.

Inicializadores
Las extensiones pueden añadir nuevos inicializadores de los tipos existentes. Esto le
permite ampliar a otros tipos de aceptar sus propios tipos personalizados como
parámetros inicializadores, o para proporcionar opciones de inicialización adicionales
que no se incluyeron como parte de la implementación original del tipo.
Las extensiones pueden añadir nuevos inicializadores de conveniencia a una clase, pero
no pueden agregar inicializadores o deinitializers nuevos designados a una
clase. Inicializadores y deinitializers designados siempre deben ser proporcionados por
la implementación original de la clase.
NOTA
Si utiliza una extensión para añadir un inicializador para un tipo de valor que
proporciona valores predeterminados para todas las propiedades guardadas y no define
ningún inicializadores personalizados, puede llamar al inicializador por defecto y
inicializador miembro por miembro para ese tipo de valor dentro de inicializador de su
extensión.
Este no sería el caso si hubiera escrito el inicializador como parte de la implementación
original del tipo de valor, como se describe en Inicializador Delegación para tipos de
valor .
El ejemplo siguiente define una costumbre Rect estructura para representar un
rectángulo geométrico. El ejemplo también define dos estructuras de apoyo
llamada Tamaño y Point , los cuales proporcionan valores por defecto de 0,0 para
todas sus propiedades:
• 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()
• }

  224  
Debido a que el Rect estructura proporciona valores predeterminados para todas sus
propiedades, que recibe un inicializador por defecto y un inicializador de miembro por
miembro automáticamente, como se describe enInicializadores predeterminados . Estos
inicializadores pueden ser utilizados para crear nuevas Rect casos:
• let defaultRect = Rect()
• let memberwiseRect = Rect(origin: Point(x: 2.0, y: 2.0),
• size: Size(width: 5.0, height: 5.0))
Puede ampliar la Rect estructura para proporcionar un inicializador adicional que toma
un punto central específico y tamaño:
• 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)
• }
• }
Este nuevo inicializador comienza calculando un punto de origen adecuado en función
de la proporcionadacentro punto y tamaño valor. El inicializador luego llama de la
estructura automática inicializador miembro por miembro init (origen: tamaño
:) , que almacena los nuevos valores de origen y tamaño en las propiedades adecuadas:
• let centerRect = Rect(center: Point(x: 4.0, y: 4.0),
• size: Size(width: 3.0, height: 3.0))
• // Origen de centerRect es (2.5, 2.5) y su tamaño es (3.0,
3.0)  
NOTA
Si usted proporciona un nuevo inicializador con una extensión, usted sigue siendo
responsable de asegurarse de que cada instancia se inicializa totalmente una vez que el
inicializador completa.
Métodos
Las extensiones pueden añadir nuevos métodos de instancia y métodos de tipo de los
tipos existentes. El ejemplo siguiente añade un nuevo método de instancia
denominado repeticiones a la Int tipo:
• extension Int {
• func repetitions(task: () -> ()) {
• for i in 0..<self {
• task()
• }
• }
• }

  225  
El repeticiones método toma un único argumento de tipo () -> () , lo que
indica una función que no tiene parámetros y no devuelve un valor.
Después de definir esta extensión, puede llamar al repeticiones método en
cualquier número entero para realizar una tarea que muchas veces:
• 3.repetitions({
• println("Hello!")
• })
• // ¡Hola!  
• // ¡Hola!  
• // ¡Hola!  
Utilice arrastrando sintaxis de cierre para realizar la llamada más sucinta:
• 3.repetitions {
• println("Goodbye!")
• }
• // ¡Adiós!  
• // ¡Adiós!  
• // ¡Adiós!  
 
Mutando Métodos de instancia
Los métodos de instancia añaden con una extensión también se puede modificar
(o mutar ) la propia instancia. Estructura y métodos de enumeración que modifican uno
mismo o sus propiedades deben marcar el método de instancia como la mutación ,
al igual que la mutación de los métodos de una implementación original.
El ejemplo siguiente añade un nuevo método mutante llamada plaza de
Swift Int tipo, que las plazas del valor original:
• extension Int {
• mutating func square() {
• self = self * self
• }
• }
• var someInt = 3
• someInt.square()
• // SomeInt es ahora 9  
•  
Los subíndices
Las extensiones pueden añadir nuevos subíndices para un tipo existente. En este
ejemplo se agrega un subíndice entero a built-in de Swift Int tipo. Este
subíndice [n] devuelve los dígitos decimales n en lugares de la derecha del número:
• 123456789 [0] devuelve 9
• 123456789 [1] devuelve 8

  226  
... Etcétera:
• extension Int {
• subscript(var digitIndex: Int) -> Int {
• var decimalBase = 1
• while digitIndex > 0 {
• decimalBase *= 10
• --digitIndex
• }
• return (self / decimalBase) % 10
• }
• }
• 746381295[0]
• // returns 5
• 746381295[1]
• // returns 9
• 746381295[2]
• // returns 2
• 746381295[8]
• // returns 7
Si el Int valor no tiene suficientes dígitos para el índice solicitado, la aplicación
devuelve el subíndice 0 , como si el número había sido rellenado con ceros a la
izquierda:
• 746381295 [ 9 ]  
• // devuelve 0, que si hubiera solicitado:  
• 0746381295 [ 9 ]  
 
Tipos anidados
Las extensiones pueden añadir nuevos tipos anidados a clases, estructuras y
enumeraciones existentes:
• extension Int {
• enum Kind {
• case Negative, Zero, Positive
• }
• var kind: Kind {
• switch self {
• case 0:
• return .Zero

  227  
• case let x where x > 0:
• return .Positive
• default:
• return .Negative
• }
• }
• }
En este ejemplo se agrega una nueva enumeración anidada a Int . Esta enumeración,
llamado Kind , expresa el tipo de número que un número entero particular
representa. Específicamente, expresa si el número es negativo, cero o positivo.
Este ejemplo también añade una nueva propiedad calculada instancia para Int ,
llamado tipo , que devuelve el apropiado Kind miembro de la enumeración de ese
entero.
La enumeración anidada ahora se puede utilizar con cualquier Int valor:
• func printIntegerKinds(numbers: [Int]) {
• for number in numbers {
• switch number.kind {
• case .Negative:
• print("- ")
• case .Zero:
• print("0 ")
• case .Positive:
• print("+ ")
• }
• }
• print("\n")
• }
• printIntegerKinds([3, 19, -27, 0, -6, 0, 7])
• // Impresiones "+ + - 0 - 0 +"  
Esta función, printIntegerKinds , toma una matriz de entrada de Int valores y
itera sobre esos valores, a su vez. Para cada número entero en la matriz, la función
considera el tipo calculado propiedad por ese número entero, e imprime una
descripción apropiada.
NOTA
number.kind ya se sabe que es de tipo Int.Kind . Debido a esto, todos
los Int.Kind valores de los miembros se puede escribir en forma abreviada en el
interior del interruptor de la declaración, como negativa es más
que Int.Kind.Negative .
 

  228  
Protocolos

Un protocolo define un plano de los métodos, propiedades y otros requisitos que se


adapten a una tarea o un pedazo de funcionalidad particular. El protocolo no
proporciona realmente una implementación de cualquiera de estos requisitos, que sólo
describe lo que una aplicación se verá así. El protocolo puede ser adoptado por una
clase, estructura o enumeración para proporcionar una implementación real de esos
requisitos. Cualquier tipo que satisfaga los requisitos de un protocolo se dice
que conforme a dicho protocolo.
Los protocolos pueden requerir que se ajusten tipos tienen propiedades específicas
ejemplo, los métodos ejemplo, los métodos de tipo, operadores y subíndices.
Sintaxis Protocolo
Usted define los protocolos de una manera muy similar a las clases, estructuras y
enumeraciones:
• protocol SomeProtocol {
• // protocol definition goes here
• }
Tipos personalizados afirman que adopten un protocolo particular poniendo el nombre
del protocolo después del nombre del tipo, separados por dos puntos, como parte de su
definición. Protocolos pueden aparecer múltiples, y están separadas por comas:
• struct SomeStructure: FirstProtocol, AnotherProtocol {
• //  Estructura  de  definición  va  aquí  
• }  
Si una clase tiene una superclase, anote el nombre de la superclase antes de cualquier
protocolo de que adopte, seguido de una coma:
• class SomeClass: SomeSuperclass, FirstProtocol, AnotherProtocol {
• AnotherProtocol {  
• //  Definición  de  clase  va  aquí  
• }  
Requisitos de Propiedad
Un protocolo puede requerir cualquier tipo conforme a proporcionar una propiedad de
instancia o tipo de propiedad con un nombre y un tipo particular. El protocolo no
especifica si la propiedad debe ser una propiedad almacenado o una computado-
propiedad sólo especifica el nombre de la propiedad requerida y el tipo. El protocolo
también especifica si cada propiedad debe ser gettable o gettable y ajustable.
Si un protocolo requiere una propiedad de ser obtenibles y configurable, que el requisito
de propiedad no puede ser satisfecha por una propiedad almacenada constante o una
propiedad calculada de sólo lectura. Si el protocolo sólo requiere de una propiedad para
ser gettable, el requisito puede cumplirse mediante cualquier tipo de propiedad, y es
válida para la propiedad de ser también ajustable si esto es útil para su propio código.
Requisitos de propiedad siempre se declaran como propiedades de las variables, el
prefijo de la var palabra clave. Propiedades getTable y ajustables se indican por

  229  
escrito {get set} después de su declaración de tipo, y las propiedades getTable se
indican por escrito {get} .
• protocol SomeProtocol {
• var mustBeSettable: Int { get set }
• var doesNotNeedToBeSettable: Int { get }
• }
Siempre requisitos de propiedades de tipo prefijo con la clase de palabras clave
cuando se defina en un protocolo. Esta norma se refiere a pesar de que los requisitos de
propiedades de tipo van precedidos de laestática palabra clave cuando se
implementa una estructura o enumeración:
• protocol AnotherProtocol {
• class var someTypeProperty: Int { get set }
• }
He aquí un ejemplo de un protocolo con un solo requisito de propiedad de instancia:
• protocol FullyNamed {
• var fullName: String { get }
• }
El FullyNamed protocolo requiere un tipo de conformación para proporcionar un
nombre totalmente calificado.El protocolo no especifica nada acerca de la naturaleza del
tipo de conformación-sólo especifica que el tipo debe ser capaz de proporcionar el
nombre completo por sí mismo. El protocolo establece que cualquierFullyNamed tipo
debe tener una propiedad de instancia denominada gettable fullName , que es del
tipo de cuerda .
He aquí un ejemplo de una estructura simple que adopta y se ajusta a
la FullyNamed protocolo:
• struct Person: FullyNamed {
• var fullName: String
• }
• let john = Person(fullName: "John Appleseed")
• //  John.fullName  es  "John  Appleseed"  
Este ejemplo define una estructura llamada persona , lo que representa una persona
llamada específica. Se afirma que adopta la FullyNamed protocolo como parte de la
primera línea de su definición.
Cada instancia de persona tiene una sola propiedad almacenado
llamado fullName , que es del tipo de cuerda .Esto coincide con el único requisito
de la FullyNamed protocolo, y significa que la persona ha cumplido
correctamente con el protocolo. (Swift informa de un error en tiempo de compilación si
un requisito de protocolo no se ha cumplido.)
Aquí hay una clase más compleja, que también adopta y se ajusta a
la FullyNamed protocolo:
• class Starship: FullyNamed {

  230  
• 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
• }
• }
• var ncc1701 = Starship(name: "Enterprise", prefix: "USS")
• //  Ncc1701.fullName  es  "USS  Enterprise"  
Esta clase implementa la fullName requisito de propiedad como de sólo lectura
computarizada-propiedad de una nave espacial. Cada Starship instancia de clase
almacena una obligatoria nombre y un opcional de
prefijo . El fullName propiedad utiliza el prefijo de valor si existe, y
antepone al comienzo de nombre para crear un nombre completo de la nave.
Requisitos del método
Protocolos específicos pueden requerir métodos de instancia y métodos de tipos que
llevará a cabo conforme tipos. Estos métodos están escritos como parte de la definición
del protocolo de la misma forma que para los métodos de instancia y de tipo normales,
pero sin llaves o un cuerpo de método. Parámetros variadic están permitidos, sujetos a
las mismas reglas que para los métodos normales.
NOTA
Protocolos utilizan la misma sintaxis que los métodos normales, pero no se les permite
especificar valores predeterminados para los parámetros del método.
Al igual que con los requisitos de propiedades de tipo, siempre se anteponga requisitos
del método de tipo con la clase de palabras clave cuando se definen en un
protocolo. Esto es cierto a pesar de que los requisitos del método de tipo van precedidos
de la estática palabra clave cuando se implementa una estructura o enumeración:
• protocolo SomeProtocol {  
• clase func someTypeMethod ()  
• }  
El ejemplo siguiente define un protocolo con un solo requisito método de instancia:
• protocol SomeProtocol {
• class func someTypeMethod()
• }
Este protocolo, RandomNumberGenerator , requiere ningún tipo de ajuste a tener
un método de instancia denominado aleatorio , que devuelve un doble valor cada
vez que se le llama. Aunque no se especifica como parte del protocolo, se supone que
este valor será un número desde 0,0 hasta (pero no incluyendo) 1.0 .

  231  
El RandomNumberGenerator protocolo no hace ninguna suposición sobre cómo se
va a cada número aleatorio generado-simplemente requiere que el generador para
proporcionar una forma estándar para generar un nuevo número aleatorio.
Aquí hay una implementación de una clase que adopta y se ajusta a
la RandomNumberGenerator protocolo. Esta clase implementa un algoritmo
generador de números pseudoaleatorios conocido como un generador de congruencia
lineal :
• class LinearCongruentialGenerator: RandomNumberGenerator {
• var lastRandom = 42.0
• let m = 139968.0
• let a = 3877.0
• let c = 29573.0
• func random() -> Double {
• lastRandom = ((lastRandom * a + c) % m)
• return lastRandom / m
• }
• }
• let generator = LinearCongruentialGenerator()
• println("Here's a random number: \(generator.random())")
• //  Impresiones  "Aquí  está  un  número  aleatorio:  0.37464991998171"  
• println("And another one: \(generator.random())")
• //  imprime  "y  otro:  ,729023776863283"  
 
Requisitos del método Mutating
A veces es necesario un método para modificar (o mutar ) la instancia al que
pertenece. Para los métodos de instancia sobre los tipos de valor (es decir, estructuras y
enumeraciones) se coloca el mutando palabra clave antes de un método func palabra
clave para indicar que se permite que el método para modificar la instancia que
pertenece y / o propiedades de esa instancia. Este proceso se describe en Modificación
de tipos de valor desde dentro de los métodos de instancia .
Si se define un método requisito instancia del protocolo que se destina a mutar
instancias de cualquier tipo que se adopta el protocolo, marque el método con
la mutación de la palabra clave como parte de la definición del protocolo. Esto
permite que las estructuras y enumeraciones para adoptar el protocolo y el
cumplimiento de dicho requisito método.
NOTA
Si marca un método requisito instancia del protocolo como la mutación , no es
necesario escribir la mutación de la palabra clave al escribir una implementación de
ese método para una clase. La mutación de la palabra clave sólo se utiliza por las
estructuras y enumeraciones.
El ejemplo siguiente define un protocolo llamado togglable , que define un único
método de instancia llamado requisito de palanca . Como su nombre indica,
  232  
la toggle método está pensado para cambiar o invertir el estado de cualquier tipo de
conformación, por lo general mediante la modificación de una propiedad de ese tipo.
La toggle método está marcado con el mutando palabra clave como parte de
la togglable definición de protocolo, para indicar que se espera que el método para
mutar el estado de una instancia conforme cuando se le llama:
• protocol Togglable {
• mutating func toggle()
• }
Si implementa la togglable protocolo para una estructura o enumeración, que
estructura o enumeración pueden ajustarse al protocolo al proporcionar una
implementación de la palanca método que también se marca como mutando .
El ejemplo siguiente define una enumeración denominada OnOffSwitch . Esta
enumeración alterna entre dos estados, indicados por los casos de
enumeración On y Off . La enumeración de toggle aplicación se marca
como mutante , para que coincida con la togglable requisitos de protocolo:
• 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  es  ahora  igual  a  .On  
Requisitos inicializador
Los protocolos pueden requerir inicializadores específicos a ser implementados por
tipos conforme. Usted escribe estos inicializadores como parte de la definición del
protocolo de la misma manera que para los inicializadores normales, pero sin llaves o
un órgano inicializador:
• protocol SomeProtocol {
• init(someParameter: Int)
• }

  233  
Las implementaciones de clase de Requisitos Protocolo inicializador
Puede aplicar un requisito de inicialización de protocolo en una clase de conformación,
ya sea como un inicializador designado o un inicializador de conveniencia. En ambos
casos, debe marcar la implementación inicializador con la requerida modificador:
• class SomeClass: SomeProtocol {
• required init(someParameter: Int) {
• //  Aplicación  inicializador  va  aquí  
• }  
• }  
El uso del required modificador garantiza que usted proporciona una
implementación explícita o heredada del requisito de inicialización de todas las
subclases de la clase de conformación, de tal manera que también cumplen con el
protocolo.
Para obtener más información sobre los inicializadores necesarios,
consulte Inicializadores obligatorios .
NOTA
No es necesario marcar las implementaciones de inicializador protocolo con
la required modificador sobre las clases que están marcados con
el último modificador, porque las clases finales no pueden ser subclases. Para más
información sobre el último modificador, consulte Prevención de anulaciones .
Si una subclase sobreescribe un inicializador designado de una superclase, y también
implementa un requisito inicializador juego de un protocolo, marque la aplicación
inicializador tanto con los requeridos yanular modificadores:
• protocol SomeProtocol {
• init()
• }

• class SomeSuperClass {
• init() {
• //  Aplicación  inicializador  va  aquí  
• }  
• }  
•  
• class SomeSubClass: SomeSuperClass, SomeProtocol {
• //  "Necesaria"  de  conformidad  SomeProtocol;  "Anular"  de  SomeSuperClass  
• required override init() {
• //  Aplicación  inicializador  va  aquí  
• }  
• }  

  234  
Protocolos como los tipos (Protocols as Types)

Protocolos en realidad no implementan ninguna funcionalidad a sí mismos. No obstante,


cualquier protocolo se crea se convertirá en un tipo de pleno derecho para el uso en el
código.
Debido a que es un tipo, puede utilizar un protocolo en muchos lugares donde se
permiten otros tipos, incluyendo:
• Como un tipo de parámetro o tipo de retorno de una función, método o inicializador
• A medida que el tipo de una constante, una variable o propiedad
• Como el tipo de elementos en una matriz, diccionario, u otro recipiente
NOTA
Debido a que los protocolos son tipos, comenzará sus nombres con una letra mayúscula
(como FullyNamed yRandomNumberGenerator ) para que coincida con los
nombres de otros tipos en Swift (como int , cuerdas ydoble ).
He aquí un ejemplo de un protocolo que se utiliza como un tipo:
• class Dice {
• let sides: Int
• let generator: RandomNumberGenerator
• init(sides: Int, generator: RandomNumberGenerator) {
• self.sides = sides
• self.generator = generator
• }
• func roll() -> Int {
• return Int(generator.random() * Double(sides)) + 1
• }
• }
En este ejemplo se define una nueva clase llamada dados , lo que representa un n -
sided dados para su uso en un juego de mesa. Dados los casos tienen una propiedad de
entero llamado lados , lo que representa el número de lados que tienen, y una
propiedad llamada generador , que proporciona un azar generador de números desde
el que crear los valores dados.
El generador de la propiedad es de tipo RandomNumberGenerator . Por lo
tanto, usted puede configurarlo para que una instancia de cualquier tipo que adopta
el RandomNumberGenerator protocolo. Nada más se requiere de la instancia que
se asigna a esta propiedad, a excepción de que la instancia debe adoptar
elRandomNumberGenerator protocolo.
Dados también tiene un inicializador, para establecer su estado inicial. Este
inicializador tiene un parámetro llamado generador , que también es de
tipo RandomNumberGenerator . Puede pasar un valor de cualquier tipo de
conformación en este parámetro cuando se inicializa un nuevo Dados instancia.
Dados proporciona un método de instancia, rodillo , que devuelve un valor entero
entre 1 y el número de lados de los dados. Este método llama del
generador aleatorio método para crear un nuevo número aleatorio

  235  
entre 0,0 y 1,0 , y utiliza este número aleatorio para crear un valor tirada de los dados
dentro del rango correcto. Debido a que el generador se conoce a
adoptar RandomNumberGenerator , es la garantía de tener unazar método a
llamar.
Así es como el de los dados clase se puede utilizar para crear un dado de seis caras
con unLinearCongruentialGenerator instancia como su generador de
números aleatorios:
• var d6 = Dice(sides: 6, generator: LinearCongruentialGenerator())
• for _ in 1...5 {
• println("Random dice roll is \(d6.roll())")
• }
• //  Tirada  de  dados  al  azar  es  de  3  
• //  Tirada  de  dados  al  azar  es  de  5  
• //  Tirada  de  dados  al  azar  es  de  4  
• //  Tirada  de  dados  al  azar  es  de  5  
• //  Tirada  de  dados  al  azar  es  de  4  
•  
Delegación
Delegación es un patrón de diseño que permite a una clase o estructura en mano fuera
(o delegado ) algunas de sus responsabilidades a una instancia de otro tipo. Este patrón
de diseño se implementa mediante la definición de un protocolo que encapsula las
responsabilidades delegadas, de tal manera que un tipo de conformación (conocida
como delegado) está garantizado para proporcionar la funcionalidad que ha sido
delegada. Delegación se puede utilizar para responder a una acción en particular, o para
recuperar datos de una fuente externa sin necesidad de conocer el tipo subyacente de esa
fuente.
El siguiente ejemplo define dos protocolos para el uso con los dados basados en juegos
de mesa:
• protocol DiceGame {
• var dice: Dice { get }
• func play()
• }
• protocol DiceGameDelegate {
• func gameDidStart(game: DiceGame)
• func game(game: DiceGame, didStartNewTurnWithDiceRoll diceRoll: Int)
• func gameDidEnd(game: DiceGame)
• }
El DiceGame protocolo es un protocolo que puede ser adoptado por cualquier juego
que consiste en dados. ElDiceGameDelegate protocolo puede ser adoptado por
cualquier tipo para seguir el progreso de un DiceGame .

  236  
Aquí hay una versión del juego de la oca juego introducido originalmente en control de
flujo . Esta versión está adaptada para utilizar un Dados ejemplo para sus dados
rollos; adoptar el DiceGame protocolo; y para notificar a
un DiceGameDelegate sobre su progreso:
• class SnakesAndLadders: DiceGame {
• let finalSquare = 25
• let dice = Dice(sides: 6, generator: LinearCongruentialGenerator())
• var square = 0
• var board: [Int]
• init() {
• board = [Int](count: finalSquare + 1, repeatedValue: 0)
• board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
• board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08
• }
• var delegate: DiceGameDelegate?
• func play() {
• square = 0
• delegate?.gameDidStart(self)
• gameLoop: while square != finalSquare {
• let diceRoll = dice.roll()
• delegate?.game(self, didStartNewTurnWithDiceRoll: diceRoll)
• switch square + diceRoll {
• case finalSquare:
• break gameLoop
• case let newSquare where newSquare > finalSquare:
• continue gameLoop
• default:
• square += diceRoll
• square += board[square]
• }
• }
• delegate?.gameDidEnd(self)
• }
• }
Para una descripción de la Serpientes y Escaleras juego, ver la rotura sección
del control de flujo capítulo.
Esta versión del juego está envuelto en una clase llamada SnakesAndLadders , que
adopta la DiceGameprotocolo. Proporciona una gettable dados propiedad y

  237  
un juego método con el fin de cumplir con el protocolo.(El dado de propiedad se
declara como una propiedad constante, ya que no tiene que cambiar después de la
inicialización, y el protocolo sólo requiere que sea gettable.)
El Serpientes y Escaleras configuración tablero de juego tiene lugar dentro de la
clase init () inicializador.Toda la lógica del juego se mueve dentro del protocolo
de juego método, que utiliza el protocolo requerido dedados propiedad para
proporcionar sus valores dados.
Tenga en cuenta que el delegado de la propiedad se define como
un opcional DiceGameDelegate , debido a que un delegado no se requiere con el
fin de jugar el juego. Debido a que es de un tipo opcional, el delegado de la
propiedad se establece automáticamente en un valor inicial de cero . A partir de
entonces, la instanciador juego tiene la opción para establecer la propiedad de un
delegado adecuado.
DiceGameDelegate proporciona tres métodos para el seguimiento del progreso de
un juego. Estos tres métodos se han incorporado a la lógica del juego dentro
del juego método anterior, y se llaman cuando un nuevo juego comienza, un nuevo
giro comienza o termina el juego.
Debido a que el delegado de la propiedad es una opción DiceGameDelegate ,
el juego utiliza el método opcional encadenamiento cada vez que se llama a un
método en el delegado. Si el delegado propiedad es nulo, estas llamadas delegadas
fallan con gracia y sin error. Si el delegado propiedad es para no-nil, los métodos de
delegado se llaman, y se pasan la SnakesAndLadders instancia como parámetro.
El siguiente ejemplo muestra una clase llamada DiceGameTracker , que adopta
la DiceGameDelegate protocolo:
• class DiceGameTracker: DiceGameDelegate {
• var numberOfTurns = 0
• func gameDidStart(game: DiceGame) {
• numberOfTurns = 0
• if game is SnakesAndLadders {
• println("Started a new game of Snakes and Ladders")
• }
• println("The game is using a \(game.dice.sides)-sided dice")
• }
• func game(game: DiceGame, didStartNewTurnWithDiceRoll diceRoll: Int) {
• ++numberOfTurns
• println("Rolled a \(diceRoll)")
• }
• func gameDidEnd(game: DiceGame) {
• println("The game lasted for \(numberOfTurns) turns")
• }
• }

  238  
DiceGameTracker implementa los tres métodos requeridos
por DiceGameDelegate . Utiliza estos métodos para realizar un seguimiento del
número de vueltas de un juego se ha tomado. Se restablece
un numberOfTurnspropiedad a cero cuando se inicia el juego, se incrementa cada
vez que comienza un nuevo turno, e imprime el número total de vueltas una vez que el
juego ha terminado.
La implementación de gameDidStart muestra arriba utiliza el juego de parámetros
para imprimir alguna información introductoria sobre el juego que está a punto de ser
jugado. El juego tiene un parámetro de tipo de DiceGame ,
no SnakesAndLadders , y así gameDidStart puede acceder y utilizar sólo los
métodos y propiedades que se implementan como parte de la DiceGame protocolo. Sin
embargo, el método sigue siendo capaz de utilizar el tipo de colada para consultar el
tipo de la instancia subyacente. En este ejemplo, se comprueba siel juego es en
realidad una instancia de SnakesAndLadders detrás de las escenas, e imprime un
mensaje apropiado en caso afirmativo.
gameDidStart también accede al dado de la propiedad del pasado juego de
parámetros. Debido a que el juegose conoce para ajustarse a
la DiceGame protocolo, es la garantía de tener un dado de la propiedad, por lo que
elgameDidStart método es capaz de acceder e imprimir de los
dados lados propiedad, independientemente de qué tipo de juego que se está jugando.
He aquí cómo DiceGameTracker ve en acción:
• let tracker = DiceGameTracker()
• let game = SnakesAndLadders()
• game.delegate = tracker
• game.play()
• //  Iniciado  un  nuevo  juego  de  Serpientes  y  Escaleras  
• //  El  juego  usa  un  dado  de  6  lados  
• //  Laminado  a  3  
• //  Laminado  a  5  
• //  Laminado  un  4  
• //  Laminado  a  5  
• //  El  juego  se  prolongó  durante  4  vueltas  
Adición de Protocolo de conformidad con una extensión
Puede extender un tipo existente para adoptar y adaptarse a un nuevo protocolo, incluso
si usted no tiene acceso al código fuente para el tipo existente. Las extensiones pueden
añadir nuevas propiedades, métodos y subíndices para un tipo existente, y por lo tanto
son capaces de añadir cualquier requisito que un protocolo puede exigir. Para obtener
más información sobre las extensiones, vea Extensiones .
NOTA
Las instancias existentes de un tipo adoptan automáticamente y se ajustan a un
protocolo cuando se añade que la conformidad con el tipo de la instancia en una
extensión.

  239  
Por ejemplo, este protocolo, llamado TextRepresentable , puede ser
implementado por cualquier tipo que tiene una manera de ser representado como
texto. Esto podría ser una descripción de la misma, o una versión de texto de su estado
actual:
• protocol TextRepresentable {
• func asText() -> String
• }
The Dice class from earlier can be extended to adopt and conform
to TextRepresentable:
• extension Dice: TextRepresentable {
• func asText() -> String {
• return "A \(sides)-sided dice"
• }
• }
Esta extensión adopta el nuevo protocolo exactamente de la misma manera que
si Dados había proporcionado en su implementación original. El nombre del protocolo
se proporciona después el nombre del tipo, separados por dos puntos, y una puesta en
práctica de todos los requisitos del protocolo se proporciona dentro de llaves de la
extensión.
Cualquier Dados ejemplo ahora se puede tratar como TextRepresentable :
• let d12 = Dice(sides: 12, generator: LinearCongruentialGenerator())
• println(d12.asText())
• println ( d12 . AsText ())  
• //  imprime  "un  dado  de  12  lados"  
Del mismo modo, la SnakesAndLadders clase de juego puede extenderse a adoptar
y ajustarse a laTextRepresentable protocolo:
• extension SnakesAndLadders: TextRepresentable {
• func asText() -> String {
• return "A game of Snakes and Ladders with \(finalSquare) squares"
• }
• }
• println(game.asText())
• //  imprime  "Un  juego  de  serpientes  y  escaleras  con  25  plazas"  
•  
Declarando Adopción Protocolo con una extensión
Si un tipo que ya cumple con todos los requisitos de un protocolo, pero aún no ha
declarado que adopta ese protocolo, puede hacer que apruebe el protocolo con una
extensión vacía:
• struct Hamster {
• var name: String

  240  
• func asText() -> String {
• return "A hamster named \(name)"
• }
• }
• extension Hamster: TextRepresentable {}
Instances of Hamster can now be used wherever TextRepresentable is the required type:
• let simonTheHamster = Hamster(name: "Simon")
• let somethingTextRepresentable: TextRepresentable = simonTheHamster
• println(somethingTextRepresentable.asText())
• //  imprime  "Un  hámster  llamado  Simón"  
NOTA
Tipos no adoptan automáticamente un protocolo sólo por la satisfacción de sus
necesidades. Ellos siempre deben declarar explícitamente su adopción del protocolo.
Colecciones de tipos de protocolo
Un protocolo se puede utilizar como el tipo que se almacena en una colección como una
matriz o un diccionario, como se menciona en protocolos como los tipos . En este
ejemplo se crea una matriz deTextRepresentable cosas:
• let things: [TextRepresentable] = [game, d12, simonTheHamster]
Ahora es posible para iterar sobre los elementos de la matriz, e imprimir la
representación textual de cada elemento:
• for thing in things {
• println(thing.asText())
• }
• //  Un  juego  de  serpientes  y  escaleras  con  25  plazas  
• //  un  dado  de  12  lados  
• //  Un  hámster  llamado  Simón  
Tenga en cuenta que la cosa constante es de tipo TextRepresentable . No es del
tipo de los dados , o DiceGameo hámster , incluso si la instancia real detrás de
las escenas es de uno de esos tipos. Sin embargo, debido a que es de
tipo TextRepresentable , y todo lo que es TextRepresentable se sabe que
tiene un AsText método, es seguro llamar thing.asText cada vez en el bucle.
Protocolo de Herencia
Un protocolo puede heredar uno o más de otros protocolos y puede añadir otros
requisitos en la parte superior de los requisitos que hereda. La sintaxis de la herencia
protocolo es similar a la sintaxis de la herencia de clases, pero con la opción a la lista de
múltiples protocolos heredados, separadas por comas:
• protocol InheritingProtocol: SomeProtocol, AnotherProtocol {
• //  Definición  de  protocolo  va  aquí  
• }  
He aquí un ejemplo de un protocolo que hereda el TextRepresentable protocolo
desde arriba:
  241  
• protocol PrettyTextRepresentable: TextRepresentable {
• func asPrettyText() -> String
• }
En este ejemplo se define un nuevo protocolo, PrettyTextRepresentable , que
hereda de TextRepresentable .Cualquier cosa que
adopta PrettyTextRepresentable debe satisfacer todos los requisitos impuestos
porTextRepresentable , además de los requisitos adicionales impuestos
por PrettyTextRepresentable . En este
ejemplo, PrettyTextRepresentable añade un único requisito de proporcionar
un método de instancia denominado asPrettyText que devuelve una Cadena .
El SnakesAndLadders clase se puede extender a adoptar y cumplir
con PrettyTextRepresentable :
• extension SnakesAndLadders: PrettyTextRepresentable {
• func asPrettyText() -> String {
• var output = asText() + ":\n"
• for index in 1...finalSquare {
• switch board[index] {
• case let ladder where ladder > 0:
• output += "▲ "
• case let snake where snake < 0:
• output += "▼ "
• default:
• output += "○ "
• }
• }
• return output
• }
• }
Esta extensión indica que adopta la PrettyTextRepresentable protocolo y
proporciona una implementación de la asPrettyText método para
la SnakesAndLadders tipo. Cualquier cosa que
es PrettyTextRepresentable también debe ser TextRepresentable , por
lo que el asPrettyText aplicación comienza llamando la AsText método
delTextRepresentable protocolo para iniciar una cadena de salida. Se añade dos
puntos y un salto de línea, y utiliza esto como el inicio de su representación de texto
bastante. A continuación, itera a través de la serie de casillas del tablero, y anexa una
forma geométrica para representar el contenido de cada cuadrado:
• Si el valor del cuadrado es mayor que 0 , es la base de una escalera, y está
representado por ▲ .
• Si el valor del cuadrado es inferior a 0 , que es la cabeza de una serpiente, y está
representado por ▼ .
  242  
• De lo contrario, el valor de la plaza es 0 , y es una plaza "libre", representada por ○ .
La implementación del método ahora se puede utilizar para imprimir una bonita
descripción de texto de cualquier SnakesAndLadders ejemplo:
• println(game.asPrettyText())
• //  Un  juego  de  serpientes  y  escaleras  con  25  plazas:  
• //  ○  ○  ▲  ○  ○  ▲  ○  ○  ▲  ▲  ○  ○  ○  ▼  ○  ○  ○  ○  ▼  ○  ○  ▼  ○  ▼  ○  
Protocolos-Class Sólo
Puede limitar la adopción del protocolo de tipos de clase (y no a las estructuras o
enumeraciones) mediante la adición de la clase de palabras clave a la lista de la
herencia de un protocolo. La clase de palabras clave siempre debe aparecer primero
en la lista de la herencia de un protocolo, antes de que los protocolos heredados:
• protocol SomeClassOnlyProtocol: class, SomeInheritedProtocol {
• //  Definición  de  protocolo  de  clase  sólo  va  aquí  
• }  
En el ejemplo anterior, SomeClassOnlyProtocol sólo puede ser adoptada por los
tipos de clase. Se trata de un error de tiempo de compilación para escribir una definición
de estructura o enumeración que intenta adoptarSomeClassOnlyProtocol .
NOTA
Utilice un protocolo de clase sólo cuando el comportamiento definido por los requisitos
de ese protocolo supone o exige que un tipo de conformación tiene una semántica de
referencia en lugar de la semántica de valor. Para más información sobre referencia y
valor semántico, ver estructuras y enumeraciones son tipos de valor y las clases son
tipos de referencia .
Protocolo de Composición
Puede ser útil exigir un tipo de ajustarse a múltiples protocolos a la vez. Se pueden
combinar varios protocolos en un único requisito con una composición
protocolo . Composiciones Protocolo tienen la forma de protocolo
<SomeProtocol, AnotherProtocol> . Usted puede enumerar tantos
protocolos dentro del par de corchetes angulares ( <> ) como necesite, separados por
comas.
He aquí un ejemplo que combina dos protocolos llamados con
nombre y envejecido en un único requisito composición protocolo en un
parámetro de la función:
• protocol Named {
• var name: String { get }
• }
• protocol Aged {
• var age: Int { get }
• }
• struct Person: Named, Aged {
• var name: String
• var age: Int

  243  
• }
• func wishHappyBirthday(celebrator: protocol<Named, Aged>) {
• println("Happy birthday \(celebrator.name) - you're \(celebrator.age)!")
• }
• let birthdayPerson = Person(name: "Malcolm", age: 21)
• wishHappyBirthday(birthdayPerson)
• //  imprime  "Feliz  cumpleaños  Malcolm  -­‐  usted  es  21!"  
En este ejemplo se define un protocolo llamado Nombrado , con un único requisito
para un gettable Cadenapropiedad llamada nombre . También define un protocolo
llamado Aged , con un único requisito para un gettableInt propiedad
llamada edad . Estos dos protocolos son adoptadas por una estructura
llamada persona .
El ejemplo también define una función llamada wishHappyBirthday , que toma un
solo parámetro denominadocelebrator . El tipo de este parámetro es el
protocolo <Nombre, Edad> , que significa "cualquier tipo que satisfaga tanto
los nombrados y envejecidas protocolos. "No importa qué tipo específico que se
pasa a la función, siempre y cuando se ajuste a tanto de los protocolos requeridos.
El ejemplo a continuación, crea una nueva persona instancia
llamada birthdayPerson y entrega esta nueva instancia de
la wishHappyBirthday función. Debido persona cumple con ambos protocolos,
esto es una llamada válida, y el wishHappyBirthday función es capaz de imprimir
su saludo de cumpleaños.
NOTA
Composiciones Protocolo no definen un nuevo tipo de protocolo permanente. Por el
contrario, definen un protocolo local temporal que tiene los requisitos combinados de
todos los protocolos en la composición.
Comprobación de la conformidad de Protocolo
Puede utilizar los es y como operadores descritos en la conversión de tipos para
comprobar el cumplimiento del protocolo, y para echar a un protocolo
específico. Comprobación de que emitan un protocolo sigue exactamente la misma
sintaxis que la revisión y la fundición a un tipo:
• El es operador devuelve verdadero si una instancia es conforme a un protocolo
y devuelve falso si no lo hace.
• El como? versión del operador abatido devuelve un valor opcional de tipo de
protocolo, y este valor esnulo si la instancia no se ajusta a ese protocolo.
• El como versión del operador abatido fuerza al abatido al tipo de protocolo y
provoca un error de ejecución si los abatidos no tiene éxito.
Este ejemplo define un protocolo llamado HasArea , con un único requisito de
propiedad de un gettable doblepropiedad llamada área :
• @objc protocol HasArea {
• var area: Double { get }
• }
NOTA

  244  
Puede comprobar el cumplimiento del protocolo sólo si el protocolo está marcado con
el objc atributo, como se ve por la HasArea protocolo anterior. Este atributo indica
que el protocolo debe ser expuesto al código de Objective-C y se describe en Uso de
Swift con Cocoa y Objective-C . Incluso si usted no está interoperar con Objective-C,
tiene que marcar sus protocolos con el objc atributo si quieres ser capaz de verificar la
conformidad del protocolo.
Tenga en cuenta también que los objc protocolos pueden ser adoptadas por las clases,
y no por estructuras o enumeraciones. Si marca el protocolo como objc con el fin de
comprobar la conformidad, usted será capaz de aplicar ese protocolo sólo para tipos de
clase.
Aquí hay dos clases, Circle y País , las cuales se ajustan a la HasArea protocolo:
• class Circle: HasArea {
• let pi = 3.1415927
• var radius: Double
• var area: Double { return pi * radius * radius }
• init(radius: Double) { self.radius = radius }
• }
• class Country: HasArea {
• var area: Double
• init(area: Double) { self.area = area }
• }
El Círculo clase implementa el área requisito de propiedad como una propiedad
calculada, en base a un almacenada radio de propiedad. El País clase implementa
el área requerimiento directamente como una propiedad almacenada. Ambas clases se
ajustan correctamente a la HasArea protocolo.
Aquí hay una clase llamada Animal , que no se ajusta a la HasArea protocolo:
• class Animal {
• var legs: Int
• init(legs: Int) { self.legs = legs }
• }
Los Circle , País y animales clases no tienen una clase base común. No obstante,
son todas las clases, y por lo tanto los casos de los tres tipos pueden utilizarse para
inicializar una matriz que almacena valores de tipoAnyObject :
• let objects: [AnyObject] = [
• Circle(radius: 2.0),
• Country(area: 243_610),
• Animal(legs: 4)
• ]
El objeto array se inicializa con un literal de matriz que contiene
un círculo instancia con un radio de 2 unidades; un País instancia inicializada con

  245  
el área de la superficie del Reino Unido en kilómetros cuadrados;y
un Animal ejemplo, con cuatro patas.
El objeto array ahora puede repetirse, y cada objeto de la matriz se puede comprobar
para ver si se ajusta a la HasArea protocolo:
• for object in objects {
• if let objectWithArea = object as? HasArea {
• println("Area is \(objectWithArea.area)")
• } else {
• println("Something that doesn't have an area")
• }
• }
• //  Area  es  12.5663708  
• //  Area  es  243610.0  
• //  Algo  que  no  tiene  un  área  
Siempre que un objeto de la matriz se ajusta a la HasArea protocolo, el valor devuelto
por el opcional como?operador se desenvuelve con la unión opcional en una constante
llamada objectWithArea . El objectWithAreaconstante es conocido por ser de
tipo HasArea , por lo que su área de la propiedad se puede acceder e imprimir de
una manera con seguridad de tipos.
Tenga en cuenta que los objetos subyacentes no se modifican por el proceso de
fundición. Ellos siguen siendo un círculo , un país y un animal . Sin embargo, en
el punto que se almacenan en la objectWithAreaconstante, sólo se sabe que son de
tipo HasArea , y así sólo su área se puede acceder a la propiedad.
Protocolo de Requisitos opcionales
Puede definir los requisitos facultativos para los protocolos, Estos requisitos no tienen
que ser aplicadas por los tipos que cumplen con el protocolo. Requisitos opcionales van
precedidos por el opcional modificador como parte de la definición del protocolo.
Un requisito de protocolo facultativo puede ser llamado con el encadenamiento
opcional, para dar cuenta de la posibilidad de que el requisito no fue implementado por
un tipo que cumpla con el protocolo. Para obtener información sobre el encadenamiento
opcional, consulte encadenamiento opcional .
Te registras para una implementación de un requisito opcional, escribiendo un signo de
interrogación después del nombre de dicho requisito cuando se llama,
como someOptionalMethod? (someArgument) .Requisitos de propiedades
opcionales, y los requisitos del método opcional que devuelven un valor, siempre
devolverá un valor opcional del tipo apropiado cuando se accede a ellos o llaman, para
reflejar el hecho de que el requisito opcional no pudo ejecutarse.
NOTA
Requisitos del protocolo opcionales sólo se pueden especificar si el protocolo está
marcado con el objcatributo. Incluso si usted no está interoperar con Objective-C,
tiene que marcar sus protocolos con el objcatributo si desea especificar requisitos
opcionales.

  246  
Tenga en cuenta también que los objc protocolos pueden ser adoptadas por las clases,
y no por estructuras o enumeraciones. Si marca el protocolo como objc con el fin de
especificar los requisitos opcionales, sólo será capaz de aplicar ese protocolo para tipos
de clase.
El ejemplo siguiente define una clase entera de conteo llamado Contador , que utiliza
una fuente de datos externa para proporcionar a su importe mínimo de la subasta. Esta
fuente de datos se define por laCounterDataSource protocolo, que tiene dos
requisitos opcionales:
• @objc protocol CounterDataSource {
• optional func incrementForCount(count: Int) -> Int
• optional var fixedIncrement: Int { get }
• }
El CounterDataSource protocolo define un requisito método opcional
llamado incrementForCount y un requisito de propiedad opcional
llamado fixedIncrement . Estos requisitos definen dos maneras diferentes para
fuentes de datos para proporcionar una cantidad de incremento apropiado para
un contador de instancia.
NOTA
En rigor, se puede escribir una clase personalizada que se ajuste
a CounterDataSource sin implementar ya sea requisito protocolo. Ellos son ambos
opcionales, después de todo. Aunque técnicamente permitido, esto no haría por una muy
buena fuente de datos.
El contador de la clase, se define a continuación, tiene un
opcional dataSource propiedad de tipoCounterDataSource? :
• @objc class Counter {
• var count = 0
• var dataSource: CounterDataSource?
• func increment() {
• if let amount = dataSource?.incrementForCount?(count) {
• count += amount
• } else if let amount = dataSource?.fixedIncrement? {
• count += amount
• }
• }
• }
El contador de la clase almacena su valor actual en una propiedad variable
llamada count . El contador de la clase también define un método llamado de
incremento , lo que incrementa el recuento de propiedad cada vez que se llama
al método.
El incremento método primero intenta recuperar un importe mínimo de la subasta
mediante la búsqueda de una implementación de la incrementForCount método en
su origen de datos. El incremento método utiliza el encadenamiento opcional para

  247  
tratar de llamar incrementForCount , y pasa el actual conteo valor como único
argumento del método.
Nota dos niveles de encadenamiento opcional en juego aquí. En primer lugar, es posible
que dataSourcepuede ser nulo , y así dataSource tiene un signo de
interrogación después de su nombre para indicar queincrementForCount sólo se
debe llamar si dataSource es no-nil. En segundo lugar, incluso
si dataSource noexiste, no hay ninguna garantía de que
aplique incrementForCount , porque es un requisito opcional. Esta es la razón
por incrementForCount también se escribe con un signo de interrogación después
de su nombre.
Debido a que la llamada a incrementForCount puede fallar por cualquiera de estas
dos razones, la llamada devuelve un opcional Int valor. Esto es cierto a pesar de
que incrementForCount se define como devolver un no opcional Int valor en la
definición de CounterDataSource .
Después de llamar incrementForCount , el opcional Int que devuelve se
desenvolvió en una constante llamadacantidad , usando opcional de unión. Si el
opcional Int contiene un valor, es decir, si el delegado y el método tanto existen, y el
método devuelve un valor sin envolver la cantidad se añade a la
almacenada recuento depropiedad, y de incremento es completa.
Si es no posible recuperar un valor de la incrementForCount método-ya sea
porque dataSource es nula, o porque la fuente de datos no
implementa incrementForCount -entonces el incremento método intenta
recuperar un valor de de la fuente de datos fixedIncrement propiedad en
lugar. El fixedIncrement propiedad es también un requisito opcional, por lo que su
nombre también se escribe con el encadenamiento opcional con un signo de
interrogación en el extremo, para indicar que el intento de acceder a el valor de la
propiedad puede fallar.Como antes, el valor devuelto es un opcional Int valor,
aunque fixedIncrement se define como una no opcional Int propiedad como
parte de la CounterDataSource definición de protocolo.
He aquí una sencilla CounterDataSource aplicación donde la fuente de datos
devuelve un valor constante de 3cada vez que se consulta. Lo hace mediante la
aplicación de la opción fixedIncrement requisito de propiedad:
• class ThreeSource: CounterDataSource {
• let fixedIncrement = 3
• }
Puede utilizar una instancia de ThreeSource como origen de datos para un
nuevo contador ejemplo:
• var counter = Counter()
• counter.dataSource = ThreeSource()
• for _ in 1...4 {
• counter.increment()
• println(counter.count)
• }

  248  
• //  3  
• //  6  
• //  9  
• //  12  
El código anterior crea un nuevo contador de instancia; establece su fuente de datos
para ser un nuevoThreeSource instancia; y pide del contador incremento método
de cuatro veces. Como era de esperar, el contador count propiedad aumenta por tres
cada vez que la subasta se llama.
He aquí una fuente de datos más compleja llamada TowardsZeroSource , lo que
hace un contador de instancia contar hacia arriba o hacia abajo a cero de su
actual cuenta de valor:
• class TowardsZeroSource: CounterDataSource {
• func incrementForCount(count: Int) -> Int {
• if count == 0 {
• return 0
• } else if count < 0 {
• return 1
• } else {
• return -1
• }
• }
• }
El TowardsZeroSource clase implementa la
opcional incrementForCount método del CounterDataSource protocolo y
utiliza el conteo valor del argumento de averiguar qué dirección para contar.
Si cuenta ya es cero, el método devuelve 0 para indicar que no hay más de conteo
debe tener lugar.
Puede utilizar una instancia de TowardsZeroSource con el
vigente Contador instancia a contar desde -4 a cero.Una vez que el contador llegue a
cero, no más de conteo se lleva a cabo:
• counter.count = -4
• counter.dataSource = TowardsZeroSource()
• for _ in 1...5 {
• counter.increment()
• println(counter.count)
• }
• //  -­‐3  
• //  -­‐2  
• //  -­‐1  

  249  
• //  0  
• //  0  
 

Genéricos

Código genérico le permite escribir, funciones flexibles reutilizables y tipos que pueden
trabajar con cualquier tipo, con sujeción a los requisitos que se definan. Se puede
escribir código que evite la duplicación y expresa su intención de una manera clara
abstraído.
Los genéricos son una de las características más potentes de Swift, y gran parte de la
biblioteca estándar de Swift está construido con código genérico. De hecho, usted ha
estado utilizando los genéricos en toda la guía de idiomas , incluso si usted no se dio
cuenta. Por ejemplo, de Swift matriz y Diccionario tipos son ambas colecciones
genéricas. Puede crear una matriz que contiene Int valores, o una matriz que
contiene Cuerdavalores, o incluso una matriz de cualquier otro tipo que se puede crear
en Swift. Del mismo modo, se puede crear un diccionario para almacenar valores de
cualquier tipo especificado, y no hay limitaciones en lo que ese tipo puede ser.
El problema que Generics Resuelva
Aquí hay un estándar de función, no genérica llamada swapTwoInts , que
intercambia dos Int valores:
• func swapTwoInts(inout a: Int, inout b: Int) {
• let temporaryA = a
• a=b
• b = temporaryA
• }
Esta función hace uso de parámetros de salida para cambiar los valores de una y b ,
como se describe enParámetros In-Out .
El swapTwoInts función intercambia el valor original de b en una , y el valor
original de una en b . Usted puede llamar a esta función para intercambiar los valores
de dos Int variables:
• var someInt = 3
• var anotherInt = 107
• swapTwoInts(&someInt, &anotherInt)
• println("someInt is now \(someInt), and anotherInt is now \(anotherInt)")
• // Impresiones "someInt es ahora 107, y anotherInt es ahora
3"  
El swapTwoInts función es útil, pero sólo se puede utilizar con Int valores. Si usted
quiere intercambiar dos de Cuerda valores, o dos dobles valores, tienes que
escribir más funciones, como las swapTwoStrings yswapTwoDoubles funciones
que se muestran a continuación:
• func swapTwoStrings(inout a: String, inout b: String) {

  250  
• let temporaryA = a
• a=b
• b = temporaryA
• }

• func swapTwoDoubles(inout a: Double, inout b: Double) {
• let temporaryA = a
• a=b
• b = temporaryA
• }
Usted puede haber notado que los cuerpos de
los swapTwoInts , swapTwoStrings y swapTwoDoubles funciones son
idénticas. La única diferencia es el tipo de los valores que se aceptan ( Int , Cuerda ,
y dobles ).
Sería mucho más útil, y considerablemente más flexible, para escribir una sola función
que podrían intercambiar dos valores de cualquier tipo. Código genérico le permite
escribir una función de este tipo. (Una versión genérica de estas funciones se define a
continuación.)
NOTA
En todas las tres funciones, es importante que los tipos de una y b se definen para ser el
mismo que el uno al otro. Si una y b no eran del mismo tipo, no sería posible cambiar
sus valores. Swift es un lenguaje de tipo seguro, y no permite que (por ejemplo) una
variable de tipo de cadena y una variable de tipo doble para intercambiar valores
entre sí. Si lo intenta, se informó como un error en tiempo de compilación.
Funciones Genéricas
Funciones genéricas pueden trabajar con cualquier tipo. Aquí hay una versión genérica
del swapTwoIntsfunción de lo alto, llamados swapTwoValues :
• func swapTwoValues<T>(inout a: T, inout b: T) {
• let temporaryA = a
• a=b
• b = temporaryA
• }
El cuerpo de la swapTwoValues función es idéntica a la del cuerpo de
la swapTwoInts función. Sin embargo, la primera línea de swapTwoValues es
ligeramente diferente de swapTwoInts . He aquí cómo se comparan las primeras
líneas:
• func swapTwoInts(inout a: Int, inout b: Int)
• func swapTwoValues<T>(inout a: T, inout b: T)
La versión genérica de la función utiliza un marcador de posición el nombre del tipo
(llamado T , en este caso) en lugar de un verdadero nombre de tipo
(como int , cuerdas , o doble ). El nombre del tipo de marcador de posición no

  251  
dice nada acerca de lo que T debe ser, pero no decir que tanto una y b deben ser del
mismo tipo T, lo que T representa. El tipo real para usar en lugar de T será determinado
cada vez que el swapTwoValues función es llamada.
La otra diferencia es que el nombre de la función genérica ( swapTwoValues ) es
seguido por el nombre del tipo de marcador de posición ( T ) dentro de corchetes
angulares ( <T> ). Los corchetes indican que Swift T es un nombre de tipo de marcador
de posición dentro de la swapTwoValues definición de la función. Debido a que T es
un marcador de posición, Swift no busca un tipo real llamado T .
El swapTwoValues función puede ser llamado ahora en la misma manera
que swapTwoInts , excepto que se puede pasar dos valores de cualquier tipo,
siempre y cuando ambos de esos valores son del mismo tipo que el uno al otro. Cada
vez swapTwoValues se llama, el tipo a utilizar para T se infiere de los tipos de
valores pasados a la función.
En los dos ejemplos siguientes, T se infiere ser Int y de cadena , respectivamente:
• var someInt = 3
• var anotherInt = 107
• swapTwoValues(&someInt, &anotherInt)
• // SomeInt es ahora 107, y anotherInt es ahora 3  
•  
• var someString = "hello"
• var anotherString = "world"
• swapTwoValues(&someString, &anotherString)
• // SomeString es ahora "mundo", y anotherString es ahora
"hola"  
NOTA
El swapTwoValues función definida anteriormente se inspira en una función
genérica llamada de intercambio , que es parte de la biblioteca estándar de Swift,
y se hace automáticamente disponible para su uso en sus aplicaciones. Si usted necesita
el comportamiento de la swapTwoValues función en su propio código, puede utilizar
existente de Swift canje función en lugar de proporcionar su propia implementación.
Parámetros de tipo
En la swapTwoValues ejemplo anterior, el tipo de marcador de posición T es un
ejemplo de un parámetro de tipo. Los parámetros de tipo especifican y nombrar un tipo
de marcador de posición, y se escriben inmediatamente después del nombre de la
función, entre un par de corchetes angulares coincidentes (como<T> ).
Una vez que se especifica un parámetro de tipo, se puede utilizar para definir el tipo de
parámetros de una función (por ejemplo, los unos y b parámetros
del swapTwoValues función), o como tipo de retorno de la función, o como una
anotación de tipo dentro del cuerpo de la función. En cada caso, el tipo de marcador de
posición representado por el parámetro de tipo se reemplaza con un real tipo cada vez
que la función se llama. (En laswapTwoValues ejemplo anterior, T fue sustituido
por Int la primera vez que la función se llama, y fue reemplazado con cuerdas la
segunda vez que se llamaba.)

  252  
Puede proporcionar más de un parámetro de tipo escribiendo múltiples nombres de los
parámetros de tipo dentro de los corchetes angulares, separadas por comas.
Nombrar parámetros de tipo
En los casos en los que una función genérica o tipo genérico se refiere a un solo tipo de
marcador de posición (como el swapTwoValues función genérica anteriormente, o
una colección genérica que almacena un solo tipo, tales como la matriz ), es
tradicional usar el nombre de un solo carácter T para el parámetro de tipo. Sin embargo,
puede utilizar cualquier identificador válido como nombre de parámetro de tipo.
Si va a definir funciones genéricas más complejas, o tipos genéricos con múltiples
parámetros, es útil para proporcionar nombres de los parámetros de tipo más
descriptivos. Por ejemplo, de Swift Diccionario tipo tiene dos parámetros de un
tipo para sus claves y otra para sus valores. Si estuviera escribiendo Diccionario ti
mismo, podría denominar estos dos parámetros de tipo KeyType y ValueType para
recordarle de su propósito como usted los utiliza en el código genérico.
NOTA
Siempre dar parámetros de tipo UpperCamelCase nombres (como T y KeyType )
para indicar que son un marcador de posición para un tipo , no un valor.
Tipos genéricos
Además de las funciones genéricas, Swift le permite definir sus propios tipos
genéricos . Estas son clases personalizadas, estructuras y enumeraciones que pueden
trabajar con cualquier tipo, de una manera similar a la matriz y Diccionario .
Esta sección le muestra cómo escribir un tipo de colección genérica
llamada Pila . Una pila es un conjunto ordenado de valores, similar a una matriz, pero
con un conjunto más restringido de las operaciones que los de Swift matriz tipo. Una
matriz permite a los nuevos elementos que se insertan y se retiran en cualquier
ubicación en la matriz. Una pila, sin embargo, permite que los nuevos elementos que se
añaden sólo al final de la colección (conocido como empujando un nuevo valor en la
pila). Del mismo modo, una pila permite que los elementos que se eliminan sólo desde
el final de la colección (conocido como apareciendo un valor de la pila).
NOTA
El concepto de una pila es utilizado por el UINavigationController clase para
modelar los controladores de vista en su jerarquía de navegación. Se llama a
la UINavigationController clase pushViewController:
animada: método para agregar (o empujar) un controlador de vista en la pila de
navegación, y supopViewControllerAnimated: método para eliminar (o pop)
un controlador de vista de la pila de navegación.Una pila es un modelo útil colección
siempre cuando necesite estricta "último en entrar, primero en salir" para la gestión de
una colección.
La siguiente ilustración muestra el comportamiento push / pop para una pila:

  253  
 

1. En este momento hay tres valores en la pila.


2. Un cuarto valor es "empujada" en la parte superior de la pila.
3. La pila ahora tiene cuatro valores, con el más reciente en la parte superior.
4. El elemento superior de la pila se elimina, o "estallar".
5. Después de hacer estallar un valor, la pila tiene una vez más tres valores.
Aquí se explica cómo escribir una versión no genérica de una pila, en este caso para una
pila de Int valores:
• struct IntStack {
• var items = [Int]()
• mutating func push(item: Int) {
• items.append(item)
• }
• mutating func pop() -> Int {
• return items.removeLast()
• }
• }
Esta estructura utiliza una matriz de propiedad denominado artículos para
almacenar los valores en la pila.Stack proporciona dos métodos, empuje y pop ,
para impulsar y valores emergentes y fuera de la pila. Estos métodos están marcados
como mutante , porque tienen que modificar (o mutar ) de la estructura de los
elementos de matriz.
El IntStack tipo mostrado anteriormente solamente se puede utilizar
con Int valores, sin embargo. Sería mucho más útil para definir
un genérico Pila clase, que puede administrar una pila de cualquier tipo de valor.
Aquí hay una versión genérica del mismo código:
• struct Stack<T> {
• var items = [T]()
• mutating func push(item: T) {

  254  
• items.append(item)
• }
• mutating func pop() -> T {
• return items.removeLast()
• }
• }
Nótese cómo la versión genérica de la pila es esencialmente la misma que la
versión no genérica, pero con un parámetro de tipo de marcador de posición
denominada T en lugar de un tipo real de Int . Este parámetro tipo se escribe dentro de
un par de corchetes angulares ( <T> ) inmediatamente después del nombre de la
estructura.
T define un nombre de marcador de posición para "Tipo de alguna T "para proporcionar
más adelante. Este tipo futuro puede ser referido como " T "en cualquier lugar dentro de
la definición de la estructura. En este caso, T se utiliza como un marcador de posición
en tres lugares:
• Para crear una propiedad llamada artículos , que se inicia con una matriz vacía
de valores de tipo T
• Para especificar que el empuje método tiene un único parámetro llamado tema ,
que debe ser de tipo T
• Para especificar que el valor devuelto por el pop método será un valor de tipo T
Debido a que es un tipo genérico, Stack se puede utilizar para crear una pila
de cualquier tipo válido en Swift, de una manera similar a
la matriz y Diccionario .
Se crea una nueva pila instancia escribiendo el tipo que se almacena en la pila dentro
de paréntesis angulares. Por ejemplo, para crear una nueva pila de cuerdas,
escribes Stack <String> () :
• var stackOfStrings = Stack<String>()
• stackOfStrings.push("uno")
• stackOfStrings.push("dos")
• stackOfStrings.push("tres")
• stackOfStrings.push("cuatro")
• // La pila ahora contiene 4 cuerdas  
Así es como stackOfStrings se ve después de empujar a estos cuatro valores en la
pila:

  255  
 

Hacer estallar un valor a partir de las declaraciones de la pila y elimina el valor de la


parte superior, "cuatro" :
• let fromTheTop = stackOfStrings.pop()
• // FromTheTop es igual a "cuatro", y la pila ahora contiene
3 cadenas  
Así es como la pila se ocupa de hacer estallar su valor superior:

La extensión de un tipo genérico


Al ampliar un tipo genérico, no proporciona una lista de parámetros de tipo como parte
de la definición de la extensión. En cambio, la lista de parámetros de tipo de la original
de definición de tipo se encuentra disponible dentro del cuerpo de la extensión, y los
nombres de los parámetros de tipo originales se utilizan para referirse a los parámetros
de tipo de la definición original.
El siguiente ejemplo extiende la genérica Stack tipo para agregar una propiedad de
sólo lectura computarizada llamada topItem , que devuelve el elemento superior de la
pila sin estallar de la pila:
• extension Stack {
• var topItem: T? {
• return items.isEmpty ? nil : items[items.count - 1]
• }
• }

  256  
El topItem propiedad devuelve un valor opcional de tipo T . Si la pila está
vacía, topItem devuelve nil ; Si la pila no está vacía, topItem devuelve el
elemento final en el artículos matriz.
Tenga en cuenta que esta extensión no define una lista de parámetros de tipo. En
cambio, la pila existente nombre de parámetro de tipo de tipo, T , se utiliza dentro de
la extensión para indicar el tipo opcional de latopItem propiedad computarizada.
El topItem propiedad calculado ahora se puede utilizar con cualquier Pila ejemplo,
para acceder y consultar su elemento superior sin sacarlo:
• if let topItem = stackOfStrings.topItem {
• println("The top item on the stack is \(topItem).")
• }
• // imprime "El primer elemento en la pila es tres."  
Tipo Restricciones
El swapTwoValues función y la Pila tipo pueden trabajar con cualquier tipo. Sin
embargo, a veces es útil para hacer cumplir ciertas restricciones de tipo de los tipos que
se pueden utilizar con las funciones genéricas y tipos genéricos. Tipo restricciones
especifican que un parámetro de tipo debe heredar de una clase específica, o se ajustan a
una composición de protocolo o protocolo particular.
Por ejemplo, de Swift Diccionario tipo coloca una limitación en los tipos que
pueden ser usadas como claves en un diccionario. Como se describe en Diccionarios , el
tipo de teclas de un diccionario debe ser Hashable .Es decir, se debe proporcionar una
forma de hacerse de forma única representable. Diccionario necesita sus claves
para ser Hashable para que pueda comprobar si ya contiene un valor para una clave
particular. Sin este requisito, Diccionario no podía decir si se debe insertar o
cambiar un valor para una clave determinada, ni sería capaz de encontrar un valor para
una clave determinada que ya está en el diccionario.
Este requisito es exigido por una restricción de tipo en el tipo de clave
de diccionario , que especifica que el tipo de clave debe ser conforme a
la Hashable protocolo, un protocolo especial definido en la librería estándar de
Swift. Todos los tipos básicos de Swift (tales como cuerdas , Int , doble ,
y Bool ) son Hashable por defecto.
Puede definir sus propias restricciones de tipo al crear tipos personalizados genéricos, y
estas limitaciones proporcionar gran parte de la potencia de la programación
genérica. Los conceptos abstractos como Hashablecaracterizan tipos en términos de
sus características conceptuales, más que su tipo explícito.
Escriba Sintaxis Restricción
Usted escribe restricciones de tipo mediante la colocación de una sola clase o restricción
protocolo después del nombre de un parámetro de tipo, separados por dos puntos, como
parte de la lista de parámetros de tipo.La sintaxis básica de restricciones de tipo en una
función genérica se muestra a continuación (aunque la sintaxis es la misma para tipos
genéricos):
• func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) {
• // Cuerpo de la función va aquí  
• }  
  257  
La función hipotética anterior tiene dos parámetros de tipo. El primer parámetro de
tipo, T , tiene una restricción que requiere tipo T de ser una subclase
de AlgunaClase . El segundo parámetro de tipo, U , tiene una restricción que
requiere tipo U para adaptarse al protocolo SomeProtocol .
Escriba Restricciones en Acción
Aquí está una función no genérica llamada findStringIndex , que se da
una Cadena de valor de encontrar y una gran variedad de Cuerda valores dentro de la
cual para encontrarlo. El findStringIndex función devuelve un
opcional Int valor, que será el índice de la primera cadena coincidente de la matriz, si
se comprueba, o nilsi la cadena no se puede encontrar:
• func findStringIndex(array: [String], valueToFind: String) -> Int? {
• for (index, value) in enumerate(array) {
• if value == valueToFind {
• return index
• }
• }
• return nil
• }
El findStringIndex función se puede utilizar para encontrar un valor de cadena en
una matriz de cadenas:
• let strings = ["cat", "dog", "llama", "parakeet", "terrapin"]
• if let foundIndex = findStringIndex(strings, "llama") {
• println("The index of llama is \(foundIndex)")
• }
• // imprime "El índice de la llama es de 2"  
El principio de encontrar el índice de un valor en una matriz no sólo es útil para las
cadenas, sin embargo.Usted puede escribir la misma funcionalidad que una función
genérica llamada FindIndex , mediante la sustitución de cualquier mención de
cadenas con valores de un cierto tipo T en su lugar.
He aquí cómo usted puede ser que espere una versión genérica
de findStringIndex , llamado FindIndex , para ser escrito. Tenga en cuenta que
el tipo de retorno de esta función es todavía Int? , porque la función devuelve un
número de índice opcional, no un valor opcional de la matriz. Se advirtió, sin embargo,
esta función no se compila, por razones que se explican a ejemplo:
• func findIndex<T>(array: [T], valueToFind: T) -> Int? {
• for (index, value) in enumerate(array) {
• if value == valueToFind {
• return index
• }
• }

  258  
• return nil
• }
Esta función no se compila lo escrito anteriormente. El problema radica en la
comprobación de igualdad, " si el valor == valueToFind ". No todos los
tipos de Swift se puede comparar con el operador igual a ( == ). Si crea su propia clase
o estructura para representar un modelo de datos complejos, por ejemplo, entonces el
significado de "igual" para esa clase o estructura no es algo que Swift puede adivinar
por ti. Debido a esto, no es posible garantizar que el código funciona para cada tipo
posible T , y se informa de un error apropiado cuando intenta compilar el código.
No todo está perdido, sin embargo. La librería estándar Swift define un protocolo
llamado equatable , que requiere cualquier tipo de conformación para aplicar el
operador igual a ( == ) y el operador no es igual a ( ! =) para comparar dos valores de
ese tipo. Todos los tipos estándar de Swift apoyan automáticamente
elequatable protocolo.
Cualquier tipo que es equiparable se puede utilizar de manera segura con
la FindIndex función, ya que se garantiza la compatibilidad de la igual al
operador. Para expresar este hecho, usted escribe una restricción de tipo
de equatable como parte de la definición del tipo de parámetro cuando se define la
función:
• func findIndex<T: Equatable>(array: [T], valueToFind: T) -> Int? {
• for (index, value) in enumerate(array) {
• if value == valueToFind {
• return index
• }
• }
• return nil
• }
El único parámetro de tipo para FindIndex se escribe como T: equatable , que
significa "cualquier tipo T que se ajusta a la equatable protocolo. "
El FindIndex función ahora compila con éxito y se puede utilizar con cualquier tipo
que sea equiparable , tales como doble o de cadena :
• let doubleIndex = findIndex([3.14159, 0.1, 0.25], 9.3)
• // DoubleIndex es un Int opcional con ningún valor, porque
no es 9,3 en la matriz  
• let stringIndex = findIndex(["Mike", "Malcolm", "Andrea"], "Andrea")
• // StringIndex es un Int opcional que contiene un valor de
2  
 
Tipos Asociados
En la definición de un protocolo, a veces es útil para declarar uno o más tipos de
asociados como parte de la definición del protocolo. Un tipo asociado da un nombre de

  259  
marcador de posición (o alias ) a un tipo que se utiliza como parte del protocolo. El tipo
real de utilizar para ese tipo asociado no se ha especificado hasta que se adopte el
protocolo. Tipos asociados se especifican con el typealias palabra clave.
Tipos Asociados en Acción
He aquí un ejemplo de un protocolo llamado Container , que declara un tipo
asociado llamado ItemType :
• protocol Container {
• typealias ItemType
• mutating func append(item: ItemType)
• var count: Int { get }
• subscript(i: Int) -> ItemType { get }
• }
El Contenedor protocolo define tres capacidades necesarias que cualquier
contenedor debe proporcionar:
• Debe ser posible añadir un nuevo elemento en el contenedor con
un append método.
• Debe ser posible acceder a un recuento de los artículos en el recipiente a través de
un recuento depropiedad que devuelve un Int valor.
• Debe ser posible para recuperar cada elemento en el recipiente con un subíndice que
toma un Int valor de índice.
Este protocolo no especifica cómo los elementos en el contenedor deben ser
almacenados o qué tipo se les permite ser. El protocolo sólo especifica los tres bits de
funcionalidad que cualquier tipo debe proporcionar a fin de ser considerado
un Contenedor . Un tipo de conformación puede proporcionar funcionalidad
adicional, con tal de que satisface estos tres requisitos.
Cualquier tipo que se ajusta a la Container protocolo debe ser capaz de especificar el
tipo de valores que almacena. En concreto, se debe asegurar que sólo los elementos del
tipo correcto se añaden al recipiente, y tiene que tener claro el tipo de los elementos
devueltos por su subíndice.
Para definir estos requisitos, el Container protocolo necesita una forma de referirse
al tipo de los elementos que caben en este recipiente, sin saber lo que el tipo es un
contenedor específico. El Contenedor protocolo debe especificar que cualquier valor
pasado al append método debe tener el mismo tipo que el tipo de elemento del
contenedor, y que el valor devuelto por el subíndice del contenedor será del mismo tipo
que el tipo de elemento del contenedor.
Para lograrlo, el Container protocolo declara un tipo asociado llamado ItemType ,
escrito como typealias ItemType . El protocolo no define lo ItemType es un
alias para información -es se deja para cualquier tipo de conformación para
proporcionar. No obstante, el ItemType alias proporciona una manera de referirse al
tipo de los elementos de un Contenedor , y para definir un tipo para su uso con
el append método y subíndice, para asegurar que el comportamiento que se espera de
cualquier Container se hace cumplir.
Aquí hay una versión de la no genérica IntStack tipo de anterior, adaptado para
ajustarse a la Containerprotocolo:

  260  
• struct IntStack: Container {
• // Aplicación IntStack originales  
• var items = [Int]()
• mutating func push(item: Int) {
• items.append(item)
• }
• mutating func pop() -> Int {
• return items.removeLast()
• }
• // La conformidad con el protocolo de contenedores  
• typealias ItemType = Int
• mutating func append(item: Int) {
• self.push(item)
• }
• var count: Int {
• return items.count
• }
• subscript(i: Int) -> Int {
• return items[i]
• }
•}
El IntStack tipo implementa los tres de la Container requisitos del protocolo, y
en cada caso envuelve parte del IntStack funcionalidad existente de tipo para
satisfacer estos requisitos.
Además, IntStack especifica que para esta implementación de contenedores , la
apropiada ItemType a utilizar es un tipo de Int . La definición de typealias
ItemType = Int convierte el tipo abstracto de ItemType en un tipo concreto
de Int para esta aplicación de la Container protocolo.
Gracias a la inferencia de tipos de Swift, que en realidad no necesita declarar un
hormigón ItemType de Intcomo parte de la definición
de IntStack . Debido IntStack cumple con todos los requisitos de
la Containerprotocolo, Swift se puede inferir la adecuada ItemType de usar,
simplemente mirando el tipo de la anexión del método de elemento de parámetros
y el tipo de retorno del subíndice. De hecho, si elimina las typealias ItemType
= Int línea del código anterior, todo sigue funcionando, porque está claro qué tipo se
debe utilizar para ItemType .
También puede hacer que el genérico Pila tipo se ajusta a la Container protocolo:
• struct Stack<T>: Container {
• // Pila <T> implementación original  

  261  
• var items = [T]()
• mutating func push(item: T) {
• items.append(item)
• }
• mutating func pop() -> T {
• return items.removeLast()
• }
• // La conformidad con el protocolo de contenedores  
• mutating func append(item: T) {
• self.push(item)
• }
• var count: Int {
• return items.count
• }
• subscript(i: Int) -> T {
• return items[i]
• }
}

Esta vez, el parámetro de tipo de marcador de posición T se utiliza como el tipo de
la anexión del método deelemento de parámetros y el tipo de retorno del
subíndice. Por lo tanto, Swift puede inferir que T es el tipo adecuado para utilizar como
el ItemType para este contenedor particular.
La extensión de un tipo existente para especificar un tipo asociado
Puede extender un tipo existente para agregar la conformidad con un protocolo, como se
describe en Adición de Protocolo de conformidad con una extensión . Esto incluye un
protocolo con un tipo asociado.
De Swift Matriz tipo ya ofrece un append método, un recuento de la propiedad,
y un subíndice con un Intíndice para recuperar sus elementos. Estas tres capacidades
coinciden con los requisitos de la Containerprotocolo. Esto significa que usted
puede extender la matriz para ajustarse a la Container protocolo simplemente
declarando que la matriz adopta el protocolo. Esto se hace con una extensión vacía,
como se describe en Declarando Adopción Protocolo con una extensión :
• extensión de matriz : Contenedor {}  
Existente de matriz append método y el subíndice Swift permiten inferir el tipo
apropiado a utilizar paraItemType , al igual que para el genérico Pila tipo
anterior. Después de definir esta extensión, se puede utilizar
cualquier matriz como de contenedores .
Dónde Cláusulas
Tipo de limitaciones, como se describe en Tipo restricciones , permiten definir los
requisitos sobre los parámetros de tipo asociadas a una función genérica o tipo.

  262  
También puede ser útil para definir los requisitos para los tipos asociados. Esto se hace
mediante la definición de dónde cláusulas como parte de una lista de parámetros de
tipo. Una cláusula where le permite exigir que un tipo asociado se ajusta a un
determinado protocolo, y / o que ciertos parámetros de tipo y tipos asociados a ser el
mismo. Usted escribe una cláusula where colocando el donde la palabra clave
inmediatamente después de la lista de parámetros de tipo, seguido de una o más
restricciones para los tipos de asociados, y / o una o más relaciones de igualdad entre los
tipos y tipos asociados.
El ejemplo siguiente define una función genérica llamada allItemsMatch , que
comprueba si dos contenedorescasos contienen los mismos elementos en el mismo
orden. La función devuelve un valor booleano de true si todos los elementos
coinciden y un valor de falso si no lo hacen.
Los dos contenedores para ser revisadas no tienen que ser del mismo tipo de contenedor
(aunque pueden ser), pero sí tiene que mantener el mismo tipo de artículos. Este
requisito se expresa a través de una combinación de restricciones de tipo y donde
cláusulas:
• func allItemsMatch<
• C1: Container, C2: Container
• where C1.ItemType == C2.ItemType, C1.ItemType: Equatable>
• (someContainer: C1, anotherContainer: C2) -> Bool {

• // Comprobar que ambos recipientes contienen el mismo
número de artículos  
• if someContainer.count != anotherContainer.count {
• return false
• }

• // Comprobar cada par de artículos para ver si son
equivalentes  
• for i in 0..<someContainer.count {
• if someContainer[i] != anotherContainer[i] {
• return false
• }
• }

•  
• // Todos los artículos coinciden, por lo devuelven true  
• return true
•  

  263  
• }  
Esta función toma dos argumentos
llamados someContainer y anotherContainer . El someContainer argume
nto es de tipo C1 , y el anotherContainer argumento es de
tipo C2 . Tanto C1 y C2 son parámetros de tipo de marcador de posición para dos tipos
de contenedores que se determinarán cuando se invoca la función.
Lista de parámetros de tipo de la función coloca los siguientes requisitos en los dos
parámetros de tipo:
• C1 debe ser conforme a la Container protocolo (escrito como C1:
Contenedor ).
• C2 también debe ajustarse a la Container protocolo (escrito como C2:
Contenedor ).
• El ItemType para C1 debe ser el mismo que el ItemType para C2 (escrito
como C1.ItemType == C2.ItemType).
• El ItemType para C1 debe ser conforme a la equatable protocolo (escrito
como C1.ItemType: equatable ).
La tercera y cuarta requisitos se definen como parte de una cláusula en donde, y se
escriben después de laque la palabra clave como parte de la lista de parámetros de tipo
de la función.
Estos requisitos se refiere a:
• someContainer es un contenedor de tipo C1 .
• anotherContainer es un contenedor de tipo C2 .
• someContainer y anotherContainer contienen el mismo tipo de artículos.
• Los artículos en someContainer se puede comprobar con el operador no igual
( ! = ) para ver si son diferentes unos de otros.
La tercera y cuarta requisitos combinan el sentido de que los artículos
en anotherContainer pueden tambiénser revisados con el ! = operador, porque
son exactamente del mismo tipo que los elementos desomeContainer .
Estos requisitos permiten la allItemsMatch función para comparar los dos
contenedores, incluso si son de un tipo de contenedor diferente.
El allItemsMatch función inicia mediante la comprobación de que ambos
recipientes contienen el mismo número de elementos. Si contienen un número diferente
de elementos, no hay manera de que puedan coincidir, y la función devuelve falso .
Después de hacer esta comprobación, las iteraciones de la función más de todos los
artículos ensomeContainer con un para - en bucle y el operador de rango medio
abierta ( .. < ). Para cada elemento, la función comprueba si el elemento
de someContainer no es igual a la partida correspondiente
enanotherContainer . Si los dos artículos no son iguales, entonces los dos
contenedores no coinciden, y la función devuelve false .
Si el bucle termina sin encontrar una falta de coincidencia, los dos contenedores
coinciden, y la función devuelve verdadero .
He aquí cómo la allItemsMatch función se ve en acción:
• stackOfStrings.push("uno")
• stackOfStrings.push("dos")
• stackOfStrings.push("tres")
  264  

• var arrayOfStrings = ["uno", "dos", "tres"]

• if allItemsMatch(stackOfStrings, arrayOfStrings) {
• println("All items match.")
• } else {
• println("Not all items match.")
• }
• // imprime "Todos los artículos coinciden".  
El ejemplo anterior crea una pila instancia para almacenar de Cuerda valores, y
empuja tres cadenas en la pila. El ejemplo también crea una matriz instancia
inicializada con un literal de matriz que contiene los mismos tres cadenas como la
pila. A pesar de que la pila y la matriz son de un tipo diferente, ambos se ajustan a
la Container protocolo, y ambos contienen el mismo tipo de valores. Por tanto,
puede llamar a laallItemsMatch función con estos dos recipientes como sus
argumentos. En el ejemplo anterior, elallItemsMatch función informa
correctamente que todos los elementos de los dos contenedores coinciden.
 

Control de Acceso

Control de acceso restringe el acceso a las partes de su código de código en otros


archivos de origen y módulos. Esta función le permite ocultar los detalles de
implementación de su código, y para especificar una interfaz preferida a través del cual
se puede acceder a ese código y utiliza.
Puede asignar niveles específicos de acceso a los distintos tipos (clases, estructuras,
enumeraciones y), así como a las propiedades, métodos, inicializadores y subíndices
que pertenecen a esos tipos. Los protocolos pueden ser restringidas a un determinado
contexto, como puede globales constantes, variables y funciones.
Además de ofrecer varios niveles de control de acceso, Swift reduce la necesidad de
especificar los niveles de control de acceso explícitas al proporcionar niveles de acceso
por defecto para los escenarios típicos. De hecho, si usted está escribiendo una
aplicación de un solo objetivo, es posible que no tenga que especificar los niveles de
control de acceso explícitas en absoluto.
NOTA
Los diversos aspectos de su código que pueden tener el control de acceso que se les
aplican (propiedades, tipos, funciones, y así sucesivamente) se denominan "entidades"
en las siguientes secciones, por razones de brevedad.

Los módulos y archivos de origen


Modelo de control de acceso de Swift se basa en el concepto de módulos y archivos de
origen.

  265  
Un módulo es una unidad de código de distribución-un marco o aplicación que se crea y
se envían como una sola entidad y que pueden ser importados por otro módulo con
Swift importación palabra clave.
Cada tipo de generación (por ejemplo, un paquete de aplicación o marco) en Xcode se
trata como un módulo separado en Swift. Si se agrupan los aspectos del código de su
aplicación como una continuación-aplicaciones todo autónomo marco-tal vez para
encapsular y reutilizar ese código a través de múltiples definir dentro de ese marco será
parte de un módulo separado cuando se importa y se utiliza dentro de una aplicación , o
cuando se utiliza dentro de otro marco.
Un archivo de código fuente es un solo archivo Swift código fuente dentro de un
módulo (en efecto, un solo archivo dentro de una aplicación o marco). Aunque es
común para definir los distintos tipos de archivos de origen independientes, un solo
archivo fuente puede contener definiciones para varios tipos, funciones, y así
sucesivamente.

Niveles de acceso
Swift ofrece tres diferentes niveles de acceso para las entidades dentro de su
código. Estos niveles de acceso son en relación con el archivo de origen en el que se
define una entidad, y también en relación con el módulo que pertenece al archivo
fuente.
• El acceso público permite a las entidades a utilizar dentro de cualquier archivo de
origen de su módulo que defina, y también en un archivo de origen de otro módulo
que importa el módulo que defina.Normalmente se utiliza el acceso del público al
especificar la interfaz pública de un marco.
• El acceso interno permite a las entidades que deben utilizarse dentro de cualquier
archivo de origen de su módulo que defina, pero no en cualquier archivo fuente
externa de ese módulo. Normalmente se utiliza el acceso interno al definir una
aplicación o de la estructura interna de un marco.
• Acceso privado restringe el uso de una entidad para su propio archivo de origen que
define. Utilice el acceso privado a ocultar los detalles de implementación de una
parte específica de la funcionalidad.
El acceso del público es el más alto nivel de acceso (menos restrictivo) y acceso privado
es el más bajo (o más restrictivo) el nivel de acceso.

Principio Rector de Niveles de Acceso


Los niveles de acceso en Swift siguen un principio rector general: Ninguna entidad
puede ser definido en términos de otra entidad que tenga un (más restrictiva) nivel de
acceso inferior.
Por ejemplo:
• Una variable pública no puede ser definido como tener un tipo interno o privado,
porque el tipo puede no estar disponible en todas partes que se utiliza la variable
pública.
• Una función no puede tener un nivel de acceso más alto que sus tipos de parámetros
y el tipo de retorno, porque la función podría ser utilizada en situaciones en las que
sus tipos de constituyentes no están disponibles para el código circundante.

  266  
Las implicaciones concretas de este principio rector para diferentes aspectos de la
lengua están cubiertos en detalle a continuación.

Los niveles de acceso predeterminados


Todas las entidades en su código (con algunas excepciones específicas, como se
describe más adelante en este capítulo) tienen un nivel de acceso predeterminado de
interior si no se especifica un nivel de acceso explícito a ti mismo. Como resultado, en
muchos casos no es necesario especificar un nivel de acceso explícita en el código.

Niveles de acceso para aplicaciones individuales-objetivo


Cuando se escribe una sencilla aplicación a un solo objetivo, el código en su aplicación
suele ser auto-contenida dentro de la aplicación y no necesita ser hecho disponible fuera
de módulo de la aplicación. El nivel de acceso predeterminado de interior ya coincide
con este requisito. Por lo tanto, no es necesario especificar un nivel de acceso
personalizado. Es posible, sin embargo, querer marcar algunas partes de su código como
privado, a fin de ocultar sus detalles de implementación de otro código dentro del
módulo de la aplicación.

Niveles de acceso para los Marcos


Al desarrollar un marco, marque la interfaz de cara al público para ese marco lo público,
por lo que se puede ver y acceder a otros módulos, como por ejemplo una aplicación
que importa el marco. Esta interfaz pública-frente es la interfaz de programación de
aplicaciones (o API) para el marco.
NOTA
Cualquier detalle de implementación internos de su marco pueden seguir utilizando el
nivel de acceso por defecto de internos, o pueden ser marcados como privados si desea
ocultar los de otras partes del código interno del marco. Es necesario para marcar una
entidad como público sólo si desea que se convierta en parte de la API de su marco.
Sintaxis de Control de Acceso
Defina el nivel de acceso de una entidad mediante la colocación de uno de
los públicos , internos o privadosmodificadores antes introductor de la
entidad:
• public class SomePublicClass {}
• internal class SomeInternalClass {}
• private class SomePrivateClass {}

• public var somePublicVariable = 0
• internal let someInternalConstant = 0
• private func somePrivateFunction() {}
A menos que se especifique lo contrario, el nivel de acceso por defecto es interna, como
se describe en los niveles de acceso predeterminados . Esto significa
que SomeInternalClass y someInternalConstant pueden ser escrito sin un
modificador de nivel de acceso explícita, y seguirán teniendo un nivel de acceso de
interior:

  267  
• class SomeInternalClass {} // implicitly internal
• var someInternalConstant = 0 // implicitly internal

Tipos personalizados
Si desea especificar un nivel de acceso explícito a un tipo personalizado, que lo hagan
en el punto que defina el tipo. El nuevo tipo puede ser utilizada siempre que sea sus
permisos de nivel de acceso. Por ejemplo, si se define una clase privada, esa clase sólo
se puede utilizar como el tipo de una propiedad, o como un parámetro de función o tipo
de retorno, en el archivo de origen en el que se define la clase privada.
El nivel de control de acceso de un tipo también afecta el nivel de acceso
predeterminado del tipo de que los miembros (sus propiedades, métodos inicializadores
y subíndices). Si se define el nivel de acceso de un tipo como privado, el nivel de acceso
por defecto de sus miembros también será privado. Si se define el nivel de acceso de un
tipo como interna o pública (o utiliza el nivel de acceso por defecto de internos sin
especificar un nivel de acceso de forma explícita), el nivel de acceso predeterminado de
los miembros del tipo será interna.
NOTA
Como se mencionó anteriormente, un tipo por defecto públicos a tener miembros
internos, no miembros públicos. Si quieres un miembro de tipo de ser pública, debe
marcar explícitamente como tal. Este requisito garantiza que la API de cara al público
para un tipo es algo que se opta en la publicación, y evita la presentación de los trabajos
internos de un tipo como API pública por error.
• public class SomePublicClass { // explicitly public class
• public var somePublicProperty = 0 // explicitly public class member
• var someInternalProperty = 0 // implicitly internal class member
• private func somePrivateMethod() {} // explicitly private class member
• }

• class SomeInternalClass { // implicitly internal class
• var someInternalProperty = 0 // implicitly internal class member
• private func somePrivateMethod() {} // explicitly private class member
• }

• private class SomePrivateClass { // explicitly private class
• var somePrivateProperty = 0 // implicitly private class member
• func somePrivateMethod() {} // implicitly private class member
• }

Tipos Tuple
El nivel de acceso de un tipo tupla es el nivel de acceso más restrictivo de los tipos
utilizados en esa tupla.Por ejemplo, si el usuario crea una tupla de dos tipos diferentes,

  268  
uno con acceso interno y otro con acceso privado, el nivel de acceso para ese tipo tupla
compuesto será privada.
NOTA
Tipos de tupla no tienen una definición independiente de la forma en que las clases,
estructuras, enumeraciones y funciones hacen. Nivel de acceso de un tipo tupla se
deduce automáticamente cuando se utiliza el tipo de tupla, y no se puede especificar de
forma explícita.

Tipos de funciones
El nivel de acceso para un tipo de función se calcula como el nivel de acceso más
restrictivo de tipos de parámetros de la función y el tipo de retorno. Debe especificar el
nivel de acceso de forma explícita como parte de la definición de la función, si el nivel
de acceso de la función calculada no coincide con el valor por defecto contextual.
El ejemplo siguiente define una función global llamada algunaFuncion , sin
proporcionar un modificador específico nivel de acceso para la función en sí. Se podría
esperar que esta función tiene el nivel de acceso predeterminado de "interno", pero este
no es el caso. De hecho, algunaFuncion no recogería como está escrito a
continuación:
• func someFunction() -> (SomeInternalClass, SomePrivateClass) {
• // Implementación de la función va aquí  
• }  
Tipo de retorno de la función es un tipo tupla compuesta a partir de dos de las clases
personalizadas definidas anteriormente en Tipos personalizados . Una de estas clases se
definió como "interno", y el otro se definió como "privado". Por lo tanto, el nivel de
acceso general de la tupla tipo compuesto es (el nivel de acceso mínimo de tipos de
constituyentes de la tupla) "privado".
Debido a que el tipo de retorno de la función es privada, debe marcar el nivel de acceso
general de la función con el privado modificador para la declaración de la función de
ser válida:
• private func someFunction() -> (SomeInternalClass, SomePrivateClass) {
• // Implementación de la función va aquí  
• }  
No es válido para marcar la definición de algunaFuncion con
los públicos o internos modificadores, o para utilizar la configuración por
defecto de internos, ya que los usuarios públicos o internos de la función podría no tener
acceso adecuado a la clase privada usada en el tipo de retorno de la función.
Tipos de enumeración
Los casos individuales de una enumeración automáticamente reciben el mismo nivel de
acceso como la enumeración que pertenecen. No se puede especificar un nivel de acceso
diferente para casos de enumeración individuales.
En el siguiente ejemplo, el CompassPoint enumeración tiene un nivel de acceso
explícita de "público". Los casos de enumeración del
Norte , Sur , Este y Oeste , por tanto, también tienen un nivel de acceso de
"público":

  269  
• public enum CompassPoint {
• case North
• case South
• case East
• case West
• }

Valores primas y valores asociados


Los tipos utilizados para cualquier valor primas o valores asociados en una definición
de enumeración deben tener un nivel de acceso por lo menos tan alto como nivel de
acceso de la enumeración. No puede utilizar unprivado tipo que el tipo de valor en
bruto de una enumeración con un interno de nivel de acceso, por ejemplo.

Tipos anidados
Tipos anidados definidos dentro de un tipo privado tienen un nivel de acceso automático
de los privados.Tipos anidados definidos dentro de un tipo de público o un tipo interno
tienen un nivel de acceso automático de los internos. Si quieres un tipo anidado dentro
de un tipo de público que esté disponible públicamente, debe declarar explícitamente el
tipo anidado como público.

Subclassing
Usted puede crear una subclase de cualquier clase que se puede acceder en el contexto
de acceso actual.Una subclase no puede tener un nivel de acceso más alto que su
ejemplo superclase-para, usted no puede escribir una subclase de una superclase pública
interna.
Además, puede invalidar cualquier miembro de la clase (método, propiedad,
inicializador, o subíndice) que es visible en un contexto de acceso seguro.
Una anulación puede hacer un miembro de la clase heredada más accesible que su
versión de la superclase.En el siguiente ejemplo, la clase A es una clase pública con un
método privado llamado someMethod. Clase Bes una subclase de A , con un nivel de
acceso reducido de "interno". Sin embargo, la clase B proporciona una anulación
de someMethod con un nivel de acceso de "interno", que es más alta que la
implementación original de someMethod:
• public class A {
• private func someMethod() {}
• }

• internal class B: A {
• override internal func someMethod() {}
• }
Incluso es válido para un miembro de la subclase llamar a un miembro de la superclase
que tiene permisos de acceso más bajos que el miembro de la subclase, siempre y
  270  
cuando la llamada a miembro de la superclase tiene lugar dentro de un contexto de nivel
de acceso permitido (es decir, dentro del mismo archivo de origen como la superclase
para una llamada de miembro privado, o dentro del mismo módulo que la superclase
para una llamada miembro interno):
• public class A {
• private func someMethod() {}
• }

• internal class B: A {
• override internal func someMethod() {
• super.someMethod()
• }
• }
Debido superclase A y subclase B se definen en el mismo archivo fuente, es válido para
el B implementación de someMethod llamar super.someMethod () .

Constantes, variables, propiedades, y subíndices


Una constante, variable o la propiedad no puede ser más público que su tipo. No es
válido para escribir una propiedad pública con un tipo privado, por ejemplo. Del mismo
modo, un subíndice no puede ser más público que sea su tipo de índice o tipo de
retorno.
Si una constante, variable, propiedad, o subíndice hace uso de un tipo privado, la
constante, variable, propiedad, o subíndice debe también ser marcado como privado :
• private var privateInstance = SomePrivateClass()

Captadores y definidores
Getters y setters para las constantes, variables, propiedades y subíndices
automáticamente reciben el mismo nivel de acceso como la constante, variable,
propiedad, o subíndice que pertenecen.
Usted puede dar un setter un menor nivel de acceso de su correspondiente captador,
para restringir el alcance de lectura-escritura de esa variable, propiedad o subíndice. Se
asigna un nivel de acceso más bajo escribiendo privado (set) o interna
(set) antes de la var o subíndice introductor.
NOTA
Esta regla se aplica a las propiedades almacenados, así como propiedades calculadas. A
pesar de que usted no escribe un captador explícito y setter para una propiedad
almacenada, Swift todavía sintetiza un captador implícita y setter para que usted
proporcione el acceso al almacenamiento de respaldo de la propiedad
almacenada. Utilice privado (set) y interior (set) para cambiar el nivel de
acceso de este organismo sintetiza exactamente de la misma manera que para un setter
explícita en una propiedad calculada.
El ejemplo siguiente define una estructura llamada TrackedString , que mantiene
un registro del número de veces que una propiedad de cadena se modifica:

  271  
• struct TrackedString {
• private(set) var numberOfEdits = 0
• var value: String = "" {
• didSet {
• numberOfEdits++
• }
• }
• }
El TrackedString estructura define una propiedad de cadena almacenado
llamado valor , con un valor inicial de "" (una cadena vacía). La estructura también
define una propiedad de entero almacenado llamadonumberOfEdits , que se utiliza
para realizar el seguimiento del número de veces que el valor se modifica. Este
seguimiento modificación se lleva a cabo con un didSet observador propiedad en
el valor de la propiedad, que se incrementa numberOfEdits cada vez que
el valor de la propiedad se establece en un nuevo valor.
El TrackedString estructura y el valor de la propiedad no proporcionan un
modificador explícito nivel de acceso, por lo que ambos reciben el nivel de acceso por
defecto de internos. Sin embargo, el nivel de acceso para
el numberOfEdits propiedad está marcada con un (juego)
privado modificador para indicar que la propiedad debe ser ajustable sólo desde
dentro del mismo archivo fuente que la TrackedString definición de
estructura. Getter de la propiedad todavía tiene el nivel de acceso por defecto de
internos, pero su organismo es ahora privado a la fuente en la que TrackedString se
define. Esto permite TrackedString modificar elnumberOfEdits propiedad
internamente, sino para presentar la propiedad como una propiedad de sólo lectura
cuando es utilizado por otros archivos de código fuente en el mismo módulo.
Si crea una TrackedString instancia y modificar su valor de cadena un par de
veces, se puede ver elnumberOfEdits actualización valor de la propiedad para que
coincida con el número de modificaciones:
• var stringToEdit = TrackedString()
• stringToEdit.value = "This string will be tracked."
• stringToEdit.value += " This edit will increment numberOfEdits."
• stringToEdit.value += " So will this one."
• println("The number of edits is \(stringToEdit.numberOfEdits)")
• // imprime "El número de ediciones es de 3"  
Aunque se puede consultar el valor actual de la numberOfEdits propiedad desde
otro archivo de origen, no se puede modificar la propiedad de otro archivo de
origen. Esta restricción protege los detalles de implementación de
la TrackedString funcionalidad de edición de seguimiento, sin dejar de ofrecer
acceso conveniente a un aspecto de esa funcionalidad.
Tenga en cuenta que puede asignar un nivel de acceso explícito a la vez un getter y un
setter si es necesario.El siguiente ejemplo muestra una versión de

  272  
la TrackedString estructura en la que la estructura se define con un nivel de acceso
explícita de público. Los miembros de la estructura (incluyendo
la numberOfEditspropiedad), por tanto, tienen un nivel de acceso interno por
defecto. Usted puede hacer de la estructuranumberOfEdits pública getter de la
propiedad, y su setter propiedad privada, mediante la combinación de
lospúblicos y privados (juego) modificadores de nivel de acceso:
• public struct TrackedString {
• public private(set) var numberOfEdits = 0
• public var value: String = "" {
• didSet {
• numberOfEdits++
• }
• }
• public init() {}
• }

Inicializadores
Inicializadores personalizados se pueden asignar un nivel de acceso inferior o igual al
tipo que inicializar. La única excepción es para los inicializadores requeridos (según se
define en Inicializadores requeridos ). Un inicializador requerido debe tener el mismo
nivel de acceso como la clase a la que pertenece.
Al igual que con los parámetros de función y de método, los tipos de los parámetros de
un inicializador no pueden ser más privado que el propio nivel de acceso del
inicializador.

Inicializadores defecto
Swift proporciona un inicializador por defecto sin ningún argumento para cualquier
estructura o base clase que proporciona valores predeterminados para todas sus
propiedades y no proporciona al menos un inicializador de sí mismo. Este inicializador
por defecto se describe en Inicializadores predeterminados . El inicializador por defecto
tiene el mismo nivel de acceso como el tipo se inicializa.
NOTA
Para un tipo que se define como pública , el inicializador por defecto se considera
interna. Si desea un tipo público sea initializable con un inicializador sin argumentos
cuando se usa en otro módulo, debe proporcionar a un público sin argumentos
inicializador ti mismo como parte de la definición del tipo.

Por defecto miembro por miembro Inicializadores de Estructura Tipos


El inicializador de miembro por miembro predeterminado para un tipo de estructura se
considera privada si alguna de las propiedades almacenados de la estructura son
privados. De lo contrario, el inicializador tiene un nivel de acceso de interior.
Al igual que con el inicializador por defecto de arriba, si quieres un tipo de estructura
pública sea initializable con un inicializador de miembro por miembro cuando se usa en

  273  
otro módulo, debe proporcionar un miembro por miembro pública inicializador a sí
mismo como parte de la definición del tipo.

Protocolos
Si desea asignar un nivel de acceso explícito a un tipo de protocolo, que lo hagan en el
punto que defina el protocolo. Esto le permite crear protocolos que sólo pueden ser
adoptadas dentro de un contexto de acceso seguro.
El nivel de acceso de cada requisito dentro de una definición de protocolo se establece
automáticamente en el mismo nivel de acceso como el protocolo. No se puede
establecer un requisito de protocolo a un nivel de acceso diferente que el protocolo que
soporta. Esto asegura que todos los requisitos del protocolo serán visibles en cualquier
tipo que adopta el protocolo.
NOTA
Si define un protocolo público, los requisitos del protocolo requieren un nivel de acceso
público a dichos requisitos cuando se implementan. Este comportamiento es diferente
de otros tipos, en una definición de tipo público implica un nivel de acceso del interno
para los miembros del tipo.

Protocolo de Herencia
Si define un nuevo protocolo que se hereda de un protocolo existente, el nuevo
protocolo puede tener como máximo el mismo nivel de acceso como el protocolo
hereda de. No se puede escribir un protocolo público que hereda de un protocolo
interno, por ejemplo.

Protocolo de Conformidad
Un tipo puede ajustarse a un protocolo con un nivel de acceso más bajo que el propio
tipo. Por ejemplo, puede definir un tipo de público que puede ser utilizado en otros
módulos, pero cuya conformidad con un protocolo interno sólo se puede utilizar dentro
de la definición de módulo del protocolo interno.
El contexto en el que un tipo se ajusta a un protocolo en particular es el mínimo de nivel
de acceso del tipo y el nivel de acceso del protocolo. Si un tipo es pública, sino un
protocolo que se ajusta a es interno, la conformidad del tipo a que el protocolo también
es interna.
Cuando se escribe o ampliar un tipo de ajustarse a un protocolo, debe asegurarse de que
la aplicación del tipo de cada requisito protocolo tiene como mínimo el mismo nivel de
acceso como la conformidad del tipo con ese protocolo. Por ejemplo, si un tipo de
público se ajusta a un protocolo interno, la aplicación del tipo de cada requisito de
protocolo debe ser por lo menos "interna".
NOTA
En Swift, como en Objective-C, de conformidad protocolo es global-no es posible para
un tipo de ajustarse a un protocolo de dos maneras diferentes dentro del mismo
programa.

Extensiones
Puede ampliar una clase, estructura o enumeración en cualquier contexto en el que el
acceso a la clase, estructura o enumeración disponible. Cualquier tipo de miembros

  274  
agregaron en una extensión tiene el mismo nivel de acceso predeterminado como
miembros de tipo declarados en el modelo original está extendiendo.Por ejemplo, si
amplía un tipo de público, los nuevos miembros de tipo que agregue tendrán un nivel de
acceso predeterminado de interior.
Alternativamente, usted puede marcar una extensión con un modificador explícito nivel
de acceso (por ejemplo, extensión privada ) para establecer un nuevo nivel de
acceso por defecto para todos los miembros definidos dentro de la extensión. Este
nuevo valor predeterminado aún se puede anular dentro de la extensión para miembros
individuales.

Adición de Protocolo de conformidad con una extensión


No se puede proporcionar un modificador explícito nivel de acceso para una extensión
si está usando esa extensión para agregar conformidad protocolo. En cambio, el propio
nivel de acceso del protocolo se utiliza para proporcionar el nivel de acceso
predeterminado para cada aplicación el requisito de protocolo dentro de la extensión.

Genéricos
El nivel de acceso de un tipo genérico o función genérica es el mínimo del nivel de
acceso del tipo genérico o de la función en sí y el nivel de acceso de las restricciones de
tipo de sus parámetros de tipo.

Tipo de los nombres


Cualquier alias de tipo que defina se consideran como tipos distintos a efectos de
control de acceso. Un alias de tipo puede tener un nivel de acceso de menos de o igual
al nivel de acceso del tipo que alias. Por ejemplo, un tipo de alias privado puede crear
un alias para un tipo privado, interno o público, sino un tipo de alias público no puede
crear un alias para un tipo interno o privado.
NOTA
Esta regla también se aplica a escribir alias para tipos asociados que se utilizan para
satisfacer las conformidades de protocolo.
 

Operadores avanzados

Además de los operadores descritos en operadores básicos , Swift proporciona varios


operadores avanzados que realizan la manipulación valor más complejo. Estos incluyen
todos los operadores de bits y bits cambiando usted estará familiarizado con de C y
Objective-C.
A diferencia de los operadores aritméticos en C, los operadores aritméticos en Swift no
hacen desbordamiento por defecto. Comportamiento de desbordamiento es atrapado y
se expresa como un error.Para optar a desbordarse comportamiento, utilice el segundo
conjunto de operadores aritméticos de Swift que se desbordan por defecto, como el
operador de suma desbordamiento ( y + ). Todos estos operadores desbordamiento
comienzan con un signo ( y ).
Al definir sus propias estructuras, clases y enumeraciones, que puede ser útil para
proporcionar sus propias implementaciones de los operadores Swift estándar para este

  275  
tipo de encargo. Swift hace que sea fácil para proporcionar implementaciones a medida
de estos operadores y para determinar exactamente lo que su comportamiento debe ser
para cada tipo que cree.
Usted no está limitado a los operadores predefinidos. Swift le da la libertad para definir
sus propios operadores infijo costumbre, prefijos, Postfix, y de asignación, con valores
de precedencia y asociatividad personalizado. Estos operadores se pueden utilizar y
adoptaron en su código como cualquiera de los operadores predefinidos, e incluso se
puede extender los tipos existentes para apoyar a los operadores de encargo que usted
defina.
Operadores a nivel de bit
Operadores bit a bit le permiten manipular los bits de datos en bruto individuales dentro
de una estructura de datos. A menudo se utilizan en la programación de bajo nivel, tales
como la programación de gráficos y la creación de controlador de
dispositivo. Operadores bit a bit también pueden ser útiles cuando se trabaja con datos
en bruto procedentes de fuentes externas, como los datos de codificación y
decodificación de la comunicación a través de un protocolo personalizado.
Swift es compatible con todos los operadores de bits que se encuentran en C, tal como
se describe a continuación.
A nivel de bit del operador NO
El nivel de bit NO operador ( ~ ) invierte todos los bits en un número:

El nivel de bit NO es un operador prefijo, y aparece inmediatamente antes del valor que
opera en, sin ningún espacio en blanco:
• let initialBits: UInt8 = 0b00001111
• let invertedBits = ~initialBits // equals 11110000
Uint8 enteros tienen ocho bits y puede almacenar cualquier valor entre 0 y 255 . Este
ejemplo inicializa unaUint8 entero con el valor binario 00001111 , que tiene sus
primeros cuatro bits puestos a 0 , y sus segundos cuatro bits se establece en 1 . Esto es
equivalente a un valor decimal de 15 .
El bit a bit NO operador se utiliza a continuación para crear una nueva constante
llamada invertedBits , que es igual a initialBits , pero con todos los bits
invertidos. Ceros conviertan, y los convierten en ceros. El valor
de invertedBits es 11110000 , que es igual a un valor decimal sin signo de 240 .

Operador AND
El operador AND ( Y ) combina los bits de dos números. Devuelve un nuevo número
cuyos bits se establecen en 1 sólo si los bits son iguales a 1 en ambos números de
entrada:

  276  
 
En el siguiente ejemplo, los valores de firstSixBits y lastSixBits ambos
tienen cuatro bits medias iguales a 1. El operador AND los combina para hacer el
número 00111100 , que es igual a un valor decimal sin signo de60 :
• let firstSixBits: UInt8 = 0b11111100
• let lastSixBits: UInt8 = 0b00111111
• let middleFourBits = firstSixBits & lastSixBits // equals 00111100

Operador binario OR
El operador binario OR ( | ) compara los bits de dos números. El operador devuelve un
nuevo número cuyos bits se ponen a 1 si los bits son iguales a 1 , en tanto el número de
entrada:

En el siguiente ejemplo, los valores de someBits y moreBits tienen diferentes bits


puestos a 1 . El operador binario OR los combina para hacer el número 11111110 , lo
que equivale a un decimal sin signo de 254 :
• let someBits: UInt8 = 0b10110010
• let moreBits: UInt8 = 0b01011110
• let combinedbits = someBits | moreBits // equals 11111110

XOR Operador
El operador XOR bit a bit , o "operador O exclusivo" ( ^ ), compara los bits de dos
números. El operador devuelve un nuevo número cuyos bits se ponen a 1 , donde los

  277  
bits de entrada son diferentes y están ajustados a 0 , donde los bits de entrada son los
mismos:

 
En el siguiente ejemplo, los valores de firstBits y otherBits tienen cada uno un
conjunto de bits a 1 en un lugar que el otro no. El operador XOR bit a bit establece
estos dos bits a 1 en su valor de salida. Todos los otros bits
en firstBits y otherBits partido y se ponen a 0 en el valor de salida:
• let firstBits: UInt8 = 0b00010100
• let otherBits: UInt8 = 0b00000101
• let outputBits = firstBits ^ otherBits // equals 00010001

Izquierda en modo bit y Operadores de desplazamiento a la derecha
La izquierda en modo bit operador de desplazamiento ( << ) y en modo bit operador de
desplazamiento a la derecha ( >> ) se mueven todos los bits de un número a la
izquierda o la derecha por un número determinado de plazas, de acuerdo con las reglas
definidas a continuación.
Bit a bit a la izquierda y desplazamientos a la derecha tener el efecto de multiplicar o
dividir un número entero en un factor de dos. Cambiando los bits de un entero a la
izquierda por una posición duplica su valor, mientras que el cambio hacia la derecha por
una posición mitades su valor.
El cambio de comportamiento para Unsigned enteros
El comportamiento de desplazamiento de bits de enteros sin signo es la siguiente:
1. Los bits existentes se desplazan hacia la izquierda o hacia la derecha por el número
solicitado de lugares.
2. Todos los bits que se mueven más allá de los límites de almacenamiento del número
entero se descartan.
3. Los ceros se insertan en los espacios que quedan después de los bits originales se
mueven a la izquierda oa la derecha.
Este enfoque es conocido como un desplazamiento lógico .
La siguiente ilustración muestra los resultados de 11111111 << 1 (que
es 11111111 movido a la izquierda por 1lugar), y 11111111 >> 1 (que
es 11111111 desplaza a la derecha por 1 lugar). Números azules se desplazan,
números grises se descartan, y se insertan ceros naranja:

  278  
 

Así es como se ve poco cambio en el código Swift:


• let shiftBits: UInt8 = 4 // 00000100 in binary
• shiftBits << 1 // 00001000
• shiftBits << 2 // 00010000
• shiftBits << 5 // 10000000
• shiftBits << 6 // 00000000
• shiftBits >> 2 // 00000001
Usted puede utilizar el desplazamiento de bits para codificar y decodificar los valores
dentro de otros tipos de datos:
• let pink: UInt32 = 0xCC6699
• let redComponent = (pink & 0xFF0000) >> 16 // redComponent is 0xCC, or 204
• let greenComponent = (pink & 0x00FF00) >> 8 // greenComponent is 0x66, or 102
• let blueComponent = pink & 0x0000FF // blueComponent is 0x99, or 153
Este ejemplo utiliza un UInt32 constante llamada rosa para almacenar un valor de
color Hojas de estilo en cascada para el color rosa. El color CSS valor # CC6699 se
escribe como 0xCC6699 en representación número hexadecimal de Swift. Este color
se descompone luego en su color rojo ( CC ), verde ( 66 ), y azul ( 99 ) componentes
por el operador AND ( Y ) y el operador de desplazamiento a la derecha en modo bit
( >> ).
El componente rojo se obtiene mediante la realización de un AND bit a bit entre los
números 0xCC6699 y0xff0000 . Los ceros en 0xFF0000 efectivamente "máscara"
el segundo y tercer bytes de 0xCC6699 , haciendo que el 6699 para ser ignorados y
dejando 0xCC0000 como el resultado.
Este número es entonces desplazado 16 lugares a la derecha ( >> 16 ). Cada par de
caracteres en un número hexadecimal utiliza 8 bits, por lo que un movimiento de 16
lugares a la derecha convertirá 0xCC0000 en0x0000CC . Este es el mismo
que 0xCC , que tiene un valor decimal de 204 .
Del mismo modo, el componente verde se obtiene mediante la realización de un AND
bit a bit entre los números 0xCC6699 y 0x00FF00 , lo que da un valor de salida
de 0x006600 . Este valor de salida es entonces desplazado ocho lugares a la derecha,
dando un valor de 0x66 , que tiene un valor decimal de 102 .
Finalmente, el componente azul se obtiene mediante la realización de un AND bit a bit
entre los números0xCC6699 y 0x0000FF , lo que da un valor de salida
de 0x000099 . No hay necesidad de cambiar esto a la derecha, como 0x000099 ya
es igual a 0x99 , que tiene un valor decimal de 153 .

  279  
El cambio de comportamiento para los enteros con signo
El comportamiento de desplazamiento es más complejo para enteros con signo que para
los enteros sin signo, debido a la forma enteros con signo se representan en
binario. (Los ejemplos siguientes se basan en 8 bits enteros con signo de simplicidad,
pero los mismos principios se aplican para los enteros con signo de cualquier tamaño.)
Los enteros con signo utilizan su primer bit (conocido como el bit de signo ) para
indicar si el entero es positivo o negativo. Un bit de signo de 0 significa positivo, y un
bit de signo de 1 significa negativo.
Los bits restantes (conocidos como los bits de valor ) almacenan el valor real. Los
números positivos se almacenan exactamente de la misma manera que para enteros sin
signo, contando hacia arriba desde 0 . He aquí cómo los bits dentro de un INT8 buscan
el número 4 :

 
El bit de signo es 0 (lo que significa "positivo"), y los siete bits de valor son sólo el
número 4 , escrito en notación binaria.
Los números negativos, sin embargo, se almacenan de manera diferente. Se almacenan
restando su valor absoluto de 2 a la potencia de n , donde n es el número de bits de
valor. Un número de ocho bits tiene siete bits de valor, por lo que esto significa 2 a la
potencia de 7 , o 128 .
He aquí cómo los bits dentro de un INT8 buscan el número -4 :

 
Esta vez, el bit de signo es 1 (que significa "negativo"), y los siete bits de valor tiene un
valor binario de 124(que es 128-4 ):

La codificación para los números negativos se conoce como un complemento a dos


de la representación.Puede parecer una manera inusual para representar números
negativos, pero tiene varias ventajas.
En primer lugar, puede agregar -1 a -4 , basta con realizar una suma binaria estándar
de todos los ocho bits (incluyendo el bit de signo), y descartar cualquier cosa que no
encaja en los ocho bits, una vez que haya terminado:

  280  
 

En segundo lugar, la representación de los dos se complementan también le permite


desplazar los bits de los números negativos a la izquierda y la derecha como números
positivos, y aún así terminar duplicando ellos por cada turno que realice a la izquierda, o
reducir a la mitad de ellos por cada turno que realice a la derecha . Para lograr esto, se
utiliza una regla adicional cuando enteros con signo se desplazan a la derecha:
• Cuando usted cambia enteros con signo a la derecha, se aplican las mismas reglas
que para los enteros sin signo, pero llenar cualquier pedacito vacío de la izquierda
con el bit de signo , en lugar de con un cero.

Esta acción asegura que los números enteros con signo tienen el mismo signo después
de que se desplazan a la derecha, y se conoce como un desplazamiento aritmético .
Debido a la forma especial que los números positivos y negativos se almacenan,
cambiando cualquiera de ellos a la derecha los mueve más cerca de cero. Mantener el
signo mordió la misma durante este cambio significa que los enteros negativos siguen
siendo negativas ya que su valor se acerca a cero.

Operadores de desbordamiento
Si intenta insertar un número en una constante entera o variable que no puede contener
ese valor, por defecto Swift informa de un error en lugar de permitir un valor no válido
que se creará. Este comportamiento da mayor seguridad cuando se trabaja con números
que son demasiado grandes o demasiado pequeñas.
Por ejemplo, la Int16 tipo entero puede contener cualquier número entero con signo
entre -32768 y 32767 .Tratar de establecer una Int16 constante o variable a un
número fuera de este rango produce un error:
• var potentialOverflow = Int16.max
• // potentialOverflow equals 32767, which is the largest value an Int16 can hold
• potentialOverflow += 1
• // Esto provoca un error  
  281  
Manipulación cuando los valores se ponen demasiado grande o demasiado pequeño
error Siempre que da mucha más flexibilidad a la hora de codificación para las
condiciones de contorno.
Sin embargo, cuando usted desea específicamente una condición de desbordamiento
para truncar el número de bits disponibles, usted puede optar por este comportamiento
en lugar de desencadenar un error. Swift proporciona cinco aritméticos operadores de
desbordamiento que opten por el comportamiento de desbordamiento para los cálculos
de enteros. Estos operadores comienzan con un signo ( Y ):
• Además Overflow ( y + )
• Sustracción de desbordamiento ( y - )
• Multiplicación de desbordamiento ( & * )
• División de desbordamiento ( y / )
• Resto de desbordamiento ( &% )
Desbordamiento del valor
He aquí un ejemplo de lo que sucede cuando se permite un valor sin signo de
desbordarse, utilizando el operador de suma desbordamiento ( y + ):
• var willOverflow = UInt8.max
• // WillOverflow es igual a 255, que es el valor más grande
puede contener un Uint8  
• willOverflow = willOverflow &+ 1
• // WillOverflow es ahora igual a 0  
La variable willOverflow se inicializa con el valor más grande de un Uint8 puede
contener ( 255 , o 11111111 en binario). A continuación, se incrementa en 1 usando
el operador de suma de desbordamiento ( y + ). Esto empuja a su representación
binaria poco más el tamaño que un Uint8 puede sostener, provocando que se desborde
más allá de sus límites, como se muestra en el siguiente diagrama. El valor que se
mantiene dentro de los límites de la Uint8 después de la adición de desbordamiento
es 00000000 , o cero:

 
Valor Underflow
Los números también pueden llegar a ser demasiado pequeño como para caber dentro
de los límites máximos de su tipo. He aquí un ejemplo.
El menor valor que un Uint8 puede contener es 0 (que es 00 millones en forma
binaria de ocho bits). Si se resta 1 de 00 millones mediante el operador de
sustracción de desbordamiento, el número se desbordará hacia atrás y vuelta
a 11111111 , o 255 en decimal:

  282  
 

Así es como que se ve en el código Swift:


• // willUnderflow equals 0, which is the smallest value a UInt8 can hold
• willUnderflow = willUnderflow &- 1
• // willUnderflow is now equal to 255
Un desbordamiento similar ocurre para los enteros con signo. Toda la resta de enteros
con signo se realiza como la resta binaria directa, con el bit de signo incluye como parte
de los números que se sustrae, como se describe en la izquierda en modo bit y
Operadores de desplazamiento a la derecha . El número más pequeño que
un INT8 puede sostener es -128 , que es 10000000 en binario. Restando 1 de este
número binario con el operador de desbordamiento da un valor binario de 01111111 ,
que alterna el bit de signo y da positivo 127 , el valor positivo más grande que
un INT8 puede contener:

Aquí está lo mismo en código Swift:


• var signedUnderflow = Int8.min
• // SignedUnderflow es igual a -128, que es el valor más
pequeño puede contener un INT8  
• signedUnderflow = signedUnderflow &- 1
• // SignedUnderflow es ahora igual a 127  
El resultado final del comportamiento de extracto y refinado descrito anteriormente es
que tanto para los números enteros con y sin signo, desbordamiento siempre da la vuelta
del mayor valor entero válido de nuevo a la más pequeña, y la corriente de fondo
siempre se envuelve alrededor del valor más pequeño al más grande.

  283  
La división por cero
Al dividir un número por cero ( i / 0 ), o tratar de calcular resto por cero ( i% 0 ),
provoca un error:
• let x = 1
• let y = x / 0
Sin embargo, las versiones de desbordamiento de estos operadores ( y / y &% )
devuelven un valor de cero si se divide por cero:
• let x = 1
• let y = x &/ 0
• // Y es igual a 0  
 
Precedencia y asociatividad
Operador precedencia da algunos operadores de mayor prioridad que otras; estos
operadores se aplican primero.
Operador asociatividad define cómo se agrupan los operadores de la misma precedencia
juntos (o asociados) -bien agrupan desde la izquierda, o agrupados por la
derecha. Piense en ello en el sentido de "que asocian con la expresión a su izquierda", o
"que se asocian con la expresión de su derecho."
Es importante tener en cuenta la precedencia y asociatividad de cada operador cuando
se trabaja con el orden en el que se calcula una expresión compuesta. He aquí un
ejemplo. ¿Por qué la siguiente expresión es igual a 4 ?
• 2 + 3 * 4 % 5  
• // Esto es igual a 4  
Tomado estrictamente de izquierda a derecha, es de esperar que esto se lea como sigue:
• 2 más 3 igual a 5;
• 5 veces 4 es igual a 20;
• 20 resto 5 es igual a 0
Sin embargo, la respuesta real es 4 , no 0 . Operadores de mayor precedencia se evalúan
antes que las de menor precedencia. En Swift, como en C, el operador de multiplicación
( * ) y el operador de resto ( % ) tienen una mayor precedencia que el operador de suma
( + ). Como resultado, ambos son evaluados antes se considera la adición.
Sin embargo, la multiplicación y el resto tienen la misma precedencia que sí. Para
calcular el orden de evaluación exacta de usar, también es necesario tener en cuenta su
asociatividad. La multiplicación y la resta tanto asociado con la expresión a su
izquierda. Piense en esto como la adición de paréntesis implícitos alrededor de estas
partes de la expresión, a partir de su izquierda:
• 2 + (( 3 * 4 )% 5 )  
(3 * 4) es 12 , así que esto es equivalente a:
• 2 + ( 12 % 5 )  
(12% 5) es 2 , así que esto es equivalente a:
• 2 + 2  
Este cálculo se obtiene la respuesta final de 4 .

  284  
Para obtener una lista completa de precedencias operador Swift y reglas de
asociatividad, vea Expresiones .
NOTA
Precedencias operador de Swift y reglas de asociatividad son más simples y más
predecible que las que se encuentran en C y Objective-C. Sin embargo, esto significa
que no son los mismos que en lenguajes basados-C. Tenga cuidado para asegurar que
las interacciones del operador aún se comportan de la manera que usted piensa cuando
al portar el código existente para Swift.
Funciones del operador
Clases y estructuras pueden proporcionar sus propias implementaciones de los
operadores existentes. Esto se conoce como la sobrecarga de los operadores existentes.
El siguiente ejemplo muestra cómo implementar el operador de suma aritmética ( + )
para una estructura personalizada. El operador de suma aritmética es un operador
binario , ya que funciona con dos objetivos y se dice que es infijo porque aparece entre
esos dos objetivos.
El ejemplo define un Vector2D estructura para un vector bidimensional posición (x,
y) , seguido de una definición de una función de operador para añadir juntos instancias
de la Vector2D estructura:
• struct Vector2D {
• var x = 0.0, y = 0.0
• }
• func + (left: Vector2D, right: Vector2D) -> Vector2D {
• return Vector2D(x: left.x + right.x, y: left.y + right.y)
• }
La función de operador se define como una función global con un nombre de función
que coincide con el operador para ser sobrecargado ( + ). Debido a que el operador de
suma aritmética es un operador binario, esta función operador toma dos parámetros de
entrada de tipo Vector2D y devuelve un único valor de salida, también de
tipo Vector2D .
En esta aplicación, los parámetros de entrada se
denominan izquierda y derecha para representar losVector2D instancias que
estarán en el lado izquierdo y el lado derecho de la + operador. La función devuelve una
nueva Vector2D ejemplo, cuya x y Y. propiedades se inicializan con la suma de
la x y Y las propiedades de los dos Vector2D casos que se agregan juntos.
La función se define a nivel mundial, en lugar de como un método en
el Vector2D estructura, de modo que pueda ser utilizado como un operador infijo
entre existentes Vector2D casos:
• let vector = Vector2D(x: 3.0, y: 1.0)
• let anotherVector = Vector2D(x: 2.0, y: 4.0)
• let combinedVector = vector + anotherVector
• // CombinedVector es una instancia de Vector2D con valores
de (5.0, 5.0)  

  285  
Este ejemplo suma los vectores (3.0, 1.0) y (2.0, 4.0) para hacer que el
vector (5.0, 5.0) , como se ilustra a continuación.

 
Prefijo y Operadores de Postfix
El ejemplo anterior demuestra una implementación personalizada de un operador infijo
binario. Clases y estructuras también pueden proporcionar implementaciones de los
estándares operadores unarios . Los operadores unarios operan en un solo
objetivo. Son prefijo cuando fueren anteriores a su destino (por ejemplo : una )
y postfix operadores si siguen su destino (como i ++ ).
Implementa un prefijo o Postfix operador unitario escribiendo el prefijo o de
sufijo modificador antes de lafunc palabra clave cuando se declara la función de
operador:
• prefix func - (vector: Vector2D) -> Vector2D {
• return Vector2D(x: -vector.x, y: -vector.y)
• }
El ejemplo anterior implementa el operador menos unario ( -a )
para Vector2D casos. El operador menos unario es un operador prefijo, por lo que
esta función tiene que ser calificado con el prefijo modificador.
Para los valores numéricos simples, el operador menos unario convierte números
positivos en su negativa versa equivalente y el vicio. La aplicación correspondiente
para Vector2D casos realiza esta operación tanto en la x y Y propiedades:
• let positive = Vector2D(x: 3.0, y: 4.0)
• let negative = -positive
• // Negativo es una instancia de Vector2D con valores de (-
3,0, -4,0)  

  286  
• let alsoPositive = -negative
• // AlsoPositive es una instancia de Vector2D con valores de
(3.0, 4.0)  
•  
Operadores de Asignación Compuesto
Operadores de asignación compuestos combinan asignación ( = ) con otra
operación. Por ejemplo, el operador de asignación de suma ( + = ) combina la adición y
la asignación en una sola operación. Usted marca parámetro de entrada izquierda una
asignación del operador compuesto como inout , porque el valor del parámetro será
modificado directamente desde dentro de la función de operador.
El siguiente ejemplo implementa una función de operador de asignación de suma
para Vector2D casos:
• func += (inout left: Vector2D, right: Vector2D) {
• left = left + right
• }
Debido a que un operador de suma se definió anteriormente, no es necesario volver a
implementar el proceso de adición aquí. En lugar de ello, la función de operador de
asignación Además se aprovecha de la función de operador de suma existente, y la
utiliza para establecer el valor de izquierda a ser el valor más el valor izquierda derecha:
• var original = Vector2D(x: 1.0, y: 2.0)
• let vectorToAdd = Vector2D(x: 3.0, y: 4.0)
• original += vectorToAdd
• // Original, ahora muestra los valores de (4.0, 6.0)  
Puede combinar la asignación, ya sea con el prefijo o de sufijo modificador,
como en esta implementación del operador de incremento prefijo ( ++ una )
para Vector2D casos:
• prefix func ++ (inout vector: Vector2D) -> Vector2D {
• vector += Vector2D(x: 1.0, y: 1.0)
• return vector
• }
La función de operador de incremento prefijo anteriormente se aprovecha de que el
operador de asignación de suma definida anteriormente. Se añade
un Vector2D con x y Y los valores de 1,0 a la Vector2D en la que se le llama, y
devuelve el resultado:
• var toIncrement = Vector2D(x: 3.0, y: 4.0)
• let afterIncrement = ++toIncrement
• // ToIncrement ahora tiene valores de (4.0, 5.0)  
• // AfterIncrement también tiene valores de (4.0, 5.0)  
NOTA

  287  
No es posible sobrecargar el operador de asignación por defecto ( = ). Sólo los
operadores de asignación compuestos se pueden sobrecargar. Del mismo modo, el
operador condicional ternario ( a b:? c ) no puede ser sobrecargado.
Operadores de equivalencia
Clases y estructuras personalizadas no reciben una implementación por defecto de
los operadores de equivalencia , conocida como la "igual a" operador ( == ) y "no es
igual a" operador ( ! = ). No es posible que Swift adivinar lo calificaría como "igual"
para sus propios tipos personalizados, ya que el significado de "igual" depende de las
funciones que desempeñan esos tipos en el código.
Para utilizar los operadores de equivalencia para comprobar la equivalencia de su propio
tipo personalizado, proporcionar una implementación de los operadores de la misma
forma que para otros operadores infijos:
• func == (left: Vector2D, right: Vector2D) -> Bool {
• return (left.x == right.x) && (left.y == right.y)
• }
• func != (left: Vector2D, right: Vector2D) -> Bool {
• return !(left == right)
• }
El ejemplo anterior implementa un "igual a" operador ( == ) para comprobar si
dos Vector2D casos tienen valores equivalentes. En el contexto de Vector2D , tiene
sentido considerar "igual" en el sentido de "ambas instancias tienen los
mismos x valores y Y valores ", y por lo que esta es la lógica utilizada por la aplicación
del operador. El ejemplo también implementa el "no es igual a" operador ( ! = ), que
simplemente devuelve el inverso del resultado de la "igual a" operador.
Ahora puede utilizar estos operadores para comprobar si dos Vector2D casos son
equivalentes:
• let twoThree = Vector2D(x: 2.0, y: 3.0)
• let anotherTwoThree = Vector2D(x: 2.0, y: 3.0)
• if twoThree == anotherTwoThree {
• println("These two vectors are equivalent.")
• }
• // imprime "Estos dos vectores son equivalentes."  
 
Operadores personalizados
Puede declarar e implementar sus propios operadores personalizados además de los
operadores estándar proporcionados por Swift. Para obtener una lista de caracteres que
se pueden utilizar para definir operadores personalizados, consulte Operadores .
Los nuevos operadores se declaran a nivel global mediante el operador de la
palabra clave, y están marcados con los prefix,infix or postfix modificadores:
• prefix operator +++ {}
El ejemplo anterior define un nuevo operador de prefijo de llamada +++ . Este operador
no tiene un significado existente en Swift, y por lo que se le da su propio significado

  288  
personalizado debajo en el contexto específico de trabajar con Vector2D casos. Para
los fines de este ejemplo, +++ se trata como un nuevo operador "prefijo duplicar
incrementador". Dobla las x y Y valores de una Vector2D ejemplo, añadiendo que el
vector propio con el operador de asignación de suma definido anteriormente:
• prefix func +++ (inout vector: Vector2D) -> Vector2D {
• vector += vector
• return vector
• }
Esta implementación de +++ es muy similar a la aplicación de ++ para Vector2D ,
excepto que esta función de operador añade el vector a sí mismo, en lugar de
añadir Vector2D (1.0, 1.0) :
• var toBeDoubled = Vector2D(x: 1.0, y: 4.0)
• let afterDoubling = +++toBeDoubled
• // ToBeDoubled ahora muestra los valores de (2.0, 8.0)  
• // AfterDoubling también tiene valores de (2.0, 8.0)  
 
Precedencia y asociatividad de operadores infijos personalizados
Custom infix operadores también pueden especificar una prioridad y
una asociatividad . Ver Precedencia y asociatividad para una explicación de cómo estas
dos características afectan a la interacción de un operador infijo con otros operadores
infijos.
Los valores posibles para la asociatividad se dejaron , derecha ,
y ninguno . Operadores asociativos por la izquierda asociado a la izquierda si se
escribe junto a otros operadores asociativos por la izquierda de la misma
precedencia. Operadores de la misma manera, asociativo por la derecha asociada a la
derecha si escrito junto a otros operadores de la derecha asociativas de la misma
precedencia. Los operadores no asociativos no se pueden escribir junto a otros
operadores con la misma precedencia.
Los asociatividad valor predeterminado es ninguno si no se
especifica. Los precedencia valor por defecto es100 , si no se especifica.
El ejemplo siguiente define una nueva costumbre infijo operador de llamada + - ,
con izquierdaasociatividad y precedencia de 140 :
• infix operator +- { associativity left precedence 140 }
• func +- (left: Vector2D, right: Vector2D) -> Vector2D {
• return Vector2D(x: left.x + right.x, y: left.y - right.y)
• }
• let firstVector = Vector2D(x: 1.0, y: 2.0)
• let secondVector = Vector2D(x: 3.0, y: 4.0)
• let plusMinusVector = firstVector +- secondVector
• // PlusMinusVector es una instancia de Vector2D con valores
de (4,0, -2,0)  

  289  
Este operador suma los x valores de dos vectores, y resta el y valor de la segunda vector
desde el primero.Debido a que es en esencia un operador "aditivo", se ha dado a los
mismos valores de asociatividad y precedencia ( izquierda y 140 ) como
operadores infijos aditivo defecto como + y - . Para obtener una lista completa de los
ajustes de precedencia y asociatividad de operadores Swift predeterminados,
veaExpresiones .
NOTA
No se especifica una prioridad en la definición de un operador de prefijo o de sufijo. Sin
embargo, si usted solicita un prefijo y un operador de sufijo al mismo operando, el
operador de sufijo se aplica primero.
 

  290  
 

Acerca de la Referencia del lenguaje


Esta parte del libro describe la gramática formal del lenguaje de programación Swift. La
gramática se describe aquí está destinado a ayudar a entender el idioma con más detalle,
en lugar de que le permite implementar directamente un analizador o compilador.
El lenguaje Swift es relativamente pequeño, debido a que muchos comunes tipos,
funciones y operadores que aparecen prácticamente en todas partes en el código Swift
están definidos en la librería estándar de Swift. Aunque estos tipos, funciones y
operadores que no forman parte de la propia lengua Swift, que se utilizan ampliamente
en las discusiones y ejemplos de código en esta parte del libro.
Cómo leer la Gramática
La notación utilizada para describir la gramática formal del lenguaje de programación
Swift sigue una serie de convenciones:
• Una flecha (→) se utiliza para marcar las producciones de la gramática y se puede
leer como "puede consistir en."
• Categorías sintácticas se indican mediante cursiva texto y aparecen en ambos lados
de una regla de producción gramática.
• Palabras literales y puntuacion se indican con negrita anchura
constante texto y sólo aparecen en el lado derecho de una regla de gramática de
producción.
• Producciones gramaticales alternativos están separados por barras verticales
(|). Cuando producciones alternativas son demasiado tiempo para leer con facilidad,
que se dividen en varias reglas de la gramática de producción en nuevas líneas.
• En unos pocos casos, el texto fuente normal se utiliza para describir el lado derecho
de una regla de gramática de producción.
• Categorías y literales sintácticas opcionales están marcadas por un subíndice de
arrastre, optan .
Como ejemplo, la gramática de un bloque getter-setter se define como sigue:

GRAMÁTICA DE UN BLOQUE GETTER-SETTER

getter-setter-block → {getter-clausesetter-clauseopt} {setter-clausegetter-clause}

Esta definición indica que un bloque getter-setter puede consistir en una cláusula getter
seguida de una cláusula facultativa setter, entre llaves, o una cláusula setter seguido por
una cláusula getter, entre llaves. La producción de la gramática anterior es equivalente a
las siguientes dos producciones, donde las alternativas se extraen explícitamente:

GRAMÁTICA DE UN BLOQUE GETTER-SETTER


getter-setter-block → {getter-clausesetter-clauseopt} {setter-clausegetter-clause}
 

  291  
Estructura léxica
En esta página
La estructura léxica de Swift describe qué secuencia de caracteres forman símbolos
válidos de la lengua.Estos tokens válidos forman los bloques de construcción de más
bajo nivel de la lengua y se utilizan para describir el resto de la lengua en los capítulos
siguientes. Un símbolo consiste en un identificador, palabra clave, puntuacion, literal, o
el operador.
En la mayoría de los casos, las fichas se generan a partir de los caracteres de un archivo
de origen Swift considerando la más larga subcadena posible del texto de entrada,
dentro de las restricciones de la gramática que se especifican a continuación. Este
comportamiento se conoce como partido más largo o munch máxima.
Los espacios en blanco y comentarios
El espacio en blanco tiene dos usos: para separar tokens en el archivo de origen y para
ayudar a determinar si un operador es un prefijo o de sufijo (ver Operadores ), pero se
ignora lo contrario. Los siguientes caracteres se consideran espacios en blanco: espacio
(U + 0020), avance de línea (U + 000A), retorno de carro (U + 000D), tabulador
horizontal (U + 0009), pestaña vertical (U + 000B), la forma de alimentación (U +
000C) y nulo (U + 0000).
Los comentarios son tratados como espacios en blanco por el compilador. Una sola
línea Los comentarios comienzan con // y continuar hasta que un retorno de carro (U +
000D) o avance de línea (U + 000A).Comentarios multilínea empiezan con / * y
terminan con * / . Anidación comentarios multilínea está permitido, pero los
marcadores de comentario debe ser equilibrado.
Identificadores
Identificadores comienzan con una letra mayúscula o minúscula de la A a la Z, un guión
bajo ( _ ), un carácter alfanumérico noncombining Unicode en el plano multilingüe
básico, o un personaje fuera del plano multilingüe básico que no está en un área de uso
privado. Después del primer carácter, también se permite la combinación de dígitos y
caracteres Unicode.
Para utilizar una palabra reservada como identificador, poner un acento grave ( ` ) antes
y después de ella.Por ejemplo, la clase no es un identificador válido,
pero `class` es válida. Los acentos abiertos no se consideran parte del
identificador; `x` y x tienen el mismo significado.
Dentro de un cierre sin nombres explícitos de los parámetros, los parámetros se
denominan implícitamente $ 0 , $ 1 , $ 2 , y así sucesivamente. Estos nombres son
identificadores válidos dentro del ámbito de aplicación del cierre.
GRAMÁTICA DE UN IDENTIFICADOR
identifier → identifier-headidentifier-charactersopt
identifier → `identifier-headidentifier-charactersopt`
identifier → implicit-parameter-name
identifier-list → identifier identifier,identifier-list
identifier-head → Upper- or lowercase letter A through Z
identifier-head → _
identifier-head → U+00A8, U+00AA, U+00AD, U+00AF, U+00B2–U+00B5, or
U+00B7–U+00BA

  292  
identifier-head → U+00BC–U+00BE, U+00C0–U+00D6, U+00D8–U+00F6, or
U+00F8–U+00FF
identifier-head → U+0100–U+02FF, U+0370–U+167F, U+1681–U+180D, or
U+180F–U+1DBF
identifier-head → U+1E00–U+1FFF
identifier-head → U+200B–U+200D, U+202A–U+202E, U+203F–U+2040, U+2054,
or U+2060–U+206F
identifier-head → U+2070–U+20CF, U+2100–U+218F, U+2460–U+24FF, or U+2776–
U+2793
identifier-head → U+2C00–U+2DFF or U+2E80–U+2FFF
identifier-head → U+3004–U+3007, U+3021–U+302F, U+3031–U+303F, or U+3040–
U+D7FF
identifier-head → U+F900–U+FD3D, U+FD40–U+FDCF, U+FDF0–U+FE1F, or
U+FE30–U+FE44
identifier-head → U+FE47–U+FFFD
identifier-head → U+10000–U+1FFFD, U+20000–U+2FFFD, U+30000–U+3FFFD, or
U+40000–U+4FFFD
identifier-head → U+50000–U+5FFFD, U+60000–U+6FFFD, U+70000–U+7FFFD, or
U+80000–U+8FFFD
identifier-head → U+90000–U+9FFFD, U+A0000–U+AFFFD, U+B0000–U+BFFFD,
or U+C0000–U+CFFFD
identifier-head → U+D0000–U+DFFFD or U+E0000–U+EFFFD
identifier-character → Digit 0 through 9
identifier-character → U+0300–U+036F, U+1DC0–U+1DFF, U+20D0–U+20FF, or
U+FE20–U+FE2F
identifier-character → identifier-head
identifier-characters → identifier-characteridentifier-charactersopt
implicit-parameter-name → $decimal-digits

Palabras clave y Puntuacion


Los siguientes palabras clave están reservados y no se pueden usar como
identificadores, a menos que estén escaparon con acentos abiertos, como se describe
anteriormente en Identificadores .
• Keywords used in
declarations: class, deinit, enum, extension, func, import, init, internal, let, opera
tor,private, protocol, public, static, struct, subscript, typealias, and var.
• Keywords used in
statements: break, case, continue, default, do, else, fallthrough, for, if, in, return,
switch, where, and while.
• Keywords used in expressions and
types: as, dynamicType, false, is, nil, self, Self, super, true,__COLUMN__, __FI
LE__, __FUNCTION__, and __LINE__.
• Keywords reserved in particular
contexts: associativity, convenience, dynamic, didSet, final, get, infix,inout, lazy
, left, mutating, none, nonmutating, optional, override, postfix, precedence, prefi

  293  
x, Protocol,required, right, set, Type, unowned, weak, and willSet. Palabras
clave reservadas, en particular, y willSet . Fuera del contexto en el que
aparecen en la gramática, que pueden utilizarse como identificadores.
Las siguientes fichas están reservados como puntuacion y no pueden ser utilizados
como operadores personalizados: ( , ) , { , } , [ , ] , . , , , : , ; , = , @ , # , y (como
operador de prefijo) , -> , ` , ? , y ! (como un operador de sufijo).

Literales
Un literal es la representación código fuente de un valor de un tipo, tal como un número
o una cadena.
Los siguientes son ejemplos de literales:
• 42 // Integer literal
• 3.14159 // Floating-point literal
• "Hello, world!" // String literal
• true // Boolean literal
Un literal no tiene un tipo por sí solo. En su lugar, un literal se analiza como tener una
precisión infinita y la inferencia de tipos de Swift intentos de inferir un tipo de lo
literal. Por ejemplo, en la declaración sea x: INT8 = 42 , Swift utiliza el tipo de
anotación explícita ( : INT8 ) para inferir que el tipo del entero literal 42 es INT8 . Si
no hay información de tipo adecuado disponible, Swift infiere que el tipo del literal es
uno de los tipos literales defecto definidos en la librería estándar de Swift. Los tipos por
defecto son Int para literales enteros, doblepara los literales de punto
flotante, Cadena de literales de cadena, y Bool para los literales booleanos. Por
ejemplo, en la declaración deje cadena = "Hola, mundo" , el tipo inferido por
defecto de la cadena literal "Hola, mundo" es de cuerda .
Al especificar la anotación de tipo por un valor literal, el tipo de la anotación debe ser
un tipo que se pueden crear instancias de ese valor literal. Es decir, el tipo debe ajustarse
a uno de los siguientes protocolos de la biblioteca estándar
Swift: IntegerLiteralConvertible para literales
enteros, FloatingPointLiteralConvertiblepara literales de punto
flotante, StringLiteralConvertible para los literales de cadena,
yBooleanLiteralConvertible para los literales booleanos. Por
ejemplo, INT8 se ajusta a laIntegerLiteralConvertible protocolo, y por lo
tanto puede ser utilizado en la anotación de tipo para el número entero literal 42 en la
declaración sea x: INT8 = 42 .

GRAMÁTICA DE UN LITERAL
literal → integer-literal floating-point-literal string-literal
literal → true false nil

Enteros literales
Literales enteros representan valores enteros de precisión sin especificar. Por defecto,
los literales enteros se expresan en decimal; puede especificar una base alternativo

  294  
usando un prefijo. Literales binarios comienzan con 0b , literales octales comienzan
con 0 ° , y los literales hexadecimales comienzan con 0x .
Literales decimales contienen los dígitos 0 a través de 9 . Literales binarios
contienen 0 y 1 , literales octales contienen 0 a través de 7 y literales hexadecimales
contienen 0 a través de 9 , así como A través de F en mayúsculas o en minúsculas.
Literales enteros negativos se expresan anteponiendo un signo menos ( - ) en un entero
literal, como en -42 .
Guiones bajos ( _ ) se permite entre los dígitos para facilitar la lectura, pero se ignoran y
por lo tanto no afectan el valor del literal. Literales enteros pueden comenzar con ceros
a la izquierda ( 0 ), pero son igualmente ignorado y no afectará a la base o el valor del
literal.
A menos que se especifique lo contrario, el tipo inferido por defecto de un entero literal
es el tipo de biblioteca estándar Swift Int . La biblioteca estándar Swift también define
los tipos para diferentes tamaños de los enteros con y sin signo, como se describe en los
números enteros .
GRAMÁTICA DE UN LITERAL ENTERO
integer-literal → binary-literal
integer-literal → octal-literal
integer-literal → decimal-literal
integer-literal → hexadecimal-literal
binary-literal → 0bbinary-digitbinary-literal-charactersopt
binary-digit → Digit 0 or 1
binary-literal-character → binary-digit _
binary-literal-characters → binary-literal-characterbinary-literal-charactersopt
octal-literal → 0ooctal-digitoctal-literal-charactersopt
octal-digit → Digit 0 through 7
octal-literal-character → octal-digit _
octal-literal-characters → octal-literal-characteroctal-literal-charactersopt
decimal-literal → decimal-digitdecimal-literal-charactersopt
decimal-digit → Digit 0 through 9
decimal-digits → decimal-digitdecimal-digitsopt
decimal-literal-character → decimal-digit _
decimal-literal-characters → decimal-literal-characterdecimal-literal-charactersopt
hexadecimal-literal → 0xhexadecimal-digithexadecimal-literal-charactersopt
hexadecimal-digit → Digit 0 through 9, a through f, or A through F
hexadecimal-literal-character → hexadecimal-digit _
hexadecimal-literal-characters → hexadecimal-literal-characterhexadecimal-literal-
characters opt

Floating-Point literales
Literales de punto flotante representan valores de punto flotante de precisión sin
especificar.
Por defecto, los literales de punto flotante se expresan en decimal (sin prefijo), pero
también pueden ser expresados en hexadecimal (con un 0x prefijo).

  295  
Literales decimales de coma flotante consisten en una secuencia de dígitos decimales
seguidos por cualquiera de una fracción decimal, un exponente decimal, o ambos. La
fracción decimal consta de un punto decimal ( . ) seguido de una secuencia de dígitos
decimales. El exponente consiste en un mayúsculas o minúsculas e prefijo seguido por
una secuencia de dígitos decimales que indica qué potencia de 10 del valor anterior a
la e se multiplica por. Por ejemplo, 1.25e2 representa 1.25 × 10 2 , que evalúa
a 125,0 . Del mismo modo, 1.25E-2 representa 1,25 x 10 -2 , que evalúa
a 0,0125 .
Hexadecimales literales de punto flotante consisten en un 0x prefijo, seguido de una
fracción hexadecimal opcional, seguido de un exponente hexadecimal. La fracción
hexadecimal consta de un punto decimal seguido por una secuencia de dígitos
hexadecimales. El exponente consiste en un mayúsculas o minúsculasp prefijo seguido
por una secuencia de dígitos decimales que indica qué potencia de 2, el valor anterior a
la pse multiplica por. Por ejemplo, 0xFp2 representa 15 × 2 2 , que evalúa a 60 . Del
mismo modo, 0xFp-2representa 15 × 2 -2 , que evalúa a 3,75 .
A diferencia de los literales enteros, números de punto flotante negativos se expresan
aplicando el operador menos unario ( - ) a un literal de coma flotante, como en -
42,0 . El resultado es una expresión, no un literal de coma flotante.
Guiones bajos ( _ ) se permite entre los dígitos para facilitar la lectura, pero se ignoran y
por lo tanto no afectan el valor del literal. Literales de punto flotante pueden comenzar
con ceros a la izquierda ( 0 ), pero están igualmente ignorado y no afectará a la base o el
valor del literal.
A menos que se especifique lo contrario, el tipo inferido por defecto de un literal de
coma flotante es el tipo de biblioteca estándar Swift doble , lo que representa un
número de punto flotante de 64 bits. La biblioteca estándar Swift también define
un flotador tipo, lo que representa un número de punto flotante de 32 bits.

GRAMÁTICA DE UN LITERAL DE COMA FLOTANTE


floating-point-literal → decimal-literaldecimal-fractionoptdecimal-exponentopt
floating-point-literal → hexadecimal-literalhexadecimal-fractionopthexadecimal-
exponent
decimal-fraction → .decimal-literal
decimal-exponent → floating-point-esignoptdecimal-literal
hexadecimal-fraction → .hexadecimal-digithexadecimal-literal-charactersopt
hexadecimal-exponent → floating-point-psignoptdecimal-literal
floating-point-e → e E
floating-point-p → p P
sign → + -

Literales de cadena
Un literal de cadena es una secuencia de caracteres entre comillas, por, con el siguiente
formulario:
• " characters "
Los literales de cadena no puede contener un doble cita no literal ( " ), una barra
invertida sin escape ( \ ), un retorno de carro o un salto de línea.

  296  
Los caracteres especiales pueden ser incluidos en los literales de cadena utilizando las
siguientes secuencias de escape:
• Carácter nulo ( \ 0 )
• Barra invertida ( \\ )
• Horizontal Tab ( \ t )
• Avance de línea ( \ n )
• Retorno de carro ( \ r )
• Doble Cita ( \ " )
• Las comillas sencillas ( \ ' )
• Unicode escalar ( \ u { n } ), donde n es entre uno y ocho dígitos hexadecimales
El valor de una expresión se puede insertar en una cadena literal mediante la colocación
de la expresión entre paréntesis después de una barra invertida ( \ ). La expresión
interpolado no debe contener un doble cita no literal ( " ), una barra invertida sin escape
( \ ), un retorno de carro o un salto de línea. La expresión debe evaluarse como un valor
de un tipo que la Cadena de clase tiene un inicializador de.
Por ejemplo, todos los siguientes literales de cadena tienen el mismo valor:
• "1 2 3"  
• "1 2 \ ( 3 ) "  
• "1 2 \ ( 1 + 2 ) "  
• dejar que x = 3 ; "1 2 \ ( x ) "  
El tipo inferido por defecto de un literal de cadena es de cuerda . El tipo inferido por
defecto de los caracteres que componen una cadena es de caracteres . Para
obtener más información acerca de las cuerdas y de Carácter tipos, vea Cadenas
y caracteres .

GRAMÁTICA DE UNA CADENA LITERAL


string-literal → "quoted-textopt"
quoted-text → quoted-text-itemquoted-textopt
quoted-text-item → escaped-character
quoted-text-item → \(expression)
quoted-text-item → Any Unicode extended grapheme cluster except ", \, U+000A, or
U+000D
escaped-character → \0 \\ \t \n \r \" \'
escaped-character → \u{unicode-scalar-digits}
unicode-scalar-digits → Between one and eight hexadecimal digits

Operadores
La biblioteca estándar Swift define una serie de operadores para su uso, muchas de las
cuales se describenOperadores básicos y Operadores avanzados . La presente sección
describe qué caracteres se pueden usar para definir operadores personalizados.
Operadores personalizados pueden comenzar con uno de los caracteres ASCII / , = , -
, + , ! , * , % , < , > , y ,| , ^ , o ~ , o uno de los caracteres Unicode definido en la
gramática de abajo. Después del primer carácter, también se permite la combinación de

  297  
caracteres Unicode. También puede definir operadores personalizados como una
secuencia de dos o más puntos (por ejemplo, .... ).
NOTA
Los tokens = , -> , // , / * , * / , . , y el operador de prefijo y se reservan. Estas
fichas no se pueden sobrecargar, ni pueden ser utilizados como operadores
personalizados.
El espacio en blanco alrededor de un operador se utiliza para determinar si un operador
se utiliza como un operador de prefijo, un operador de sufijo, o un operador
binario. Este comportamiento se resume en las siguientes reglas:
• Si un operador ha de espacio en blanco alrededor de ambos lados o alrededor de
ninguna de las partes, se trata como un operador binario. A modo de ejemplo,
el + operador en un + b y a + b es tratado como un operador binario.
• Si el operador tiene espacios en blanco sólo en el lado izquierdo, se trata como un
operador unario prefijo. Como un ejemplo, el ++ operador en un ++ b se trata
como un operador unario prefijo.
• Si el operador tiene espacios en blanco sólo en el lado derecho, se trata como un
operador unario postfix. A modo de ejemplo, el ++ operador en un ++ b es
tratado como un operador unario postfix.
• Si un operador no tiene espacios en blanco a la izquierda, pero es seguida
inmediatamente por un punto ( . ), se trata como un operador unario postfix. Como
un ejemplo, el ++ operador en un ++. B se trata como un operador unario postfix
( a ++ .b en lugar de un ++ .b ).
Para los efectos de este reglamento, los personajes ( , [ , y { antes de un operador, de
los personajes ) , ] y} después de un operador, y los personajes , , , , y : también se
consideran espacios en blanco.
Hay una advertencia a las reglas anteriores. Si el ! o ? operador predefinido no tiene
espacios en blanco a la izquierda, se trata como un operador de sufijo,
independientemente de si se tiene un espacio en blanco a la derecha. Para utilizar
el ? como el operador opcional en cadena, que no debe tener espacios en blanco a la
izquierda. Para usarlo en el ternario condicional ( ? : ) operador, debe tener un espacio
en blanco alrededor de ambos lados.
En ciertas construcciones, los operadores con un líder < o > se pueden dividir en dos o
más fichas. El resto es tratado de la misma manera y se puede dividir de nuevo. Como
resultado, no hay necesidad de utilizar espacios en blanco para eliminar la ambigüedad
entre el cierre > caracteres en constructos como Diccionario <String, Array
<Int >> . En este ejemplo, las de cierre > personajes no son tratados como una sola
señal de que luego pueden ser mal interpretada como un desplazamiento de
bits >> operador.
Para saber cómo definir nuevos operadores personalizados, vea Operadores
personalizados y Declaración del operador . Para aprender a sobrecargar los operadores
existentes, consulte Funciones del operador .

GRAMÁTICA DE LOS OPERADORES


operator → operator-headoperator-charactersopt
operator → dot-operator-headdot-operator-charactersopt
operator-head → / = - + ! * % < > & | ^ ~

  298  
operator-head → U+00A1–U+00A7
operator-head → U+00A9 or U+00AB
operator-head → U+00AC or U+00AE
operator-head → U+00B0–U+00B1, U+00B6, U+00BB, U+00BF, U+00D7, or
U+00F7
operator-head → U+2016–U+2017 or U+2020–U+2027
operator-head → U+2030–U+203E
operator-head → U+2041–U+2053
operator-head → U+2055–U+205E
operator-head → U+2190–U+23FF
operator-head → U+2500–U+2775
operator-head → U+2794–U+2BFF
operator-head → U+2E00–U+2E7F
operator-head → U+3001–U+3003
operator-head → U+3008–U+3030
operator-character → operator-head
operator-character → U+0300–U+036F
operator-character → U+1DC0–U+1DFF
operator-character → U+20D0–U+20FF
operator-character → U+FE00–U+FE0F
operator-character → U+FE20–U+FE2F
operator-character → U+E0100–U+E01EF
operator-characters → operator-characteroperator-charactersopt
dot-operator-head → ..
dot-operator-character → . operator-character
dot-operator-characters → dot-operator-characterdot-operator-charactersopt
binary-operator → operator
prefix-operator → operator
postfix-operator → operator
 

Tipos

En Swift, hay dos clases de tipos: tipos con nombre y tipos de compuestos. Un tipo con
nombre es un tipo que se puede dar un nombre en particular cuando se define. Tipos con
nombre incluyen clases, estructuras, enumeraciones y protocolos. Por ejemplo, las
instancias de una clase llamada definidos por el usuario MyClasstienen el
tipo MyClass . Además de los tipos con nombres definidos por el usuario, la biblioteca
estándar Swift define muchos tipos con nombre de uso común, incluidos aquellos que
representan arrays, diccionarios, y los valores opcionales.
Tipos de datos que normalmente se consideran básicos o primitivos en otros idiomas-
como los tipos que representan números, caracteres y cadenas-se nombren tipos,
definidos e implementados en la biblioteca estándar Swift utilizando estructuras. Debido
a que se nombran los tipos, puede extender su comportamiento para adaptarse a las
necesidades de su programa, usando una ampliación de declaración, se discutió
enExtensiones y ampliación de declaración .

  299  
Un tipo de compuesto es un tipo sin nombre, que se define en el propio idioma
Swift. Hay dos tipos de compuestos: tipos de funciones y tipos de tupla. Un tipo de
compuesto puede contener tipos con nombre y otros tipos compuestos. Por ejemplo, el
tipo tupla (Int, (Int, Int)) contiene dos elementos: el primero es el tipo
llamado Int , y el segundo es otro tipo compuesto (Int, Int) .
Este capítulo trata de los tipos definidos en el propio idioma Swift y describe el
comportamiento inferencia tipo de Swift.

GRAMÁTICA DE UN TIPO
type → array-type dictionary-type function-type type-identifier tuple-type optional-
type implicitly-unwrapped-optional-type protocol-composition-type metatype-type

Tipo de anotación
Una anotación de tipo especifica explícitamente el tipo de una variable o
expresión. Tipo anotaciones empiezan con dos puntos ( : ) y terminan con un tipo,
como muestran los siguientes ejemplos:
• let someTuple: (Double, Double) = (3.14159, 2.71828)
• func someFunction(a: Int) { /* ... */ }
En el primer ejemplo, la expresión someTuple Se especifica que el tipo de
tupla (Doble, doble) . En el segundo ejemplo, el parámetro de una función a
la algunaFuncion Se especifica que el tipo int .
Tipo anotaciones pueden contener una lista opcional de atributos de tipo antes de que el
tipo.

GRAMÁTICA DE UNA ANOTACIÓN DE TIPO


type-annotation → :attributesopttype

Identificador de Tipo
Un identificador de tipo hace referencia a un tipo con nombre o un alias de tipo de un
tipo con nombre o compuesto.
La mayoría del tiempo, un identificador de tipo se refiere directamente a un tipo
llamado con el mismo nombre que el identificador. Por ejemplo, int es un
identificador de tipo que se refiera directamente al tipo llamado Int, y el identificador
de tipo Dictionary <String, int> se refiere directamente al tipo
llamado Diccionario <String, int> .
Hay dos casos en los que un identificador de tipo no se refiere a un tipo con el mismo
nombre. En el primer caso, un identificador de tipo se refiere a un alias de tipo de un
tipo llamado o compuesto. Por ejemplo, en el siguiente ejemplo, el uso de punto en la
anotación de tipo se refiere al tipo tupla (Int, Int) .
• typealias Point = (Int, Int)
• let origin: Point = (0, 0)
En el segundo caso, un identificador de tipo utiliza punto ( . ) sintaxis para referirse a
tipos con nombre declaradas en otros módulos o anidados dentro de otros tipos. Por

  300  
ejemplo, el identificador de tipo en el código siguiente se hace referencia al tipo
llamado MyType que se declara en la ExampleModule módulo.
• var someValue: ExampleModule.MyType

GRAMÁTICA DE UN IDENTIFICADOR DE TIPO
type-identifier → type-namegeneric-argument-clauseopt type-namegeneric-argument-
clauseopt.type-identifier
type-name → identifier

Tipo Tuple
Un tipo tupla es una lista separada por comas de cero o más tipos, entre paréntesis.
Puede utilizar un tipo tupla como el tipo de retorno de una función para activar la
función para devolver un solo tupla que contiene varios valores. También puede
nombrar a los elementos de un tipo tupla y utilizar esos nombres para referirse a los
valores de los elementos individuales. Un nombre de elemento consta de un
identificador seguido inmediatamente por dos puntos (:). Para ver un ejemplo que
demuestra tanto de estas funciones, consulte Funciones con múltiples valores de
retorno .
Vacío es un typealias para el tipo de tupla vacía, () . Si sólo hay un elemento dentro
de los paréntesis, el tipo es simplemente el tipo de ese elemento. Por ejemplo, el tipo
de (Int) es Int , no (Int) . Como resultado, puede nombrar a un elemento de la
tupla sólo cuando el tipo de tupla tiene dos o más elementos.

GRAMÁTICA DE UN TIPO TUPLA


de tipo tupla → ( tupla tipo de cuerpo opt)
tupla de tipo de cuerpo → tupla-tipo-elemento-lista ... opt
tupla de tipo de elemento lista → tipo tupla de elementos de tipo tupla de
elementos , tupla-tipo-elemento-lista
tupla de tipo de elemento → atributos optan inout opt tipo inout opt elemento-
nombre -tipo de anotación

Tipo de función
Un tipo de función representa el tipo de una función, método, o el cierre y se compone
de un tipo de parámetro y retorno separados por una flecha ( -> ):
• tipo de parámetro -> tipo de retorno
Debido a que el tipo de parámetro y el tipo de retorno puede ser un tipo tupla, tipos de
funciones de soporte a las funciones y métodos que toman múltiples parámetros y
devuelven varios valores.
Puede aplicar el autoclosure atributo a un tipo de función que tiene un tipo de
parámetro de () y que devuelve el tipo de una expresión (ver Tipo Atributos ). Una
función autoclosure capta un cierre implícito sobre la expresión especificada, en lugar
de la propia expresión. El ejemplo siguiente utiliza la autoclosure atributo en la
definición de una función assert muy simple:

  301  
• func simpleAssert(condition: @autoclosureautoclosure () -> Bool, message:
String) {
• if !condition() {
• println(message)
• }
• }
• let testNumber = 5
• simpleAssert(testNumber % 2 == 0, "testNumber isn't an even number.")
• // Impresiones "testNumber no es un número par."  
Un tipo de función puede tener un parámetro variadic como el último parámetro en
su tipo de parámetro .Sintácticamente, un parámetro variadic consta de un nombre de
tipo base, seguido inmediatamente por tres puntos ( ... ), como en Int ... . Un
parámetro variadic se trata como una matriz que contiene los elementos del nombre de
tipo de base. Por ejemplo, el parámetro variadic Int ... se trata como [Int] . Para
ver un ejemplo que utiliza un parámetro variadic, consulte Parámetros variadic .
Para especificar un parámetro in-out, prefijar el tipo de parámetro con el inout palabra
clave. No se puede marcar un parámetro variadic o un tipo de retorno con
el inout palabra clave. In-Out parámetros se discuten en Parámetros In-Out .
Los tipos de función de una función de curry se agrupan de derecha a izquierda. Por
ejemplo, el tipo de función Int -> Int -> Int se entiende como Int -> (Int
-> Int) , es decir, una función que toma un int y devuelve otra función que toma y
devuelve un int . Función al curry se describen en Funciones curry .

GRAMÁTICA DE UN TIPO DE FUNCIÓN


function-type → type->type

Tipo de matriz
El lenguaje Swift proporciona la siguiente manera de expresar el Swift de la biblioteca
estándar de matriz <T>Tipo:
• [ type ]
En otras palabras, las dos declaraciones siguientes son equivalentes:
• let someArray: [String] = ["Alex", "Brian", "Dave"]
• let someArray: Array<String> = ["Alex", "Brian", "Dave"]
En ambos casos, la constante someArray se declara como una matriz de cadenas. Los
elementos de una matriz se puede acceder a través de subíndices especificando un valor
de índice válido entre corchetes:someArray [0] se refiere al elemento en el índice
0, "Alex" .
Puede crear matrices multidimensionales anidando pares de corchetes, donde el nombre
del tipo base de los elementos está contenido en el par más interno de corchetes. Por
ejemplo, puede crear una matriz tridimensional de números enteros utilizando tres
conjuntos de corchetes:
• var array3D: [[[Int]]] = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]

  302  
Cuando se accede a los elementos en una matriz multidimensional, el índice más a la
izquierda subíndice se refiere al elemento en ese índice de la matriz externa. El
siguiente índice subíndice a la derecha se refiere al elemento en ese índice de la matriz
que está anidado en un nivel. Y así sucesivamente. Esto significa que en el ejemplo
anterior, array3D [0] se refiere a [[1, 2], [3, 4]] , array3D [0]
[1] se refiere a [3, 4] , y array3D [0] [1 ] [1] se refiere al valor 4.
Para una discusión detallada de la librería estándar de Swift matriz tipo,
vea Matrices .

GRAMÁTICA DE UN TIPO DE MATRIZ


array-type → [type]

Diccionario Type
El lenguaje Swift proporciona la siguiente manera de expresar la biblioteca estándar
Swift Dictionary <KeyType, ValueType> Tipo:
• [ key type : value type ]
En otras palabras, las dos declaraciones siguientes son equivalentes:
• let someDictionary: [String: Int] = ["Alex": 31, "Paul": 39]
• let someDictionary: Dictionary<String, Int> = ["Alex": 31, "Paul": 39]
En ambos casos, la constante someDictionary se declara como un diccionario con
cadenas como claves y números enteros como valores.
Los valores de un diccionario se puede acceder a través de subíndices especificando la
clave correspondiente entre corchetes: someDictionary ["Alex"] se refiere al
valor asociado a la clave "Alex" . El subíndice devuelve un valor opcional de valor
tipo del diccionario. Si la clave especificada no se encuentra en el diccionario, el
subíndice retornos nil .
El tipo de clave de un diccionario debe ser conforme a la biblioteca estándar
Swift Hashable protocolo, como se describe en valores hash para los tipos clave de
diccionario .
Para una discusión detallada de la Swift estándar biblioteca Diccionario tipo,
vea Diccionarios .

GRAMÁTICA DE UN TIPO DE DICCIONARIO


dictionary-type → [type:type]

Tipo Opcional
El lenguaje Swift define el postfix ? como azúcar sintáctico para el tipo de
llamada opcional <T> , que se define en la biblioteca estándar de Swift. En otras
palabras, las dos declaraciones siguientes son equivalentes:
• var optionalInteger: Int?
• var optionalInteger: Optional<Int>
En ambos casos, la variable optionalInteger se declararon tener el tipo de un
entero opcional. Tenga en cuenta que no hay espacio en blanco puede aparecer entre el
tipo y el ? .

  303  
El tipo opcional <T> es una enumeración con dos casos, Ninguno y Algunos
(T) , que se utilizan para representar valores que pueden o no pueden estar
presentes. Cualquier tipo puede ser declarado explícitamente que ser (o implícitamente
convertido a) un tipo opcional. Si usted no proporciona un valor inicial cuando se
declara una variable o propiedad opcional, su valor cambia automáticamente a cero .
Si una instancia de un tipo opcional contiene un valor, se puede acceder a ese valor con
el operador de sufijo! , como se muestra a continuación:
• optionalInteger = 42
• optionalInteger! // 42
Usando el ! operador a desenvolver un opcional que tiene un valor de nil resultados
en un error de ejecución.
También puede utilizar el encadenamiento opcional y de unión opcional para realizar
condicionalmente una operación en una expresión opcional. Si el valor es cero , no se
realiza ninguna operación, por lo que no se produce ningún error de ejecución.
Para obtener más información y ver ejemplos que muestran cómo utilizar los tipos
opcionales, consulteOpcionales .

GRAMÁTICA DE TIPO OPCIONAL


optional-type → type?

Implícitamente Unwrapped Tipo Opcional


El lenguaje Swift define el postfix ! como azúcar sintáctico para el tipo
llamado ImplicitlyUnwrappedOptional <T> , que se define en la biblioteca
estándar de Swift. En otras palabras, las dos declaraciones siguientes son equivalentes:
• var implicitlyUnwrappedString: String!
• var implicitlyUnwrappedString: ImplicitlyUnwrappedOptional<String>
En ambos casos, la variable implicitlyUnwrappedString se declararon tener el
tipo de una cadena opcional implícitamente sin envolver. Tenga en cuenta que no hay
espacio en blanco puede aparecer entre el tipo y el! .
Puede utilizar opcionales implícitamente abierto en todos los mismos lugares en su
código que puede utilizar opcionales. Por ejemplo, puede asignar valores de opcionales
implícitamente abierto a variables, constantes y propiedades de opcionales, y viceversa.
Al igual que con los opcionales, si no se proporciona un valor inicial cuando se declara
una variable opcional implícitamente sin envolver o propiedad, su valor cambia
automáticamente a cero .
Debido a que el valor de una manera implícita sin envolver opcional es
automáticamente sin envolver cuando lo utiliza, no hay necesidad de utilizar
el ! operador desenvuelva. Dicho esto, si intenta utilizar una opción implícita sin
envolver que tiene un valor de cero , obtendrá un error de ejecución.
Utilice encadenamiento opcional para realizar condicionalmente una operación en una
expresión opcional implícitamente sin envolver. Si el valor es cero , no se realiza
ninguna operación, por lo que no se produce ningún error de ejecución.
Para obtener más información acerca de los tipos opcionales implícitamente abierto,
ver Implícitamente Unwrapped Opcionales .

  304  
GRAMÁTICA DE TIPO OPCIONAL IMPLÍCITAMENTE SIN
ENVOLVER
implicitly-unwrapped-optional-type → type!

Protocolo Tipo Composición


Un tipo de composición protocolo describe un tipo que se ajusta a cada protocolo en una
lista de protocolos especificados. Protocolo de tipos de composición se pueden usar en
anotaciones de tipo y en los parámetros genéricos.
Tipos de composición Protocolo tienen el siguiente formulario:

• protocol< Protocol 1 , Protocol 2 >


Un tipo de composición protocolo permite especificar un valor cuyo tipo se ajusta a los
requisitos de múltiples protocolos sin tener que definir explícitamente un nuevo
protocolo llamado que hereda de cada protocolo que desea el tipo de ajustarse a. Por
ejemplo, la especificación de un protocolo de tipo composición protocolo
<ProtocolA, ProtocolB, ProtocolC> es efectivamente el mismo que definir
un nuevo protocolo ProtocolD que hereda
de ProtocolA , ProtocolB y ProtocolC , pero sin tener que introducir un nuevo
nombre.
Cada elemento de una lista composición protocolo debe ser el nombre de protocolo o un
alias de tipo de un tipo de composición protocolo. Si la lista está vacía, que especifica el
tipo de composición protocolo vacío, que se ajusta a todos los tipos.

GRAMÁTICA DE UN TIPO DE COMPOSICIÓN PROTOCOLO


protocol-composition-type → protocol<protocol-identifier-listopt>
protocol-identifier-list → protocol-identifier protocol-identifier,protocol-identifier-list
protocol-identifier → type-identifier

Metatipo Tipo
Un tipo metatipo se refiere al tipo de cualquier tipo, incluyendo tipos de clase, tipos de
estructura, tipos de enumeración y tipos de protocolo.
El metatipo de un tipo de clase, estructura o enumeración es el nombre de ese tipo,
seguido de .Type . El metatipo de un protocolo de tipo-no el tipo de hormigón que
cumpla con el protocolo en tiempo de ejecución-es el nombre de ese protocolo seguido
por .Protocol . Por ejemplo, el metatipo del tipo de
clase AlgunaClasees SomeClass.Type y la metatipo del
protocolo SomeProtocol es SomeProtocol.Protocol .
Usted puede utilizar el postfix auto expresión para acceder a un tipo como un
valor. Por ejemplo,SomeClass.self devuelve AlgunaClase sí mismo, no una
instancia
de AlgunaClase . Y SomeProtocol.selfdevuelve SomeProtocol sí mismo,
no una instancia de un tipo que se ajusta a SomeProtocol en tiempo de
ejecución. Puede utilizar un dynamicType expresión con una instancia de un tipo
para acceder tipo en tiempo de ejecución de esa instancia como un valor, como muestra
el siguiente ejemplo:

  305  
• class SomeBaseClass {
• class func printClassName() {
• println("SomeBaseClass")
• }
• }
• class SomeSubClass: SomeBaseClass {
• override class func printClassName() {
• println("SomeSubClass")
• }
• }
• let someInstance: SomeBaseClass = SomeSubClass()
• // SomeInstance es de tipo SomeBaseClass en tiempo de
compilación, pero  
• // SomeInstance es de tipo SomeSubClass en tiempo de
ejecución  
• someInstance.dynamicType.printClassName()
• // Impresiones "SomeSubClass"  
•  
GRAMÁTICA DE UN TIPO METATIPO
metatype-type → type.Type type.Protocol

Tipo Herencia Cláusula


Una cláusula tipo de herencia se utiliza para especificar qué clase de un tipo llamado
hereda y qué protocolos un tipo designado cumple con. Una cláusula tipo de herencia
también se utiliza para especificar una clase derequisito en un protocolo. Una
cláusula tipo de herencia comienza con dos puntos ( : ), seguido por cualquiera de
una clase de requisito, una lista de identificadores de tipo, o ambos.
Tipos de clases pueden heredar de una única superclase y ajustarse a cualquier número
de protocolos.Cuando se define una clase, el nombre de la superclase debe aparecer
primero en la lista de identificadores de tipo, seguido de cualquier número de protocolos
de la clase debe cumplir. Si la clase no se hereda de otra clase, la lista puede comenzar
con un protocolo en su lugar. Para una extensa discusión y varios ejemplos de la
herencia de clases, vea Herencia .
Otros tipos con nombre sólo pueden heredar de o ajustarse a una lista de
protocolos. Tipos de protocolo pueden heredar de cualquier número de otros
protocolos. Cuando un tipo de protocolo hereda de otros protocolos, el conjunto de
requisitos de los otros protocolos son agregados juntos, y de cualquier tipo que hereda
de la actual protocolo debe cumplir con todos esos requisitos. Como se discutió en la
declaración el Protocolo , puede incluir la clase de palabras clave como el primer
elemento de la cláusula de tipo de herencia para marcar una declaración protocolo con
una clase requisito.

  306  
Una cláusula tipo de herencia en una definición de enumeración puede ser una lista de
protocolos, o en el caso de una enumeración que asigna valores de primas a sus casos,
una sola, el tipo con nombre que especifica el tipo de los valores brutos. Para ver un
ejemplo de una definición de la enumeración que utiliza una cláusula tipo de herencia
para especificar el tipo de sus valores brutos, consulte Raw Values.
GRAMÁTICA DE UNA CLÁUSULA DE HERENCIA DE TIPO
type-inheritance-clause → :class-requirement,type-inheritance-list
type-inheritance-clause → :class-requirement
type-inheritance-clause → :type-inheritance-list
type-inheritance-list → type-identifier type-identifier,type-inheritance-list
class-requirement → class
-requisito → clase

Tipo Inferencia
Swift utiliza la inferencia de tipos ampliamente, lo que le permite omitir el tipo o la
parte del tipo de muchas variables y expresiones en el código. Por ejemplo, en lugar de
escribir var x: int = 0 , se puede escribir var x = 0 , omitiendo el tipo
completamente-el compilador infiere correctamente que x nombres un valor de
tipoint . Del mismo modo, se puede omitir parte de un tipo cuando el tipo completo se
puede deducir por el contexto. Por ejemplo, si escribes dejar dict:
Diccionario = ["A": 1] , el compilador infiere que dict tiene el
tipo Dictionary <String, int> .
En los dos ejemplos anteriores, la información de tipo se pasa desde las hojas del árbol
de expresión a su raíz. Es decir, el tipo de x en var x: int = 0 se deduce
comprobando primero el tipo de 0 y después de pasar esta información de tipo hasta la
raíz (la variable x ).
En Swift, información de tipo también puede fluir en la dirección opuesta, desde la raíz
hasta las hojas. En el ejemplo siguiente, por ejemplo, la anotación de tipo explícita ( :
flotador ) de la constante de eFloat hace que el literal numérico 2,71828 tener
un tipo inferido de flotador en lugar de doble .
• let e = 2.71828 // The type of e is inferred to be Double.
• let eFloat: Float = 2.71828 // The type of eFloat is Float.
Tipo de inferencia en Swift opera en el nivel de una sola expresión o declaración. Esto
significa que toda la información necesaria para inferir un tipo omitido o parte de un
tipo en una expresión debe ser accesible desde el tipo de comprobación de la expresión
o uno de sus subexpresiones.
 
Expresiones
En esta página
En Swift, hay cuatro tipos de expresiones: expresiones de prefijos binarios, expresiones,
expresiones primarias, y las expresiones de sufijo. Evaluación de una expresión
devuelve un valor, provoca un efecto secundario, o ambos.
Prefijo y expresiones binarias le permiten aplicar los operadores para expresiones más
pequeñas.Expresiones primarias son conceptualmente el tipo más simple de expresión,
y que proporcionan una forma de acceder a los valores. Expresiones Postfix, como

  307  
prefijo y expresiones binarias, le permiten construir hasta expresiones más complejas
utilizando sufijos tales como llamadas a funciones y acceso de los miembros.Cada tipo
de expresión se describe en detalle en las siguientes secciones.

GRAMÁTICA DE UNA EXPRESIÓN


expression → prefix-expressionbinary-expressionsopt
expression-list → expression expression,expression-list

Prefijo Expresiones
Expresiones prefijo combinan un operador prefijo opcional con una
expresión. Operadores de prefijo toman un argumento, la expresión que les sigue.
La biblioteca estándar Swift ofrece los siguientes operadores de prefijo:
• ++ Increment
• -- Decrement
• ! Logical NOT
• ~ Bitwise NOT
• + Unary plus
• - Unary minus
Para obtener información sobre el comportamiento de estos operadores,
consulte Operadores básicos yOperadores avanzados .
Además de los operadores de la biblioteca estándar mencionados anteriormente, se
utiliza y de inmediato antes de que el nombre de una variable que está siendo pasado
como un argumento en la salida a una expresión de llamada a la función. Para obtener
más información y ver un ejemplo, consulte In-Out Parameters .

GRAMÁTICA DE UNA EXPRESIÓN PREFIJO


prefix-expression → prefix-operatoroptpostfix-expression
prefix-expression → in-out-expression
in-out-expression → &identifier

Expresiones binarias
Expresiones binarias combinan un operador infijo binario con la expresión que se toma
como la izquierda y los argumentos de la mano derecha. Tiene la siguiente forma:
• left-hand argument operator right-hand argument
La biblioteca estándar Swift proporciona los siguientes operadores binarios:
• Exponentiative (No asociatividad, nivel de precedencia 160)
o << izquierda en modo bit turno
o >> bit a bit desplazamiento a la derecha
• Multiplicativo (asociativo Izquierda, nivel de precedencia 150)
o * Multiplicar
o / Divide
o % El resto
o & * Multiplicar, desbordamiento ignorando
o Y / Divide, desbordamiento ignorando
o &% El resto, haciendo caso omiso de desbordamiento

  308  
o Y AND bit a bit
• Aditivo (asociativo Izquierda, nivel de precedencia 140)
o + Añadir
o - Restar
o Y + Añadir a desbordamiento
o Y - Resta con rebosadero
o | OR bit a bit
o ^ XOR
• Range (No asociatividad, nivel de precedencia 135)
o .. < gama semiabierta
o ... gama Cerrado
• Reparto (No asociatividad, nivel de precedencia 132)
o es Tipo de verificación
o como Tipo elenco
• Comparado (No asociatividad, precedencia nivel 130)
o < menos que
o <= Menor o igual que
o > Mayor que
o > = Mayor o igual
o == Igualdad
o ! = No igual
o === Idéntica
o ! == no idénticos
o ~ = Coincidencia de patrón
• Conjuntiva (asociativo Izquierda, nivel 120 precedencia)
o && Y lógico
• Disyuntivo (asociativo Izquierda, nivel de precedencia 110)
o || OR lógico
• Ninguna de coalescencia (asociativo derecho, nivel de precedencia 110)
o ?? Ninguna coalescencia
• Ternario condicional (asociativo derecho, nivel de precedencia 100)
o ? : condicional ternario
• Asignación (asociativo derecho, nivel de prioridad 90)
o = Asignar
o * = Multiplicar y asignar
o / = Dividir y asignar
o % = Resto y asignar
o + = Agregar y asignar
o - = Restar y asignar
o << = desplazamiento de bits izquierda y asignar
o >> = desplazamiento de bits derecho y asignar
o & = AND bit a bit y asignar
o ^ = XOR bit a bit y de asignación
o | = OR bit a bit y de asignación
o && = Y lógico y asignar
o || = O lógico y asignar

  309  
Para obtener información sobre el comportamiento de estos operadores,
consulte Operadores básicos yOperadores avanzados .
NOTA
En tiempo de análisis, una expresión formada por operadores binarios se representa
como una lista plana.Esta lista se transforma en un árbol mediante la aplicación de la
precedencia de operadores. Por ejemplo, la expresión 2 + 3 * 5 se entiende
inicialmente como una lista plana de cinco artículos, 2 , + , 3 , * , y 5 . Este proceso
transforma en el árbol (2 + (3 * 5)).

GRAMÁTICA DE UNA EXPRESIÓN BINARIA


binary-expression → binary-operatorprefix-expression
binary-expression → assignment-operatorprefix-expression
binary-expression → conditional-operatorprefix-expression
binary-expression → type-casting-operator
binary-expressions → binary-expressionbinary-expressionsopt

Operador de asignación
El operador CESION establece un nuevo valor para una expresión dada. Tiene la
siguiente forma:
• expression = value
El valor de la expresión se establece en el valor obtenido mediante la evaluación
del valor . Si la expresión es una tupla, el valor debe ser una tupla con el mismo número
de elementos. (Tuplas anidadas están permitidos.) Asignación se realiza desde cada
parte del valor a la parte correspondiente de la expresión . Por ejemplo:
• (a, _, (b, c)) = ("test", 9.45, (12, 3))
• // a is "test", b is 12, c is 3, and 9.45 is ignored
El operador de asignación no devuelve ningún valor.

GRAMÁTICA DE UN OPERADOR DE ASIGNACIÓN


asignación-operador → =

Operador condicional ternario


El operador condicional ternario evalúa como uno de los dos valores dados en función
del valor de una condición. Tiene la siguiente forma:
• condition ? expression used if true : expression used if false
Si la condición se evalúa como verdadera , el operador condicional evalúa la
primera expresión y devuelve su valor. De lo contrario, se evalúa la segunda expresión y
devuelve su valor. La expresión no utilizada no se evalúa.
Para ver un ejemplo que utiliza el operador condicional ternario, ver ternario operador
condicional .

  310  
GRAMÁTICA DE UN OPERADOR CONDICIONAL
assignment-operator → =

Operadores encasillamiento
Hay tres operadores de tipo de fundición a presión, el is el operador, el as? operador,
y el as operador.Tienen el siguiente formulario:
• expression is type
• expression as? type
• expression as type
Las is check de operador en tiempo de ejecución si la expresión puede ser abatido a la
especificadatipo . Devuelve verdadero si la expresión puede ser abatido a la
especificada tipo ; de lo contrario, devuelvefalse . Si vas a vaciar a la
especificada tipo está garantizado para tener éxito o fracasar, se eleva un error en
tiempo de compilación. Por ejemplo, 10 es Int y 10 es de cadena tanto elevar
los errores en tiempo de compilación.
El as operador realiza un elenco condicional de la expresión a la
especificada tipo . El as operador devuelve un opcional de la especificada tipo . En
tiempo de ejecución, si la conversión se realiza correctamente, el valor de la
expresión se envuelve en una opcional y regresó; de lo contrario, el valor devuelto
es nulo . Si vas a vaciar a la especificada tipo está garantizada a fallar, se eleva un
error en tiempo de compilación. Por ejemplo, la conversión a un tipo que no es ni una
subclase o superclase del tipo de laexpresión es un error.
El as operador realiza una conversión forzada de la expresión a la
especificada tipo . El as operador devuelve un valor de la especificada tipo , no un tipo
opcional. Si la conversión falla, se produce un error de ejecución. El comportamiento
de x as T es el mismo que el comportamiento de (x como? T)! .
Para obtener más información acerca de la conversión de tipos y para ver ejemplos que
utilizan los operadores de tipo de fundición a presión, ver la conversión de tipos .

GRAMÁTICA DE UN OPERADOR DE TIPO CASTING


type-casting-operator → istype
type-casting-operator → astype
type-casting-operator → as?type

Expresiones primarias
Expresiones primarias son el tipo más básico de expresión. Pueden ser utilizados como
expresiones de su propia, y se pueden combinar con otras fichas para hacer expresiones
de prefijos binarios, expresiones y expresiones de sufijo.
GRAMÁTICA DE UNA EXPRESIÓN PRIMARIA
primary-expression → identifiergeneric-argument-clauseopt
primary-expression → literal-expression
primary-expression → self-expression
primary-expression → superclass-expression
primary-expression → closure-expression
  311  
primary-expression → parenthesized-expression
primary-expression → implicit-member-expression
primary-expression → wildcard-expression

Expresión Literal
Una expresión literal consiste ya sea de un literal ordinario (tal como una cadena o un
número), una matriz o diccionario literal, o uno de los siguientes literales especiales:
Literal Tipo Valor
__FILE__ Cadena El nombre del archivo en el que aparece.
__LINE__ Int En la que aparece el número de línea.
__COLUMN__ Int El número de columna en el que comienza.
__FUNCTION__ Cadena El nombre de la declaración en la que aparece.
Dentro de una función, el valor de __FUNCTION__ es el nombre de esa función,
dentro de un método que es el nombre de ese método, dentro de un captador de
propiedad o Setter es el nombre de esa propiedad, dentro de los miembros especiales
como init o subíndice es el nombre de esa palabra clave, y en el nivel superior de
un archivo es el nombre del módulo actual.
Un literal de matriz es una colección ordenada de valores. Tiene la siguiente forma:
• [ value 1 , value 2 , ... ]
La última expresión en la matriz puede ser seguida por una coma opcional. El valor de
un literal de matriz tiene tipo [T] , donde T es el tipo de las expresiones en su
interior. Si hay expresiones de varios tipos, T es su supertipo común más
cercano. Literales de matriz vacíos se escriben utilizando un par vacío de corchetes y se
pueden utilizar para crear una matriz vacía de un tipo especificado.
• var emptyArray: [Double] = []
Un literal diccionario es una colección desordenada de pares clave-valor. Tiene la
siguiente forma:
• [ key 1 : value 1 , key 2 : value 2 , ... ]
La última expresión en el diccionario puede ser seguida por una coma opcional. El valor
de un literal diccionario tiene el tipo [KeyType: ValueType] ,
donde KeyType es el tipo de sus expresiones clave y ValueTypees el tipo de sus
expresiones de valor. Si hay expresiones de varios tipos, KeyType y ValueType son
el supertipo común más cercano por sus respectivos valores. Un diccionario vacío literal
se escribe como dos puntos dentro de un par de corchetes ( [:] ) para distinguirlo de un
array vacío literal. Puede utilizar un diccionario vacío literal para crear un diccionario
vacío literal de tipos de clave y valor especificados.
• var emptyDictionary : [ Cadena : Doble ] = [:]  
•  
GRAMÁTICA DE UNA EXPRESIÓN LITERAL
literal-expression → literal
literal-expression → array-literal dictionary-literal

  312  
literal-expression → __FILE__ __LINE__ __COLUMN__ __FUNCTION__
array-literal → [array-literal-itemsopt]
array-literal-items → array-literal-item,opt array-literal-item,array-literal-items
array-literal-item → expression
dictionary-literal → [dictionary-literal-items] [:]
dictionary-literal-items → dictionary-literal-item,opt dictionary-literal-item,dictionary-
literal-items
dictionary-literal-item → expression:expression

Auto Expresión
La auto expresión es una referencia explícita al tipo actual o instancia del tipo en el
que se produce. Tiene las siguientes formas:
• self
• self. member name
• self[ subscript index ]
• self( initializer arguments )
• self.init( initializer arguments )
En un inicializador, subíndice, o método de instancia, sí hace referencia a la instancia
actual del tipo en el que se produce. En un método estático o de clase, sí se refiere al
tipo actual en el que se produce.
La auto expresión se utiliza para especificar el alcance cuando se accede a los
miembros, proporcionando desambiguación cuando hay otra variable del mismo
nombre en su alcance, como por ejemplo un parámetro de la función. Por ejemplo:
• class SomeClass {
• var greeting: String
• init(greeting: String) {
• self.greeting = greeting
• }
• }
En un procedimiento de mutación de un tipo de valor, se puede asignar una nueva
instancia de ese tipo de valor para uno mismo . Por ejemplo:
• struct Point {
• var x = 0.0, y = 0.0
• mutating func moveByX(deltaX: Double, y deltaY: Double) {
• self = Point(x: x + deltaX, y: y + deltaY)
• }
• }

  313  
GRAMÁTICA DE LA LIBRE EXPRESIÓN
self-expression → self
self-expression → self.identifier
self-expression → self[expression]
self-expression → self.init

Expresión Superclase
Una expresión superclase permite un interactúan clase con su superclase. Cuenta con
una de las siguientes formas:
• super. member name
• super[ subscript index ]
• super.init( initializer arguments )
La primera forma se utiliza para acceder a un miembro de la superclase. La segunda
forma se utiliza para acceder a la aplicación subíndice de la superclase. La tercera forma
se utiliza para acceder a un inicializador de la superclase.
Las subclases pueden utilizar una expresión superclase en la aplicación de los
miembros, subíndices y inicializadores para hacer uso de la aplicación en su superclase.

GRAMÁTICA DE UNA EXPRESIÓN SUPERCLASE


superclass-expression → superclass-method-expression superclass-subscript-
expression superclass-initializer-expression
superclass-method-expression → super.identifier
superclass-subscript-expression → super[expression]
superclass-initializer-expression → super.init

Expresión Clausura
Una expresión de cierre crea un cierre, también conocido como una lambda o
una función anónima en otros lenguajes de programación. Al igual que las declaraciones
de función, los cierres contienen declaraciones que abonan, y capturan los valores de su
ámbito circundante. Tiene la siguiente forma:
• { ( parameters ) -> return type in
• statements

• }
Los parámetros tienen la misma forma que los parámetros en una declaración de la
función, tal como se describe en la declaración de la función .
Hay varias formas especiales que permiten a los cierres que se escriben de manera más
concisa:
• Un cierre puede omitir los tipos de sus parámetros, el tipo de retorno, o ambos. Si
omite los nombres de los parámetros y de ambos tipos, omita el de palabra clave
antes de las sentencias. Si los tipos omitidos no se pueden deducir, se eleva un error
en tiempo de compilación.

  314  
• Un cierre puede omitir los nombres de sus parámetros. Sus parámetros son entonces
implícitamente nombrado $ seguidos de su posición: $ 0 , $ 1 , $ 2 , y así
sucesivamente.
• Un cierre que consta de sólo una única expresión se entiende para devolver el valor
de esa expresión.El contenido de esta expresión también se consideran cuando se
realiza la inferencia de tipos en la expresión de los alrededores.
Las siguientes expresiones de cierre son equivalentes:
• myFunction {
• (x: Int, y: Int) -> Int in
• return x + y
• }

• myFunction {
• (x, y) in
• return x + y
• }

• myFunction { return $0 + $1 }

• myFunction { $0 + $1 }
Para obtener información acerca de pasar un cierre como argumento a una función,
consulte Función de llamada Expresión .
Una expresión de cierre puede especificar explícitamente los valores que retrata tanto en
el ámbito circundante utilizando una lista de captura . Una lista de captura está escrita
como una lista separada por comas entre corchetes, antes de que la lista de
parámetros. Si utiliza una lista de captura, también debe usar el de palabra clave,
incluso si se omite los nombres de parámetros, tipos de parámetros y el tipo de retorno.
Cada entrada en la lista de captura puede ser marcado como débil o sin
dueño para capturar una referencia débil o sin dueño al valor.
• myFunction { print(self.title) } // captura fuerte
• myFunction { [weak self] in print(self!.title) } // captura debil
• myFunction { [unowned self] in print(self.title) } // captura sin dueño
También puede enlazar una expresión arbitraria a un valor con nombre en la lista de
captura. Se evalúa la expresión cuando se forma el cierre, y capturó con la resistencia
especificada. Por ejemplo:
• // Débil captura de "self.parent" como "padre"  
myFunction { [weak parent = self.parent] in print(parent!.title) }

Para obtener más información y ejemplos de expresiones de cierre,
consulte Expresiones de cierre .

  315  
GRAMÁTICA DE UNA EXPRESIÓN DE CIERRE
closure-expression → {closure-signatureoptstatements}
closure-signature → parameter-clausefunction-resultoptin
closure-signature → identifier-listfunction-resultoptin
closure-signature → capture-listparameter-clausefunction-resultoptin
closure-signature → capture-listidentifier-listfunction-resultoptin
closure-signature → capture-listin
capture-list → [capture-specifierexpression]
capture-specifier → débil sin dueño sin dueño (seguro) sin
dueño (no seguro)

Implícita Expresión miembros


Un miembro de la expresión implícita es una forma abreviada para acceder a un
miembro de un tipo, tal como un caso de enumeración o un método de clase, en un
contexto en la inferencia de tipos puede determinar el tipo implícito. Tiene la siguiente
forma:
• . member name
Por ejemplo:
• var x = MyEnumeration.SomeValue
• x = .AnotherValue

GRAMÁTICA DE UN MIEMBRO DE LA EXPRESIÓN IMPLÍCITA
implícita-miembro de la expresión → . identificador

Expresión entre paréntesis


Una expresión entre paréntesis consiste en una lista separada por comas de expresiones
rodeadas por paréntesis. Cada expresión puede tener un identificador opcional ante sí,
separados por dos puntos ( : ).Tiene la siguiente forma:
• ( identifier 1 : expression 1 , identifier 2 : expression 2 , ... )
Utilice expresiones entre paréntesis para crear tuplas y para pasar argumentos a una
llamada de función. Si sólo hay un valor dentro de la expresión entre paréntesis, el tipo
de la expresión entre paréntesis es el tipo de ese valor. Por ejemplo, el tipo de la
expresión entre paréntesis (1) es Int , no (Int) .

GRAMÁTICA DE UNA EXPRESIÓN CON PARÉNTESIS


parenthesized-expression → (expression-element-listopt)
expression-element-list → expression-element expression-element,expression-element-
list
expression-element → expression identifier:expression

  316  
Expresión Comodín
Una expresión comodín se utiliza para ignorar explícitamente un valor durante una
asignación. Por ejemplo, en la siguiente asignación de 10 se asigna a x y 20 se ignora:
• (x, _) = (10, 20)
• // x is 10, 20 is ignored
GRAMÁTICA DE UNA EXPRESIÓN COMODÍN
wildcard-expresión → _
Postfix Expresiones
Expresiones Postfix se forman mediante la aplicación de un operador de sufijo u otra
sintaxis postfix a una expresión. Sintácticamente, cada expresión primaria es también
una expresión postfix.
La biblioteca estándar Swift ofrece los siguientes operadores de sufijo:
• ++ Incremento
• - Disminuir
Para obtener información sobre el comportamiento de estos operadores,
consulte Operadores básicos yOperadores avanzados .

GRAMÁTICA DE UNA EXPRESIÓN POSTFIX


postfix-expression → primary-expression
postfix-expression → postfix-expressionpostfix-operator
postfix-expression → function-call-expression
postfix-expression → initializer-expression
postfix-expression → explicit-member-expression
postfix-expression → postfix-self-expression
postfix-expression → dynamic-type-expression
postfix-expression → subscript-expression
postfix-expression → forced-value-expression
postfix-expression → optional-chaining-expression

Función Expresión Call


Una expresión de llamada a la función consiste en un nombre de la función seguido de
una lista separada por comas de los argumentos de la función entre
paréntesis. Expresiones de llamada de función tiene la siguiente forma:
• function name ( argument value 1 , argument value 2 )
El nombre de la función puede ser cualquier expresión cuyo valor es de un tipo de
función.
Si la definición de función incluye nombres de sus parámetros, la llamada de función
tiene que incluir los nombres antes de sus valores de argumentos separados por dos
puntos ( : ). Este tipo de expresión llamada de función tiene la siguiente forma:
• function name ( argument name 1 : argument value 1 , argument name 2 : argument
value 2 )
Una expresión de llamada a la función puede incluir un cierre posterior en forma de una
expresión de cierre inmediatamente después del paréntesis de cierre. El cierre posterior

  317  
se entiende como un argumento a la función, agregado después del último argumento
entre paréntesis. Las siguientes llamadas a funciones son equivalentes:
• // AlgunaFuncion toma un entero y un cierre como sus
argumentos  
• someFunction(x, {$0 == 13})
someFunction(x) {$0 == 13}

Si el cierre de salida es sólo el argumento de la función, los paréntesis pueden omitirse.
• // AlgunaFuncion toma un cierre como único argumento  

• myData.someMethod() {$0 == 13}


• myData.someMethod {$0 == 13}

GRAMÁTICA DE UNA EXPRESIÓN DE LLAMADA A LA


FUNCIÓN
function-call-expression → postfix-expressionparenthesized-expression
function-call-expression → postfix-expressionparenthesized-expressionopttrailing-
closure
trailing-closure → closure-expression

Inicializador Expresión
Una expresión de inicializador proporciona acceso a inicializador de un tipo. Tiene la
siguiente forma:
• expression .init( initializer arguments )
Se utiliza la expresión de inicialización en una expresión de llamada a una función para
inicializar una nueva instancia de un tipo. A diferencia de las funciones, un inicializador
no puede ser utilizado como un valor. Por ejemplo:
• var x = SomeClass.someClassFunction // ok
• var y = SomeClass.init // error
También puede utilizar una expresión de inicializador delegar en el inicializador de una
superclase.
• class SomeSubClass: SomeSuperClass {
• init() {
• // Inicialización subclase va aquí  
• super.init()
• }
• }

  318  
GRAMÁTICA DE UNA EXPRESIÓN DE INICIALIZADOR
initializer-expression → postfix-expression.init

Explícita Expresión miembros


Un miembro de la expresión explícita permite el acceso a los miembros de un tipo
llamado, una tupla, o un módulo. Se compone de un punto ( . ) entre el elemento y el
identificador de su miembro.
• expresión . nombre de miembro
Los miembros de un tipo con nombre se nombran como parte de la declaración o
ampliación del tipo. Por ejemplo:
• class SomeClass {
• var someProperty = 42
• }
• let c = SomeClass()
• let y = c.someProperty // Member access
Los miembros de una tupla se nombran de forma implícita mediante números enteros en
el orden en que aparecen, a partir de cero. Por ejemplo:
• var t = (10, 20, 30)
• t.0 = t.1
• // Ahora t es (20, 20, 30)  
Los miembros de un módulo de acceso a las declaraciones de alto nivel de ese módulo.

GRAMÁTICA DE UNA EXPRESIÓN EXPLÍCITA MIEMBRO


explicit-member-expression → postfix-expression.decimal-digits
explicit-member-expression → postfix-expression.identifiergeneric-argument-clauseopt

Postfix Auto Expresión


Un sufijo auto expresión consiste de una expresión o el nombre de un tipo, seguido
inmediatamente por .self. Tiene las siguientes formas:
• expression .self
• type .self
La primera forma se evalúa como el valor de la expresión . Por
ejemplo, x.self evalúa como x .
La segunda forma se evalúa al valor del tipo . Utilice este formulario para acceder a un
tipo como un valor.Por ejemplo, porque SomeClass.self evalúa
al AlgunaClase mismo tipo, puede pasar a una función o método que acepta un
argumento de nivel de tipo.

  319  
GRAMÁTICA DE LA LIBRE EXPRESIÓN
postfix-self-expression → postfix-expression.self

Tipo Dinámico Expresión


A dynamicType expresión consiste en una expresión, seguida inmediatamente
por .dynamicType . Tiene la siguiente forma:
• expression .dynamicType
La expresión no puede ser el nombre de un tipo. Todo el dynamicType expresión se
evalúa como el valor del tipo de tiempo de ejecución de la expresión , como muestra el
siguiente ejemplo:
• class SomeBaseClass {
• class func printClassName() {
• println("SomeBaseClass")
• }
• }
• class SomeSubClass: SomeBaseClass {
• override class func printClassName() {
• println("SomeSubClass")
• }
• }
• let someInstance: SomeBaseClass = SomeSubClass()
• // SomeInstance es de tipo SomeBaseClass en tiempo de
compilación, pero  
• // SomeInstance es de tipo SomeSubClass en tiempo de
ejecución  
• someInstance.dynamicType.printClassName()
• // Impresiones "SomeSubClass"  
•  
GRAMÁTICA DE UN TIPO DE EXPRESIÓN DINÁMICA
dynamic-type-expression → postfix-expression.dynamicType

Expresión Subíndice
Una expresión subíndice proporciona acceso subíndice usando el get y set de la
declaración subíndice correspondiente. Tiene la siguiente forma:
• expresión [ expresiones de índice ]
Para evaluar el valor de una expresión de subíndice, el captador subíndice para
la expresión de tipo 's se denomina con las expresiones de índice pasados como los
parámetros subíndice. Para establecer su valor, el setter subíndice se llama de la misma
manera.

  320  
Para obtener información sobre las declaraciones de subíndice, consulte Protocolo
Declaración Subíndice .

GRAMÁTICA DE UNA EXPRESIÓN SUBÍNDICE


subscript-expression → postfix-expression[expression-list]

-Valor forzado Expresión


Una expresión-valor forzado desenvuelve un valor opcional que está seguro de que no
es nula . Tiene la siguiente forma:
• expresión !
Si el valor de la expresión no es nula , el valor opcional es desenvuelto y volvió con el
tipo no opcional correspondiente. De lo contrario, se produce un error de ejecución.
El valor de envolver de una expresión-valor forzado puede ser modificado, ya sea por
mutación del valor en sí, o mediante la asignación a uno de los miembros del valor. Por
ejemplo:
• var x: Int? = 0
• x!++
• // x is now 1

• var someDictionary = ["a": [1, 2, 3], "b": [10, 20]]
• someDictionary["a"]![0] = 100
• // SomeDictionary es ahora ["a": [100, 2, 3], "b": [10,
20]]  
•  
GRAMÁTICA DE UNA EXPRESIÓN-VALOR FORZADO
forced-value-expression → postfix-expression!

Opcional-encadenamiento Expresión
Una expresión opcional encadenamiento proporciona una sintaxis simplificada para el
uso de los valores opcionales en las expresiones de sufijo. Tiene la siguiente forma:
• expression ?
Por su parte, el postfix ? operador simplemente devuelve el valor de su argumento
como un opcional.
Postfix expresiones que contienen una expresión opcional de encadenamiento se
evalúan de una manera especial. Si la expresión-opcional encadenamiento es nulo ,
todas las otras operaciones en la expresión postfix son ignorados y toda la expresión
postfix evalúa como nula . Si la expresión-opcional encadenamiento no es nula , el
valor de la expresión-opcional encadenamiento se desenvuelve y se utiliza para evaluar
el resto de la expresión postfix. En cualquier caso, el valor de la expresión postfix sigue
siendo de un tipo opcional.
Si una expresión postfix que contiene una expresión opcional en cadena está anidado
dentro de otras expresiones de sufijo, sólo la expresión más externa devuelve un tipo

  321  
opcional. En el ejemplo siguiente, cuando c no es nula , su valor es sin envolver y se
utiliza para evaluar tanto .property y .performAction () , y toda la
expresión c? .property.performAction () tiene un valor de un tipo
opcional.
• var c: SomeClass?
• var result: Bool? = c?.property.performAction()
El siguiente ejemplo muestra el comportamiento del ejemplo anterior sin usar el
encadenamiento opcional.
• if let unwrappedC = c {
• result = unwrappedC.property.performAction()
• }
El valor de envolver de una expresión opcional de encadenamiento puede ser
modificado, ya sea por mutación del valor en sí, o mediante la asignación a uno de los
miembros del valor. Si el valor de la expresión-opcional encadenamiento es nula , no
se evalúa la expresión en el lado derecho del operador de asignación. Por ejemplo:
• func someFunctionWithSideEffects() -> Int {
• return 42
• }
• var someDictionary = ["a": [1, 2, 3], "b": [10, 20]]

• someDictionary["not here"]?[0] = someFunctionWithSideEffects()
• // someFunctionWithSideEffects no se evalúa  
• // SomeDictionary sigue siendo ["a": [1, 2, 3], "b": [10,
20]]  
•  
• someDictionary["a"]?[0] = someFunctionWithSideEffects()
• ()  
• // someFunctionWithSideEffects se evalúa  
• // SomeDictionary es ahora ["a": [100, 2, 3], "b": [10,
20]]  
•  
GRAMÁTICA DE UNA EXPRESIÓN-OPCIONAL
ENCADENAMIENTO
optional-chaining-expression → postfix-expression?
 

Declaraciones
En Swift, hay dos tipos de declaraciones: declaraciones simples y estados de flujo de
control. Declaraciones simples son los más comunes y consisten tanto en una expresión
o una declaración. Estados de flujos de control se utilizan para controlar el flujo de

  322  
ejecución de un programa. Hay tres tipos de sentencias de control de flujo en Swift:
sentencias de bucle, declaraciones de sucursales, y las declaraciones de transferencia de
control.
Las sentencias de bucle permiten que un bloque de código que se ejecuta repetidamente,
declaraciones sucursales permiten un determinado bloque de código que se ejecutará
sólo cuando se cumplan ciertas condiciones, y las declaraciones de transferencia de
control proporcionan una forma de alterar el orden en el que se ejecuta el código. Cada
tipo de declaración de flujo de control se describe en detalle a continuación.
Un punto y coma ( ; ) opcionalmente puede aparecer después de cualquier declaración
y se utiliza para separar varias declaraciones si aparecen en la misma línea.
GRAMÁTICA DE UNA DECLARACIÓN
statement → expression;opt
statement → declaration;opt
statement → loop-statement;opt
statement → branch-statement;opt
statement → labeled-statement;opt
statement → control-transfer-statement;opt
statements → statementstatementsopt

Declaraciones Loop
Sentencias de bucle permiten un bloque de código que se ejecuta repetidamente,
dependiendo de las condiciones especificadas en el bucle. Swift tiene cuatro sentencias
de bucle: una para la declaración, unapara - en la declaración,
una mientras declaración, y un do - mientras comunicado.
El flujo de control en un comunicado de bucle se puede cambiar por una ruptura y
una declaración continuardeclaración y se discute en sentencia break y Continuar
Declaración de abajo.

GRAMÁTICA DE UNA SENTENCIA DE BUCLE


loop-statement → for-statement
loop-statement → for-in-statement
loop-statement → while-statement
loop-statement → do-while-statement

Para Declaración
Una de declaración permite un bloque de código que se ejecuta repetidamente mientras
incrementando un contador, siempre y cuando una condición sigue siendo cierto.
Una de instrucción tiene la siguiente forma:
• for initialization ; condition ; increment {
• statements

• }
Los punto y coma entre la inicialización , condición , y la subasta se requieren. Los
apoyos en torno a lasdeclaraciones también son necesarios en el cuerpo del bucle.
Una de sentencia se ejecuta de la siguiente manera:

  323  
1. La inicialización se evalúa sólo una vez. Normalmente se utiliza para declarar e
inicializar las variables que se necesitan para el resto del ciclo.
2. La condición se evalúa la expresión.
Si cierto , el programa ejecuta las declaraciones , y la ejecución continúa al paso
3 Si falso , el programa no se ejecuta las declaraciones o el incremento de la
expresión, y el programa ha terminado de ejecutar el de declaración.
3. El incremento se evalúa la expresión, y la ejecución vuelve al paso 2.
Las variables definidas dentro de la inicialización sólo son válidos en el ámbito de
la de declaración en sí.
El valor de la condición de expresión debe tener un tipo que se ajusta a
la BooleanType protocolo.

GRAMÁTICA DE UNA SENTENCIA FOR


for-statement → forfor-initopt;expressionopt;expressionoptcode-block
for-statement → for(for-initopt;expressionopt;expressionopt)code-block
for-init → variable-declaration expression-list

Para-In Declaración
Una de - en la declaración permite un bloque de código que se ejecuta una vez para
cada elemento de una colección (o de cualquier tipo) que se ajusta a
la SequenceType protocolo.
Una de - en la declaración tiene la siguiente forma:
• for item in collection {
• statements

• }
El generar método se llama en la colección de expresión para obtener un valor de un
tipo que es generador, un tipo que se ajusta a la GeneratorType protocolo. El
programa comienza la ejecución de un bucle mediante una llamada
al siguiente método en la secuencia. Si el valor devuelto no es Ninguno , se le
asigna a la partidapatrón, el programa ejecuta las declaraciones , y luego continúa la
ejecución en el principio del bucle. De lo contrario, el programa no realiza cesión o
ejecutar las sentencias , y que se haya ejecutado la para - encomunicado.

GRAMÁTICA DE UNA DECLARACIÓN FOR-IN


for-in-statement → forpatterninexpressioncode-block

Mientras Declaración
Un mientras declaración permite un bloque de código que se ejecuta repetidamente,
siempre y cuando una condición sigue siendo cierto.
A mientras que la declaración tiene la siguiente forma:
• while condition {
• statements

  324  
• }
A mientras sentencia se ejecuta de la siguiente manera:
1. La condición es evaluada.
Si cierto , la ejecución continúa con el paso 2 Si falso , el programa ha
terminado de ejecutar elmientras comunicado.
2. El programa ejecuta las declaraciones , y la ejecución vuelve al paso 1.
Debido a que el valor de la condición es evaluada antes de que las declaraciones se
ejecutan, lasdeclaraciones en una mientras que la declaración se pueden ejecutar
cero o más veces.
El valor de la condición debe tener un tipo que se ajusta a
la BooleanType protocolo. La condición también puede ser una declaración de unión
opcional, como se discute en Opcional Binding .

GRAMÁTICA DE UNA SENTENCIA WHILE


while-statement → whilewhile-conditioncode-block
while-condition → expression declaration

Hágalo hasta instrucción (Do-While)


A do – while sentencia permite un bloque de código que se ejecutará una o varias
veces, siempre y cuando una condición se mantiene fiel.
A do – while declaración tiene la siguiente forma:

• do {
• statements
• } while condition
A do – while sentencia se ejecuta de la siguiente manera:
1. El programa ejecuta las declaraciones , y la ejecución continúa con el paso 2.
2. La condición es evaluada.
Si cierto , la ejecución vuelve al paso 1 Si falso , el programa ha terminado de
ejecutar el do - mientrascomunicado.
Debido a que el valor de la condición se evalúa después de las declaraciones se
ejecutan, las declaracionesen un do - , mientras que la declaración se ejecutan al
menos una vez.
El valor de la condición debe tener un tipo que se ajusta a
la BooleanType protocolo. La condición también puede ser una declaración de unión
opcional, como se discute en Opcional Binding .

GRAMÁTICA DE UNA DECLARACIÓN DO-WHILE


do-while-statement → docode-blockwhilewhile-condition

Declaraciones Branch
Declaraciones Branch permiten al programa para ejecutar ciertas partes de código en
función del valor de una o más condiciones. Los valores de las condiciones
especificadas en un comunicado rama controlan la forma, por lo tanto, lo que el bloque

  325  
de código se ejecuta el programa se bifurca y,. Swift tiene dos declaraciones sucursal:
un si declaración y un interruptor comunicado.
El flujo de control en un interruptor de declaración puede ser modificada por
una ruptura declaración y se discute en sentencia break abajo.
GRAMÁTICA DE UNA DECLARACIÓN DE LA RAMA
branch-statement → if-statement
branch-statement → switch-statement

Si Declaración
Un if de declaración se utiliza para ejecutar código basado en la evaluación de una o
más condiciones.
Hay dos formas básicas de un if declaración. En cada formulario, se requiere que las
llaves de apertura y cierre.
La primera forma permite que el código se ejecuta sólo cuando una condición es
verdadera y tiene la siguiente forma:
• if condition {
• statements

• }
La segunda forma de un si declaración proporciona un adicional cláusula
else (introducido por la otra palabra clave) y se utiliza para ejecutar una parte de
código cuando la condición es verdadera y otra parte del código cuando la misma
condición es falsa. Cuando una sola cláusula más está presente, un caso
de declaración tiene la siguiente forma:
• if condition {
• statements to execute if condition is true

• } else {
• statements to execute if condition is false

• }
La cláusula else de un caso de declaración puede contener otro si la declaración
para poner a prueba más de una condición. Un caso de declaración encadenado
juntos de esta manera tiene la siguiente forma:
• if condition 1 {
• statements to execute if condition 1 is true
• } else if condition 2 {
• statements to execute if condition 2 is true

• } else {
• statements to execute if both conditions are false

  326  
• }
El valor de cualquier condición en un caso de declaración debe tener un tipo que se
ajusta a la BooleanTypeprotocolo. La condición también puede ser una declaración
de unión opcional, como se discute en Opcional Binding .

GRAMÁTICA DE UNA SENTENCIA IF


if-statement → ifif-conditioncode-blockelse-clauseopt
if-condition → expression declaration
else-clause → elsecode-block elseif-statement

Sentencia switch
Un switch de declaración permite que ciertos bloques de código a ejecutar en
función del valor de una expresión de control.
Una sentencia switch tiene la siguiente forma:
• switch control expression {
• case pattern 1 :
• statements
• case pattern 2 where condition :
• statements
• case pattern 3 where condition ,
• pattern 4 where condition :
• statements

• default:
• statements

• }
La expresión de control del switch de declaración se evalúa y se compara entonces
con los patrones especificados en cada caso. Si se encuentra una coincidencia, el
programa ejecuta las declaraciones que figuran en el marco de ese caso. El alcance de
cada caso no puede estar vacío. Como resultado, debe incluir al menos una declaración
después de los dos puntos ( : ) de cada etiqueta de la caja. Use un solo break
declaración si usted no tiene intención de ejecutar cualquier código en el cuerpo de un
caso compatible.
Los valores de las expresiones de su código puede ramificar en son muy flexibles. Por
ejemplo, además de los valores de los tipos escalares, como enteros y caracteres, su
código puede ramificarse en los valores de cualquier tipo, incluidos los números de
punto flotante, cadenas, tuplas, las instancias de clases personalizadas, y opcionales. El
valor de la expresión de control incluso puede ser igualada al valor de un caso en una
enumeración y se comprueba para su inclusión en un rango especificado de

  327  
valores. Para obtener ejemplos de cómo utilizar estos diversos tipos de valores en los
switch declaraciones, consulte Switch en el control de flujo capítulo.
Un switch de caso puede contener opcionalmente una expresión guardia después de
cada patrón. Unprotector de expresión se introduce por la palabra clave , where
seguido por una expresión, y se utiliza para proporcionar una condición adicional antes
de un patrón en un caso se considera adaptado a la expresión de control . Si una
expresión guardia está presente, las declaraciones en el caso pertinente sólo se ejecutan
si el valor de la expresión de control coincide con uno de los patrones del caso y la
expresión guardia evalúa comoverdadera . Por ejemplo, una expresión de
control coincide con el caso en el ejemplo siguiente sólo si es una tupla que contiene
dos elementos del mismo valor, tales como (1, 1) .
• case let (x, y) where x == y:
Como muestra el ejemplo de arriba muestra, los patrones en un caso también se pueden
unir constantes utilizando la palabra clave let (también pueden unirse variables
utilizando la palabra clave var ). Estas constantes (o variables) a continuación, se
puede hacer referencia en una expresión de guardia correspondiente y durante todo el
resto del código dentro del alcance de la caja. Dicho esto, si el caso contiene varios
patrones que coinciden con la expresión de control, ninguno de esos patrones puede
contener enlaces constantes o variables.
Un switch de declaración también puede incluir un caso default, introducido por la
palabra clave default. El código dentro de un caso por defecto sólo se ejecuta si no
hay otros casos coinciden con la expresión de control. Un switch de declaración
puede incluir sólo un caso por defecto, que debe aparecer al final del switch
comunicado.
Aunque el orden de ejecución real de las operaciones de búsqueda de patrones, y, en
particular, el orden de evaluación de los patrones de los casos, no se especifica,
búsqueda de patrones en un interruptordeclaración se comporta como si la
evaluación se realiza con el fin-esa fuente es, el orden en el que aparecerá en el código
fuente. Como resultado, si hay varios casos contienen patrones que dan como resultado
el mismo valor, y por lo tanto puede coincidir con el valor de la expresión de control, el
programa ejecuta sólo el código en el primer caso a juego con el fin de origen.

Declaraciones interruptor debe ser exhaustiva


En Swift, cada posible valor de tipo de control de la expresión debe coincidir con el
valor de al menos un patrón de un caso. Cuando esto simplemente no es viable (por
ejemplo, cuando el tipo de la expresión de control es Int ), puede incluir un caso por
defecto para satisfacer el requisito.
La ejecución no se caiga a través de casos Implícitamente
Después de que el código dentro de un caso emparejado ha terminado de ejecutarse, el
programa sale delinterruptor comunicado. La ejecución del programa no continúa
o "caer a través de" al siguiente caso o caso por defecto. Dicho esto, si quieres continuar
la ejecución de un caso a otro, explícitamente incluye unfallthrough declaración,
que consiste simplemente en la palabra clave fallthrough , en el caso de la que
desea que continúe la ejecución. Para obtener más información acerca de
la fallthrough declaración, veaDeclaración fallthrough continuación.

  328  
GRAMÁTICA DE UNA SENTENCIA SWITCH
switch-statement → switchexpression{switch-casesopt}
switch-cases → switch-caseswitch-casesopt
switch-case → case-labelstatements default-labelstatements
switch-case → case-label; default-label;
case-label → casecase-item-list:
case-item-list → patternguard-clauseopt patternguard-clauseopt,case-item-list
default-label → default:
guard-clause → whereguard-expression
guard-expression → expression

Declaración Etiquetada
Usted puede prefijar una sentencia de bucle o un switch declaración con una etiqueta
de declaración , que consiste en el nombre de la etiqueta seguido inmediatamente por
dos puntos (:). Utilice las etiquetas de sentencia con break y continue
declaraciones al ser explícito acerca de cómo desea cambiar el flujo de control en un
comunicado de bucle o un switch de declaración, como se explica en la sentencia
break yContinuar Declaración de abajo.
El alcance de una sentencia etiquetada es toda la instrucción que sigue a la etiqueta
comunicado. Puede anidar declaraciones etiquetado, pero el nombre de cada etiqueta de
declaración debe ser único.
Para obtener más información y ver ejemplos de cómo utilizar las etiquetas de
sentencia, consulteDeclaraciones Etiquetada en el control de flujo capítulo.

GRAMÁTICA DE UNA SENTENCIA ETIQUETADA


control-transfer-statement → break-statement
control-transfer-statement → continue-statement
control-transfer-statement → fallthrough-statement
control-transfer-statement → return-statement

Declaraciones de transferencia de control


Enunciados de transferencia de control puede cambiar el orden en el que el código de su
programa es ejecutado por incondicionalmente transferir el control del programa a partir
de una sola pieza de código a otro. Swift tiene cuatro enunciados de transferencia de
control: una ruptura , una declaración continuardeclaración,
un fallthrough declaración, y un retorno de los estados.
GRAMÁTICA DE UNA DECLARACIÓN DE TRANSFERENCIA DE
CONTROL
control-transfer-statement → break-statement
control-transfer-statement → continue-statement
control-transfer-statement → fallthrough-statement
control-transfer-statement → return-statement

  329  
Sentencia break
Un break declaración termina la ejecución del programa de un bucle o un switch
de declaración. Una break comunicado puede consistir en sólo la palabra
clave break, o puede consistir en la palabra clave break seguido del nombre de una
etiqueta de declaración, como se muestra a continuación.

• break
• break label name
Cuando una break declaración es seguida por el nombre de una etiqueta de
declaración, termina la ejecución del programa del bucle o switch sentencia indicada
por esa etiqueta.
Cuando una break declaración no es seguido por el nombre de una etiqueta de
declaración, termina la ejecución del programa del switch de declaración o la
sentencia de bucle más interno en el que se produce.
En ambos casos, el control del programa se transfiere entonces a la primera línea de
código siguiente que encierra el bucle o switch de declaración, si los hubiere.
Para obtener ejemplos de cómo utilizar un break declaración,
ver Receso y etiquetadas declaraciones en el control de flujo capítulo.

GRAMÁTICA DE UNA SENTENCIA BREAK


break-statement → breaklabel-nameopt

Continuar Declaración
A continue declaración termina la ejecución del programa de la iteración actual de
una sentencia de bucle, pero no detiene la ejecución de la sentencia de
bucle. A seguir comunicado puede consistir en sólo la palabra clave continue , o
puede consistir en la palabra clave siguen seguido del nombre de una etiqueta de
declaración, como se muestra a continuación.
• continue
• continue label name
Cuando un continue declaración es seguida por el nombre de una etiqueta de
declaración, termina la ejecución del programa de la iteración actual de la sentencia de
bucle llamado por esa etiqueta.
Cuando un continue declaración no es seguido por el nombre de una etiqueta de
declaración, termina la ejecución del programa de la iteración actual de la sentencia de
bucle más interno en el que se produce.
En ambos casos, el control del programa se transfiere entonces a la condición de la
sentencia de bucle encierra.
En una for declaración, la expresión de incremento todavía se evalúa después de
la continue se ejecuta declaración, debido a que la expresión de incremento se
evalúa después de la ejecución del cuerpo del bucle.
Para ver ejemplos de cómo usar un continue declaración,
véase Continuar y Etiquetada declaraciones en elcontrol de flujo capítulo.

  330  
GRAMÁTICA DE UNA SENTENCIA CONTINUE
continue-statement → continuelabel-nameopt

Declaración fallthrough
A fallthrough declaración consiste en la fallthrough palabra clave y sólo se
produce en un bloque caso de un switch comunicado. A fallthrough causas de
los estados de ejecución del programa para continuar de un caso en un switch
declaración al siguiente caso. La ejecución del programa continúa con el siguiente caso,
incluso si los patrones de la etiqueta de la caja no coinciden con el valor del switch
decontrol de la expresión de la declaración.
Un fallthrough declaración puede aparecer en cualquier lugar dentro de
un switch de declaración, no sólo como la última instrucción de un bloque caso,
pero no puede ser utilizado en el caso de bloque final.También no puede transferir el
control en un bloque caso cuyo patrón contiene patrones de enlace de valor.
Para ver un ejemplo de cómo utilizar un fallthrough declaración en
un interruptor de declaración, verdeclaraciones de transferencia de control en
el control de flujo capítulo.

GRAMÁTICA DE UNA DECLARACIÓN FALLTHROUGH


fallthrough-statement → fallthrough

Declaración de retorno
Un retorno declaración se produce sólo en el cuerpo de una ejecución del programa
función o método definición y las causas para volver a la función de llamada o
método. La ejecución del programa continúa en el punto inmediatamente después de la
llamada a una función o método.
Un retorno comunicado puede consistir en sólo la palabra clave de retorno , o
puede consistir en la palabra clave de retorno seguida de una expresión, como se
muestra a continuación.
• return
• return expression
Cuando un return declaración es seguida por una expresión, el valor de la expresión
se devuelve a la función de llamada o método. Si el valor de la expresión no coincide
con el valor del tipo de retorno declarado en la declaración de la función o método, el
valor de la expresión se convierte en el tipo de retorno antes de que se devuelve a la
función de llamada o método.
Cuando un return declaración no es seguido por una expresión, que puede ser
utilizado sólo para volver de una función o método que no devuelve un valor (es decir,
cuando el tipo de retorno de la función o método esvacío o () ).

GRAMÁTICA DE UNA SENTENCIA RETURN


return-statement → returnexpressionopt
 

  331  
 

Declaraciones

Una declaración introduce un nuevo nombre o construir en su programa. Por ejemplo,


utiliza las declaraciones de introducir funciones y métodos, variables y constantes, y
para definir nuevos tipos de enumeración, estructura, clase, y de protocolo, con
nombre. También puede utilizar una declaración para extender el comportamiento de un
tipo con nombre existente e importar símbolos en el programa que se declaró en otro
lugar.
En Swift, la mayoría de las declaraciones son también las definiciones en el sentido de
que se implementan o inicializadas a la vez que se declaran. Dicho esto, ya que los
protocolos no implementan sus miembros, la mayoría de los miembros de protocolo son
sólo declaraciones. Por comodidad y porque la distinción no es tan importante en el
Swift, el plazo de declaración abarca tanto las declaraciones y definiciones.
GRAMÁTICA DE UNA DECLARACIÓN
declaration → import-declaration
declaration → constant-declaration
declaration → variable-declaration
declaration → typealias-declaration
declaration → function-declaration
declaration → enum-declaration
declaration → struct-declaration
declaration → class-declaration
declaration → protocol-declaration
declaration → initializer-declaration
declaration → deinitializer-declaration
declaration → extension-declaration
declaration → subscript-declaration
declaration → operator-declaration
declarations → declarationdeclarationsopt

De nivel superior Código


El código de nivel superior en un archivo fuente Swift consiste en cero o más
declaraciones, declaraciones y expresiones. Por defecto, las variables, constantes, y
otras declaraciones con nombre que se declaró en el nivel superior de un archivo de
origen se puede acceder al código en cada archivo de origen que es parte del mismo
módulo. Puede anular este comportamiento predeterminado marcando la declaración
con un modificador de nivel de acceso, como se describe en los niveles de control de
acceso .

GRAMÁTICA DE UNA DECLARACIÓN DE ALTO NIVEL


top-level-declaration → statementsopt

  332  
Bloques de Código
Un bloque de código es utilizado por una variedad de declaraciones y las estructuras de
control de los estados agrupar. Tiene la siguiente forma:
• {
• statements

• }
Las declaraciones dentro de un bloque de código incluyen declaraciones, expresiones y
otros tipos de sentencias y se ejecutan en el orden en que aparecen en el código fuente.

GRAMÁTICA DE UN BLOQUE DE CÓDIGO


code-block → {statementsopt}

Declaración de Importación
Una declaración de importación le permite acceder a los símbolos que se declaran fuera
del archivo actual.La forma básica importa todo el módulo; que consiste en
la importación de palabra clave seguida de un nombre de módulo:
• import module
Proporcionar más límites que se detalle símbolos importan-puede especificar un
submódulo específico o una declaración específica dentro de un grupo o
módulo. Cuando se utiliza esta forma detallada, sólo el símbolo importado (y no el
módulo que lo declara) se pone a disposición en el ámbito actual.
• import import kind module . symbol name
• import module . submodule


GRAMÁTICA DE UNA DECLARACIÓN DE IMPORTACIÓN
import-declaration → attributesoptimportimport-kindoptimport-path
import-kind → typealias struct class enum protocol var func
import-path → import-path-identifier import-path-identifier.import-path
import-path-identifier → identifier operator

Declaración Constant
Una declaración de constante introduce un valor constante con nombre en su
programa. Declaraciones de constantes se declaran utilizando la palabra clave dejar y
tienen la siguiente forma:
• let constant name : type = expression
Una declaración define una constante de unión entre el inmutable nombre de la
constante y el valor del inicializador de expresión ; después de que el valor de una
constante se establece, no se puede cambiar.Dicho esto, si una constante se inicializa
con un objeto de clase, el objeto en sí mismo puede cambiar, pero la unión entre el
nombre de la constante y el objeto que se refiere a que no puede.

  333  
Cuando se declara una constante en el ámbito global, se debe inicializar con un
valor. Cuando una declaración de constante se produce en el contexto de una
declaración de clase o estructura, se considera una propiedad constante . Declaraciones
constantes no están computados propiedades y por lo tanto no tienen getters o setters.
Si el nombre de constante de una declaración constante es un patrón de tupla, el nombre
de cada elemento de la tupla está destinada a el valor correspondiente en el
inicializador expresión .
• let (firstNumber, secondNumber) = (10, 42)

En este ejemplo, primerNumero es una constante con nombre para el valor 10 ,
y secondNumber es una constante llamada para el valor 42 . Ambas constantes ahora
se pueden utilizar independientemente:
• println("The first number is \(firstNumber).")
• // imprime "El primer número es 10"  
• println("The second number is \(secondNumber).")
• // imprime "El segundo número es 42"  
La anotación de tipo ( : tipo ) es opcional en una declaración de constante cuando el
tipo del nombre de la constante se puede deducir, como se describe en Tipo de
inferencia .
Para declarar una propiedad constante estática, marque la declaración con
la estática modificador declaración. Las propiedades estáticas se discuten en Tipo
de Propiedades .
Para obtener más información acerca de las constantes y de orientación sobre cuándo
usarlos, veaConstantes y Variables y propiedades almacenadas .

GRAMÁTICA DE UNA DECLARACIÓN DE CONSTANTE


constant-declaration → attributesoptdeclaration-modifiersoptletpattern-initializer-list
pattern-initializer-list → pattern-initializer pattern-initializer,pattern-initializer-list
pattern-initializer → patterninitializeropt
initializer → =expression

Declaración de variables
Una declaración de variable introduce un valor con nombre variable en su programa y
se declara mediante la palabra clave var .
Las declaraciones de variables tienen varias formas que declaran diferentes tipos de
llamados, valores mutables, incluyendo variables almacenadas y calculadas y
propiedades, variable almacenada y observadores de propiedad y propiedades de las
variables estáticas. La forma apropiada de usar depende del ámbito en el que se declara
la variable y el tipo de variable que se va a declarar.
NOTA
También puede declarar propiedades en el contexto de una declaración de protocolo, tal
como se describe en el Protocolo de Declaración de bienes .

  334  
Puede anular una propiedad en una subclase marcando declaración de propiedad de la
subclase con laanulación modificador de declaración, como se describe
en Overriding .
Propiedades de variables almacenados Variables y almacenados
El siguiente formulario declara una propiedad almacenada variable o almacenada:
• var variable name : type = expression
Usted define esta forma de una declaración de variable en el ámbito global, el alcance
local de una función, o en el contexto de una declaración de clase o estructura. Cuando
una declaración de variable de esta forma se declara en el ámbito global o del ámbito
local de una función, que se conoce como una variable almacenada .Cuando se declara
en el contexto de una declaración de clase o estructura, que se conoce como
unapropiedad de variable almacenada .
El inicializador de expresión no puede estar presente en una declaración de protocolo,
pero en todos los demás contextos, el inicializador de expresión es opcional. Dicho esto,
si no inicializador expresión está presente, la declaración de variables debe incluir una
anotación de tipo explícita ( : tipo ).
Al igual que con declaraciones de constantes, si el nombre de la variable es un patrón
de tupla, el nombre de cada elemento de la tupla está destinada a el valor
correspondiente en el inicializador expresión .
Como su nombre indica, el valor de una variable almacenada o guardada propiedad
variable se almacena en la memoria.
Las variables calculadas y Propiedades calculadas
El siguiente formulario declara una propiedad calculada variable o computarizada:
• var variable name : type {

• get {
• statements

• }
• set( setter name ) {
• statements

• }
• }
Usted define esta forma de una declaración de variable en el ámbito global, el alcance
local de una función, o en el contexto de una estructura, enumeración o ampliación de
declaración de clase. Cuando una declaración de variable de esta forma se declara en el
ámbito global o del ámbito local de una función, que se conoce como la variable
calculada . Cuando se declara en el contexto de una estructura o ampliación de
declaración de clase, que se conoce como una propiedad calculada .
El captador se utiliza para leer el valor, y el colocador se utiliza para escribir el
valor. La cláusula setter es opcional, y cuando sólo se necesita un captador, puede
omitir ambas cláusulas y devuelva el valor solicitado directamente, como se describe

  335  
en sólo lectura computarizada Propiedades . Pero si usted proporciona una cláusula
setter, también debe proporcionar una cláusula getter.
El nombre del organismo y los paréntesis que encierran es opcional. Si proporciona un
nombre de setter, que se utiliza como el nombre del parámetro al setter. Si no se
proporciona un nombre de setter, el nombre del parámetro por defecto para el setter
es nuevoValor , como se describe en taquigrafía Declaración Setter .
A diferencia de propiedades de las variables almacenadas valores con nombre y
almacenados, el valor de un valor con nombre computarizada o una propiedad calculada
no se almacena en la memoria.
Para obtener más información y ver ejemplos de propiedades calculadas,
vea Propiedades calculadas .

Observadores variable almacenada y observadores de Propiedad


También puede declarar una variable almacenada o propiedad
con willSet y didSet observadores. Una variable o propiedad almacenada
declarado con observadores tiene la siguiente forma:
• var variable name : type = expression {
• willSet( setter name ) {
• statements

• }
• didSet( setter name ) {
• statements

• }
• }
Usted define esta forma de una declaración de variable en el ámbito global, el alcance
local de una función, o en el contexto de una declaración de clase o estructura. Cuando
una declaración de variable de esta forma se declara en el ámbito global o del ámbito
local de una función, los observadores se refieren comoobservadores variables
almacenadas . Cuando se declara en el contexto de una declaración de clase o
estructura, los observadores se les conoce como los observadores de propiedad .
Puede agregar observadores de propiedad a cualquier propiedad almacenado. También
puede agregar los observadores de propiedad a cualquier propiedad heredada (si
almacena o calcula) por razones imperiosas de la propiedad dentro de una subclase,
como se describe en observadores Overriding propiedad .
El inicializador de expresión es opcional en el contexto de una declaración de clase o
estructura, pero requerido en otro lugar. Se requiere que la anotación de tipo en todas las
declaraciones de variables que incluyen observadores, sin importar el contexto en el que
se declaran.
Los willSet y didSet observadores proporcionan una manera de observar (y para
responder adecuadamente) cuando se está estableciendo el valor de una variable o
propiedad. Los observadores no se les llama cuando la variable o propiedad se inicializa

  336  
por primera vez. En su lugar, se les llama sólo cuando el valor se establece fuera de un
contexto de inicialización.
A willSet observador se llama justo antes de que se fije el valor de la variable o
propiedad. El nuevo valor se pasa a la willSet observador como una constante, y por
lo tanto no se puede cambiar en la aplicación de
lawillSet cláusula. El didSet observador se llama inmediatamente después de que
el nuevo valor se establece.En contraste con la willSet observador, el antiguo valor
de la variable o la propiedad se pasa al didSetobservador en caso de que todavía
necesita el acceso a la misma. Dicho esto, si se asigna un valor a una variable o
propiedad dentro de su propio didSet cláusula observador, ese nuevo valor que asigne
sustituirá a la que se acaba de establecer y pasa al willSet observador.
El nombre del organismo y que encierran entre paréntesis en
las willSet y didSet cláusulas son opcionales.Si usted proporciona nombres setter,
que se utilizan como los nombres de los parámetros a
los willSet ydidSet observadores. Si usted no proporciona nombres setter, el
nombre del parámetro por defecto para elwillSet observador es nuevoValor y el
nombre del parámetro por defecto para el didSet observador esoldValue .
El didSet cláusula es opcional cuando se proporciona un willSet cláusula. Del
mismo modo, la willSetcláusula es opcional cuando se proporciona
un didSet cláusula.
Para obtener más información y para ver un ejemplo de cómo utilizar los observadores
de propiedades, consulte Observadores propiedad .

Clase y propiedades de variables estáticas


Para declarar una clase computarizada propiedad, marque la declaración con
la clase modificador declaración. Para declarar una propiedad estática variables,
marque la declaración con la estáticamodificador declaración. Las propiedades de
clase y estáticas se discuten en Tipo de Propiedades .

GRAMÁTICA DE UNA DECLARACIÓN DE VARIABLE


variable-declaration → variable-declaration-headpattern-initializer-list
variable-declaration → variable-declaration-headvariable-nametype-annotationcode-
block
variable-declaration → variable-declaration-headvariable-nametype-annotationgetter-
setter-block
variable-declaration → variable-declaration-headvariable-nametype-annotationgetter-
setter-keyword-block
variable-declaration → variable-declaration-headvariable-nametype-annotation-
initializeroptwillSet-didSet-block
variable-declaration-head → attributesoptdeclaration-modifiersoptvar
variable-name → identifier
getter-setter-block → {getter-clausesetter-clauseopt}
getter-setter-block → {setter-clausegetter-clause}
getter-clause → attributesoptgetcode-block
setter-clause → attributesoptsetsetter-nameoptcode-block

  337  
setter-name → (identifier)
getter-setter-keyword-block → {getter-keyword-clausesetter-keyword-clauseopt}
getter-setter-keyword-block → {setter-keyword-clausegetter-keyword-clause}
getter-keyword-clause → attributesoptget
setter-keyword-clause → attributesoptset
willSet-didSet-block → {willSet-clausedidSet-clauseopt}
willSet-didSet-block → {didSet-clausewillSet-clause}
willSet-clause → attributesoptwillSetsetter-nameoptcode-block
didSet-clause → attributesoptdidSetsetter-nameoptcode-block

Escriba Declaración Alias


Una declaración de tipo alias introduce un alias llamado de un tipo existente en su
programa. Tipo declaraciones de alias se declaran utilizando la palabra
clave typealias y tienen la siguiente forma:
• typealias name = existing type
Después de que se declare un alias tipo, el alias nombre se puede utilizar en lugar
del tipo existente en todas partes en su programa. El tipo existente puede ser un tipo con
nombre o un tipo compuesto. Tipo alias no crean nuevos tipos; simplemente permiten
un nombre para referirse a un tipo existente.
Consulte también Protocolo Asociadas Declaración Tipo .

GRAMÁTICA DE UNA DECLARACIÓN TYPEALIAS


typealias-declaration → typealias-headtypealias-assignment
typealias-head → attributesoptaccess-level-modifieropttypealiastypealias-name
typealias-name → identifier
typealias-assignment → =type

Declaración de funciones
Una declaración de la función introduce una función o un método en su programa. Una
función declarada en el contexto de la clase, estructura, enumeración, o protocolo se
conoce como un método . Las declaraciones de funciones se declaran usando la palabra
clave func y tienen la siguiente forma:
• func function name ( parameters ) -> return type {
• statements

• }
If the function has a return type of Void, the return type can be omitted as follows:
• func function name ( parameters ) {
• statements

• }
El tipo de cada parámetro debe ser incluido-no se puede inferir. Aunque los parámetros
a una función son constantes por defecto, usted puede escribir dejó delante del nombre

  338  
de un parámetro para enfatizar este comportamiento. Escribir var delante del nombre
de un parámetro para que sea una variable, la determinación del alcance cualquier
cambio realizado en la variable sólo para el cuerpo de la función, o escribir inout para
hacer esos cambios se aplican también al argumento de que fue aprobada en el alcance
de la persona que llama. Para un análisis de los parámetros de salida, consulte In-
Parámetros que .
Las funciones pueden devolver varios valores con un tipo tupla como el tipo de retorno
de la función.
Una definición de función puede aparecer dentro de otra declaración de la función. Este
tipo de función se conoce como una función anidada . Para un análisis de las funciones
anidadas, consulte Funciones anidadas.

Nombres de parámetros
Parámetros de la función son una lista separada por comas donde cada parámetro tiene
una de varias formas. El orden de argumentos en una llamada a la función debe
coincidir con el orden de los parámetros en la declaración de la función. La entrada más
simple en una lista de parámetros tiene la siguiente forma:
• parameter name : parameter type
Para los parámetros de función, el nombre del parámetro se utiliza en el cuerpo de la
función, pero no se utiliza cuando se llama a la función. Para los parámetros del
método, el nombre del parámetro se utiliza como dentro del cuerpo de la función, y
también se utiliza como una etiqueta para el argumento al llamar al método.El nombre
del primer parámetro de un método sólo se utiliza dentro del cuerpo de la función, como
el parámetro de una función. Por ejemplo:
• func f(x: Int, y: String) -> String {
• return y + String(x)
• }
• f(7, "hello") // x and y have no name

• class C {
• func f(x: Int, y: String) -> String {
• return y + String(x)
• }
• }
• let c = C()
• c.f(7, y: "hello") // x has no name, y has a name
Puede reemplazar el comportamiento predeterminado de cómo los nombres de
parámetro se utiliza con una de las siguientes formas:
• external parameter name local parameter name : parameter type
• # parameter name : parameter type

  339  
• _ local parameter name : parameter type
Un segundo nombre antes el nombre de parámetro local da el parámetro de un nombre
externo, que puede ser diferente del nombre de parámetro local. El nombre del
parámetro externo debe utilizar cuando se invoca la función. El argumento
correspondiente debe tener el nombre externo en los métodos o funciones llamadas.
Un símbolo de almohadilla ( # ) delante de un nombre de parámetro indica que el
nombre debe ser utilizado como un nombre de un parámetro local, externa e. Tiene el
mismo significado que escribir el nombre de parámetro local dos veces. El argumento
correspondiente debe tener este nombre en los métodos o funciones llamadas.
Un guión bajo ( _ ) delante del nombre parámetro local da ese parámetro sin nombre
que se utilizará en las llamadas a funciones. El argumento correspondiente debe tener
ningún nombre en los métodos o funciones llamadas.
Tipos especiales de Parámetros
Los parámetros pueden ser ignoradas, toman un número variable de valores, y
proporcionan valores por defecto usando las siguientes formas:
• _ : parameter type
• parameter name : parameter type ...
• parameter name : parameter type = default argument value

Un parámetro con nombre con un guión bajo ( _ ) se ignora de forma explícita y no se


puede acceder dentro del cuerpo de la función.
Un parámetro con un nombre del tipo de base seguida inmediatamente por tres puntos
( ... ) se entiende como un parámetro variadic. Una función puede tener como
máximo un parámetro variadic, que debe ser el último parámetro. Un parámetro variadic
se trata como una matriz que contiene los elementos del nombre de tipo de base. Por
ejemplo, el parámetro variadic Int ... se trata como [Int] . Para ver un ejemplo
que utiliza un parámetro variadic, consulte Parámetros variadic .
Un parámetro con un signo igual ( = ) y una expresión después de su tipo se entiende
que tienen un valor por defecto de la expresión dada. Si el parámetro se omite cuando se
llama a la función, el valor predeterminado se utiliza en su lugar. Si el parámetro no se
omite, debe tener su nombre en la llamada a la función. Por ejemplo, f () y f (x,
7) son las dos llamadas válidas a una función con un solo parámetro predeterminado
denominado x , pero f (7) no es válido, ya que proporciona un valor sin un nombre.
Tipos especiales de Métodos
Métodos de una enumeración o una estructura que modifican self deben estar
marcados con el mutating modificador declaración.
Los métodos que anulen un método de superclase deben estar marcados con
la override modificador declaración. Es un error en tiempo de compilación para
anular un método sin la override modificador o utilizar el override modificador
en un método que no define un método de superclase.
Métodos asociados con un tipo en lugar de una instancia de un tipo deben estar
marcados con la estatic modificador de declaración de enumeraciones y estructuras
o la clase de modificador de declaración para las clases.

  340  
Funciones Curried
Puede volver a escribir una función que toma varios parámetros como una función
equivalente que toma un solo parámetro y devuelve una función. La función devuelto
tiene el siguiente parámetro y devuelve otra función. Esto continúa hasta que no hay
parámetros restantes, momento en el que la última función devuelve el valor de retorno
de la función de múltiples parámetros originales. La función reescrito se conoce como
unafunción de curry . Por ejemplo, se puede reescribir la addTwoInts funcionan
como el equivalenteaddTwoIntsCurried función:
• addTwoInts(a: Int, b: Int) -> Int {
• return a + b
• }
• func addTwoIntsCurried(a: Int) -> (Int -> Int) {
• func addTheOtherInt(b: Int) -> Int {
• return a + b
• }
• return addTheOtherInt
• }
El addTwoInts función toma dos enteros y devuelve el resultado de
sumarlos. El addTwoIntsCurried función toma un solo entero, y devuelve otra
función que toma el segundo entero y lo añade a la primera. (La función anidada captura
el valor del primer argumento número entero de la función envolvente.)
En Swift, puede escribir una función al curry más concisa con la siguiente sintaxis:
• func function name ( parameter )( parameter ) -> return type {
• statements

• }
Por ejemplo, las dos declaraciones siguientes son equivalentes:
• func addTwoIntsCurried(a: Int)(b: Int) -> Int {
• return a + b
• }
• func addTwoIntsCurried(a: Int) -> (Int -> Int) {
• func addTheOtherInt(b: Int) -> Int {
• return a + b
• }
• return addTheOtherInt
• }
Para utilizar el addTwoIntsCurried funcionan de la misma manera que el
noncurried addTwoInts función, debe llamar a la addTwoIntsCurried función
con el primer argumento entero y luego llamar a su función vuelto con el segundo
argumento entero:

  341  
• addTwoInts(4, 5)
• // Devuelve un valor de 9  
• addTwoIntsCurried(4)(5)
• // Devuelve un valor de 9  
Aunque usted debe proporcionar los argumentos a una función noncurried todos a la vez
en una sola llamada, usted puede utilizar el formulario al curry de una función de
proporcionar argumentos en varias llamadas a funciones, una a la vez (incluso en
diferentes lugares en su código). Esto se conoce comoaplicación de función
parcial . Por ejemplo, puede aplicar el addTwoIntsCurried función a un
argumento entero1 y asignar el resultado a la constante PlusOne :
• let plusOne = addTwoIntsCurried(1)
• // PlusOne es una función del tipo Int -> Int  
Debido PlusOne refiere a la addTwoIntsCurried función con su argumento
enlaza con el valor 1 , llamandoPlusOne con un argumento entero simplemente
añade 1 al argumento.
• plusOne(10)
• // Devuelve un valor de 11  
 
GRAMÁTICA DE UNA DECLARACIÓN DE FUNCIÓN
function-declaration → function-headfunction-namegeneric-parameter-clauseopt-
function-signaturefunction-body
function-head → attributesoptdeclaration-modifiersoptfunc
function-name → identifier operator
function-signature → parameter-clausesfunction-resultopt
function-result → ->attributesopttype
function-body → code-block
parameter-clauses → parameter-clauseparameter-clausesopt
parameter-clause → () (parameter-list...opt)
parameter-list → parameter parameter,parameter-list
parameter → inoutoptletopt#optexternal-parameter-nameoptlocal-parameter-nametype-
annotationdefault-argument-clauseopt
parameter → inoutoptvar#optexternal-parameter-nameoptlocal-parameter-nametype-
annotationdefault-argument-clauseopt
parameter → attributesopttype
external-parameter-name → identifier _
local-parameter-name → identifier _
default-argument-clause → =expression

Declaración Enumeración
Una declaración de la enumeración introduce un tipo de enumeración llamado en su
programa.
Declaraciones de enumeración tienen dos formas básicas y se declaran usando la
palabra clave enum . El cuerpo de una enumeración declarada utilizando formulario

  342  
contiene los llamados valores cero o más casos de enumeración -y cualquier número de
declaraciones, incluidas las propiedades calculadas, métodos de instancia, los métodos
estáticos, inicializadores, alias de tipo, e incluso otra enumeración, estructura, y las
declaraciones de clase . Declaraciones de enumeración no pueden contener deinitializer
o protocolo declaraciones.
Tipos de enumeración pueden adoptar cualquier número de protocolos, pero no pueden
heredar de clases, estructuras u otras enumeraciones.
A diferencia de clases y estructuras, tipos de enumeración no tienen un inicializador por
defecto proporcionado implícitamente; todos los inicializadores deben declararse
explícitamente. Inicializadores pueden delegar a otros inicializadores en la
enumeración, pero el proceso de inicialización se ha completado sólo después de un
inicializador asigna uno de los casos de enumeración a uno mismo .
Al igual que las estructuras, pero a diferencia de las clases, enumeraciones son tipos de
valor; se copian las instancias de una enumeración cuando se asigna a las variables o
constantes, o cuando se pasa como argumentos de una llamada de función. Para obtener
información sobre los tipos de valor, vea Estructuras y enumeraciones son tipos de
valor .
Puede extender el comportamiento de un tipo de enumeración con una ampliación de
declaración, como se discutió en la Declaración de extensión .
Las enumeraciones con casos de Cualquier Tipo
El siguiente formulario declara un tipo de enumeración que contiene los casos de
enumeración de cualquier tipo:
• enum enumeration name : adopted protocols {
• case enumeration case 1
• case enumeration case 2 ( associated value types )

• }
Enumeraciones declaradas en esta forma a veces se llaman uniones discriminadas en
otros lenguajes de programación.
En esta forma, cada bloque caso consiste en la palabra clave caso seguido por uno o
más casos de enumeración, separados por comas. El nombre de cada caso debe ser
único. Cada caso también puede especificar que almacena los valores de un tipo
determinado. Estos tipos se especifican en el tipo de valor asociado tupla,
inmediatamente después del nombre del caso. Para obtener más información y ver
ejemplos de casos con tipos de valor asociadas, ver valores asociados .
Las enumeraciones con casos de un tipo de valor crudo
La forma siguiente declara un tipo de enumeración que contiene los casos de
enumeración del mismo tipo básico:
• enum enumeration name : raw-value type , adopted protocols {
• case enumeration case 1 = raw value 1
• case enumeration case 2 = raw value 2

• }

  343  
En esta forma, cada bloque caso consiste en la palabra clave caso , seguido de uno o
más casos de enumeración, separados por comas. A diferencia de los casos en la
primera forma, cada caso tiene un valor subyacente, llamado valor en bruto , del mismo
tipo básico. El tipo de estos valores se especifica en el tipo de valor crudo y debe
representar un número entero, el número de punto flotante, cadena, o de un solo
carácter.En particular, el tipo de prima-valor debe ajustarse a la equatable protocolo
y uno de los siguientes protocolos literal
convertibles: IntegerLiteralConvertible para literales
enteros, FloatingPointLiteralConvertible para los literales de punto
flotante, StringLiteralConvertible para los literales de cadena que contienen
cualquier número de caracteres,
y ExtendedGraphemeClusterLiteralConvertible para literales de cadena
que contienen sólo un único carácter.
Cada caso debe tener un nombre único y se le asigna un valor prima única. Si no se
especifica el tipo de valor crudo como int y no asigna un valor a los casos
explícitamente, se les asigna implícitamente los valores0 , 1 , 2 , y así
sucesivamente. Cada caso sin asignar de tipo Int está implícitamente asigna un valor
en bruto que se incrementa automáticamente del valor bruto del caso anterior.
• enum ExampleEnum: Int {
• case A, B, C = 5, D
• }
En el ejemplo anterior, el valor bruto de ExampleEnum.A es 0 y el valor
de ExampleEnum.B es 1 . Y debido a que el valor de ExampleEnum.C se establece
explícitamente en 5 , el valor de ExampleEnum.D se incrementa automáticamente a
partir de 5 y por lo tanto es 6 .
El valor en bruto de un caso de enumeración se puede acceder llamando a
su toRaw método, como enExampleEnum.B.toRaw () . También puede utilizar
un valor crudo para encontrar un caso correspondiente, si es que existe, llamando a
la fromRaw método, que devuelve un caso opcional. Para obtener más información y
ver ejemplos de casos con tipos de valor en bruto, vea Raw Values.

Acceso Casos de enumeración


Para hacer referencia al caso de un tipo de enumeración, utilice punto ( . sintaxis),
como enEnumerationType.EnumerationCase . Cuando el tipo de enumeración
puede inferirse a partir del contexto, puede omitirlo (todavía se requiere que el punto),
como se describe en Sintaxis Enumeración y Implícita Expresión miembros .
Para comprobar los valores de la enumeración de los casos, utilizar un interruptor
de declaración, como se muestra en juego valores de enumeración con una sentencia
switch . El tipo de enumeración coincide-patrón en contra de los patrones de casos de
enumeración en los bloques de caso del interruptor de la declaración, como se
describe en el Modelo de Enumeración Case .

  344  
GRAMÁTICA DE UNA DECLARACIÓN DE LA ENUMERACIÓN
enum-declaration → attributesoptaccess-level-modifieroptunion-style-enum
enum-declaration → attributesoptaccess-level-modifieroptraw-value-style-enum
union-style-enum → enumenum-namegeneric-parameter-clauseopttype-inheritance-
clauseopt{union-style-enum-membersopt}
union-style-enum-members → union-style-enum-memberunion-style-enum-membersopt
union-style-enum-member → declaration union-style-enum-case-clause
union-style-enum-case-clause → attributesoptcaseunion-style-enum-case-list
union-style-enum-case-list → union-style-enum-case union-style-enum-case,union-
style-enum-case-list
union-style-enum-case → enum-case-nametuple-typeopt
enum-name → identifier
enum-case-name → identifier
raw-value-style-enum → enumenum-namegeneric-parameter-clauseopttype-inheritance-
clause{raw-value-style-enum-members}
raw-value-style-enum-members → raw-value-style-enum-memberraw-value-style-
enum-membersopt
raw-value-style-enum-member → declaration raw-value-style-enum-case-clause
raw-value-style-enum-case-clause → attributesoptcaseraw-value-style-enum-case-list
raw-value-style-enum-case-list → raw-value-style-enum-case raw-value-style-enum-
case,raw-value-style-enum-case-list
raw-value-style-enum-case → enum-case-nameraw-value-assignmentopt
raw-value-assignment → =literal

Estructura Declaración
Una declaración de la estructura presenta un tipo de estructura llamado en su
programa. Estructura declaraciones se declaran usando la palabra clave struct y
tienen la siguiente forma:
• struct structure name : adopted protocols {
• declarations

• }
El cuerpo de una estructura contiene cero o
más declaraciones . Estas declaraciones pueden incluir tanto almacenados y calculados
propiedades, propiedades estáticas, métodos de instancia, los métodos estáticos,
inicializadores, subíndices, alias de tipo, e incluso otra estructura, clase, y las
declaraciones de enumeración.Estructura de las declaraciones no pueden contener
deinitializer o protocolo declaraciones. Para una discusión y varios ejemplos de
estructuras que incluyen diversos tipos de declaraciones, vea Clases y Estructuras .
Tipos de estructura puede adoptar cualquier número de protocolos, pero no pueden
heredar de clases, enumeraciones, u otras estructuras.
Hay tres formas de crear una instancia de una estructura previamente declarado:
• Llame a uno de los inicializadores declarados dentro de la estructura, como se
describe eninicializadores .

  345  
• Si son declarados no inicializadores, llame inicializador miembro por miembro de la
estructura, como se describe en el miembro por miembro Inicializadores de
Estructura Tipos .
• Si son declarados no inicializadores, y todas las propiedades de la declaración de la
estructura se dieron valores iniciales, llame inicializador por defecto de la estructura,
como se describe enInicializadores predeterminados .
El proceso de inicialización de propiedades declaradas de una estructura se describe en
la inicialización .
Propiedades de una instancia de estructura se puede acceder mediante punto
( . sintaxis), como se describe en Acceso a las propiedades .
Las estructuras son tipos de valor; se copian las instancias de una estructura cuando se
asigna a las variables o constantes, o cuando se pasa como argumentos de una llamada
de función. Para obtener información sobre los tipos de valor, vea Estructuras y
enumeraciones son tipos de valor .
Puede extender el comportamiento de un tipo de estructura con una ampliación de
declaración, como se discutió en la Declaración de extensión .

GRAMÁTICA DE UNA DECLARACIÓN DE LA ESTRUCTURA


struct-declaration → attributesoptaccess-level-modifieroptstructstruct-namegeneric-
parameter-clauseopttype-inheritance-clauseoptstruct-body
struct-name → identifier
struct-body → {declarationsopt}

Declaración de Clase
Una declaración de la clase introduce un tipo de clase nombrada en su
programa. Declaraciones de clase se declaran usando la palabra clave de clase y
tienen la siguiente forma:
• class class name : superclass , adopted protocols {
• declarations

• }
El cuerpo de una clase contiene cero o más declaraciones . Estas declaraciones pueden
incluir tanto almacenados y calculados propiedades, métodos de instancia, métodos de
clase, inicializadores, un solo deinitializer, subíndices, alias de tipo, e incluso otra clase,
la estructura, y las declaraciones de enumeración.Declaraciones de clase no pueden
contener declaraciones de protocolo. Para una discusión y varios ejemplos de clases que
incluyen diversos tipos de declaraciones, vea Clases y Estructuras .
Un tipo de clase puede heredar de una sola clase padre, su superclase , pero puede
adoptar cualquier número de protocolos. La superclase aparece por primera vez después
de que el nombre de la clase y el colon, seguido por cualquier protocolos
adoptados . Clases genéricas pueden heredar de otras clases genéricas y no genéricos,
sino una clase no genérica pueden heredar sólo de otras clases no genéricos.Cuando se
escribe el nombre de una clase superclase genérica tras los dos puntos, debe incluir el
nombre completo de esa clase genérica, incluida su cláusula de parámetro genérico.

  346  
Como se discutió en la Declaración Inicializador , las clases pueden han designado y los
inicializadores de conveniencia. El inicializador designado de una clase debe inicializar
todas las propiedades declaradas de la clase y debe hacerlo antes de llamar a cualquiera
de los inicializadores designados de su superclase.
Una clase puede anular las propiedades, los métodos, los subíndices y los
inicializadores de su superclase.Propiedades alteradas temporalmente, los métodos, los
subíndices y inicializadores designados deben estar marcados con
la anulación modificador declaración.
Exigir que las subclases implementan inicializador de una superclase, marcan
inicializador de la superclase con el requerido modificador declaración. La
implementación de la subclase de que inicializador también debe estar marcado con
el requerido modificador declaración.
Aunque las propiedades y métodos declarados en la superclase son heredados por la
clase actual, inicializadores designados declarados en la superclase no lo son. Dicho
esto, si la clase actual anula todos los inicializadores designados de la superclase, hereda
inicializadores de conveniencia de la superclase.Clases Swift no heredan de una clase
base universal.
Hay dos maneras de crear una instancia de una clase declarada con anterioridad:
• Llame a uno de los inicializadores declarados dentro de la clase, como se describe
en inicializadores .
• Si son declarados no inicializadores, y todas las propiedades de la declaración de
clase se les dio valores iniciales, llame inicializador por defecto de la clase, como se
describe en Inicializadores predeterminados .
Propiedades de acceso de una instancia de la clase con el punto ( . ) sintaxis, como se
describe en Acceso a las propiedades .
Las clases son tipos de referencia; instancias de una clase se denominan, en lugar de
copiar, cuando se asigna a las variables o constantes, o cuando se pasa como
argumentos de una llamada de función. Para obtener información acerca de los tipos de
referencia, consulte Estructuras y enumeraciones son tipos de valor .
Puede extender el comportamiento de un tipo de clase con una ampliación de
declaración, como se discutió en la Declaración de extensión .

GRAMÁTICA DE UNA DECLARACIÓN DE CLASE


class-declaration → attributesoptaccess-level-modifieroptclassclass-namegeneric-
parameter-clauseopttype-inheritance-clauseoptclass-body
class-name → identifier
class-body → {declarationsopt}

Declaración Protocolo
Una declaración protocolo introduce un tipo de protocolo llamado en su
programa. Declaraciones de protocolo se declaran usando la palabra clave de
protocolo y tienen la siguiente forma:
• protocol protocol name : inherited protocols {
• protocol member declarations

  347  
• }
El cuerpo de un protocolo contiene cero o más declaraciones de miembros de
protocolo , que describen los requisitos de conformidad que cualquier tipo que adoptan
el protocolo debe cumplir. En particular, un protocolo puede declarar que los tipos se
ajusten deben implementar ciertas propiedades, métodos, inicializadores y
subíndices. Los protocolos también pueden declarar los tipos especiales de alias de tipo,
llamados tipos asociados , que pueden especificar las relaciones entre las diversas
declaraciones del protocolo. Las declaraciones de miembros protocolo se discuten en
detalle a continuación.
Tipos de protocolo pueden heredar de cualquier número de otros protocolos. Cuando un
tipo de protocolo hereda de otros protocolos, el conjunto de requisitos de los otros
protocolos se agregan, y cualquier tipo que hereda de la actual protocolo debe cumplir
con todos los requisitos. Para ver un ejemplo de cómo utilizar la herencia de protocolo,
vea Herencia Protocolo .
NOTA
También puede agregar los requisitos de conformidad de múltiples protocolos que
utilizan tipos de composición del protocolo, según se describe en el Protocolo Tipo
Composición y Composición Protocolo .
Usted puede agregar la conformidad de protocolo a un tipo declarado previamente
mediante la adopción del protocolo en una ampliación de declaración de ese tipo. En la
extensión, debe implementar todos los requisitos del protocolo aprobado. Si el tipo ya se
implementa todos los requisitos, se puede dejar el cuerpo de la ampliación de
declaración vacía.
De forma predeterminada, los tipos que se ajustan a un protocolo deben implementar
todas las propiedades, métodos y subíndices declaradas en el protocolo. Dicho esto,
puede marcar estas declaraciones de miembros de protocolo con
el opcional modificador de declaración para especificar que su aplicación por un tipo
de conformación es opcional. El opcional modificador sólo puede aplicarse a los
protocolos que están marcados con el objc atributo. Como resultado, sólo los tipos de
clase pueden adoptar y cumplir con un protocolo que contiene requisitos miembro
opcionales. Para obtener más información acerca de cómo utilizar
la opción modificador de declaración y de orientación sobre cómo acceder opcional
ejemplo de protocolo miembros-para, cuando no estás seguro de si un tipo de
conformación implementa ellos-véase Requisitos del Protocolo Facultativo .
Para restringir la adopción de un protocolo para los tipos de clases solamente, marque el
protocolo con laclase de requerimiento por escrito la clase de palabras clave
como el primer elemento en el protocolos heredados lista después de los dos
puntos. Por ejemplo, el siguiente protocolo puede ser adoptada sólo por los tipos de
clases:
• protocol SomeProtocol: class {
• /* Protocol members go here */
• }
Cualquier protocolo que hereda de un protocolo que está marcado con la clase
de requisito puede igualmente adoped sólo por los tipos de clase.
NOTA
  348  
Si un protocolo está marcado con el objc atributo, la clase de requisito se aplica
implícitamente a ese protocolo; no hay necesidad de marcar el protocolo con la clase
de requisito de forma explícita.
Los protocolos se denominan tipos, y por lo tanto pueden aparecer en todos los mismos
lugares en su código como otros tipos con nombre, como se discute en los Protocolos
como Tipos . Sin embargo, no se puede construir una instancia de un protocolo, ya que
los protocolos en realidad no ofrecen las implementaciones de los requisitos que se
especifican.
Puede usar los protocolos para declarar que los métodos delegado de una clase o
estructura debe aplicar, como se describe en Delegación .

GRAMÁTICA DE UNA DECLARACIÓN PROTOCOLO


protocol-declaration → attributesoptaccess-level-modifieroptprotocolprotocol-nametype-
inheritance-clauseoptprotocol-body
protocol-name → identifier
protocol-body → {protocol-member-declarationsopt}
protocol-member-declaration → protocol-property-declaration
protocol-member-declaration → protocol-method-declaration
protocol-member-declaration → protocol-initializer-declaration
protocol-member-declaration → protocol-subscript-declaration
protocol-member-declaration → protocol-associated-type-declaration
protocol-member-declarations → protocol-member-declarationprotocol-member-
declarationsopt

Protocolo Declaración de bienes


Protocolos declaran que los tipos se ajusten deben implementar una propiedad mediante
la inclusión de unadeclaración de propiedad de protocolo en el cuerpo de la declaración
de protocolo. Declaraciones de bienes Protocolo tienen una forma especial de una
declaración de variable:
• var property name : type { get set }
Al igual que con otras declaraciones de miembros de protocolo, estas declaraciones de
bienes declaran sólo los requisitos get y set para los tipos que cumplen con el
protocolo. Como resultado, no se implementa el getter o setter directamente en el
protocolo en el que se declara.
Los requisitos getter y setter pueden ser satisfechas por un tipo de conformación en una
variedad de maneras. Si una declaración de propiedad incluye tanto
los get y set palabras clave, un tipo de conformación puede implementar con un
almacenada propiedad variable o una propiedad calculada que es a la vez de lectura y
escritura (es decir, una que implementa un getter y un setter). Sin embargo, esa
declaración de propiedad no se puede implementar como una propiedad constante o una
propiedad calculada de sólo lectura. Si una declaración de propiedad incluye sólo
el get de palabras clave, que puede implementarse como cualquier tipo de
propiedad. Para ver ejemplos de tipos que implementan conforme a los requisitos de las
propiedades de un protocolo, vea Requisitos de Propiedad .
Ver también declaración de variables .

  349  
GRAMÁTICA DE UNA DECLARACIÓN DE PROPIEDAD
PROTOCOLO
protocol-property-declaration → variable-declaration-headvariable-nametype-
annotationgetter-setter-keyword-block

Protocolo Declaración Método


Protocolos declaran que tipos conformes deben implementar un método mediante la
inclusión de una declaración de método protocolo en el cuerpo de la declaración de
protocolo. Declaraciones de métodos Protocolo tienen la misma forma que las
declaraciones de funciones, con dos excepciones: No se incluyen un cuerpo de la
función, y no se puede proporcionar ningún valores de los parámetros por defecto como
parte de la declaración de la función. Para ver ejemplos de tipos que implementan
conforme los requisitos del método de un protocolo, vea Requisitos del método .
Para declarar una clase o requisito método estático en una declaración protocolo,
marque la declaración de método con la clase modificador declaración. Las clases
que implementan este método también declaran el método con la clase
de modificador. Estructuras que lo implementan deben declarar el método con
laestática modificador de declaración en su lugar. Si está implementando el método
en una extensión, utilice laclase modificador si está extendiendo una clase y
la estática modificador si está extendiendo una estructura.
Véase también la Declaración de funciones .

GRAMÁTICA DE UNA DECLARACIÓN DE MÉTODO DE


PROTOCOLO
protocol-method-declaration → function-headfunction-namegeneric-parameter-clause-
optfunction-signature

Protocolo Declaración Inicializador


Protocolos declaran que los tipos se ajusten deben implementar un inicializador al
incluir una declaración de inicialización de protocolo en el cuerpo de la declaración de
protocolo. Declaraciones Protocolo de inicializador tienen la misma forma que las
declaraciones de inicializador, excepto que no incluyen el cuerpo del inicializador.
Cuando una clase implementa un inicializador para satisfacer el requisito de
inicialización de un protocolo, el inicializador debe estar marcado con el required
modificador de declaración si la clase no está marcada con el final modificador
declaración.
Ver también Declaración inicializador .

GRAMÁTICA DE UNA DECLARACIÓN INICIALIZADOR


PROTOCOLO
protocol-initializer-declaration → initializer-headgeneric-parameter-clauseopt-
parameter-clause

  350  
Protocolo Declaración Subíndice
Protocolos declaran que los tipos se ajusten deben implementar un subíndice al incluir
una declaración subíndice protocolo en el cuerpo de la declaración de
protocolo. Declaraciones de bienes Protocolo tienen una forma especial de una
declaración subíndice:
• subscript ( parameters ) -> return type { get set }
Declaraciones subíndices sólo declaran los requisitos mínimos getter y setter de
aplicación para los tipos que cumplen con el protocolo. Si la declaración subíndice
incluye tanto los get y set palabras clave, un tipo de conformación debe
implementar tanto un captador y una cláusula de setter. Si la declaración subíndice
incluye sólo el get palabra clave, un tipo de conformación debe implementar al
menos una cláusula getter y opcionalmente puede aplicar una cláusula de setter.
Ver también Declaración Subíndice .

GRAMÁTICA DE UNA DECLARACIÓN SUBÍNDICE PROTOCOLO


protocol-subscript-declaration → subscript-headsubscript-resultgetter-setter-keyword-
block

Protocolo asociado Declaración Tipo


Protocolos declaran tipos asociados con la palabra clave typealias . Un tipo
asociado proporciona un alias para un tipo que se utiliza como parte de la declaración de
un protocolo. Tipos asociados son similares a los parámetros de tipo de cláusulas de
parámetros genéricos, pero están asociados con self en el protocolo en el que están
declaradas. En ese contexto, Self refiere al tipo eventual que cumpla con el
protocolo. Para obtener más información y ejemplos, vea Tipos asociados .
Véase también el tipo de declaración Alias .

GRAMÁTICA DE UNA DECLARACIÓN DE TIPO DE


PROTOCOLO ASOCIADO
protocol-associated-type-declaration → typealias-headtype-inheritance-clauseopt-
typealias-assignmentopt

Declaración Inicializador
Una declaración inicializador introduce un inicializador para una clase, estructura o
enumeración en su programa. Declaraciones de inicializador se declaran usando la
palabra clave init y tienen dos formas básicas.
Estructura, enumeración y tipos de clase pueden tener cualquier número de
inicializadores, pero las reglas y el comportamiento asociado para inicializadores de
clase son diferentes. A diferencia de las estructuras y enumeraciones, las clases tienen
dos tipos de inicializadores: inicializadores designados y los inicializadores de
conveniencia, como se describe en la inicialización .
El siguiente formulario declara inicializadores de estructuras, enumeraciones, y
inicializadores designados de clases:
• init( parameters ) {

  351  
• statements

• }
Un inicializador designado de una clase inicializa todas las propiedades de la clase
directamente. No se puede llamar a cualquier otro inicializadores de la misma clase, y si
la clase tiene una superclase, debe llamar a uno de los inicializadores designados de la
superclase. Si la clase hereda todas las propiedades de su superclase, uno de
inicializadores designados de la superclase debe ser llamado antes de cualquiera de estas
propiedades pueden ser establecidas o modificadas en la clase actual.
Inicializadores designados pueden ser declarados en el contexto de sólo una declaración
de clase y, por tanto, no se pueden agregar a una clase utilizando una ampliación de
declaración.
Inicializadores en estructuras y enumeraciones pueden llamar a otros inicializadores
declarados a delegar parte o la totalidad del proceso de inicialización.
Declarar inicializadores de conveniencia para una clase, marcar la declaración
inicializador con la convenience modificador declaración.
• convenience init( parameters ) {
• statements

• }
Inicializadores de Conveniencia pueden delegar el proceso de inicialización a otro
inicializador conveniencia o para uno de los inicializadores designados de la
clase. Dicho esto, los procesos de inicialización deben terminar con una llamada a un
inicializador designado que en última instancia se inicializa las propiedades de la
clase. Inicializadores de conveniencia no pueden llamar inicializadores de una
superclase.
Puede marcar designado y los inicializadores de conveniencia con el required
modificador de declaración para exigir que cada subclase implementar el
inicializador. Aplicación de una subclase de que inicializador también debe estar
marcado con el requirted modificador declaración.
Por defecto, los inicializadores declarados en una superclase no son heredados por las
subclases. Dicho esto, si una subclase inicializa todas sus propiedades almacenados con
valores por defecto y no define ningún inicializadores de su propia, hereda todos los
inicializadores de la superclase. Si la subclase sobreescribe todos los inicializadores
designados de la superclase, hereda inicializadores de conveniencia de la superclase.
Al igual que con los métodos, propiedades y subíndices, es necesario marcar
inicializadores designados anulados con la override modificador declaración.
NOTA
Si marca un inicializador con la required modificador de declaración, no es también
marca el inicializador con la override modificador cuando omite el inicializador
requerido en una subclase.
Para ver ejemplos de inicializadores en diversas declaraciones de tipo,
consulte inicialización .

  352  
GRAMÁTICA DE UNA DECLARACIÓN INICIALIZADOR
initializer-declaration → initializer-head generic-parameter-clause opt parameter-
clause initializer-body
inicializador-cabeza → atributos opt declaración modificadores optan init
inicializador-cuerpo → code-block
Declaración Deinitializer
Una declaración deinitializer declara un deinitializer para un tipo de
clase. Deinitializers tomar ningún parámetro y tienen la siguiente forma:

• deinit {
• statements

• }
A deinitializer se llama automáticamente cuando ya no hay ninguna referencia a un
objeto de clase, justo antes de que se cancela la asignación del objeto de clase. A
deinitializer se puede declarar sólo en el cuerpo de una clase de declaración-, pero no en
una extensión de una clase y cada clase puede tener como máximo una.
Una subclase hereda deinitializer de su superclase, que se llama implícitamente justo
antes de se desasigna el objeto subclase. El objeto subclase no se cancela la asignación
hasta que todos deinitializers en su cadena de herencia han terminado de ejecutarse.
Deinitializers no se llaman directamente.
Para ver un ejemplo de cómo utilizar un deinitializer en una declaración de clase,
véase deinicialización .

GRAMÁTICA DE UNA DECLARACIÓN DEINITIALIZER


deinitializer-declaration → attributesoptdeinitcode-block

Declaración de Extensión
Una ampliación de declaración le permite extender el comportamiento de los tipos de
clase, estructura, enumeración y existentes. Declaraciones de extensión se declaran
usando la palabra clave de extensión y tienen la siguiente forma:
• extension type name : adopted protocols {
• declarations
El cuerpo de una ampliación de declaración contiene cero o
más declaraciones . Estas declaraciones pueden incluir propiedades calculadas,
propiedades estáticas calculadas, métodos de instancia, los métodos estáticos y de clase,
inicializadores, declaraciones subíndice, e incluso de clase, la estructura, y las
declaraciones de enumeración. Declaraciones de extensión no pueden contener
deinitializer o protocolo declaraciones, propiedades almacenadas, observadores de
propiedad, u otras declaraciones de extensión.Para una discusión y varios ejemplos de
extensiones que incluyen diversos tipos de declaraciones, veaExtensiones .
Declaraciones de extensión pueden añadir conformidad protocolo para una clase,
estructura y tipo de enumeración existente en los protocolos aprobados . Declaraciones
de extensión no pueden añadir herencia de clases para una clase existente, y por lo tanto

  353  
sólo se puede especificar una lista de protocolos después de que el nombre del tipo y el
colon.
Propiedades, métodos y inicializadores de un tipo existente no se pueden sustituir en
una extensión de ese tipo.
Declaraciones de extensión pueden contener declaraciones de inicializador. Dicho esto,
si el tipo que está extendiéndose está definida en otro módulo, una declaración
inicializador debe delegar en un inicializador ya definido en ese módulo para asegurar
que los miembros de ese tipo se inicializan correctamente.

GRAMÁTICA DE UNA AMPLIACIÓN DE DECLARACIÓN


extension-declaration → access-level-modifieroptextensiontype-identifiertype-
inheritance-clauseoptextension-body
extension-body → {declarationsopt}

Declaración Subíndice
Un subíndice declaración le permite añadir soporte subíndices para los objetos de un
tipo determinado y se utilizan normalmente para proporcionar una sintaxis conveniente
para acceder a los elementos de una colección, una lista o secuencia. Declaraciones
subíndices se declaran utilizando la palabra clave subíndice y tienen la siguiente
forma:
• subscript ( parameters ) -> return type {

• get {
• statements

• }
• set( setter name ) {
• statements

• }
• }
Declaraciones subíndices pueden aparecer sólo en el contexto de una estructura,
enumeración, extensión, o declaración protocolo clase.
Los parámetros especifican uno o más índices que se utilizan para acceder a los
elementos del tipo correspondiente en una expresión de subíndice (por ejemplo, la i en
la expresión object[i] ). Aunque los índices utilizados para acceder a los elementos
pueden ser de cualquier tipo, cada parámetro debe incluir una anotación de tipo para
especificar el tipo de cada índice. El tipo de retorno especifica el tipo de elemento que
se está accediendo.
Al igual que con las propiedades calculadas, declaraciones subíndice apoyar la lectura y
la escritura el valor de los elementos de los que se accede. El captador se utiliza para
leer el valor, y el colocador se utiliza para escribir el valor. La cláusula setter es
opcional, y cuando sólo se necesita un captador, puede omitir ambas cláusulas y

  354  
devuelva directamente el valor solicitado. Dicho esto, si usted proporciona una cláusula
setter, también debe proporcionar una cláusula getter.
El nombre del organismo y los paréntesis que encierran son opcionales. Si proporciona
un nombre de setter, que se utiliza como el nombre del parámetro al setter. Si no se
proporciona un nombre de setter, el nombre del parámetro por defecto para el setter
es valor . El tipo del nombre setter debe ser el mismo que el tipo de retorno .
Usted puede sobrecargar una declaración subíndice en el tipo en el que se declara,
siempre y cuando losparámetros o el tipo de retorno son diferentes de la que usted está
sobrecargando. También puede anular una declaración subíndice heredado de una
superclase. Al hacerlo, debe marcar la declaración subíndice se reemplaza con
la anulación modificador declaración.
También puede declarar subíndices en el contexto de una declaración de protocolo, tal
como se describe en la Declaración Protocolo Subíndice .
Para obtener más información acerca de subíndices y para ver ejemplos de
declaraciones de subíndice, versubíndices .

GRAMÁTICA DE UNA DECLARACIÓN SUBÍNDICE


subscript-declaration → subscript-headsubscript-resultcode-block
subscript-declaration → subscript-headsubscript-resultgetter-setter-block
subscript-declaration → subscript-headsubscript-resultgetter-setter-keyword-block
subscript-head → attributesoptdeclaration-modifiersoptsubscriptparameter-clause
subscript-result → ->attributesopttype

Declaración del operador


Una declaración de operador introduce un nuevo infijo, prefijo, o operador de sufijo en
su programa y se declara utilizando la palabra clave operator .
Puede declarar los operadores de tres empotramientos diferentes: infijo, prefijo, y
postfix. La fijeza de un operador especifica la posición relativa de un operador a sus
operandos.
Hay tres formas básicas de una declaración del operador, una para cada fijeza. La fijeza
de la operadora se especifica mediante el marcado de la declaración del operador con
el infijo , prefijo o de sufijo modificador declaración ante el operador
de la palabra clave. En cada formulario, el nombre del operador puede contener sólo los
caracteres operadores definidos en Operadores .
El siguiente formulario se declara un nuevo operador infijo:
• infix operator operator name {
• precedence precedence level
• associativity associativity

• }
Un operador infijo es un operador binario que se escribe entre sus dos operandos, como
el operador de suma familiarizados ( + ) en la expresión 1 + 2 .
Operadores infijos pueden especificar opcionalmente una precedencia, asociatividad, o
ambos.

  355  
La precedencia de un operador especifica cómo un operador fuertemente se une a sus
operandos en ausencia de agrupar paréntesis. Se especifica la precedencia de un
operador escribiendo la palabra clave contextual prioridad seguido por el nivel de
precedencia . El nivel de precedencia puede ser cualquier número entero (número
entero decimal) de 0 a 255; a diferencia de literales enteros decimales, que no puede
contener caracteres de subrayado. Aunque el nivel de precedencia es un número
específico, es significativo sólo en relación a otro operador. Es decir, cuando dos
operadores compiten entre sí por sus operandos, como en la expresión 2 + 3 * 5 , el
operador con el nivel de prioridad más alta se une más estrechamente a sus operandos.
La asociatividad de un operador especifica cómo una secuencia de operadores con el
mismo nivel de precedencia se agrupan en ausencia de paréntesis de agrupación. Se
especifica la asociatividad de un operador escribiendo la palabra clave
contextual asociatividad seguido de la asociatividad , que es una de las palabras
clave contextuales izquierda , derecha , o ninguno . Los operadores que son
asociativos por la izquierda del grupo de izquierda a derecha. Por ejemplo, el operador
de resta ( - ) se asociativo por la izquierda, y por lo tanto la expresión 4 - 5 - 6 se
agrupan como (4 - 5) - 6 y evalúa a -7 . Los operadores que son grupo asociativo
por la derecha derecha a izquierda, y los operadores que se especifican con una
asociatividad de ninguno no asocian en absoluto. Operadores no asociativo de la
misma nivel de precedencia no pueden aparecer adyacente a cada uno para el otro. Por
ejemplo, 1 <2 <3 no es una expresión válida.
Operadores infijos que se declaran sin especificar una precedencia o asociatividad se
inicializan con un nivel de precedencia de 100 y una asociatividad de ninguno .
El siguiente formulario se declara un nuevo operador de prefijo:
• prefix operator operator name {}
Un operador de prefijo es un operador unitario que está escrito inmediatamente antes de
su operando, tales como el operador de incremento prefijo ( ++ ) es en la expresión ++
i.
Declaraciones operadores de prefijo no especifican un nivel de precedencia. Operadores
de prefijo son no asociativo.
El siguiente formulario se declara un nuevo operador de sufijo:
• postfix operator operator name {}
Un operador de sufijo es un operador unario que se escribe inmediatamente después de
su operando, como el operador de incremento postfix ( ++ ) está en la expresión i ++ .
Al igual que con los operadores de prefijo, declaraciones operador postfix no
especifican un nivel de precedencia. Operadores de Postfix son no asociativo.
Después de declarar un nuevo operador, a ponerla en práctica, al declarar una función
que tiene el mismo nombre que el operador. Si está implementando un operador de
prefijo o de sufijo, también debe marcar esa declaración de la función con el
correspondiente prefijo o de sufijo modificador declaración. Si está
implementando un operador infijo, no marca que declaración de la función con
el infijo modificador declaración. Para ver un ejemplo de cómo crear e implementar
un nuevo operador, consulte Operadores personalizados .

  356  
GRAMÁTICA DE UNA DECLARACIÓN DE OPERADOR
operator-declaration → prefix-operator-declaration postfix-operator-declaration-
infix-operator-declaration
prefix-operator-declaration → prefixoperatoroperator{}
postfix-operator-declaration → postfixoperatoroperator{}
infix-operator-declaration → infixoperatoroperator{infix-operator-attributesopt}
infix-operator-attributes → precedence-clauseoptassociativity-clauseopt
precedence-clause → precedenceprecedence-level
precedence-level → A decimal integer between 0 and 255, inclusive
associativity-clause → associativityassociativity
associativity → left right none

Los modificadores de la Declaración


Modificadores de la Declaración son palabras clave o palabras clave de contexto, que
modifican el comportamiento o el significado de una declaración. Se especifica un
modificador de declaración escribiendo la palabra clave apropiada o palabra clave
contextual entre los atributos de una declaración (si existe) y la palabra clave que
presenta la declaración.
dynamic

Aplicar este modificador a cualquier miembro de una clase que se puede


representar por Objective-C.Cuando se marca una declaración de miembro con
la dybnamic modificador, el acceso a ese miembro siempre se distribuye de
forma dinámica con el tiempo de ejecución de Objective-C. El acceso a ese
miembro no se colocarán en línea o desvirtualizada por el compilador.
Debido a las declaraciones marcadas con el dinamic modificador se envían
usando el tiempo de ejecución de Objective-C, que están implícitamente
marcados con el objc atributo.
final  

Aplicar este modificador a una clase oa una propiedad, método o miembro


subíndice de una clase. Se aplica a una clase para indicar que la clase no puede
tener subclases. Se aplica a una propiedad, método o subíndice de una clase para
indicar que ese miembro de la clase no se puede anular en cualquier subclase.
lazy  

Aplicar este modificador a un almacenado propiedad de variable de una clase o


estructura para indicar que el valor inicial de la propiedad se calcula y almacena
como máximo una vez, cuando la propiedad se accede por primera vez. Para ver
un ejemplo de cómo utilizar el perezoso modificador, consulte Lazy
Propiedades almacenados .
optional  

  357  
Aplicar este modificador a la propiedad, método o miembros subíndice de un
protocolo para indicar que un tipo de conformación no está obligado a poner en
práctica esos miembros.
Puede aplicar el opcional modificador sólo a los protocolos que están
marcados con el objc atributo. Como resultado, sólo los tipos de clase pueden
adoptar y cumplir con un protocolo que contiene requisitos miembro
opcionales. Para obtener más información acerca de cómo utilizar la opción de
modificación y de orientación sobre cómo acceder opcional ejemplo de
protocolo miembros-para, cuando no estás seguro de si un tipo de conformación
implementa ellos-véase Requisitos del Protocolo Facultativo .
required  

Aplicar este modificador a un inicializador designado o conveniencia de una


clase para indicar que cada subclase debe implementar que inicializador. La
implementación de la subclase de que inicializador también debe estar marcado
con el required modificador.
weak  

La weakmodificador se aplica a una variable o una propiedad de variable


almacenada para indicar que la variable o propiedad tiene una referencia débil
para el objeto almacenado como su valor. El tipo de la variable o propiedad debe
ser un tipo de clase opcional. Utilice la weak modificador para evitar los ciclos
de referencia fuertes. Para ver un ejemplo y obtener más información acerca de
la weak modificador, consultelas referencias débiles .

Los niveles de control de acceso


Swift proporciona tres niveles de control de acceso: público, internos y privados. Puede
marcar una declaración con uno de los modificadores de nivel de acceso siguientes para
especificar el nivel de acceso de la declaración. El control de acceso se discute en
detalle en el control de acceso .
public  

Aplicar este modificador a una declaración que indique la declaración se puede


acceder con el código en el mismo módulo como la declaración. Declaraciones
marcados con el público modificador-nivel de acceso también se puede
acceder con el código en un módulo que importa el módulo que contiene la
declaración.
internal  

Aplicar este modificador a una declaración que indique la declaración sólo se


puede acceder con el código en el mismo módulo como la declaración. Por
defecto, la mayoría de las declaraciones están marcados implícitamente con
el internal modificador-nivel de acceso.
private  

Aplicar este modificador a una declaración que indique la declaración sólo se


puede acceder con el código en el mismo archivo de origen como la declaración.

  358  
Cada modificador de nivel de acceso por encima opcionalmente acepta un solo
argumento, que consiste en la palabra clave conjunto entre paréntesis (por
ejemplo, private(set) ). Utilice esta forma de un modificador de nivel de acceso
cuando desea especificar un nivel de acceso para el colocador de una variable o
subíndice que es menor o igual al nivel de acceso de la variable o subíndice en sí, como
se discute en los captadores y definidores .

GRAMÁTICA DE UN MODIFICADOR DE DECLARACIÓN


declaration-modifier → class convenience dynamic final infix lazy mutating-
nonmutating optional override postfix prefix required static unowned-
unowned(safe) unowned(unsafe) weak
declaration-modifier → access-level-modifier
declaration-modifiers → declaration-modifierdeclaration-modifiersopt
access-level-modifier → internal internal(set)
access-level-modifier → private private(set)
access-level-modifier → public public(set)
access-level-modifiers → access-level-modifieraccess-level-modifiersopt
 

Atributos

Los atributos proporcionan más información acerca de una declaración o escribe. Hay
dos tipos de atributos en Swift, los que se aplican a las declaraciones y las que se
aplican a los tipos.
Se especifica un atributo escribiendo el @ símbolo seguido por el nombre del atributo y
cualquier argumento que el atributo acepta:
• @ attribute name
• @ attribute name ( attribute arguments )
Algunos atributos de declaración aceptan argumentos que especifican más información
sobre el atributo y cómo se aplica a una declaración particular. Estos argumentos de
atributos se escriben entre paréntesis, y su formato está definido por el atributo al que
pertenecen.

Atributos Declaración
Se puede aplicar un atributo de declaración a sólo declaraciones. Sin embargo, también
se puede aplicar elNoReturn atributo a una función o método tipo .
disponibilidad  

Aplique este atributo a toda declaración que indique la declaración de ciclo de


vida en relación con determinadas plataformas y versiones de sistema operativo.
La disponibilidad de atributos siempre aparece con una lista de dos o más
argumentos de atributos separados por comas. Estos argumentos comienzan con
uno de los siguientes nombres de
plataforma: iOS, iOSApplicationExtension , OSX ,
o OSXApplicationExtension . También puede utilizar un asterisco ( * )

  359  
para indicar la disponibilidad de la declaración de todos los nombres de
plataformas mencionadas anteriormente.Los argumentos restantes pueden
aparecer en cualquier orden y especificar información adicional acerca del ciclo
de vida de la declaración, incluyendo los hitos importantes.
• El disponible argumento indica que la declaración no está disponible en
la plataforma especificada.
• El introducido argumento indica la primera versión de la plataforma
especificada en el que se introdujo la declaración. Tiene la siguiente forma:
El introducido argumento tiene la siguiente forma:
ointroduced= version number
El número de versión se compone de un número entero positivo o número de
coma flotante decimal.
• El obsoleto argumento indica la primera versión de la plataforma
especificada en el que está desfasada y la declaración. Tiene la siguiente
forma:
o deprecated= version number
El número de versión se compone de un número entero positivo o número de
coma flotante decimal.
• El Obsoleted argumento indica la primera versión de la plataforma
especificada en el que se obsoleta la declaración. Cuando es obsoleto una
declaración, se elimina de la plataforma especificada y ya no se puede
utilizar. El Obsoleted argumento tiene la siguiente forma:
o obsoleted= version number
El número de versión se compone de un número entero positivo o número de
coma flotante decimal.
• El mensaje argumento se utiliza para proporcionar un mensaje de texto
que se muestra por el compilador al emitir una advertencia o de error sobre
el uso de una declaración en desuso o obsoleto.Tiene la siguiente forma:
o message= message
El mensaje consiste en una cadena literal.
• El renamed argumento se utiliza para proporcionar un mensaje de texto
que indica el nuevo nombre para una declaración que se ha cambiado el
nombre. El nuevo nombre se muestra por el compilador cuando se emite un
error acerca de la utilización de una declaración renombrado. Tiene la
siguiente forma:
o renamed= new name
El nuevo nombre se compone de una cadena literal.
Usted puede utilizar el renamed argumento junto con el unavailable
argumento y una declaración alias tipo para indicar a los clientes de su
código que una declaración se ha cambiado de nombre. Por ejemplo, esto es
útil cuando el nombre de una declaración se cambia entre versiones de un
marco o biblioteca.

  360  
o // Primera versión  
o protocol MyProtocol {
o // Definición de protocolo  
o }  
o // Posterior liberación renombra MyProtocol  
o protocol MyRenamedProtocol {
o // Definición de protocolo  
o }
o
o @availability(*, unavailable, renamed="MyRenamedProtocol")
typealias MyProtocol = MyRenamedProtocol
o
Puede aplicar múltiples availability atributos en una sola declaración
para especificar la disponibilidad de la declaración en diferentes plataformas. El
compilador utiliza una availability atributo sólo cuando el atributo
especifica una plataforma que coincida con la plataforma de destino actual.
NoReturn  

Aplique este atributo a una declaración de la función o método para indicar que
el tipo correspondiente de esa función o método, T , se noreturn T . Puede
marcar un tipo de función o método con este atributo para indicar que la función
o el método no devuelve a su invocador.
Puede sustituir una función o método que no esté marcado con
la NoReturn atributo con una función o método que es. Dicho esto, no se
puede anular una función o método que está marcado con el NoReturnatributo
con una función o método que no es. Reglas similares se aplican cuando se
implementa un método de protocolo en un tipo conforme.
NSCopying  

Aplique este atributo a un almacenado propiedad de variable de una clase. Este


atributo hace setter de la propiedad que se sintetiza con una copia del valor
devuelto de la propiedad por el copyWithZone método-en lugar del valor de
la propiedad en sí. El tipo de la propiedad debe cumplir con
la NSCopying protocolo.
El NSCopying atributo se comporta de una manera similar a la de Objective-
C copia atributo de propiedad.
NSManaged  

Aplique este atributo a un almacenado propiedad de variable de una clase que


hereda de NSManagedObjectpara indicar que el almacenamiento y la
aplicación de la propiedad se proporciona dinámicamente de Datos Básicos en
tiempo de ejecución basado en la descripción de la entidad asociada.
objc  

  361  
Aplique este atributo a toda declaración que se puede representar en Objective-
C, por ejemplo, las clases no anidadas, protocolos, propiedades y métodos
(incluyendo getters y setters) de las clases y los protocolos, inicializadores,
deinitializers y subíndices. El objc atributo le dice al compilador que la
declaración está disponible para su uso en el código de Objective-C.
Si aplica el objc atributo a una clase o un protocolo, se aplica implícitamente a
los miembros de esa clase o protocolo. El compilador también se añaden
automáticamente las objc atributo a una clase que hereda de otra clase marcada
con el objc atributo. Protocolos marcados con el objc atributo no pueden
heredar de protocolos que no son.
El objc atributo opcionalmente acepta un solo argumento atributo, que consta
de un identificador. Utilice este atributo cuando desee exponer un nombre
diferente a Objective-C para la entidad la objc atributo se aplica a. Usted puede
utilizar este argumento para nombrar clases, protocolos, métodos getters, setters,
y inicializadores. El ejemplo a continuación expone el comprador para
el habilitado propiedad delExampleClass al código de Objective-C
como isEnabled y no sólo como el nombre de la propiedad en sí.
• @objc
• class ExampleClass {
• var enabled: Bool {
• @objc(isEnabled) get {
• // Return the appropriate value
• }
• }
• }
UIApplicationMain

Aplicar este atributo para una clase para indicar que es el delegado aplicación. El
uso de este atributo es equivalente a llamar la UIApplicationMain función
y pasando el nombre de esta clase como el nombre de la clase delegada.
Si no se utiliza este atributo, suministrar un main.swift archivo con
un principal función que llama a laUIApplicationMain función. Por
ejemplo, si su aplicación utiliza una subclase personalizada
de UIApplicationcomo su clase principio, llame a
la UIApplicationMain función en lugar de utilizar este atributo.

Atributos Declaración usados por Interface Builder


Atributos Interface Builder son atributos de declaración utilizados por Interface Builder
para sincronizar con Xcode. Swift proporciona atributos de la interfaz siguiente
Constructor: IBAction , IBDesignable , IBInspectabley IBOutlet . Estos
atributos son conceptualmente lo mismo que sus homólogos de Objective-C.
Se aplica la IBOutlet y IBInspectable atributos a las declaraciones de
propiedades de una clase. Se aplica laIBAction atributo a declaraciones de métodos
de una clase y la IBDesignable atributo a las declaraciones de clase.

  362  
Tipo Atributos
Puede aplicar los atributos de texto a sólo tipos. Sin embargo, también se puede aplicar
el NoReturn atributo a una función o método declaración .
autoclosure  

Este atributo se utiliza para demorar la evaluación de una expresión envolviendo


automáticamente esa expresión en un cierre sin argumentos. Aplique este
atributo a una función o método de tipo que no toma ningún argumento y que
devuelve el tipo de la expresión. Para ver un ejemplo de cómo utilizar
elautoclosure atributo, vea Tipo de función .
NoReturn  

Aplicar este atributo para el tipo de una función o método para indicar que la
función o el método no devuelve a su llamador. También puede marcar una
función o declaración de método con este atributo para indicar que el tipo
correspondiente de esa función o método, T , es noreturn T .
GRAMÁTICA DE UN ATRIBUTO
attribute → @attribute-nameattribute-argument-clauseopt
attribute-name → identifier
attribute-argument-clause → (balanced-tokensopt)
attributes → attributeattributesopt
balanced-tokens → balanced-tokenbalanced-tokensopt
balanced-token → (balanced-tokensopt)
balanced-token → [balanced-tokensopt]
balanced-token → {balanced-tokensopt}
balanced-token → Any identifier, keyword, literal, or operator
balanced-token → Any punctuation except (, ), [, ], {, or }
 

Patrones

Un patrón representa la estructura de un solo valor o un valor compuesto. Por ejemplo,


la estructura de una tupla (1, 2) es una lista separada por comas de dos
elementos. Dado que los patrones representan la estructura de un valor en lugar de
cualquier valor particular, puede hacer coincidir con una variedad de valores. Por
ejemplo, el patrón (x, y) coincide con la tupla (1, 2) y cualquier otro elemento de
la tupla de dos. Además de hacer coincidir un patrón con un valor, puede extraer parte o
todo de un valor compuesto y unir cada parte a un nombre constante o variable.
En Swift, los patrones se producen en las declaraciones de variables y constantes (en su
lado izquierdo), en for- in las declaraciones y en los switch declaraciones (en
sus etiquetas de caso). Aunque ningún patrón puede ocurrir en las etiquetas de caso de
un switch de declaración, en los otros contextos, sólo los patrones de comodín,
patrones de identificador, y los patrones que contienen esos dos patrones pueden
ocurrir.

  363  
Puede especificar una anotación de tipo para un patrón de comodines, un patrón
identificador, y un patrón de tupla para restringir el modelo que debe coincidir sólo los
valores de un tipo determinado.

GRAMÁTICA DE UN PATRÓN
pattern → wildcard-patterntype-annotationopt
pattern → identifier-patterntype-annotationopt
pattern → value-binding-pattern
pattern → tuple-patterntype-annotationopt
pattern → enum-case-pattern
pattern → type-casting-pattern
pattern → expression-pattern

Comodín Patrón
Un patrón de comodines coincide e ignora cualquier valor y se compone de un guión
bajo ( _ ). Utilice un patrón de comodín cuando no se preocupan por los valores que se
comparan con. Por ejemplo, los código siguiente se repite a través de la gama cerrado 1
... 3 , ignorando el valor actual de la gama en cada iteración del bucle:
• for _ in 1...3 {
• // Do something three times.
• }

GRAMÁTICA DE UN PATRÓN DE COMODINES
wildcard-patrón → _

Patrón Identificador
Un patrón identificador coincide con cualquier valor y se une el valor coincidente con
un nombre de variable o constante. Por ejemplo, en la siguiente declaración
constante, someValue es un patrón identificador que coincide con el valor 42 de
tipo Int :
• let someValue = 42
Cuando el partido tiene éxito, el valor 42 está obligado (asignado) para el nombre de
constante someValue .
Cuando el patrón en el lado izquierdo de una declaración de variable o constante es un
patrón de identificador, el identificador de modelo es implícitamente un sub-patrón de
un patrón de enlace de valor-.

GRAMÁTICA DE UN PATRÓN IDENTIFICADOR


identifier-pattern → identifier

Valor de Unión Patrón


Un patrón de enlace de valor- ata el valor corresponde a los nombres de variables o
constantes. Patrones de enlace de valor-que se unen un valor coincidente con el nombre

  364  
de una constante comenzar con la palabra clave dejar ; los que se unen al nombre de
la variable comienzan con la palabra clave var .
Identificadores de patrones dentro de un patrón de enlace de valor-se unen las nuevas
variables o constantes con nombre a sus valores coincidentes. Por ejemplo, se puede
descomponer los elementos de una tupla y enlazar el valor de cada elemento a un patrón
identificador correspondiente.
• let point = (3, 2)
• switch point {
• // Bind x and y to the elements of point.
• case let (x, y):
• println("The point is at (\(x), \(y)).")
• }
• // imprime "El punto es en (3, 2)."  
En el ejemplo anterior, dejar que distribuye a cada patrón identificador en el patrón
tupla (x, y) . Debido a este comportamiento, el interruptor casos caso dejó
(x, y): y caso (sea x, y mucho y): coincide con los mismos valores.

GRAMÁTICA DE UN PATRÓN DE ENLACE DE VALOR-


value-binding-pattern → varpattern letpattern

Patrón Tuple
Un patrón tupla es una lista separada por comas de cero o más patrones, entre
paréntesis. Patrones Tuple coinciden los valores de tipos de tupla correspondientes.
Puede restringir un patrón tupla para que coincida con ciertos tipos de tipos de tupla
utilizando anotaciones de tipo. Por ejemplo, el patrón de tupla (x, y): (Int,
Int) en la declaración constante let (x, y): (Int, Int) = (1,
2) coincide únicos tipos de tupla en la que ambos elementos son del tipo Int . Para
restringir sólo algunos elementos de un patrón tupla, proporcionar anotaciones de tipo
directamente a los elementos individuales. Por ejemplo, el patrón de tupla en let (x:
Stinrg, y) coincide con cualquier tipo tupla de dos elementos, siempre que el
primer elemento es de tipo String.
Cuando se utiliza un patrón tupla como el patrón en una for- in estado o en una
declaración de variable o constante, que sólo puede contener patrones de comodines, los
patrones de identificadores, u otros patrones de tupla que contienen esos. Por ejemplo,
el siguiente código no es válido porque el elemento 0 en el patrón tupla (x, 0) es un
patrón de expresión:
• let points = [(0, 0), (1, 0), (1, 1), (2, 0), (2, 1)]
• // This code isn't valid.
• for (x, 0) in points {
• /* ... */
• }

  365  
Los paréntesis alrededor de un patrón tupla que contiene un solo elemento no tienen
ningún efecto. El patrón coincide con los valores de tipo de ese solo elemento. Por
ejemplo, los siguientes son equivalentes:
• let a = 2 // a: Int = 2
• let (a) = 2 // a: Int = 2
• let (a): Int = 2 // a: Int = 2

GRAMÁTICA DE UN PATRÓN TUPLA
tuple-pattern → (tuple-pattern-element-listopt)
tuple-pattern-element-list → tuple-pattern-element tuple-pattern-element,tuple-pattern-
element-list
tuple-pattern-element → pattern

Patrón Enumeración Caso


Un patrón de la enumeración caso coincide con un caso de un tipo de enumeración
existente. Patrones de casos de enumeración sólo aparecen en el switch etiquetas
case declaración.
Si el caso de enumeración que estés tratando de coincidir con los valores asociados, el
patrón caso enumeración correspondiente deberá especificar un patrón de tupla que
contiene un elemento por cada valor asociado. Para ver un ejemplo que utiliza
un switch de declaración para que coincida con los casos de enumeración que
contienen valores asociados, ver valores asociados .

GRAMÁTICA DE UN PATRÓN DE CASO ENUMERACIÓN


enum-case-pattern → type-identifieropt.enum-case-nametuple-patternopt

Patrones Tipo-casting
Hay dos patrones de tipo de fundición a presión, el es patrón y el como patrón. Ambos
patrones de tipo de fundición a presión sólo aparecen en el interruptor etiquetas
case declaración. El es y como los patrones tienen la siguiente forma:
• is type
• pattern as type
El es el patrón coincide con un valor si el tipo de valor que en tiempo de ejecución es
el mismo que el tipo especificado en el lado derecho de la que is patrón o una
subclase de ese tipo. El is el patrón se comporta como el is operador en que ambos
realizan una conversión de tipos, pero descartan el tipo devuelto.
El as patrón coincide con un valor si el tipo de ese valor en tiempo de ejecución es el
mismo que el tipo especificado en el lado derecho de la as patrón o una subclase de
ese tipo. Si el partido tiene éxito, el tipo del valor coincidente se convierte
al modelo especificado en el lado izquierdo de la as patrón.
Para ver un ejemplo que utiliza un switch de declaración para que coincida con los
valores es y comopatrones, vea la conversión de tipos para Todas y AnyObject .

  366  
GRAMÁTICA DE UN PATRÓN DE CONVERSIÓN DE TIPOS
(CASTING PATTERN)
type-casting-pattern → is-pattern as-pattern
is-pattern → istype
as-pattern → patternastype

Patrón de Expresión
Un patrón de expresión representa el valor de una expresión. Los patrones de expresión
sólo aparecen en el switch etiquetas case declaración.
La expresión representada por el patrón de expresión se compara con el valor de una
expresión de entrada utilizando la biblioteca estándar Swift ~ = operador. Los partidos
tiene éxito si el ~ = operador devuelve true .Por defecto, el ~ = operador compara
dos valores del mismo tipo con el == operador. También puede coincidir con un valor
entero con un rango de enteros en un rango de objetos, como muestra el siguiente
ejemplo:
• let point = (1, 2)
• switch point {
• case (0, 0):
• println("(0, 0) is at the origin.")
• case (-2...2, -2...2):
• println("(\(point.0), \(point.1)) is near the origin.")
• default:
• println("The point is at (\(point.0), \(point.1)).")
• }
• // imprime "(1, 2) se encuentra cerca del origen."  
Usted puede sobrecargar el ~ = operador para proporcionar un comportamiento a juego
expresión personalizada. Por ejemplo, se puede reescribir el ejemplo anterior para
comparar el punto de expresión con representaciones de serie de puntos.
• // Sobrecargue el ~ = operador para que coincida con una
cadena con un entero  
• func ~=(pattern: String, value: Int) -> Bool {
• return pattern == "\(value)"
• }
• switch point {
• case ("0", "0"):
• println("(0, 0) is at the origin.")
• default:
• println("The point is at (\(point.0), \(point.1)).")
• }
• // imprime "El punto está en (1, 2)."  

  367  
GRAMÁTICA DE UN PATRÓN DE EXPRESIÓN
expression-pattern → expression
 
Parámetros genéricos y argumentos

En este capítulo se describen los parámetros y argumentos de tipos genéricos, las


funciones y los inicializadores. Cuando se declara un tipo genérico, función o
inicializador, se especifican los parámetros de tipo genérico que el tipo, función o
inicializador pueden trabajar. Estos parámetros de tipo actúan como marcadores de
posición que se reemplazan por los argumentos de tipo concretas reales cuando se crea
una instancia de un tipo genérico o de una función genérica o inicializador se llama.
Para una visión general de los genéricos en Swift, vea Genéricos .

Cláusula Parámetro genérico


Una cláusula de parámetro genérico especifica los parámetros de tipo de un tipo o una
función genérica, junto con las limitaciones y requisitos asociados en esos
parámetros. Una cláusula parámetro genérico está entre corchetes angulares (<>) y tiene
una de las siguientes formas:
• < generic parameter list >
• < generic parameter list where requirements >
La lista de parámetros genéricos es una lista separada por comas de parámetros
genéricos, cada uno de los cuales tiene la siguiente forma:
• type parameter : constraint
Un parámetro genérico consta de un parámetro de tipo seguido por una
opcional restricción . Un parámetro de tipo es simplemente el nombre de un tipo de
marcador de posición (por ejemplo, T , U , V , KeyType ,ValueType , y así
sucesivamente). Usted tiene acceso a los parámetros de tipo (y cualquiera de sus tipos
asociados) en el resto de la clase, función, o declaración de inicialización, incluso en la
firma de la función o inicializador.
La restricción se especifica que un parámetro de tipo hereda de una clase específica o se
ajusta a una composición de protocolo o protocolo. Por ejemplo, en la función genérica
a continuación, el parámetro genérico T: Comparable indica que cualquier
argumento de tipo sustituido por el parámetro de tipo T debe ser conforme a
la Comparable protocolo.
• func simpleMin<T: Comparable>(x: T, y: T) -> T {
• if x < y {
• return y
• }
• return x
• }
Debido a que Int y double , por ejemplo, ambos se ajustan a
la Comparable protocolo, esta función acepta argumentos de cualquier tipo. En

  368  
contraste con los tipos genéricos, no se especifica una cláusula argumento genérico
cuando se utiliza una función genérica o inicializador. Los argumentos de tipo en
cambio se infiere a partir del tipo de los argumentos que se pasan a la función o
inicializador.
• simpleMin(17, 42) // T is inferred to be Int
• simpleMin(3.14159, 2.71828) // T is inferred to be Double
 
Where Cláusulas
Puede especificar requisitos adicionales sobre los parámetros de tipo y sus tipos
asociados mediante la inclusión de una where la cláusula después de la lista de
parámetros genéricos . A where cláusula consiste en la palabra clave en where,
seguido por una lista separada por comas de uno o varios requisitos .
Los requisitos en una where cláusula especifica que un parámetro de tipo hereda de
una clase o se ajusta a una composición de protocolo o protocolo. Aunque el where
cláusula prevé azúcar sintáctico para expresar restricciones simples sobre los parámetros
de tipo (por ejemplo, T: Comparable es equivalente a T where T:
Comparable y así sucesivamente), se puede utilizar para proporcionar restricciones
más complejas sobre los parámetros de tipo y sus tipos asociados . Por ejemplo, puede
expresar las limitaciones que un tipo genéricoT hereda de una clase C y se ajusta a un
protocolo P como <T donde T: C, T: P> .
Como se mencionó anteriormente, puede restringir los tipos asociados de parámetros de
tipo para cumplir con los protocolos. Por ejemplo, la cláusula de parámetro
genérico <T: Generador where T.Element: equatable> especifica
que T se ajusta al Generador de protocolo y el tipo asociado de T , T.Element ,
se ajusta a la equatable protocolo ( T tiene el tipo
asociado Element porque Generador declara Element y T se ajusta
aGenerador ).
También puede especificar el requisito de que dos tipos sean idénticos, utilizando
el == operador. Por ejemplo, la cláusula de parámetro genérico <T: Generador,
U: Generador donde T.Element == U.Element>expresa las restricciones
que T y U se ajustan al Generador de protocolo y que sus tipos asociados deben ser
idénticos.
Cualquier argumento de tipo sustituido por un parámetro de tipo debe cumplir con todas
las restricciones y requisitos que debe cumplir el parámetro de tipo.
Usted puede sobrecargar una función genérica o inicializador proporcionando diferentes
restricciones, requisitos, o ambos en los parámetros de tipo en la cláusula parámetro
genérico. Cuando se llama a una función genérica sobrecargado o inicializador, el
compilador utiliza estas limitaciones para resolver la función o el inicializador para
invocar sobrecargado.

GRAMÁTICA DE UNA CLÁUSULA DE PARÁMETRO GENÉRICO


generic-parameter-clause → <generic-parameter-listrequirement-clauseopt>
generic-parameter-list → generic-parameter generic-parameter,generic-parameter-list
generic-parameter → type-name
generic-parameter → type-name:type-identifier
  369  
generic-parameter → type-name:protocol-composition-type
requirement-clause → whererequirement-list
requirement-list → requirement requirement,requirement-list
requirement → conformance-requirement same-type-requirement
conformance-requirement → type-identifier:type-identifier
conformance-requirement → type-identifier:protocol-composition-type
same-type-requirement → type-identifier==type-identifier

Cláusula Argumento Genérico


Una cláusula argumento genérico especifica los argumentos de tipo de un tipo
genérico. Una cláusula argumento genérico está entre corchetes angulares (<>) y tiene
la siguiente forma:
• < generic argument list >
La lista de argumentos genéricos es una lista separada por comas de los argumentos de
tipo. Un argumento de tipo es el nombre de un tipo concreto real que sustituye a un
parámetro de tipo correspondiente en la cláusula genérica de un parámetro de tipo
genérico. El resultado es una versión especializada de este tipo genérico. Como
ejemplo, la biblioteca estándar Swift define un tipo de diccionario genérico como:
• struct Dictionary<KeyType: Hashable, ValueType>: CollectionType,
DictionaryLiteralConvertible {
• /* ... */
• }
La versión especializada de la genérica Diccionario tipo, Diccionario
<String, int> se forma mediante la sustitución de los parámetros
genéricos KeyType: Hashable y ValueType con los argumentos de tipo
concreto de Cuerda y Int . Cada argumento de tipo debe satisfacer todas las
restricciones del parámetro genérico al que sustituye, incluidos cualesquiera requisitos
adicionales especificados en donde cláusula. En el ejemplo anterior,
el KeyType parámetro de tipo está obligado a cumplir con la Hashable protocolo y,
por tanto, de cuerdastambién debe ajustarse a la Hashable protocolo.
También puede sustituir un parámetro de tipo con un argumento de tipo que es en sí una
versión especializada de un tipo genérico (siempre que cumplan las restricciones y los
requisitos apropiados). Por ejemplo, puede reemplazar el parámetro de tipo T en
el array <T> con una versión especializada de una matriz, array <Int> , para
formar una matriz cuyos elementos son a su vez matrices de enteros.

• let arrayOfArrays: Array<Array<Int>> = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]


Como se menciona en la cláusula genérica de parámetros , no utiliza una cláusula
argumento genérico para especificar los argumentos de tipo de una función genérica o
inicializador.

  370  
GRAMÁTICA DE UNA CLÁUSULA ARGUMENTO GENÉRICO
generic-argument-clause → <generic-argument-list>
generic-argument-list → generic-argument generic-argument,generic-argument-list
generic-argument → type
 

Resumen de la gramática
En esta página
Declaraciones
GRAMMAR OF A STATEMENT
statement → expression;opt
statement → declaration;opt
statement → loop-statement;opt
statement → branch-statement;opt
statement → labeled-statement;opt
statement → control-transfer-statement;opt
statements → statementstatementsopt
GRAMMAR OF A LOOP STATEMENT
loop-statement → for-statement
loop-statement → for-in-statement
loop-statement → while-statement
loop-statement → do-while-statement
GRAMMAR OF A FOR STATEMENT
for-statement → forfor-initopt;expressionopt;expressionoptcode-block
for-statement → for(for-initopt;expressionopt;expressionopt)code-block
for-init → variable-declaration expression-list
GRAMMAR OF A FOR-IN STATEMENT
for-in-statement → forpatterninexpressioncode-block
GRAMMAR OF A WHILE STATEMENT
while-statement → whilewhile-conditioncode-block
while-condition → expression declaration
GRAMMAR OF A DO-WHILE STATEMENT
do-while-statement → docode-blockwhilewhile-condition
GRAMMAR OF A BRANCH STATEMENT
branch-statement → if-statement
branch-statement → switch-statement
GRAMMAR OF AN IF STATEMENT
if-statement → ifif-conditioncode-blockelse-clauseopt
if-condition → expression declaration
else-clause → elsecode-block elseif-statement
GRAMMAR OF A SWITCH STATEMENT

  371  
switch-statement → switchexpression{switch-casesopt}
switch-cases → switch-caseswitch-casesopt
switch-case → case-labelstatements default-labelstatements
switch-case → case-label; default-label;
case-label → casecase-item-list:
case-item-list → patternguard-clauseopt patternguard-clauseopt,case-item-list
default-label → default:
guard-clause → whereguard-expression
guard-expression → expression
GRAMMAR OF A LABELED STATEMENT
labeled-statement → statement-labelloop-statement statement-labelswitch-statement
statement-label → label-name:
label-name → identifier
GRAMMAR OF A CONTROL TRANSFER STATEMENT
control-transfer-statement → break-statement
control-transfer-statement → continue-statement
control-transfer-statement → fallthrough-statement
control-transfer-statement → return-statement
GRAMMAR OF A BREAK STATEMENT
break-statement → breaklabel-nameopt
GRAMMAR OF A CONTINUE STATEMENT
continue-statement → continuelabel-nameopt
GRAMMAR OF A FALLTHROUGH STATEMENT
fallthrough-statement → fallthrough
GRAMMAR OF A RETURN STATEMENT
return-statement → returnexpressionopt
Generic Parameters and Arguments

GRAMMAR OF A GENERIC PARAMETER CLAUSE


generic-parameter-clause → <generic-parameter-listrequirement-clauseopt>
generic-parameter-list → generic-parameter generic-parameter,generic-parameter-list
generic-parameter → type-name
generic-parameter → type-name:type-identifier
generic-parameter → type-name:protocol-composition-type
requirement-clause → whererequirement-list
requirement-list → requirement requirement,requirement-list
requirement → conformance-requirement same-type-requirement
conformance-requirement → type-identifier:type-identifier
conformance-requirement → type-identifier:protocol-composition-type
same-type-requirement → type-identifier==type-identifier
GRAMMAR OF A GENERIC ARGUMENT CLAUSE
generic-argument-clause → <generic-argument-list>
generic-argument-list → generic-argument generic-argument,generic-argument-list
  372  
generic-argument → type
Declarations

GRAMMAR OF A DECLARATION
declaration → import-declaration
declaration → constant-declaration
declaration → variable-declaration
declaration → typealias-declaration
declaration → function-declaration
declaration → enum-declaration
declaration → struct-declaration
declaration → class-declaration
declaration → protocol-declaration
declaration → initializer-declaration
declaration → deinitializer-declaration
declaration → extension-declaration
declaration → subscript-declaration
declaration → operator-declaration
declarations → declarationdeclarationsopt
GRAMMAR OF A TOP-LEVEL DECLARATION
top-level-declaration → statementsopt
GRAMMAR OF A CODE BLOCK
code-block → {statementsopt}
GRAMMAR OF AN IMPORT DECLARATION
import-declaration → attributesoptimportimport-kindoptimport-path
import-kind → typealias struct class enum protocol var func
import-path → import-path-identifier import-path-identifier.import-path
import-path-identifier → identifier operator
GRAMMAR OF A CONSTANT DECLARATION
constant-declaration → attributesoptdeclaration-modifiersoptletpattern-initializer-list
pattern-initializer-list → pattern-initializer pattern-initializer,pattern-initializer-list
pattern-initializer → patterninitializeropt
initializer → =expression
GRAMMAR OF A VARIABLE DECLARATION
variable-declaration → variable-declaration-headpattern-initializer-list
variable-declaration → variable-declaration-headvariable-nametype-annotationcode-
block
variable-declaration → variable-declaration-headvariable-nametype-annotationgetter-
setter-block
variable-declaration → variable-declaration-headvariable-nametype-annotationgetter-
setter-keyword-block
variable-declaration → variable-declaration-headvariable-nametype-annotation-
initializeroptwillSet-didSet-block

  373  
variable-declaration-head → attributesoptdeclaration-modifiersoptvar
variable-name → identifier
getter-setter-block → {getter-clausesetter-clauseopt}
getter-setter-block → {setter-clausegetter-clause}
getter-clause → attributesoptgetcode-block
setter-clause → attributesoptsetsetter-nameoptcode-block
setter-name → (identifier)
getter-setter-keyword-block → {getter-keyword-clausesetter-keyword-clauseopt}
getter-setter-keyword-block → {setter-keyword-clausegetter-keyword-clause}
getter-keyword-clause → attributesoptget
setter-keyword-clause → attributesoptset
willSet-didSet-block → {willSet-clausedidSet-clauseopt}
willSet-didSet-block → {didSet-clausewillSet-clause}
willSet-clause → attributesoptwillSetsetter-nameoptcode-block
didSet-clause → attributesoptdidSetsetter-nameoptcode-block
GRAMMAR OF A TYPE ALIAS DECLARATION
typealias-declaration → typealias-headtypealias-assignment
typealias-head → attributesoptaccess-level-modifieropttypealiastypealias-name
typealias-name → identifier
typealias-assignment → =type
GRAMMAR OF A FUNCTION DECLARATION
function-declaration → function-headfunction-namegeneric-parameter-clauseopt-
function-signaturefunction-body
function-head → attributesoptdeclaration-modifiersoptfunc
function-name → identifier operator
function-signature → parameter-clausesfunction-resultopt
function-result → ->attributesopttype
function-body → code-block
parameter-clauses → parameter-clauseparameter-clausesopt
parameter-clause → () (parameter-list...opt)
parameter-list → parameter parameter,parameter-list
parameter → inoutoptletopt#optexternal-parameter-nameoptlocal-parameter-nametype-
annotationdefault-argument-clauseopt
parameter → inoutoptvar#optexternal-parameter-nameoptlocal-parameter-nametype-
annotationdefault-argument-clauseopt
parameter → attributesopttype
external-parameter-name → identifier _
local-parameter-name → identifier _
default-argument-clause → =expression
GRAMMAR OF AN ENUMERATION DECLARATION
enum-declaration → attributesoptaccess-level-modifieroptunion-style-enum
enum-declaration → attributesoptaccess-level-modifieroptraw-value-style-enum
union-style-enum → enumenum-namegeneric-parameter-clauseopttype-inheritance-
clauseopt{union-style-enum-membersopt}

  374  
union-style-enum-members → union-style-enum-memberunion-style-enum-membersopt
union-style-enum-member → declaration union-style-enum-case-clause
union-style-enum-case-clause → attributesoptcaseunion-style-enum-case-list
union-style-enum-case-list → union-style-enum-case union-style-enum-case,union-
style-enum-case-list
union-style-enum-case → enum-case-nametuple-typeopt
enum-name → identifier
enum-case-name → identifier
raw-value-style-enum → enumenum-namegeneric-parameter-clauseopttype-inheritance-
clause{raw-value-style-enum-members}
raw-value-style-enum-members → raw-value-style-enum-memberraw-value-style-
enum-membersopt
raw-value-style-enum-member → declaration raw-value-style-enum-case-clause
raw-value-style-enum-case-clause → attributesoptcaseraw-value-style-enum-case-list
raw-value-style-enum-case-list → raw-value-style-enum-case raw-value-style-enum-
case,raw-value-style-enum-case-list
raw-value-style-enum-case → enum-case-nameraw-value-assignmentopt
raw-value-assignment → =literal
GRAMMAR OF A STRUCTURE DECLARATION
struct-declaration → attributesoptaccess-level-modifieroptstructstruct-namegeneric-
parameter-clauseopttype-inheritance-clauseoptstruct-body
struct-name → identifier
struct-body → {declarationsopt}
GRAMMAR OF A CLASS DECLARATION
class-declaration → attributesoptaccess-level-modifieroptclassclass-namegeneric-
parameter-clauseopttype-inheritance-clauseoptclass-body
class-name → identifier
class-body → {declarationsopt}
GRAMMAR OF A PROTOCOL DECLARATION
protocol-declaration → attributesoptaccess-level-modifieroptprotocolprotocol-nametype-
inheritance-clauseoptprotocol-body
protocol-name → identifier
protocol-body → {protocol-member-declarationsopt}
protocol-member-declaration → protocol-property-declaration
protocol-member-declaration → protocol-method-declaration
protocol-member-declaration → protocol-initializer-declaration
protocol-member-declaration → protocol-subscript-declaration
protocol-member-declaration → protocol-associated-type-declaration
protocol-member-declarations → protocol-member-declarationprotocol-member-
declarationsopt
GRAMMAR OF A PROTOCOL PROPERTY DECLARATION
protocol-property-declaration → variable-declaration-headvariable-nametype-
annotationgetter-setter-keyword-block
GRAMMAR OF A PROTOCOL METHOD DECLARATION

  375  
protocol-method-declaration → function-headfunction-namegeneric-parameter-clause-
optfunction-signature
GRAMMAR OF A PROTOCOL INITIALIZER DECLARATION
protocol-initializer-declaration → initializer-headgeneric-parameter-clauseopt-
parameter-clause
GRAMMAR OF A PROTOCOL SUBSCRIPT DECLARATION
protocol-subscript-declaration → subscript-headsubscript-resultgetter-setter-keyword-
block
GRAMMAR OF A PROTOCOL ASSOCIATED TYPE
DECLARATION
protocol-associated-type-declaration → typealias-headtype-inheritance-clauseopt-
typealias-assignmentopt
GRAMMAR OF AN INITIALIZER DECLARATION
initializer-declaration → initializer-headgeneric-parameter-clauseoptparameter-clause-
initializer-body
initializer-head → attributesoptdeclaration-modifiersoptinit
initializer-body → code-block
GRAMMAR OF A DEINITIALIZER DECLARATION
deinitializer-declaration → attributesoptdeinitcode-block
GRAMMAR OF AN EXTENSION DECLARATION
extension-declaration → access-level-modifieroptextensiontype-identifiertype-
inheritance-clauseoptextension-body
extension-body → {declarationsopt}
GRAMMAR OF A SUBSCRIPT DECLARATION
subscript-declaration → subscript-headsubscript-resultcode-block
subscript-declaration → subscript-headsubscript-resultgetter-setter-block
subscript-declaration → subscript-headsubscript-resultgetter-setter-keyword-block
subscript-head → attributesoptdeclaration-modifiersoptsubscriptparameter-clause
subscript-result → ->attributesopttype
GRAMMAR OF AN OPERATOR DECLARATION
operator-declaration → prefix-operator-declaration postfix-operator-declaration-
infix-operator-declaration
prefix-operator-declaration → prefixoperatoroperator{}
postfix-operator-declaration → postfixoperatoroperator{}
infix-operator-declaration → infixoperatoroperator{infix-operator-attributesopt}
infix-operator-attributes → precedence-clauseoptassociativity-clauseopt
precedence-clause → precedenceprecedence-level
precedence-level → A decimal integer between 0 and 255, inclusive
associativity-clause → associativityassociativity
associativity → left right none
GRAMMAR OF A DECLARATION MODIFIER

  376  
declaration-modifier → class convenience dynamic final infix lazy mutating-
nonmutating optional override postfix prefix required static unowned-
unowned(safe) unowned(unsafe) weak
declaration-modifier → access-level-modifier
declaration-modifiers → declaration-modifierdeclaration-modifiersopt
access-level-modifier → internal internal(set)
access-level-modifier → private private(set)
access-level-modifier → public public(set)
access-level-modifiers → access-level-modifieraccess-level-modifiersopt
Patterns

GRAMMAR OF A PATTERN
pattern → wildcard-patterntype-annotationopt
pattern → identifier-patterntype-annotationopt
pattern → value-binding-pattern
pattern → tuple-patterntype-annotationopt
pattern → enum-case-pattern
pattern → type-casting-pattern
pattern → expression-pattern
GRAMMAR OF A WILDCARD PATTERN
wildcard-pattern → _
GRAMMAR OF AN IDENTIFIER PATTERN
identifier-pattern → identifier
GRAMMAR OF A VALUE-BINDING PATTERN
value-binding-pattern → varpattern letpattern
GRAMMAR OF A TUPLE PATTERN
tuple-pattern → (tuple-pattern-element-listopt)
tuple-pattern-element-list → tuple-pattern-element tuple-pattern-element,tuple-pattern-
element-list
tuple-pattern-element → pattern
GRAMMAR OF AN ENUMERATION CASE PATTERN
enum-case-pattern → type-identifieropt.enum-case-nametuple-patternopt
GRAMMAR OF A TYPE CASTING PATTERN
type-casting-pattern → is-pattern as-pattern
is-pattern → istype
as-pattern → patternastype
GRAMMAR OF AN EXPRESSION PATTERN
expression-pattern → expression
Attributes

GRAMMAR OF AN ATTRIBUTE
attribute → @attribute-nameattribute-argument-clauseopt

  377  
attribute-name → identifier
attribute-argument-clause → (balanced-tokensopt)
attributes → attributeattributesopt
balanced-tokens → balanced-tokenbalanced-tokensopt
balanced-token → (balanced-tokensopt)
balanced-token → [balanced-tokensopt]
balanced-token → {balanced-tokensopt}
balanced-token → Any identifier, keyword, literal, or operator
balanced-token → Any punctuation except (, ), [, ], {, or }
Expressions

GRAMMAR OF AN EXPRESSION
expression → prefix-expressionbinary-expressionsopt
expression-list → expression expression,expression-list
GRAMMAR OF A PREFIX EXPRESSION
prefix-expression → prefix-operatoroptpostfix-expression
prefix-expression → in-out-expression
in-out-expression → &identifier
GRAMMAR OF A BINARY EXPRESSION
binary-expression → binary-operatorprefix-expression
binary-expression → assignment-operatorprefix-expression
binary-expression → conditional-operatorprefix-expression
binary-expression → type-casting-operator
binary-expressions → binary-expressionbinary-expressionsopt
GRAMMAR OF AN ASSIGNMENT OPERATOR
assignment-operator → =
GRAMMAR OF A CONDITIONAL OPERATOR
conditional-operator → ?expression:
GRAMMAR OF A TYPE-CASTING OPERATOR
type-casting-operator → istype
type-casting-operator → astype
type-casting-operator → as?type
GRAMMAR OF A PRIMARY EXPRESSION
primary-expression → identifiergeneric-argument-clauseopt
primary-expression → literal-expression
primary-expression → self-expression
primary-expression → superclass-expression
primary-expression → closure-expression
primary-expression → parenthesized-expression
primary-expression → implicit-member-expression
primary-expression → wildcard-expression
GRAMMAR OF A LITERAL EXPRESSION
literal-expression → literal
  378  
literal-expression → array-literal dictionary-literal
literal-expression → __FILE__ __LINE__ __COLUMN__ __FUNCTION__
array-literal → [array-literal-itemsopt]
array-literal-items → array-literal-item,opt array-literal-item,array-literal-items
array-literal-item → expression
dictionary-literal → [dictionary-literal-items] [:]
dictionary-literal-items → dictionary-literal-item,opt dictionary-literal-item,dictionary-
literal-items
dictionary-literal-item → expression:expression
GRAMMAR OF A SELF EXPRESSION
self-expression → self
self-expression → self.identifier
self-expression → self[expression]
self-expression → self.init
GRAMMAR OF A SUPERCLASS EXPRESSION
superclass-expression → superclass-method-expression superclass-subscript-
expression superclass-initializer-expression
superclass-method-expression → super.identifier
superclass-subscript-expression → super[expression]
superclass-initializer-expression → super.init
GRAMMAR OF A CLOSURE EXPRESSION
closure-expression → {closure-signatureoptstatements}
closure-signature → parameter-clausefunction-resultoptin
closure-signature → identifier-listfunction-resultoptin
closure-signature → capture-listparameter-clausefunction-resultoptin
closure-signature → capture-listidentifier-listfunction-resultoptin
closure-signature → capture-listin
capture-list → [capture-specifierexpression]
capture-specifier → weak unowned unowned(safe) unowned(unsafe)
GRAMMAR OF A IMPLICIT MEMBER EXPRESSION
implicit-member-expression → .identifier
GRAMMAR OF A PARENTHESIZED EXPRESSION
parenthesized-expression → (expression-element-listopt)
expression-element-list → expression-element expression-element,expression-element-
list
expression-element → expression identifier:expression
GRAMMAR OF A WILDCARD EXPRESSION
wildcard-expression → _
GRAMMAR OF A POSTFIX EXPRESSION
postfix-expression → primary-expression
postfix-expression → postfix-expressionpostfix-operator
postfix-expression → function-call-expression
postfix-expression → initializer-expression

  379  
postfix-expression → explicit-member-expression
postfix-expression → postfix-self-expression
postfix-expression → dynamic-type-expression
postfix-expression → subscript-expression
postfix-expression → forced-value-expression
postfix-expression → optional-chaining-expression
GRAMMAR OF A FUNCTION CALL EXPRESSION
function-call-expression → postfix-expressionparenthesized-expression
function-call-expression → postfix-expressionparenthesized-expressionopttrailing-
closure
trailing-closure → closure-expression
GRAMMAR OF AN INITIALIZER EXPRESSION
initializer-expression → postfix-expression.init
GRAMMAR OF AN EXPLICIT MEMBER EXPRESSION
explicit-member-expression → postfix-expression.decimal-digits
explicit-member-expression → postfix-expression.identifiergeneric-argument-clauseopt
GRAMMAR OF A SELF EXPRESSION
postfix-self-expression → postfix-expression.self
GRAMMAR OF A DYNAMIC TYPE EXPRESSION
dynamic-type-expression → postfix-expression.dynamicType
GRAMMAR OF A SUBSCRIPT EXPRESSION
subscript-expression → postfix-expression[expression-list]
GRAMMAR OF A FORCED-VALUE EXPRESSION
forced-value-expression → postfix-expression!
GRAMMAR OF AN OPTIONAL-CHAINING EXPRESSION
optional-chaining-expression → postfix-expression?
Lexical Structure

GRAMMAR OF AN IDENTIFIER
identifier → identifier-headidentifier-charactersopt
identifier → `identifier-headidentifier-charactersopt`
identifier → implicit-parameter-name
identifier-list → identifier identifier,identifier-list
identifier-head → Upper- or lowercase letter A through Z
identifier-head → _
identifier-head → U+00A8, U+00AA, U+00AD, U+00AF, U+00B2–U+00B5, or
U+00B7–U+00BA
identifier-head → U+00BC–U+00BE, U+00C0–U+00D6, U+00D8–U+00F6, or
U+00F8–U+00FF
identifier-head → U+0100–U+02FF, U+0370–U+167F, U+1681–U+180D, or
U+180F–U+1DBF
identifier-head → U+1E00–U+1FFF

  380  
identifier-head → U+200B–U+200D, U+202A–U+202E, U+203F–U+2040, U+2054,
or U+2060–U+206F
identifier-head → U+2070–U+20CF, U+2100–U+218F, U+2460–U+24FF, or U+2776–
U+2793
identifier-head → U+2C00–U+2DFF or U+2E80–U+2FFF
identifier-head → U+3004–U+3007, U+3021–U+302F, U+3031–U+303F, or U+3040–
U+D7FF
identifier-head → U+F900–U+FD3D, U+FD40–U+FDCF, U+FDF0–U+FE1F, or
U+FE30–U+FE44
identifier-head → U+FE47–U+FFFD
identifier-head → U+10000–U+1FFFD, U+20000–U+2FFFD, U+30000–U+3FFFD, or
U+40000–U+4FFFD
identifier-head → U+50000–U+5FFFD, U+60000–U+6FFFD, U+70000–U+7FFFD, or
U+80000–U+8FFFD
identifier-head → U+90000–U+9FFFD, U+A0000–U+AFFFD, U+B0000–U+BFFFD,
or U+C0000–U+CFFFD
identifier-head → U+D0000–U+DFFFD or U+E0000–U+EFFFD
identifier-character → Digit 0 through 9
identifier-character → U+0300–U+036F, U+1DC0–U+1DFF, U+20D0–U+20FF, or
U+FE20–U+FE2F
identifier-character → identifier-head
identifier-characters → identifier-characteridentifier-charactersopt
implicit-parameter-name → $decimal-digits
GRAMMAR OF A LITERAL
literal → integer-literal floating-point-literal string-literal
literal → true false nil
GRAMMAR OF AN INTEGER LITERAL
integer-literal → binary-literal
integer-literal → octal-literal
integer-literal → decimal-literal
integer-literal → hexadecimal-literal
binary-literal → 0bbinary-digitbinary-literal-charactersopt
binary-digit → Digit 0 or 1
binary-literal-character → binary-digit _
binary-literal-characters → binary-literal-characterbinary-literal-charactersopt
octal-literal → 0ooctal-digitoctal-literal-charactersopt
octal-digit → Digit 0 through 7
octal-literal-character → octal-digit _
octal-literal-characters → octal-literal-characteroctal-literal-charactersopt
decimal-literal → decimal-digitdecimal-literal-charactersopt
decimal-digit → Digit 0 through 9
decimal-digits → decimal-digitdecimal-digitsopt
decimal-literal-character → decimal-digit _
decimal-literal-characters → decimal-literal-characterdecimal-literal-charactersopt
hexadecimal-literal → 0xhexadecimal-digithexadecimal-literal-charactersopt

  381  
hexadecimal-digit → Digit 0 through 9, a through f, or A through F
hexadecimal-literal-character → hexadecimal-digit _
hexadecimal-literal-characters → hexadecimal-literal-characterhexadecimal-literal-
charactersopt
GRAMMAR OF A FLOATING-POINT LITERAL
floating-point-literal → decimal-literaldecimal-fractionoptdecimal-exponentopt
floating-point-literal → hexadecimal-literalhexadecimal-fractionopthexadecimal-
exponent
decimal-fraction → .decimal-literal
decimal-exponent → floating-point-esignoptdecimal-literal
hexadecimal-fraction → .hexadecimal-digithexadecimal-literal-charactersopt
hexadecimal-exponent → floating-point-psignoptdecimal-literal
floating-point-e → e E
floating-point-p → p P
sign → + -
GRAMMAR OF A STRING LITERAL
string-literal → "quoted-textopt"
quoted-text → quoted-text-itemquoted-textopt
quoted-text-item → escaped-character
quoted-text-item → \(expression)
quoted-text-item → Any Unicode extended grapheme cluster except ", \, U+000A, or
U+000D
escaped-character → \0 \\ \t \n \r \" \'
escaped-character → \u{unicode-scalar-digits}
unicode-scalar-digits → Between one and eight hexadecimal digits
GRAMMAR OF OPERATORS
operator → operator-headoperator-charactersopt
operator → dot-operator-headdot-operator-charactersopt
operator-head → / = - + ! * % < > & | ^ ~
operator-head → U+00A1–U+00A7
operator-head → U+00A9 or U+00AB
operator-head → U+00AC or U+00AE
operator-head → U+00B0–U+00B1, U+00B6, U+00BB, U+00BF, U+00D7, or
U+00F7
operator-head → U+2016–U+2017 or U+2020–U+2027
operator-head → U+2030–U+203E
operator-head → U+2041–U+2053
operator-head → U+2055–U+205E
operator-head → U+2190–U+23FF
operator-head → U+2500–U+2775
operator-head → U+2794–U+2BFF
operator-head → U+2E00–U+2E7F
operator-head → U+3001–U+3003
operator-head → U+3008–U+3030

  382  
operator-character → operator-head
operator-character → U+0300–U+036F
operator-character → U+1DC0–U+1DFF
operator-character → U+20D0–U+20FF
operator-character → U+FE00–U+FE0F
operator-character → U+FE20–U+FE2F
operator-character → U+E0100–U+E01EF
operator-characters → operator-characteroperator-charactersopt
dot-operator-head → ..
dot-operator-character → . operator-character
dot-operator-characters → dot-operator-characterdot-operator-charactersopt
binary-operator → operator
prefix-operator → operator
postfix-operator → operator
Types

GRAMMAR OF A TYPE
type → array-type dictionary-type function-type type-identifier tuple-type optional-
type implicitly-unwrapped-optional-type protocol-composition-type metatype-type
GRAMMAR OF A TYPE ANNOTATION
type-annotation → :attributesopttype
GRAMMAR OF A TYPE IDENTIFIER
type-identifier → type-namegeneric-argument-clauseopt type-namegeneric-argument-
clauseopt.type-identifier
type-name → identifier
GRAMMAR OF A TUPLE TYPE
tuple-type → (tuple-type-bodyopt)
tuple-type-body → tuple-type-element-list...opt
tuple-type-element-list → tuple-type-element tuple-type-element,tuple-type-element-list
tuple-type-element → attributesoptinoutopttype inoutoptelement-nametype-annotation
element-name → identifier
GRAMMAR OF A FUNCTION TYPE
function-type → type->type
GRAMMAR OF AN ARRAY TYPE
array-type → [type]
GRAMMAR OF A DICTIONARY TYPE
dictionary-type → [type:type]
GRAMMAR OF AN OPTIONAL TYPE
optional-type → type?
GRAMMAR OF AN IMPLICITLY UNWRAPPED OPTIONAL TYPE
implicitly-unwrapped-optional-type → type!
GRAMMAR OF A PROTOCOL COMPOSITION TYPE

  383  
protocol-composition-type → protocol<protocol-identifier-listopt>
protocol-identifier-list → protocol-identifier protocol-identifier,protocol-identifier-list
protocol-identifier → type-identifier
GRAMMAR OF A METATYPE TYPE
metatype-type → type.Type type.Protocol
GRAMMAR OF A TYPE INHERITANCE CLAUSE
type-inheritance-clause → :class-requirement,type-inheritance-list
type-inheritance-clause → :class-requirement
type-inheritance-clause → :type-inheritance-list
type-inheritance-list → type-identifier type-identifier,type-inheritance-list
class-requirement → class
 

  384  

También podría gustarte