Introducción al aprendizaje de SWIFT
El primer programa debería imprimir "Hola, mundo" en la pantalla. En Swift, esto se puede lograr con una línea de código:
println("Hello, world")
Si ha escrito código C u Objective-C, debería estar familiarizado con este formulario: en Swift, esta línea de código es un
programa completo. No necesita importar una biblioteca separada para entrada/salida o procesamiento de cadenas. El código en el ámbito global se utilizará automáticamente como punto de entrada del programa, por lo que no necesita la función principal. Tampoco es necesario poner un punto y coma al final de cada declaración.
Este tutorial le brindará una comprensión preliminar de Swift a través de una serie de ejemplos de programación. No se preocupe si hay algo que no comprende:
Todo lo que se presenta en este capítulo. Se cubrirá Esto se explicará en detalle en capítulos posteriores.
Nota:
Para obtener la mejor experiencia, utilice la función de vista previa del código en Xcode. La función de vista previa del código le permite editar el código y ver los resultados de la ejecución en tiempo real. Utilice let para declarar constantes y var para declarar variables. No es necesario obtener el valor de una constante en el momento de la compilación, pero solo puedes asignarle un valor una vez
. Es decir, puedes usar una constante para representar un valor que solo necesitas decidir una vez, pero que debes usar muchas veces.
var myVariable = 42
myVariable = 50
let myConstant = 42
El tipo de constante o variable debe ser el mismo como el tipo que les asignas. El valor es el mismo. Sin embargo, el tipo es opcional al declarar. Si se asigna un valor en el momento de la declaración, el compilador inferirá automáticamente el tipo. En el ejemplo anterior, el compilador infiere que myVariable es un número entero porque su valor inicial es un número entero.
Si el valor inicial no proporciona suficiente información (o no hay ningún valor inicial), entonces es necesario declarar el tipo después de la variable, separado por dos puntos.
let implicitInteger = 70
let implicitDouble = 70.0
let explicitDouble: Double = 70
Crea una constante y especifica explícitamente el tipo Sea flotante y especifique un valor inicial de 4.
Los valores nunca se convierten implícitamente a otros tipos. Si necesita convertir un valor a otro tipo, hágalo explícitamente.
let label = "El ancho es"
let width = 94
let widthLabel = label String(ancho)
Eliminar el última cadena en una línea, ¿cuál es el mensaje de error?
Existe una forma más sencilla de convertir un valor en una cadena: escribir el valor entre paréntesis y escribir una barra invertida antes del paréntesis. Por ejemplo:
let apples = 3
let oranges = 5
let appleSummary = "Tengo \(manzanas) manzanas."
let fruitSummary = "Tengo \(manzanas naranjas) trozos de fruta."
Utiliza \() para convertir un cálculo de punto flotante en una cadena, agrega el nombre de alguien y juega con él. Un hola.
Utilice corchetes [] para crear matrices y diccionarios, y utilice subíndices o claves para acceder a los elementos.
var shoppingList = ["bagre", "agua", "tulipanes", "pintura azul"]
shoppingList[1] = "botella de agua"
var ocupaciones = [
"Malcolm": "Capitán",
"Kaylee": "Mecánico",
]
ocupaciones["Jayne"] = "Relaciones públicas"
Para crear una matriz o diccionario vacío, utilice la sintaxis de inicialización.
let vacíoArray = [String]()
let vacíoDictionary = Dictionarylt;String, Floatgt;()
Si la información de tipo se puede inferir, puede Utilice [] y [:] para crear matrices y diccionarios vacíos, como cuando declara variables o pasa parámetros a funciones
.
shoppingList = [] // Ir de compras y comprar algo Use if y switch para realizar operaciones condicionales, y use for-in, for, while y do- while para realizar bucles. Los paréntesis que rodean la condición y la variable de bucle
se pueden omitir, pero las llaves en el cuerpo de la declaración son obligatorias.
deje que individualScores = [75, 43, 103, 87, 12]
var teamScore = 0
para obtener puntuación en individualScores {
si la puntuación es 50 {
teamScore = 3
} más {
teamScore = 1
}
}
teamScore
En la declaración if, la condición debe ser una expresión booleana; esto significa que un código como if score {...} informará un error, mientras que no se comparará implícitamente con 0
.
Puedes usar if y let juntos para manejar los valores faltantes. Algunos valores de variables son opcionales. Un valor opcional puede ser un valor específico
o nulo, lo que indica que falta el valor. Agregar un signo de interrogación después del tipo marca el valor de la variable como opcional.
var cadena opcional: cadena? = "Hola"
cadena opcional == nil
var nombre opcional: cadena = "John Appleseed"
var saludo = "¡Hola!"
if let nombre = nombreopcional {
saludo = "Hola, \(nombre)"
}
Cambie el nombre opcional a nil, ¿cuál será el saludo? Agregue una declaración else para darle al saludo
un valor diferente cuando el nombre opcional sea nulo.
Si el valor opcional de la variable es nulo, la condición se evaluará como falsa y se omitirá el código entre llaves. Si no es nulo, el valor se asignará a la constante después de let
, para que el valor pueda usarse en el bloque de código.
switch admite cualquier tipo de datos y una variedad de operaciones de comparación, no solo números enteros y pruebas de igualdad.
let vegetal = "pimiento rojo"
cambiar vegetal {
caso "apio":
let vegetalComment = "Agrega algunas pasas y hacer hormigas en un tronco."
case "pepino", "berros":
let vegetalComment = "Eso sería un buen sándwich de té."
case let x donde x.hasSuffix("pepper"):
let vegetalComment = "¿Es picante \(x)?"
predeterminado:
let vegetalComment = "Todo sabe bien en la sopa."
}
¿Eliminar la declaración predeterminada y ver si hay algún error?
Después de ejecutar las cláusulas coincidentes en switch, el programa saldrá de la instrucción switch y no continuará ejecutándose hacia abajo, por lo que no es necesario escribir una pausa al final de cada cláusula
.
Puedes usar for-in para iterar sobre el diccionario, lo que requiere dos variables para representar cada par clave-valor.
let interestNumbers = [
"Prime": [2, 3, 5, 7, 11, 13],
"Fibonacci": [1, 1, 2, 3, 5, 8],
"Cuadrado": [1, 4, 9, 16, 25],
]
var mayor = 0
para (tipo, números) en números interesantes {
para número en números {
si el número gt mayor {
más grande = número
}
}
}
más grande
Agrega otra variable para registrar cuál El tipo de número es el más grande.
Utilice while para ejecutar repetidamente un fragmento de código hasta que no se cumpla una condición. La condición del bucle puede estar al principio o al final.
var n = 2
mientras n lt 100 {
n = n * 2
}
n
var m = 2
hacer {
m = m * 2
} mientras m lt 100
m
Puedes usar ..lt; en el bucle para representar el rango, o puedes usar el método de escritura tradicional. Los dos son equivalentes:
var firstForLoop. = 0
para i en 0..lt; 3 {
firstForLoop = i
}
firstForLoop
var secondForLoop = 0
para var i = 0; i lt; i {
segundoForLoop = 1
}
secondForLoop
Utilice ..lt; el rango creado no incluye el límite superior. Si desea incluirlo, debe utilizar.... Utilice func para declarar una función y llamar a la función utilizando su nombre y parámetros. Utilice -gt; para especificar el valor de retorno de la función.
func greet(nombre: String, día: String) -gt; String {
return "Hola \(nombre), hoy es \(día)."
}
saludo("Bob", "Tuesday")
Elimine el parámetro del día y agregue un parámetro para indicar qué almuerzo se comió hoy.
Utiliza una tupla para devolver múltiples valores.
func getGasPrices() -gt; (Doble, Doble, Doble) {
return (3.59, 3.69, 3.79)
}
getGasPrices()
La función puede tener un número variable de parámetros, que se expresan como matrices dentro de la función:
func sumOf(numbers: Int... ) -gt ; Int {
var suma = 0
para número en números {
suma = número
}
return sum
}
sumOf()
sumOf(42, 597, 12)
Las funciones se pueden anidar. Las funciones anidadas pueden acceder a las variables de la función externa. Puede utilizar funciones anidadas para reconstruir una función que sea demasiado larga o compleja
.
func returnQuince() -gt; Int {
var y = 10
func add() {
y = 5
}
add()
devuelve y
}
returnQuince()
Las funciones son tipos de primera clase, lo que significa que una función puede ser el valor de retorno de otra función.
func makeIncrementer() -gt; (Int -gt; Int) {
func addOne(número: Int) -gt {
return 1; número
}
return addOne
}
var incremento = makeIncrementer()
incremento(7)
Una función también se puede pasar como parámetro a otra función.
func hasAnyMatches(list: Int[], condition: Int -gt; Bool) -gt; Bool {
para el elemento de la lista {
if condition (elemento) {
devuelve verdadero
}
}
devuelve falso
}
func lessThanTen(número: Int) -gt; bool {
devuelve número lt;
}
var números = [20, 19, 7, 12]
hasAnyMatches(numbers, lessThanTen)
La función es en realidad un cierre especial. Puedes usar {} para crear un cierre anónimo. Úselo para separar las declaraciones de tipo de parámetro y valor de retorno del cuerpo de la función de cierre del paquete.
números.map({
(número: Int) -gt; Int in
dejar resultado = 3 * número
regresar resultado
})
Hay muchas formas de crear cierres. Si se conoce el tipo de cierre, como por ejemplo si es una función de devolución de llamada, puede ignorar los tipos de parámetros y el valor de retorno. Un cierre de declaración única devuelve como resultado el valor de su declaración.
numbers.map({ number in 3 * number })
Puede hacer referencia a los parámetros por su posición en lugar de por su nombre; este método es muy útil en cierres muy cortos. obras. Cuando se pasa un cierre como último argumento a una función, puede seguir directamente al paréntesis.
sort([1, 5, 3, 12, 2]) { $0 gt; $1 } Utilice la clase y el nombre de la clase para crear una clase. La declaración de atributos en una clase es la misma que la declaración de constantes y variables. La única diferencia es que su contexto es una clase. Lo mismo ocurre con las declaraciones de métodos y funciones.
clase Forma {
var numberOfSides = 0
func simpleDescription() -gt; String {
return "Una forma con \ (numberOfSides) lados."
}
}
Para crear una instancia de una clase, agregue paréntesis después del nombre de la clase. Utilice la sintaxis de puntos para acceder a las propiedades y métodos de la instancia.
var shape = Shape()
shape.numberOfSides = 7
var shapeDescription = shape.simpleDescription()
Esta versión A la clase Shape le falta algo importante: un constructor para inicializar la instancia de la clase. Utilice init para crear un constructor
clase NamedShape {
var numberOfSides: Int = 0
var nombre: String
init( nombre : Cadena) {
self.name = nombre
}
func simpleDescription() -gt; Cadena {
return " A forma con \(numberOfSides) lados."
}
}
Tenga en cuenta que self se usa para distinguir variables de instancia. Cuando crea una instancia, pase los argumentos del constructor a la clase como si fueran argumentos de función. A cada propiedad se le debe asignar un valor, ya sea mediante una declaración (como numberOfSides) o mediante un constructor (como el nombre). Si necesita hacer alguna limpieza antes de eliminar el objeto, use deinit para crear un destructor. Las subclases se definen agregando el nombre de la clase principal al nombre de su clase, separado por dos puntos. No necesita una clase raíz estándar al crear una clase, por lo que puede ignorar la clase principal.
Si una subclase desea anular el método de la clase principal, debe marcarse con override; si anula el método de la clase principal sin agregar anulación, el compilador informará un error. El compilador también comprobará si el método marcado con anulación está realmente en la clase principal.
class Square: NamedShape {
var sideLength: Double
init(sideLength: Double, name: String) {
self. sideLength = sideLength
super.init(nombre: nombre)
numberOfSides = 4
}
func area() -gt; Doble {
return sideLength * sideLength
}
override func simpleDescription() -gt; String {
return "Un cuadrado con lados de longitud \(longitudlado)."
}
}
let test = Square(longitudlado: 5.2, nombre: "mi cuadrado de prueba")
test.area()
test.simpleDescription()
Crea otra subclase de NamedShape, Circle. El constructor recibe dos parámetros, uno es el radio y el. el otro es el radio. Es el nombre, implementa el área y describe los métodos.
Las propiedades pueden tener captadores y definidores.
clase EquilateralTriangle: NamedShape {
var sideLength: Double = 0.0
init(sideLength: Double, nombre: String) {
self.sideLength = sideLength
super.init(nombre: nombre)
numberOfSides = 3
}
var perímetro: Doble {
obtener {
retorno 3.0 * sideLength
}
establecer {
sideLength = newValue / 3.0
}
}
override func simpleDescription() -gt; String {
return "Un triángulo equilátero con lados de longitud \( sideLength)."
}
}
var triángulo = EquilateralTriangle(sideLength: 3.1, nombre: "un triángulo")
Triangle.perimeter
triangle.perimeter = 9.9
triangle.sideLength
En el definidor de perímetro, el nombre del nuevo valor es newValue. Puede establecer explícitamente un nombre después de establecerlo.
Tenga en cuenta que el constructor de la clase EquilateralTriangle realiza tres pasos:
Establecer el valor del atributo declarado por la subclase
Llamar al constructor de la clase padre p>
Cambiar el valor del atributo definido por la clase principal. En esta etapa también se pueden realizar otros trabajos, como llamar a métodos, captadores y definidores.
Si no necesita una propiedad calculada pero necesita ejecutar algún código antes de establecer un nuevo valor, use willSet y didSet.
Por ejemplo, la siguiente clase garantiza que los lados de un triángulo sean siempre iguales a los lados de un cuadrado.
clase TriangleAndSquare {
var triángulo: EquilateralTriangle {
willSet {
square.sideLength = newValue.sideLength
}
}
var cuadrado: Cuadrado {
willSet {
triangle.sideLength = newValue.sideLength
}
}
init(tamaño: Doble, nombre: Cadena) {
cuadrado = Cuadrado(ladoLongitud: tamaño, nombre: nombre)
triángulo = EquiláteroTriángulo(ladoLongitud: tamaño, nombre: nombre)
}
}
var triánguloAndCuadrado = TriánguloAndCuadrado(tamaño: 10, nombre: "otra forma de prueba")
triangleAndSquare.square.sideLength
triangleAndSquare.triangle.sideLength
triangleAndSquare.square = Square(sideLength: 50, nombre : "cuadrado más grande")
triangleAndSquare.triangle.sideLength
Existe una diferencia importante entre los métodos de la clase y las funciones generales. Los nombres de los parámetros de la función solo se usan dentro. la función, pero los nombres de los parámetros del método deben indicarse explícitamente cuando se llama a
(excepto el primer parámetro). De forma predeterminada, el nombre del parámetro de un método es el mismo que su nombre dentro del método, pero también puede definir un segundo nombre, que se usa dentro del método.
Contador de clases {
var count: Int = 0
func incrementBy(cantidad: Int, numberOfTimes veces: Int) {
recuento = cantidad * veces
}
}
var contador = Contador()
contador.incrementBy(2, númeroDeVeces: 7 )
Cuando se trata de valores opcionales para variables, puede agregar? antes de las operaciones (como métodos, propiedades y subíndices). Si el valor anterior a ? es nulo, cualquier valor posterior a
se ignorará y la expresión completa devolverá nulo. De lo contrario, se ejecutará todo lo que sigue a ? En ambos casos, el valor de toda la tabla
expresión también es un valor opcional.
let optionSquare: Square? = Square(sideLength: 2.5, name: "optional square")
let sideLength = opcionalSquare?.sideLength Utilice enumeración para crear una enumeración.
Al igual que las clases y todos los demás tipos con nombre, las enumeraciones pueden contener métodos.
Rango de enumeración: Int {
caso As = 1
caso Dos, Tres, Cuatro, Cinco, Seis, Siete, Ocho, Nueve, Diez p> p>
caso Jota, Reina, Rey
func simpleDescription() -gt; String {
cambiar self {
caso .As:
p>
devuelve "as"
caso .Jack:
devuelve "jota"
caso .Reina:
devuelve "reina"
caso .Rey:
devuelve "rey"
valor predeterminado:
devuelve cadena (self.toRaw())
}
}
}
let ace = Rank.Ace
let aceRawValue = ace.toRaw ()
Escribe una función para comparar dos valores de Rank comparando sus valores originales.
En el ejemplo anterior, el tipo de valor primitivo de enumeración es Int, por lo que solo necesita establecer el primer valor primitivo. Los valores originales restantes se asignarán en orden
. También puede utilizar cadenas o puntos flotantes como valores sin formato para las enumeraciones.
Utilice las funciones toRaw y fromRaw para convertir entre valores sin formato y valores de enumeración.
if let convertRank = Rank.fromRaw(3) {
let threeDescription = convertRank.simpleDescription()
}
Enumeración La El valor del miembro de es el valor real, no otra expresión del valor original. En realidad, no es necesario establecerlo si el valor original no tiene sentido.
enum Palo {
caso Espadas, Corazones, Diamantes, Tréboles
func simpleDescription() - gt; String {
cambiar self {
case .Spades:
devuelve "picas"
case . Corazones:
devuelve "corazones"
caso .Diamantes:
devuelve "diamantes"
caso .Clubs:
devolver " palos"
}
}
}
dejar corazones = Suit.Hearts
let corazonesDescripción = corazones .simpleDescription()
Agregue un método de color al Traje, que devuelve "negro" para espadas y tréboles, y "rojo" para corazones y diamantes.
Tenga en cuenta que hay dos formas de hacer referencia al miembro Hearts: al asignar un valor a la constante de corazones, se debe hacer referencia al miembro de enumeración Suit.Hearts por su nombre completo
porque la constante no es un tipo especificado explícitamente. En Switch, se hace referencia a los miembros de la enumeración utilizando la abreviatura .Hearts, porque ya se sabe que el valor de self
es un palo. Puede utilizar abreviaturas cuando se conoce el tipo de variable.
Utiliza struct para crear una estructura. Las estructuras y las clases tienen muchas cosas en común, como métodos y constructores. La mayor diferencia entre ellos
es que las estructuras se pasan por valor, mientras que las clases se pasan por referencia.
struct Card {
var rango: Rango
var traje: Traje
func simpleDescription() -gt; p>
return "El \(rank.simpleDescription()) de \
(suit.simpleDescription())"
}
}
let threeOfSpades = Card(rank: .Three, palo: .Spades)
let threeOfSpadesDescription = threeOfSpades.simpleDescription()
Agregar un método a Card para crear Una baraja completa de naipes y el rango y palo correspondiente de cada carta.
Una instancia de un miembro de enumeración puede tener valores de instancia. Las instancias del mismo miembro de enumeración pueden tener valores diferentes. Simplemente pase el valor al crear la instancia.
Los valores de instancia y los valores primitivos son diferentes: los valores primitivos de los miembros de la enumeración son los mismos para todas las instancias, y usted establece
los valores primitivos cuando usted define la enumeración.
Por ejemplo, considere obtener las horas de salida y puesta del sol del servidor. El servidor devolverá resultados normales o mensajes de error.
enum ServerResponse {
caso Resultado(Cadena, Cadena)
caso Error(Cadena)
}
let Success = ServerResponse.Result("6:00 am", "8:09 pm")
let Failure = ServerResponse.Error("Sin queso.")
switch Success {
case let .Result(sunrise, sunset):
let serverResponse = "El amanecer es a las \(sunrise) y el atardecer es a las \(sunset)". p> p>
caso let .Error(error):
let serverResponse = "Error... \(error)"
}
A ServerResponse y cambie para agregar un tercer caso.
Observe cómo las horas de salida y puesta del sol se extraen de ServerResponse. Utilice el protocolo para declarar una interfaz.
protocolo EjemploProtocolo {
var simpleDescription: String { get }
función mutante ajustar()
}
Las clases, enumeraciones y estructuras pueden implementar interfaces.
class SimpleClass: EjemploProtocol {
var simpleDescription: String = "Una clase muy simple."
var anotherProperty: Int = 69105
func ajustar() {
simpleDescription = " Ahora 100 ajustados."
}
}
var a = SimpleClass()
a.adjust()
let aDescription = a.simpleDescription
struct SimpleStructure: EjemploProtocol {
var simpleDescription: String = " Una estructura simple"
función mutante ajustar() {
simpleDescription = " (ajustado)"
}
}
var b = SimpleStructure()
b.adjust()
let bDescription = b.simpleDescription
Escribe una enumeración que implemente esta interfaz.
Tenga en cuenta que al declarar SimpleStructure, la palabra clave mutating se utiliza para marcar un método que modificará la estructura. La declaración de SimpleClass no necesita marcar ningún método porque los métodos de una clase a menudo modifican la clase.
Utilice extensiones para agregar funcionalidad a tipos existentes, como agregar un método para calcular propiedades. Puede usar extensiones para agregar protocolos a cualquier tipo
incluso tipos que importe desde bibliotecas o marcos externos.
extensión Int: EjemploProtocol {
var simpleDescripción: Cadena {
return "El número \(self)"
} p>
función mutante ajustar() {
self = 42
}
}
7.simpleDescription
Escriba una extensión para el tipo Doble y agregue la función valor absoluto.
Puedes usar nombres de interfaz como cualquier otro tipo con nombre, por ejemplo, para crear una colección de objetos de diferentes tipos que implementen una interfaz.
Cuando se trata de valores cuyo tipo es una interfaz, los métodos definidos fuera de la interfaz no están disponibles.
let protocolValue: EjemploProtocol = a
protocolValue.simpleDescription
// protocoloValue.anotherProperty // Descomentar para ver el error
Incluso El tipo de tiempo de ejecución de la variable ProtocolValue es simpleClass y el compilador tratará su tipo como EjemploProtocol. Esto significa
que no puedes llamar a métodos o propiedades que una clase implementa fuera de la interfaz que implementa. Cree una función o tipo genérico escribiendo un nombre entre corchetes angulares.
func repetición; ItemTypegt; (elemento: ItemType, tiempos: Int) -gt; ItemType[] {
var resultado = ItemType[]()
para i en 0..lt; multiplicado por {
resultado = elemento
}
devolver resultado
}
repeat("knock", 4)
También puedes crear clases, enumeraciones y estructuras genéricas.
// Reimplementar el tipo opcional de la biblioteca estándar Swift
enum OpcionalValuelt; {
case None
case Some(T)
}
var posibleInteger: OpcionalValuelt; Intgt; = .None
possibleInteger = .Some(100)
Después del nombre del tipo Utilice dónde para especificar una lista de requisitos; por ejemplo, para restringir los tipos que implementan un protocolo a dos tipos
que sean iguales, o para restringir una clase para que tenga una clase principal específica.
func anyCommonElements Equatable, T.GeneratorType.Element == U.GeneratorType.Elementgt; (lhs: T, rhs: U) -gt; Bool { para lhsItem en lhs { para rhsItem en rhs { si lhsItem == rhsItem { devuelve verdadero } } } devuelve falso } anyCommonElements([1, 2, 3], [3]) Modifica la función anyCommonElements para crear una función que devuelva una matriz cuyo contenido son las dos secuencias** * Hay elementos. Para simplificar, puedes ignorar dónde y simplemente escribir la interfaz o el nombre de la clase después de los dos puntos. lt;T: Equatablegt; y lt;T donde T: Equatablegt son equivalentes.