Swift - Guía rápida

Swift 4 es un nuevo lenguaje de programación desarrollado por Apple Inc para el desarrollo de iOS y OS X. Swift 4 adopta lo mejor de C y Objective-C, sin las limitaciones de la compatibilidad con C.

  • Swift 4 utiliza patrones de programación seguros.

  • Swift 4 ofrece funciones de programación modernas.

  • Swift 4 proporciona una sintaxis similar a Objective-C.

  • Swift 4 es una forma fantástica de escribir aplicaciones iOS y OS X.

  • Swift 4 proporciona un acceso perfecto a los marcos Cocoa existentes.

  • Swift 4 unifica las partes procedimentales y orientadas a objetos del lenguaje.

  • Swift 4 no necesita una importación de biblioteca separada para admitir funcionalidades como entrada / salida o manejo de cadenas.

Swift 4 usa el mismo tiempo de ejecución que el sistema Obj-C existente en Mac OS e iOS, lo que permite que los programas Swift 4 se ejecuten en muchas plataformas iOS 6 y OS X 10.8 existentes.

Swift 4 viene con una función de área de juegos donde los programadores de Swift 4 pueden escribir su código y ejecutarlo para ver los resultados de inmediato.

El primer lanzamiento público de Swift se lanzó en 2010. Se necesitó Chris Lattnercasi 14 años para llegar a la primera versión oficial, y más tarde, fue apoyada por muchos otros colaboradores. Swift 4 se ha incluido en Xcode 6 beta.

Los diseñadores de Swift tomaron ideas de varios otros lenguajes populares como Objective-C, Rust, Haskell, Ruby, Python, C # y CLU.

Configuración del entorno local

Swift 4 proporciona una plataforma de juegos con fines de aprendizaje y vamos a configurar la misma. Necesita el software xCode para iniciar su codificación Swift 4 en Playground. Una vez que se sienta cómodo con los conceptos de Swift 4, puede usar xCode IDE para el desarrollo de aplicaciones iOS / OS x.

Para empezar, consideramos que ya tiene una cuenta en el sitio web de desarrolladores de Apple. Una vez que haya iniciado sesión, vaya al siguiente enlace: Descargar para desarrolladores de Apple

Esto mostrará una lista de software disponible de la siguiente manera:

Ahora seleccione xCode y descárguelo haciendo clic en el enlace proporcionado cerca de la imagen del disco. Después de descargar el archivo dmg, puede instalarlo simplemente haciendo doble clic en él y siguiendo las instrucciones dadas. Finalmente, siga las instrucciones dadas y suelte el icono de xCode en la carpeta de la Aplicación.

Ahora tiene xCode instalado en su máquina. A continuación, abra Xcode desde la carpeta de la Aplicación y continúe después de aceptar los términos y condiciones. Si todo está bien, aparecerá la siguiente pantalla:

Seleccione Get started with a playgroundopción e ingrese un nombre para el área de juegos y seleccione iOS como plataforma. Finalmente, obtendrá la ventana del patio de juegos de la siguiente manera:

A continuación se muestra el código tomado de la ventana Swift 4 Playground predeterminada.

import UIKit
var str = "Hello, playground"

Si crea el mismo programa para el programa OS X, incluirá import Cocoa y el programa se verá de la siguiente manera:

import Cocoa
var str = "Hello, playground"

Cuando se carga el programa anterior, debería mostrar el siguiente resultado en el área de resultados del Patio de juegos (lado derecho).

Hello, playground

Felicitaciones, tiene listo su entorno de programación Swift 4 y puede continuar con su vehículo de aprendizaje "Tutorials Point".

Ya hemos visto una parte del programa Swift 4 mientras configuramos el entorno. Comencemos una vez más con lo siguienteHello, World! programa creado para el patio de juegos de OS X, que incluye import Cocoa como se muestra a continuación -

/* My first program in Swift 4 */
var myString = "Hello, World!"

print(myString)

Si crea el mismo programa para el patio de juegos de iOS, incluirá import UIKit y el programa se verá de la siguiente manera:

import UIKit
var myString = "Hello, World!"
print(myString)

Cuando ejecutamos el programa anterior usando un patio de recreo apropiado, obtendremos el siguiente resultado:

Hello, World!

Veamos ahora la estructura básica de un programa Swift 4, de modo que le resulte fácil comprender los componentes básicos del lenguaje de programación Swift 4.

Importar en Swift 4

Puedes usar el importdeclaración para importar cualquier marco Objective-C (o biblioteca C) directamente a su programa Swift 4. Por ejemplo, lo anteriorimport cocoa declaración hace que todas las bibliotecas, API y tiempos de ejecución de Cocoa que forman la capa de desarrollo para todo OS X, estén disponibles en Swift 4.

Cocoa está implementado en Objective-C, que es un superconjunto de C, por lo que es fácil mezclar C e incluso C ++ en sus aplicaciones Swift 4.

Fichas en Swift 4

Un programa Swift 4 consta de varios tokens y un token es una palabra clave, un identificador, una constante, una cadena literal o un símbolo. Por ejemplo, la siguiente declaración de Swift 4 consta de tres tokens:

print("test!")
The individual tokens are:
print("test!")

Comentarios

Los comentarios son como textos de ayuda en su programa Swift 4. El compilador los ignora. Los comentarios de varias líneas comienzan con / * y terminan con los caracteres * / como se muestra a continuación -

/* My first program in Swift 4 */

Los comentarios de varias líneas se pueden anidar en Swift 4. A continuación, se muestra un comentario válido en Swift 4:

/* My first program in Swift 4 is Hello, World!
/* Where as second program is Hello, Swift 4! */ */

Los comentarios de una sola línea se escriben utilizando // al principio del comentario.

// My first program in Swift 4

Punto y coma

Swift 4 no requiere que escriba un punto y coma (;) después de cada declaración en su código, aunque es opcional; y si usa un punto y coma, el compilador no se queja.

Sin embargo, si está utilizando varias declaraciones en la misma línea, entonces es necesario utilizar un punto y coma como delimitador, de lo contrario, el compilador generará un error de sintaxis. Puede escribir lo anterior ¡Hola, mundo! programe de la siguiente manera -

/* My first program in Swift 4 */
var myString = "Hello, World!"; print(myString)

Identificadores

Un identificador de Swift 4 es un nombre que se utiliza para identificar una variable, función o cualquier otro elemento definido por el usuario. Un identificador comienza con un alfabeto de la A a la Z o de la aa la z o un guión bajo _ seguido de cero o más letras, guiones bajos y dígitos (0 a 9).

Swift 4 no permite caracteres especiales como @, $ y% dentro de los identificadores. Swift 4 es uncase sensitivelenguaje de programación. Por lo tanto, Manpower y manpower son dos identificadores diferentes en Swift 4. A continuación, se muestran algunos ejemplos de identificadores aceptables:

Azad        zara   abc   move_name   a_123
myname50    _temp  j     a23b9       retVal

Para usar una palabra reservada como identificador, deberá poner una tilde (`) antes y después de ella. Por ejemplo,class no es un identificador válido, pero `class`es válido.

Palabras clave

Las siguientes palabras clave están reservadas en Swift 4. Estas palabras reservadas no se pueden usar como constantes o variables o cualquier otro nombre de identificador, a menos que se escapen con comillas invertidas:

Palabras clave utilizadas en declaraciones

Clase deinit Enum extensión
Func importar En eso interno
Dejar operador privado protocolo
público estático estructura subíndice
typealias var

Palabras clave utilizadas en declaraciones

romper caso Seguir defecto
hacer más caer a través para
Si en regreso cambiar
dónde mientras

Palabras clave utilizadas en expresiones y tipos

como dynamicType falso es
nulo yo Yo súper
cierto _COLUMNA_ _ARCHIVO_ _FUNCIÓN_
_LÍNEA_

Palabras clave utilizadas en contextos particulares

asociatividad conveniencia dinámica didSet
final obtener infijo En fuera
perezoso izquierda mutante ninguna
no mutante Opcional anular sufijo
precedencia prefijo Protocolo necesario
derecho conjunto Tipo sin propietario
débiles establecerá

Espacios en blanco

Una línea que contiene solo espacios en blanco, posiblemente con un comentario, se conoce como línea en blanco, y un compilador de Swift 4 la ignora por completo.

Espacio en blanco es el término utilizado en Swift 4 para describir espacios en blanco, tabulaciones, caracteres de nueva línea y comentarios. Los espacios en blanco separan una parte de una declaración de otra y permiten al compilador identificar dónde termina un elemento de una declaración, como int, y comienza el siguiente. Por lo tanto, en la siguiente declaración:

var age

Debe haber al menos un carácter de espacio en blanco (generalmente un espacio) entre var y agepara que el compilador pueda distinguirlos. Por otro lado, en la siguiente declaración:

int fruit = apples + oranges   //get the total fruits

No se necesitan espacios en blanco entre frutas y =, o entre = y manzanas, aunque puede incluir algunos para una mejor legibilidad.

El espacio a ambos lados de un operador debe ser igual, por ejemplo.

int fruit = apples +oranges    //is a wrong statement
int fruit = apples + oranges   //is a Correct statement

Literales

Un literal es la representación del código fuente de un valor de un entero, un número de punto flotante o un tipo de cadena. Los siguientes son ejemplos de literales:

92               // Integer literal
4.24159          // Floating-point literal
"Hello, World!"  // String literal

Imprimir en Swift

Para imprimir cualquier cosa en Swift, tenemos la palabra clave 'imprimir'.

La impresión tiene tres propiedades diferentes.

Items - Elementos a imprimir

Separator - separador entre elementos

Terminator - el valor con el que debe terminar la línea, veamos un ejemplo y sintaxis de la misma.

print("Items to print", separator: "Value " , terminator: "Value")
// E.g. of print statement.

print("Value one")
// prints "Value one \n" Adds, \n as terminator and " " as separator by
default.

print("Value one","Value two", separator: " Next Value" , terminator: " End")
//prints "Value one Next Value Value two End"

En el código anterior, la primera declaración de impresión agrega \ n, nueva línea Feed como terminador por defecto, mientras que en la segunda declaración de impresión hemos dado "End" como terminador, por lo que imprimirá "End" en lugar de \ n.

Podemos ofrecer nuestros separadores y terminadores personalizados de acuerdo con nuestros requisitos.

Al programar en cualquier lenguaje de programación, debe utilizar diferentes tipos de variables para almacenar información. Las variables no son más que ubicaciones de memoria reservadas para almacenar valores. Esto significa que cuando crea una variable, reserva algo de espacio en la memoria.

Es posible que desee almacenar información de varios tipos de datos como cadena, carácter, carácter ancho, entero, punto flotante, booleano, etc. Según el tipo de datos de una variable, el sistema operativo asigna memoria y decide qué se puede almacenar en el reservado. memoria.

Tipos de datos integrados

Swift 4 ofrece al programador una amplia variedad de tipos de datos integrados y definidos por el usuario. Los siguientes tipos de tipos de datos básicos son los más frecuentes al declarar variables:

  • Int or UInt- Esto se usa para números enteros. Más específicamente, puede usar Int32, Int64 para definir enteros con signo de 32 o 64 bits, mientras que UInt32 o UInt64 para definir variables enteras sin signo de 32 o 64 bits. Por ejemplo, 42 y -23.

  • Float- Se utiliza para representar un número de coma flotante de 32 bits y números con puntos decimales más pequeños. Por ejemplo, 3.14159, 0.1 y -273.158.

  • Double- Se utiliza para representar un número de punto flotante de 64 bits y se utiliza cuando los valores de punto flotante deben ser muy grandes. Por ejemplo, 3.14159, 0.1 y -273.158.

  • Bool - Esto representa un valor booleano que es verdadero o falso.

  • String- Esta es una colección ordenada de personajes. Por ejemplo, "¡Hola, mundo!"

  • Character- Este es un literal de cadena de un solo carácter. Por ejemplo, "C"

  • Optional - Esto representa una variable que puede contener un valor o ningún valor.

  • Tuples - Esto se utiliza para agrupar varios valores en un solo valor compuesto.

Hemos enumerado aquí algunos puntos importantes relacionados con los tipos de números enteros:

  • En una plataforma de 32 bits, Int tiene el mismo tamaño que Int32.

  • En una plataforma de 64 bits, Int tiene el mismo tamaño que Int64.

  • En una plataforma de 32 bits, UInt tiene el mismo tamaño que UInt32.

  • En una plataforma de 64 bits, UInt tiene el mismo tamaño que UInt64.

  • Int8, Int16, Int32, Int64 se pueden utilizar para representar formas de entero con signo de 8 bits, 16 bits, 32 bits y 64 bits.

  • UInt8, UInt16, UInt32 y UInt64 se pueden utilizar para representar formas de entero sin signo de 8 bits, 16 bits, 32 bits y 64 bits.

Valores vinculados

La siguiente tabla muestra el tipo de variable, cuánta memoria se necesita para almacenar el valor en memoria, y cuál es el valor máximo y mínimo que se puede almacenar en ese tipo de variables.

Tipo Ancho típico de la broca Rango típico
Int8 1 byte -127 hasta 127
UInt8 1 byte 0 hasta 255
Int32 4 bytes -2147483648 al 2147483647
UInt32 4 bytes 0 hasta 4294967295
Int64 8 bytes -9223372036854775808 al 9223372036854775807
UInt64 8 bytes 0 a 18446744073709551615
Flotador 4 bytes 1.2E-38 a 3.4E + 38 (~ 6 dígitos)
Doble 8 bytes 2.3E-308 a 1.7E + 308 (~ 15 dígitos)

Alias ​​de tipo

Puede crear un nuevo nombre para un tipo existente usando typealias. Aquí está la sintaxis simple para definir un nuevo tipo usando typealias:

typealias newname = type

Por ejemplo, la siguiente línea le indica al compilador que Feet es otro nombre para Int -

typealias Feet = Int

Ahora, la siguiente declaración es perfectamente legal y crea una variable entera llamada distancia:

typealias Feet = Int
var distance: Feet = 100
print(distance)

Cuando ejecutamos el programa anterior usando playground, obtenemos el siguiente resultado.

100

Tipo de seguridad

Swift 4 es un lenguaje de tipo seguro, lo que significa que si una parte de su código espera un String, no puede pasarle un Int por error.

Como Swift 4 es de tipo seguro, realiza comprobaciones de tipo al compilar su código y marca cualquier tipo no coincidente como error.

var varA = 42
varA = "This is hello"
print(varA)

Cuando compilamos el programa anterior, produce el siguiente error de tiempo de compilación.

main.swift:2:8: error: cannot assign value of type 'String' to type 'Int'
varA = "This is hello"

Inferencia de tipo

La inferencia de tipos permite a un compilador deducir el tipo de una expresión en particular automáticamente cuando compila su código, simplemente examinando los valores que usted proporciona. Swift 4 usa la inferencia de tipos para calcular el tipo apropiado de la siguiente manera.

// varA is inferred to be of type Int
var varA = 42
print(varA)

// varB is inferred to be of type Double
var varB = 3.14159
print(varB)

// varC is also inferred to be of type Double
var varC = 3 + 0.14159
print(varC)

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

42
3.14159
3.14159

Una variable nos proporciona un almacenamiento con nombre que nuestros programas pueden manipular. Cada variable en Swift 4 tiene un tipo específico, que determina el tamaño y el diseño de la memoria de la variable; el rango de valores que se pueden almacenar dentro de esa memoria; y el conjunto de operaciones que se pueden aplicar a la variable.

Swift 4 admite los siguientes tipos básicos de variables:

  • Int or UInt- Esto se usa para números enteros. Más específicamente, puede usar Int32, Int64 para definir enteros con signo de 32 o 64 bits, mientras que UInt32 o UInt64 para definir variables enteras sin signo de 32 o 64 bits. Por ejemplo, 42 y -23.

  • Float- Se utiliza para representar un número de coma flotante de 32 bits. Se utiliza para contener números con puntos decimales más pequeños. Por ejemplo, 3.14159, 0.1 y -273.158.

  • Double- Se utiliza para representar un número de punto flotante de 64 bits y se utiliza cuando los valores de punto flotante deben ser muy grandes. Por ejemplo, 3.14159, 0.1 y -273.158.

  • Bool - Esto representa un valor booleano que es verdadero o falso.

  • String- Esta es una colección ordenada de personajes. Por ejemplo, "¡Hola, mundo!"

  • Character- Este es un literal de cadena de un solo carácter. Por ejemplo, "C"

Swift 4 también permite definir varios otros tipos de variables, que cubriremos en capítulos posteriores, como Optional, Array, Dictionaries, Structures, y Classes.

La siguiente sección cubrirá cómo declarar y usar varios tipos de variables en la programación de Swift 4.

Declaración de variable

Una declaración de variable le dice al compilador dónde y cuánto crear el almacenamiento para la variable. Antes de usar variables, debe declararlas usandovar palabra clave de la siguiente manera:

var variableName = <initial value>

El siguiente ejemplo muestra cómo declarar una variable en Swift 4:

var varA = 42
print(varA)

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

42

Tipo de anotaciones

Puede proporcionar un type annotationcuando declara una variable, para tener claro el tipo de valores que la variable puede almacenar. Aquí está la sintaxis:

var variableName:<data type> = <optional initial value>

El siguiente ejemplo muestra cómo declarar una variable en Swift 4 usando Anotación. Aquí es importante tener en cuenta que si no estamos usando la anotación de tipo, entonces es obligatorio proporcionar un valor inicial para la variable; de ​​lo contrario, podemos simplemente declarar nuestra variable usando la anotación de tipo.

var varA = 42
print(varA)

var varB:Float

varB = 3.14159
print(varB)

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

42
3.1415901184082

Nombrar variables

El nombre de una variable puede estar compuesto por letras, dígitos y el carácter de subrayado. Debe comenzar con una letra o un guión bajo. Las letras mayúsculas y minúsculas son distintas porque Swift 4 es un lenguaje de programación que distingue entre mayúsculas y minúsculas.

Puede usar caracteres simples o Unicode para nombrar sus variables. Los siguientes ejemplos muestran cómo puede nombrar las variables:

var _var = "Hello, Swift 4!"
print(_var)

var 你好 = "你好世界"
print(你好)

Cuando ejecutamos el programa anterior usando playground, obtenemos el siguiente resultado.

Hello, Swift 4!
你好世界

Impresión de variables

Puede imprimir el valor actual de una constante o variable con la función de impresión. Puede interpolar un valor de variable envolviendo el nombre entre paréntesis y escapando con una barra invertida antes del paréntesis de apertura: A continuación se muestran ejemplos válidos:

var varA = "Godzilla"
var varB = 1000.00

print("Value of \(varA) is more than \(varB) millions")

Cuando ejecutamos el programa anterior usando playground, obtenemos el siguiente resultado.

Value of Godzilla is more than 1000.0 millions

Swift 4 también presenta Optionalstype, que maneja la ausencia de un valor. Los opcionales dicen "hay un valor y es igual a x" o "no hay ningún valor".

Un Opcional es un tipo en sí mismo, en realidad una de las nuevas enumeraciones superpoderosas de Swift 4. Tiene dos valores posibles,None y Some(T), dónde T es un valor asociado del tipo de datos correcto disponible en Swift 4.

Aquí hay una declaración Integer opcional:

var perhapsInt: Int?

Aquí hay una declaración de cadena opcional:

var perhapsStr: String?

La declaración anterior es equivalente a inicializarla explícitamente a nil lo que significa que no tiene valor -

var perhapsStr: String? = nil

Tomemos el siguiente ejemplo para comprender cómo funcionan las opciones en Swift 4:

var myString:String? = nil

if myString != nil {
   print(myString)
} else {
   print("myString has nil value")
}

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

myString has nil value

Los opcionales son similares a usar nil con punteros en Objective-C, pero funcionan para cualquier tipo, no solo para clases.

Desenvolver forzado

Si definió una variable como optional, luego para obtener el valor de esta variable, tendrá que unwrapeso. Esto solo significa poner un signo de exclamación al final de la variable.

Tomemos un ejemplo simple:

var myString:String?

myString = "Hello, Swift 4!"

if myString != nil {
   print(myString)
} else {
   print("myString has nil value")
}

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Optional("Hello, Swift 4!")

Ahora apliquemos el desenvolvimiento para obtener el valor correcto de la variable:

var myString:String?

myString = "Hello, Swift 4!"

if myString != nil {
   print( myString! )
} else {
   print("myString has nil value")
}

Cuando ejecutamos el programa anterior usando playground, obtenemos el siguiente resultado.

Hello, Swift 4!

Desenvasado automático

Puede declarar variables opcionales utilizando un signo de exclamación en lugar de un signo de interrogación. Dichas variables opcionales se desenvolverán automáticamente y no es necesario utilizar ningún otro signo de exclamación al final de la variable para obtener el valor asignado. Tomemos un ejemplo simple:

var myString:String!
myString = "Hello, Swift 4!"

if myString != nil {
   print(myString)
} else {
   print("myString has nil value")
}

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Hello, Swift 4!

Encuadernación opcional

Utilice el enlace opcional para averiguar si un opcional contiene un valor y, de ser así, para que ese valor esté disponible como una constante o variable temporal.

Un enlace opcional para el if declaración es la siguiente:

if let constantName = someOptional {
   statements
}

Tomemos un ejemplo simple para comprender el uso del enlace opcional:

var myString:String?
myString = "Hello, Swift 4!"

if let yourString = myString {
   print("Your string has - \(yourString)")
} else {
   print("Your string does not have a value")
}

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Your string has - Hello, Swift 4!

Swift 4 también presenta Tuples type, que se utilizan para agrupar varios valores en un solo valor compuesto.

Los valores de una tupla pueden ser de cualquier tipo y no es necesario que sean del mismo tipo.

Por ejemplo, ("Tutorials Point", 123) es una tupla con dos valores, uno de tipo cadena y otro de tipo entero. Es un mandato legal.

let ImplementationError = (501, "No implementado") es un error cuando algo en el servidor no está implementado. Devuelve dos valores. Código de error y descripción.

Puede crear tuplas a partir de tantos valores como desee y de cualquier número de tipos de datos diferentes.

Aquí está la sintaxis de la declaración Tuple:

var TupleName = (Value1, value2,… any number of values)

Aquí hay una declaración de Tuple:

var error501 = (501, “Not implemented”)

Puede acceder a los valores de tupla utilizando los números de índice que comienzan en 0.

Aquí hay un ejemplo de cómo acceder a valores de tupla:

print(“The code is\(error501.0)”)
print(“The definition of error is\(error501.1)”)

Puede nombrar las variables de una tupla mientras declara, y puede llamarlas usando sus nombres

var error501 = (errorCode: 501, description: “Not Implemented”)
print(error501.errorCode)   // prints 501.

Las tuplas son útiles para devolver múltiples valores de una función. Por ejemplo, una aplicación web puede devolver una tupla de tipo ("String", Int) para mostrar si la carga se realizó correctamente o no.

Al devolver diferentes valores en una tupla, podemos tomar decisiones en función de los diferentes tipos de tuplas.

Note - Las tuplas son útiles para valores temporales y no son adecuadas para datos complejos.

Las constantes se refieren a valores fijos que un programa no puede alterar durante su ejecución. Las constantes pueden ser de cualquiera de los tipos de datos básicos, como una constante entera, una constante flotante, una constante de carácter o una cadena literal . También hay constantes de enumeración .

Constants se tratan como variables regulares excepto el hecho de que sus valores no se pueden modificar después de su definición.

Declaración de constantes

Antes de usar constantes, debe declararlas usando let palabra clave de la siguiente manera:

let constantName = <initial value>

A continuación se muestra un ejemplo simple para mostrar cómo declarar una constante en Swift 4:

let constA = 42
print(constA)

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

42

Tipo de anotaciones

Puede proporcionar un type annotationcuando declara una constante, para tener claro el tipo de valores que la constante puede almacenar. A continuación se muestra la sintaxis:

var constantName:<data type> = <optional initial value>

El siguiente ejemplo muestra cómo declarar una constante en Swift 4 usando Anotación. Aquí es importante tener en cuenta que es obligatorio proporcionar un valor inicial mientras se crea una constante:

let constA = 42
print(constA)

let constB:Float = 3.14159
print(constB)

Cuando ejecutamos el programa anterior usando playground, obtenemos el siguiente resultado.

42
3.1415901184082

Nombrar constantes

El nombre de una constante puede estar compuesto por letras, dígitos y el carácter de subrayado. Debe comenzar con una letra o un guión bajo. Las letras mayúsculas y minúsculas son distintas porque Swift 4 es un lenguaje de programación que distingue entre mayúsculas y minúsculas.

Puede usar caracteres simples o Unicode para nombrar sus variables. Los siguientes son ejemplos válidos:

let _const = "Hello, Swift 4!"
print(_const)

let 你好 = "你好世界"
print(你好)

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Hello, Swift 4!
你好世界

Constantes de impresión

Puede imprimir el valor actual de una constante o variable usando printfunción. Puede interpolar un valor de variable envolviendo el nombre entre paréntesis y escapando con una barra invertida antes del paréntesis de apertura: A continuación se muestran ejemplos válidos:

let constA = "Godzilla"
let constB = 1000.00

print("Value of \(constA) is more than \(constB) millions")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Value of Godzilla is more than 1000.0 millions

Un literal es la representación del código fuente de un valor de un entero, un número de punto flotante o un tipo de cadena. Los siguientes son ejemplos de literales:

42                // Integer literal
3.14159           // Floating-point literal
"Hello, world!"   // String literal

Literales enteros

Un literal entero puede ser una constante decimal, binaria, octal o hexadecimal. Los literales binarios comienzan con 0b, los literales octales comienzan con 0o y los literales hexadecimales comienzan con 0x y nada para decimales.

Aquí hay algunos ejemplos de literales enteros:

let decimalInteger = 17         // 17 in decimal notation
let binaryInteger = 0b10001     // 17 in binary notation
let octalInteger = 0o21         // 17 in octal notation
let hexadecimalInteger = 0x11   // 17 in hexadecimal notation

Literales de coma flotante

Un literal de coma flotante tiene una parte entera, una coma decimal, una parte fraccionaria y una parte exponente. Puede representar literales de coma flotante en forma decimal o hexadecimal.

Los literales decimales de coma flotante consisten en una secuencia de dígitos decimales seguidos de una fracción decimal, un exponente decimal o ambos.

Los literales hexadecimales de coma flotante constan de un prefijo 0x, seguido de una fracción hexadecimal opcional, seguida de un exponente hexadecimal.

Aquí hay algunos ejemplos de literales de punto flotante:

let decimalDouble = 12.1875
let exponentDouble = 1.21875e1
let hexadecimalDouble = 0xC.3p0

Literales de cadena

Un literal de cadena es una secuencia de caracteres rodeada de comillas dobles, con la siguiente forma:

"characters"

Los literales de cadena no pueden contener comillas dobles sin escape ("), una barra invertida sin escape (\), un retorno de carro o un salto de línea. Se pueden incluir caracteres especiales en los literales de cadena mediante las siguientes secuencias de escape:

Secuencia de escape Sentido
\ 0 Carácter nulo
\\ \personaje
\segundo Retroceso
\F Alimentación de formulario
\norte Nueva línea
\ r Retorno de carro
\ t Pestaña horizontal
\ v Pestaña vertical
\ ' Una frase
\ " Cotización doble
\ 000 Número octal de uno a tres dígitos
\ xhh ... Número hexadecimal de uno o más dígitos

El siguiente ejemplo muestra cómo utilizar algunos literales de cadena:

let stringL = "Hello\tWorld\n\nHello\'Swift 4\'"
print(stringL)

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Hello World

Hello'Swift 4'

Literales booleanos

Hay tres literales booleanos y forman parte de las palabras clave estándar de Swift 4:

  • Un valor de true representando verdadero.

  • Un valor de false representando falso.

  • Un valor de nil representando ningún valor.

Un operador es un símbolo que le dice al compilador que realice manipulaciones matemáticas o lógicas específicas. Objective-C es rico en operadores integrados y proporciona los siguientes tipos de operadores:

  • Operadores aritméticos
  • Operadores de comparación
  • Operadores logicos
  • Operadores bit a bit
  • Operadores de Asignación
  • Operadores de rango
  • Operadores varios

Este tutorial explicará los operadores aritméticos, relacionales, lógicos, bit a bit, de asignación y otros, uno por uno.

Operadores aritméticos

La siguiente tabla muestra todos los operadores aritméticos compatibles con el lenguaje Swift 4. Asumir variableA tiene 10 y variable B tiene 20, entonces -

Operador Descripción Ejemplo
+ Agrega dos operandos A + B dará 30
- Resta el segundo operando del primero A - B dará -10
* Multiplica ambos operandos A * B dará 200
/ Divide el numerador por el denominador B / A dará 2
% Operador de módulo y resto de después de una división entera / flotante B% A dará 0

Operadores de comparación

La siguiente tabla muestra todos los operadores relacionales compatibles con el lenguaje Swift 4. Asumir variableA tiene 10 y variable B tiene 20, entonces -

Operador Descripción Ejemplo
== Comprueba si los valores de dos operandos son iguales o no; si es así, entonces la condición se vuelve verdadera. (A == B) no es cierto.
! = Comprueba si los valores de dos operandos son iguales o no; si los valores no son iguales, la condición se cumple. (A! = B) es cierto.
> Comprueba si el valor del operando izquierdo es mayor que el valor del operando derecho; si es así, entonces la condición se vuelve verdadera. (A> B) no es cierto.
< Comprueba si el valor del operando izquierdo es menor que el valor del operando derecho; si es así, entonces la condición se vuelve verdadera. (A <B) es cierto.
> = Comprueba si el valor del operando izquierdo es mayor o igual que el valor del operando derecho; si es así, entonces la condición se vuelve verdadera. (A> = B) no es cierto.
<= Comprueba si el valor del operando izquierdo es menor o igual que el valor del operando derecho; si es así, entonces la condición se vuelve verdadera. (A <= B) es cierto.

Operadores logicos

La siguiente tabla muestra todos los operadores lógicos compatibles con el lenguaje Swift 4. Asumir variableA contiene 1 y variable B tiene 0, entonces -

Operador Descripción Ejemplo
&& Operador llamado lógico AND. Si ambos operandos son distintos de cero, la condición se cumple. (A && B) es falso.
|| Operador OR lógico llamado. Si alguno de los dos operandos es distinto de cero, la condición se cumple. (A || B) es cierto.
! Operador llamado lógico NOT. Úselo para revertir el estado lógico de su operando. Si una condición es verdadera, entonces el operador lógico NOT la convertirá en falsa. ! (A && B) es cierto.

Operadores bit a bit

Los operadores bit a bit trabajan en bits y realizan operaciones bit a bit. Las tablas de verdad para &, | y ^ son las siguientes:

pags q p & q p | q p ^ q
0 0 0 0 0
0 1 0 1 1
1 1 1 1 0
1 0 0 1 1
Assume A = 60; and B = 13;

In binary format, they will be as follows:

A = 0011 1100

B = 0000 1101

-----------------

A & B = 0000 1100

A|B = 0011 1101

A^B = 0011 0001

~A = 1100 0011

Los operadores bit a bit compatibles con el idioma Swift 4 se enumeran en la siguiente tabla. Asumir variableA tiene 60 y variable B tiene 13, luego 7−

Operador Descripción Ejemplo
Y El operador AND binario copia un bit al resultado, si existe en ambos operandos. (A & B) dará 12, que es 0000 1100
| El operador OR binario copia un bit, si existe en cualquiera de los operandos. (A | B) dará 61, que es 0011 1101
^ El operador binario XOR copia el bit, si está establecido en un operando pero no en ambos. (A ^ B) dará 49, que es 0011 0001
~ El operador de complemento binario es unario y tiene el efecto de "voltear" bits. (~ A) dará -61, que es 1100 0011 en forma de complemento a 2.
<< Operador binario de cambio a la izquierda. El valor de los operandos de la izquierda se mueve a la izquierda el número de bits especificado por el operando de la derecha. (A << 2 dará 240, que es 1111 0000
>> Operador de cambio a la derecha binario. El valor de los operandos de la izquierda se mueve hacia la derecha el número de bits especificado por el operando de la derecha. A >> 2 dará 15, que es 0000 1111

Operadores de Asignación

SSwift 4 admite los siguientes operadores de asignación:

Operador Descripción Ejemplo
= Operador de asignación simple, asigna valores de los operandos del lado derecho al operando del lado izquierdo C = A + B asignará el valor de A + B en C
+ = Agregar operador de asignación Y, agrega el operando derecho al operando izquierdo y asigna el resultado al operando izquierdo C + = A es equivalente a C = C + A
- = Restar operador de asignación AND, resta el operando derecho del operando izquierdo y asigna el resultado al operando izquierdo C - = A es equivalente a C = C - A
* = Operador de asignación de multiplicar Y, multiplica el operando derecho con el operando izquierdo y asigna el resultado al operando izquierdo C * = A es equivalente a C = C * A
/ = Operador de división Y asignación, divide el operando izquierdo con el operando derecho y asigna el resultado al operando izquierdo C / = A es equivalente a C = C / A
% = Operador de asignación de módulo Y, toma el módulo usando dos operandos y asigna el resultado al operando izquierdo C% = A es equivalente a C = C% A
<< = Operador de desplazamiento Y asignación a la izquierda C << = 2 es lo mismo que C = C << 2
>> = Operador de desplazamiento Y asignación a la derecha C >> = 2 es lo mismo que C = C >> 2
& = Operador de asignación AND bit a bit C & = 2 es lo mismo que C = C & 2
^ = Operador de asignación y OR exclusivo bit a bit C ^ = 2 es lo mismo que C = C ^ 2
| = OR inclusivo bit a bit y operador de asignación C | = 2 es lo mismo que C = C | 2

Operadores de rango

Swift 4 incluye dos operadores de rango, que son atajos para expresar un rango de valores. La siguiente tabla explica estos dos operadores.

Operador Descripción Ejemplo
Rango cerrado (a ... b) define un rango que va desde a hasta b, e incluye los valores ay b. 1 ... 5 da 1, 2, 3, 4 y 5
Gama semiabierta (a .. <b) define un rango que va desde a hasta b, pero no incluye b. 1 .. <5 da 1, 2, 3 y 4
Rango unilateral

a…, define un rango que va desde un hasta el final de los elementos

… A, define un rango desde el principio hasta un

1 ... da 1, 2,3 ... final de elementos

... 2 da comienzo ... a 1,2

Operadores varios

Swift 4 admite algunos otros operadores importantes, incluidos rangey : que se explican en la siguiente tabla.

Operador Descripción Ejemplo
Unario menos El signo de un valor numérico se puede alternar con un prefijo - -3 o -4
Unario Plus Devuelve el valor sobre el que opera, sin ningún cambio. +6 da 6
Condicional ternario ¿Condición? X: Y ¿Si la condición es verdadera? Entonces valor X: De lo contrario valor Y

Precedencia de operadores

La precedencia del operador determina la agrupación de términos en una expresión. Esto afecta cómo se evalúa una expresión. Ciertos operadores tienen mayor precedencia que otros; por ejemplo, el operador de multiplicación tiene mayor precedencia que el operador de suma.

Por ejemplo, x = 7 + 3 * 2; aquí, a x se le asigna 13, no 20 porque el operador * tiene mayor precedencia que +, por lo que primero se multiplica por 3 * 2 y luego se suma a 7.

Aquí, los operadores con mayor precedencia aparecen en la parte superior de la tabla, los que tienen la menor prioridad aparecen en la parte inferior. Dentro de una expresión, los operadores de mayor precedencia se evaluarán primero.

Operador Descripción Ejemplo
Operadores de expresión primaria () []. expr ++ expr-- de izquierda a derecha
Operadores unarios

* & + -! ~ ++ expr --expr

* /%

+ -

>> <<

<> <=> =

==! =

De derecha a izquierda
Operadores binarios

Y

^

|

&&

||

de izquierda a derecha
Operador ternario ?: De derecha a izquierda
Operadores de Asignación = + = - = * = / =% = >> = << = & = ^ = | = De derecha a izquierda
Coma , de izquierda a derecha

Las estructuras de toma de decisiones requieren que el programador especifique una o más condiciones para ser evaluadas o probadas por el programa, junto con una declaración o declaraciones que se ejecutarán si se determina que la condición es truey, opcionalmente, otras sentencias que se ejecutarán si se determina que la condición es false.

A continuación se muestra la forma general de una estructura de toma de decisiones típica que se encuentra en la mayoría de los lenguajes de programación:

Swift 4 proporciona los siguientes tipos de declaraciones para la toma de decisiones. Haga clic en los siguientes enlaces para verificar su detalle.

No Señor Declaración y descripción
1 si declaración

Una instrucción if consta de una expresión booleana seguida de una o más declaraciones.

2 declaración if ... else

Una instrucción if puede ir seguida de una instrucción else opcional, que se ejecuta cuando la expresión booleana es falsa.

3 if ... else if ... else Statement

Una instrucción if puede ir seguida de una instrucción else if ... else opcional, que es muy útil para probar varias condiciones utilizando una instrucción if ... else if.

4 declaraciones if anidadas

Puede usar una instrucción if o else if dentro de otra instrucción if o else if.

5 declaración de cambio

Una instrucción de cambio permite probar la igualdad de una variable con una lista de valores.

Los ? : Operador

Nosotros hemos cubierto conditional operator ? : en el capítulo anterior que se puede utilizar para reemplazar if...elsedeclaraciones. Tiene la siguiente forma general:

Exp1 ? Exp2 : Exp3;

Donde Exp1, Exp2 y Exp3 son expresiones. Observe el uso y la ubicación del colon.

¿El valor de un? La expresión se determina así: Se evalúa Exp1. Si es cierto, entonces Exp2 se evalúa y se convierte en el valor de la totalidad? expresión. Si Exp1 es falso, entonces se evalúa Exp3 y su valor se convierte en el valor de la expresión.

Puede haber una situación en la que necesite ejecutar un bloque de código varias veces. En general, las sentencias se ejecutan secuencialmente: la primera sentencia de una función se ejecuta primero, seguida de la segunda, y así sucesivamente.

Los lenguajes de programación proporcionan varias estructuras de control que permiten rutas de ejecución más complicadas.

Una declaración de bucle nos permite ejecutar una declaración o grupo de declaraciones varias veces. A continuación se muestra la forma general de una declaración de bucle en la mayoría de los lenguajes de programación:

El lenguaje de programación Swift 4 proporciona los siguientes tipos de bucle para manejar los requisitos de bucle. Haga clic en los siguientes enlaces para verificar su detalle.

No Señor Tipo de bucle y descripción
1 for-in

Este ciclo realiza un conjunto de declaraciones para cada elemento en un rango, secuencia, colección o progresión.

2 while loop

Repite una declaración o un grupo de declaraciones mientras una condición determinada es verdadera. Prueba la condición antes de ejecutar el cuerpo del bucle.

3 repetir ... mientras bucle

Como una instrucción while, excepto que prueba la condición al final del cuerpo del bucle.

Declaraciones de control de bucle

Las sentencias de control de bucle cambian la ejecución de su secuencia normal. Cuando la ejecución abandona un ámbito, todos los objetos automáticos que se crearon en ese ámbito se destruyen.

Swift 4 admite las siguientes declaraciones de control. Haga clic en los siguientes enlaces para verificar su detalle.

No Señor Declaración de control y descripción
1 Continuar declaración

Esta declaración le dice a un bucle que detenga lo que está haciendo y comience de nuevo al comienzo de la siguiente iteración a través del bucle.

2 declaración de ruptura

Termina la instrucción de bucle y transfiere la ejecución a la instrucción que sigue inmediatamente al bucle.

3 declaración fallida

La declaración fallthrough simula el comportamiento del cambio Swift 4 al cambio de estilo C.

Las cadenas en Swift 4 son una colección ordenada de caracteres, como "¡Hola, mundo!" y están representados por el tipo de datos Swift 4String, que a su vez representa una colección de valores de Character tipo.

Crear una cadena

Puede crear una cadena utilizando un literal de cadena o creando una instancia de una clase de cadena de la siguiente manera:

// String creation using String literal
var stringA = "Hello, Swift 4!"
print( stringA )

// String creation using String instance
var stringB = String("Hello, Swift 4!")
print( stringB )

//Multiple line string

let stringC = """
Hey this is a
example of multiple Line
string by tutorialsPoint 

"""
print(stringC)

Cuando el código anterior se compila y ejecuta, produce el siguiente resultado

Hello, Swift 4!
Hello, Swift 4!
Hey this is a
example of multiple Line
string by tutorialsPoint

Cuerda vacía

Puede crear una cadena vacía utilizando un literal de cadena vacía o creando una instancia de la clase String como se muestra a continuación. También puede verificar si una cadena está vacía o no usando la propiedad booleanaisEmpty.

// Empty string creation using String literal
var stringA = ""

if stringA.isEmpty {
   print( "stringA is empty" )
} else {
   print( "stringA is not empty" )
}

// Empty string creation using String instance
let stringB = String()

if stringB.isEmpty {
   print( "stringB is empty" )
} else {
   print( "stringB is not empty" )
}

Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:

stringA is empty
stringB is empty

Constantes de cadena

Puede especificar si su cadena se puede modificar (o mutar) asignándola a una variable, o será constante asignándola a una constante usando let palabra clave como se muestra a continuación -

// stringA can be modified
var stringA = "Hello, Swift 4!"
stringA + = "--Readers--"
print( stringA )

// stringB can not be modified
let stringB = String("Hello, Swift 4!")
stringB + = "--Readers--"
print( stringB )

Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:

Playground execution failed: error: <EXPR>:10:1: error: 'String' is not
convertible to '@lvalue UInt8'
stringB + = "--Readers--"

Interpolación de cadenas

La interpolación de cadenas es una forma de construir un nuevo valor de cadena a partir de una combinación de constantes, variables, literales y expresiones al incluir sus valores dentro de una cadena literal.

Cada elemento (variable o constante) que inserta en el literal de cadena está envuelto en un par de paréntesis, precedido por una barra invertida. Aquí hay un ejemplo simple:

var varA = 20
let constA = 100
var varC:Float = 20.0

var stringA = "\(varA) times \(constA) is equal to \(varC * 100)"
print( stringA )

Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:

20 times 100 is equal to 2000.0

Concatenación de cadenas

Puede utilizar el operador + para concatenar dos cadenas o una cadena y un carácter, o dos caracteres. Aquí hay un ejemplo simple:

let constA = "Hello,"
let constB = "World!"

var stringA = constA + constB
print( stringA )

Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:

Hello,World!

Longitud de la cuerda

Swift 4 cuerdas no tienen lengthpropiedad, pero puede usar la función global count () para contar el número de caracteres en una cadena. Aquí hay un ejemplo simple:

var varA = "Hello, Swift 4!"

print( "\(varA), length is \((varA.count))" )

Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:

Hello, Swift 4!, length is 15

Comparación de cadenas

Puede utilizar el operador == para comparar dos cadenas de variables o constantes. Aquí hay un ejemplo simple:

var varA = "Hello, Swift 4!"
var varB = "Hello, World!"

if varA == varB {
   print( "\(varA) and \(varB) are equal" )
} else {
   print( "\(varA) and \(varB) are not equal" )
}

Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:

Hello, Swift 4! and Hello, World! are not equal

Iterando cadena

Las cadenas son nuevamente una colección de valores en swift 4, por lo que podemos iterar sobre cadenas usando bucles. -

for chars in "ThisString" {
   print(chars, terminator: " ")
}

Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:

T h i s S t r i n g

Cadenas Unicode

Puede acceder a una representación UTF-8 y UTF-16 de una cadena iterando sobre sus propiedades utf8 y utf16 como se demuestra en el siguiente ejemplo:

var unicodeString = "Dog???"

print("UTF-8 Codes: ")
for code in unicodeString.utf8 {
   print("\(code) ")
}

print("\n")

print("UTF-16 Codes: ")
for code in unicodeString.utf16 {
   print("\(code) ")
}

Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:

UTF-8 Codes: 
68 
111 
103 
63 
63 
63 


UTF-16 Codes: 
68 
111 
103 
63 
63 
63

Funciones y operadores de cadenas

Swift 4 admite una amplia gama de métodos y operadores relacionados con Strings:

No Señor Funciones / Operadores y propósito
1

isEmpty

Un valor booleano que determina si una cadena está vacía o no.

2

hasPrefix(prefix: String)

Función para comprobar si una determinada cadena de parámetros existe como prefijo de la cadena o no.

3

hasSuffix(suffix: String)

Función para comprobar si una determinada cadena de parámetros existe como sufijo de la cadena o no.

4

toInt()

Función para convertir un valor de cadena numérico en entero.

5

count()

Función global para contar el número de caracteres en una cadena.

6

utf8

Propiedad para devolver una representación UTF-8 de una cadena.

7

utf16

Propiedad para devolver una representación UTF-16 de una cadena.

8

unicodeScalars

Propiedad para devolver una representación escalar Unicode de una cadena.

9

+

Operador para concatenar dos cadenas, o una cadena y un carácter, o dos caracteres.

10

+=

Operador para agregar una cadena o carácter a una cadena existente.

11

==

Operador para determinar la igualdad de dos cadenas.

12

<

Operador para realizar una comparación lexicográfica para determinar si una cadena se evalúa como menor que otra.

13

startIndex

Para obtener el valor en el índice inicial de la cadena.

14

endIndex

Para obtener el valor en el índice final de la cadena.

15

Indices

Para acceder a los índices uno a uno. es decir, todos los caracteres de la cadena uno por uno.

dieciséis

insert("Value", at: position)

Para insertar un valor en una posición.

17

remove(at: position)

removeSubrange(range)

para eliminar un valor en una posición o para eliminar un rango de valores de la cadena.

18

reversed()

devuelve el reverso de una cadena

UN character en Swift es un literal de cadena de un solo carácter, dirigido por el tipo de datos Character. Eche un vistazo al siguiente ejemplo. Utiliza dos constantes de caracteres:

let char1: Character = "A"
let char2: Character = "B"

print("Value of char1 \(char1)")
print("Value of char2 \(char2)")

Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:

Value of char1 A
Value of char2 B

Si intenta almacenar más de un carácter en una variable o constante de tipo carácter, Swift 4 no lo permitirá. Intente escribir el siguiente ejemplo en Swift 4 Playground y obtendrá un error incluso antes de la compilación.

// Following is wrong in Swift 4
let char: Character = "AB"

print("Value of char \(char)")

Variables de caracteres vacías

No es posible crear una constante o variable de carácter vacía que tendrá un valor vacío. La siguiente sintaxis no es posible:

// Following is wrong in Swift 4
let char1: Character = ""
var char2: Character = ""

print("Value of char1 \(char1)")
print("Value of char2 \(char2)")

Accediendo a caracteres desde cadenas

Como se explicó al analizar las cadenas de Swift 4, String representa una colección de valores de caracteres en un orden específico. Entonces podemos acceder a caracteres individuales de la Cadena dada iterando sobre esa cadena con unfor-in bucle -

for ch in "Hello" {
   print(ch)
}

Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:

H
e
l
l
o

Concatenación de cadenas con caracteres

El siguiente ejemplo demuestra cómo se puede concatenar el personaje de Swift 4 con String de Swift 4.

var varA:String = "Hello "
let varB:Character = "G"

varA.append( varB )

print("Value of varC = \(varA)")

Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:

Value of varC = Hello G

Las matrices Swift 4 se utilizan para almacenar listas ordenadas de valores del mismo tipo. Swift 4 pone un control estricto que no le permite ingresar un tipo incorrecto en una matriz, incluso por error.

Si asigna una matriz creada a una variable, siempre será mutable, lo que significa que puede cambiarla agregando, eliminando o cambiando sus elementos; pero si asigna una matriz a una constante, esa matriz es inmutable y su tamaño y contenido no se pueden cambiar.

Crear matrices

Puede crear una matriz vacía de un cierto tipo utilizando la siguiente sintaxis de inicializador:

var someArray = [SomeType]()

Aquí está la sintaxis para crear una matriz de un tamaño dado a * e inicializarla con un valor:

var someArray = [SomeType](count: NumbeOfElements, repeatedValue: InitialValue)

Puede utilizar la siguiente declaración para crear una matriz vacía de Int tipo que tiene 3 elementos y el valor inicial como cero -

var someInts = [Int](count: 3, repeatedValue: 0)

A continuación se muestra un ejemplo más para crear una matriz de tres elementos y asignar tres valores a esa matriz:

var someInts:[Int] = [10, 20, 30]

Acceso a matrices

Puede recuperar un valor de una matriz utilizando subscript sintaxis, pasando el índice del valor que desea recuperar entre corchetes inmediatamente después del nombre de la matriz de la siguiente manera:

var someVar = someArray[index]

Aquí el indexcomienza desde 0, lo que significa que se puede acceder al primer elemento usando el índice como 0, se puede acceder al segundo elemento usando el índice como 1 y así sucesivamente. El siguiente ejemplo muestra cómo crear, inicializar y acceder a matrices:

var someInts = [Int](count: 3, repeatedValue: 10)

var someVar = someInts[0]
print( "Value of first element is \(someVar)" )
print( "Value of second element is \(someInts[1])" )
print( "Value of third element is \(someInts[2])" )

Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:

Value of first element is 10
Value of second element is 10
Value of third element is 10

Modificar matrices

Puedes usar append()método u operador de asignación de adición (+ =) para agregar un nuevo elemento al final de una matriz. Eche un vistazo al siguiente ejemplo. Aquí, inicialmente, creamos una matriz vacía y luego agregamos nuevos elementos a la misma matriz:

var someInts = [Int]()

someInts.append(20)
someInts.append(30)
someInts += [40]

var someVar = someInts[0]

print( "Value of first element is \(someVar)" )
print( "Value of second element is \(someInts[1])" )
print( "Value of third element is \(someInts[2])" )

Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:

Value of first element is 20
Value of second element is 30
Value of third element is 40

Puede modificar un elemento existente de una matriz asignando un nuevo valor a un índice determinado como se muestra en el siguiente ejemplo:

var someInts = [Int]()

someInts.append(20)
someInts.append(30)
someInts += [40]

// Modify last element
someInts[2] = 50

var someVar = someInts[0]

print( "Value of first element is \(someVar)" )
print( "Value of second element is \(someInts[1])" )
print( "Value of third element is \(someInts[2])" )

Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:

Value of first element is 20
Value of second element is 30
Value of third element is 50

Iterando sobre una matriz

Puedes usar for-in bucle para iterar sobre todo el conjunto de valores en una matriz como se muestra en el siguiente ejemplo:

var someStrs = [String]()

someStrs.append("Apple")
someStrs.append("Amazon")
someStrs += ["Google"]
for item in someStrs {
   print(item)
}

Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:

Apple
Amazon
Google

Puedes usar enumerate() función que devuelve el índice de un elemento junto con su valor como se muestra a continuación en el siguiente ejemplo:

var someStrs = [String]()

someStrs.append("Apple")
someStrs.append("Amazon")
someStrs += ["Google"]

for (index, item) in someStrs.enumerated() {
   print("Value at index = \(index) is \(item)")
}

Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:

Value at index = 0 is Apple
Value at index = 1 is Amazon
Value at index = 2 is Google

Agregar dos matrices

Puede usar el operador de suma (+) para agregar dos matrices del mismo tipo que producirán una nueva matriz con una combinación de valores de las dos matrices de la siguiente manera:

var intsA = [Int](count:2, repeatedValue: 2)
var intsB = [Int](count:3, repeatedValue: 1)

var intsC = intsA + intsB
for item in intsC {
   print(item)
}

Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:

2
2
1
1
1

La propiedad del recuento

Puede utilizar el modo de solo lectura count propiedad de una matriz para averiguar el número de elementos en una matriz que se muestra a continuación:

var intsA = [Int](count:2, repeatedValue: 2)
var intsB = [Int](count:3, repeatedValue: 1)

var intsC = intsA + intsB

print("Total items in intsA = \(intsA.count)")
print("Total items in intsB = \(intsB.count)")
print("Total items in intsC = \(intsC.count)")

Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:

Total items in intsA = 2
Total items in intsB = 3
Total items in intsC = 5

La propiedad vacía

Puede utilizar el modo de solo lectura empty propiedad de una matriz para averiguar si una matriz está vacía o no, como se muestra a continuación:

var intsA = [Int](count:2, repeatedValue: 2)
var intsB = [Int](count:3, repeatedValue: 1)
var intsC = [Int]()

print("intsA.isEmpty = \(intsA.isEmpty)")
print("intsB.isEmpty = \(intsB.isEmpty)")
print("intsC.isEmpty = \(intsC.isEmpty)")

Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:

intsA.isEmpty = false
intsB.isEmpty = false
intsC.isEmpty = true

Rápido 4 sets se utilizan para almacenar valores distintos de los mismos tipos pero no tienen un orden definido como lo tienen las matrices.

Puede usar conjuntos en lugar de matrices si el orden de los elementos no es un problema o si desea asegurarse de que no haya valores duplicados. (los conjuntos permiten solo valores distintos).

Un tipo debe ser hash para ser almacenado en un conjunto. Un valor hash es un valor Int que es igual para objetos iguales. Por ejemplo, si x == y, entoncesx.hashvalue == y.hashvalue.

Todos los valores rápidos básicos son de tipo hash de forma predeterminada y se pueden usar como valores establecidos.

Creando Conjuntos

Puede crear un conjunto vacío de un cierto tipo utilizando la siguiente sintaxis de inicializador:

var someSet = Set<Character>()     //Character can be replaced by data type of set.

Acceder y modificar conjuntos

Puede acceder o modificar un conjunto utilizando sus métodos y propiedades:

El método "count" se puede utilizar para mostrar el número de elementos del conjunto.

someSet.count        // prints the number of elements

El método "insertar" se puede utilizar para insertar valores en el conjunto.

someSet.insert("c")   // adds the element to Set.

De manera similar, isEmpty se puede usar para verificar si el conjunto está vacío.

someSet.isEmpty       // returns true or false depending on the set Elements.

El método "eliminar" se puede utilizar para eliminar el valor del conjunto.

someSet.remove("c")     // removes a element , removeAll() can be used to remove all elements

El método "contiene" se puede utilizar para comprobar la existencia de valor en un conjunto.

someSet.contains("c")     // to check if set contains this value.

Iterando sobre un conjunto

Puede iterar sobre un conjunto usando el bucle for-in -

for items in someSet {
   print(someSet)
}

//Swift sets are not in an ordered way, to iterate over a set in ordered way use

for items in someSet.sorted() {
   print(someSet)
}

Realización de operaciones de set

Puede realizar operaciones básicas de conjuntos en conjuntos rápidos.

A continuación se muestran los métodos para realizar operaciones de conjuntos:

  • Intersection
  • Union
  • subtracting
let evens: Set = [10,12,14,16,18]
let odds: Set = [5,7,9,11,13]
let primes = [2,3,5,7]
odds.union(evens).sorted()
// [5,7,9,10,11,12,13,14,16,18]
odds.intersection(evens).sorted()
//[]
odds.subtracting(primes).sorted()
//[9, 11, 13]

Rápido 4 dictionariesse utilizan para almacenar listas desordenadas de valores del mismo tipo. Swift 4 realiza un control estricto que no le permite ingresar un tipo incorrecto en un diccionario, incluso por error.

Los diccionarios Swift 4 utilizan un identificador único conocido como keypara almacenar un valor que luego se puede referenciar y buscar a través de la misma clave. A diferencia de los elementos de una matriz, los elementos de unadictionaryno tiene un pedido específico. Puedes usar undictionary cuando necesite buscar valores basados ​​en sus identificadores.

Una clave de diccionario puede ser un número entero o una cadena sin restricción, pero debe ser única dentro de un diccionario.

Si asigna un diccionario creado a una variable, siempre será mutable, lo que significa que puede cambiarlo agregando, quitando o cambiando sus elementos. Pero si asigna un diccionario a una constante, ese diccionario es inmutable y su tamaño y contenido no se pueden cambiar.

Crear diccionario

Puede crear un diccionario vacío de un determinado tipo utilizando la siguiente sintaxis de inicializador:

var someDict = [KeyType: ValueType]()

Puede utilizar la siguiente sintaxis simple para crear un diccionario vacío cuya clave será de tipo Int y los valores asociados serán cadenas:

var someDict = [Int: String]()

Aquí hay un ejemplo para crear un diccionario a partir de un conjunto de valores dados:

var someDict:[Int:String] = [1:"One", 2:"Two", 3:"Three"]

Inicialización basada en secuencia

Swift 4 le permite crear diccionarios a partir de matrices (pares clave-valor).

var cities = [“Delhi”,”Bangalore”,”Hyderabad”]

Puede utilizar la siguiente sintaxis simple para crear un diccionario vacío cuya clave será de tipo Int y los valores asociados serán cadenas:

var Distance = [2000,10, 620]

Aquí hay un ejemplo para crear un diccionario a partir de un conjunto de valores dados:

let cityDistanceDict = Dictionary(uniqueKeysWithValues: zip(cities, Distance))

Las líneas de código anteriores crearán un diccionario con Ciudades como clave y Distancia como Valor -

Filtración

Swift 4 le permite filtrar valores de un diccionario.

var closeCities = cityDistanceDict.filter { $0.value < 1000 }

Si ejecutamos el código anterior, nuestro diccionario closeCities será.

["Bangalore" : 10 , "Hyderabad" : 620]

Agrupación de diccionario

Swift 4 le permite crear agrupaciones de valores de diccionario.

var cities = ["Delhi","Bangalore","Hyderabad","Dehradun","Bihar"]

Puede utilizar la siguiente sintaxis simple para agrupar los valores del diccionario según el primer alfabeto.

var GroupedCities = Dictionary(grouping: cities ) { $0.first! }

El resultado del código anterior será

["D" :["Delhi","Dehradun"], "B" : ["Bengaluru","Bihar"], "H" : ["Hyderabad"]]

Acceder a diccionarios

Puede recuperar un valor de un diccionario utilizando la sintaxis de subíndice, pasando la clave del valor que desea recuperar entre corchetes inmediatamente después del nombre del diccionario de la siguiente manera:

var someVar = someDict[key]

Veamos el siguiente ejemplo para crear, inicializar y acceder a valores desde un diccionario:

var someDict:[Int:String] = [1:"One", 2:"Two", 3:"Three"]
var someVar = someDict[1]

print( "Value of key = 1 is \(someVar)" )
print( "Value of key = 2 is \(someDict[2])" )
print( "Value of key = 3 is \(someDict[3])" )

Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:

Value of key = 1 is Optional("One")
Value of key = 2 is Optional("Two")
Value of key = 3 is Optional("Three")

Modificar diccionarios

Puedes usar updateValue(forKey:)método para agregar un valor existente a una clave dada del diccionario. Este método devuelve un valor opcional del tipo de valor del diccionario. Aquí hay un ejemplo simple:

var someDict:[Int:String] = [1:"One", 2:"Two", 3:"Three"]
var oldVal = someDict.updateValue("New value of one", forKey: 1)
var someVar = someDict[1]

print( "Old value of key = 1 is \(oldVal)" )
print( "Value of key = 1 is \(someVar)" )
print( "Value of key = 2 is \(someDict[2])" )
print( "Value of key = 3 is \(someDict[3])" )

Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:

Old value of key = 1 is Optional("One")
Value of key = 1 is Optional("New value of one")
Value of key = 2 is Optional("Two")
Value of key = 3 is Optional("Three")

Puede modificar un elemento existente de un diccionario asignando un nuevo valor a una clave determinada, como se muestra en el siguiente ejemplo:

var someDict:[Int:String] = [1:"One", 2:"Two", 3:"Three"]
var oldVal = someDict[1]
someDict[1] = "New value of one"
var someVar = someDict[1]

print( "Old value of key = 1 is \(oldVal)" )
print( "Value of key = 1 is \(someVar)" )
print( "Value of key = 2 is \(someDict[2])" )
print( "Value of key = 3 is \(someDict[3])" )

Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:

Old value of key = 1 is Optional("One")
Value of key = 1 is Optional("New value of one")
Value of key = 2 is Optional("Two")
Value of key = 3 is Optional("Three")

Eliminar pares clave-valor

Puedes usar removeValueForKey()método para eliminar un par clave-valor de un diccionario. Este método elimina el par clave-valor si existe y devuelve el valor eliminado, o devuelve nil si no existía ningún valor. Aquí hay un ejemplo simple:

var someDict:[Int:String] = [1:"One", 2:"Two", 3:"Three"]
var removedValue = someDict.removeValue(forKey: 2)

print( "Value of key = 1 is \(someDict[1])" )
print( "Value of key = 2 is \(someDict[2])" )
print( "Value of key = 3 is \(someDict[3])" )

Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:

Value of key = 1 is Optional("One")
Value of key = 2 is nil
Value of key = 3 is Optional("Three")

También puede utilizar la sintaxis de subíndice para eliminar un par clave-valor de un diccionario asignando un valor de nilpara esa llave. Aquí hay un ejemplo simple:

var someDict:[Int:String] = [1:"One", 2:"Two", 3:"Three"]

someDict[2] = nil

print( "Value of key = 1 is \(someDict[1])" )
print( "Value of key = 2 is \(someDict[2])" )
print( "Value of key = 3 is \(someDict[3])" )

Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:

Value of key = 1 is Optional("One")
Value of key = 2 is nil
Value of key = 3 is Optional("Three")

Iterando sobre un diccionario

Puedes usar un for-in bucle para iterar sobre todo el conjunto de pares clave-valor en un diccionario, como se muestra en el siguiente ejemplo:

var someDict:[Int:String] = [1:"One", 2:"Two", 3:"Three"]

for (index, keyValue) in someDict.enumerated() {
   print("Dictionary key \(index) - Dictionary value \(keyValue)")
}

Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:

Dictionary key 2 - Dictionary value Two
Dictionary key 3 - Dictionary value Three
Dictionary key 1 - Dictionary value One

Puedes usar enumerate() función que devuelve el índice del elemento junto con su par (clave, valor) como se muestra a continuación en el ejemplo:

var someDict:[Int:String] = [1:"One", 2:"Two", 3:"Three"]
for (key, value) in someDict.enumerated() {
   print("Dictionary key \(key) - Dictionary value \(value)")
}

Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:

Dictionary key 0 - Dictionary value (key: 2, value: "Two")
Dictionary key 1 - Dictionary value (key: 3, value: "Three")
Dictionary key 2 - Dictionary value (key: 1, value: "One")

Convertir a matrices

Puede extraer una lista de pares clave-valor de un diccionario determinado para crear matrices separadas para claves y valores. Aquí hay un ejemplo:

var someDict:[Int:String] = [1:"One", 2:"Two", 3:"Three"]

let dictKeys = [Int](someDict.keys)
let dictValues = [String](someDict.values)

print("Print Dictionary Keys")

for (key) in dictKeys {
   print("\(key)")
}
print("Print Dictionary Values")

for (value) in dictValues {
   print("\(value)")
}

Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:

Print Dictionary Keys
2
3
1
Print Dictionary Values
Two
Three
One

La propiedad del recuento

Puede utilizar el modo de solo lectura count propiedad de un diccionario para averiguar el número de elementos en un diccionario como se muestra a continuación:

var someDict1:[Int:String] = [1:"One", 2:"Two", 3:"Three"]
var someDict2:[Int:String] = [4:"Four", 5:"Five"]

print("Total items in someDict1 = \(someDict1.count)")
print("Total items in someDict2 = \(someDict2.count)")

Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:

Total items in someDict1 = 3
Total items in someDict2 = 2

La propiedad vacía

Puedes usar solo lectura empty propiedad de un diccionario para averiguar si un diccionario está vacío o no, como se muestra a continuación:

var someDict1:[Int:String] = [1:"One", 2:"Two", 3:"Three"]
var someDict2:[Int:String] = [4:"Four", 5:"Five"]
var someDict3:[Int:String] = [Int:String]()

print("someDict1 = \(someDict1.isEmpty)")
print("someDict2 = \(someDict2.isEmpty)")
print("someDict3 = \(someDict3.isEmpty)")

Cuando el código anterior se compila y ejecuta, produce el siguiente resultado:

someDict1 = false
someDict2 = false
someDict3 = true

Una función es un conjunto de declaraciones organizadas juntas para realizar una tarea específica. Una función Swift 4 puede ser tan simple como una función C simple o tan compleja como una función del lenguaje Objective C. Nos permite pasar valores de parámetros locales y globales dentro de las llamadas a funciones.

  • Function Declaration - le dice al compilador sobre el nombre de una función, el tipo de retorno y los parámetros.

  • Function Definition - Proporciona el cuerpo real de la función.

Las funciones de Swift 4 contienen el tipo de parámetro y sus tipos de retorno.

Definición de función

En Swift 4, una función se define mediante la palabra clave "func". Cuando una función se define recientemente, puede tomar uno o varios valores como 'parámetros' de entrada para la función y procesará las funciones en el cuerpo principal y devolverá los valores a las funciones como 'tipos de retorno' de salida.

Cada función tiene un nombre de función, que describe la tarea que realiza la función. Para usar una función, "llama" a esa función con su nombre y pasa valores de entrada (conocidos como argumentos) que coinciden con los tipos de parámetros de la función. Los parámetros de función también se denominan "tuplas".

Los argumentos de una función siempre deben proporcionarse en el mismo orden que la lista de parámetros de la función y los valores de retorno van seguidos de →.

Sintaxis

func funcname(Parameters) -> returntype {
   Statement1
   Statement2
   ---
   Statement N
   return parameters
}

Eche un vistazo al siguiente código. El nombre del estudiante se declara como un tipo de datos de cadena declarado dentro de la función 'estudiante' y cuando se llama a la función, devolverá el nombre del estudiante.

func student(name: String) -> String {
   return name
}

print(student(name: "First Program"))
print(student(name: "About Functions"))

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

First Program
About Functions

Llamar a una función

Supongamos que definimos una función llamada 'pantalla' para considerar, por ejemplo, para mostrar los números, una función con el nombre de función 'pantalla' se inicializa primero con el argumento 'no1' que contiene el tipo de datos enteros. Luego, el argumento 'no1' se asigna al argumento 'a' que, en adelante, apuntará al mismo tipo de datos entero. Ahora el argumento 'a' se devuelve a la función. Aquí la función display () mantendrá el valor entero y devolverá los valores enteros cada vez que se invoca la función.

func display(no1: Int) -> Int {
   let a = no1
   return a
}

print(display(no1: 100))
print(display(no1: 200))

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

100
200

Parámetros y valores devueltos

Swift 4 proporciona parámetros de función flexibles y sus valores de retorno de valores simples a complejos. Al igual que en C y Objective C, las funciones en Swift 4 también pueden tomar varias formas.

Funciones con parámetros

Se accede a una función pasando los valores de sus parámetros al cuerpo de la función. Podemos pasar valores de parámetros individuales a múltiples como tuplas dentro de la función.

func mult(no1: Int, no2: Int) -> Int {
   return no1*no2
}

print(mult(no1: 2, no2: 20))
print(mult(no1: 3, no2: 15))
print(mult(no1: 4, no2: 30))

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

40
45
120

Funciones sin parámetros

También podemos tener funciones sin ningún parámetro.

Sintaxis

func funcname() -> datatype {
   return datatype
}

A continuación se muestra un ejemplo que tiene una función sin un parámetro:

func votersname() -> String {
   return "Alice"
}
print(votersname())

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Alice

Funciones con valores devueltos

Las funciones también se utilizan para devolver valores de tipo de datos de cadena, enteros y flotantes como tipos de retorno. Para encontrar el número más grande y más pequeño en una matriz dada, la función 'ls' se declara con tipos de datos enteros grandes y pequeños.

Una matriz se inicializa para contener valores enteros. Luego, la matriz se procesa y todos y cada uno de los valores de la matriz se leen y comparan con su valor anterior. Cuando el valor es menor que el anterior, se almacena en el argumento 'pequeño', de lo contrario, se almacena en el argumento 'grande' y los valores se devuelven llamando a la función.

func ls(array: [Int]) -> (large: Int, small: Int) {
   var lar = array[0]
   var sma = array[0]

   for i in array[1..<array.count] {
      if i < sma {
         sma = i
      } else if i > lar {
         lar = i
      }
   }
   return (lar, sma)
}

let num = ls(array: [40,12,-5,78,98])
print("Largest number is: \(num.large) and smallest number is: \(num.small)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Largest number is: 98 and smallest number is: -5

Funciones sin valores de retorno

Algunas funciones pueden tener argumentos declarados dentro de la función sin ningún valor de retorno. El siguiente programa declaraa y bcomo argumentos de la función sum (). dentro de la función misma los valores de los argumentosa y b se pasan invocando la función sum () y sus valores se imprimen eliminando así los valores de retorno.

func sum(a: Int, b: Int) {
   let a = a + b
   let b = a - b
   print(a, b)
}

sum(a: 20, b: 10)
sum(a: 40, b: 10)
sum(a: 24, b: 6)

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

30 20
50 40
30 24

Funciones con tipos de devolución opcionales

Swift 4 presenta una función 'opcional' para eliminar los problemas mediante la introducción de una medida de seguridad. Considere, por ejemplo, que estamos declarando el tipo de retorno de valores de función como entero, pero qué sucederá cuando la función devuelva un valor de cadena o un valor nulo. En ese caso, el compilador devolverá un valor de error. Se introducen 'opcionales' para eliminar estos problemas.

Las funciones opcionales tomarán dos formas, 'valor' y 'nulo'. Mencionaremos 'Opcionales' con el carácter de clave reservada '?' para comprobar si la tupla devuelve un valor o un valor nulo.

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)
}

if let bounds = minMax(array: [8, -6, 2, 109, 3, 71]) {
   print("min is \(bounds.min) and max is \(bounds.max)")
}

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

min is -6 and max is 109

Los '' opcionales '' se utilizan para verificar valores 'nulos' o basura, lo que consume mucho tiempo en la depuración y hace que el código sea eficiente y legible para el usuario.

Funciones Nombres de parámetros locales versus externos

Nombres de parámetros locales

Se accede a los nombres de los parámetros locales solo dentro de la función.

func sample(number: Int) {
   print(number)
}

Aquí el funcEl número de argumento de muestra se declara como variable interna, ya que la función sample () accede a él internamente. Aquí el 'número' se declara como variable local, pero la referencia a la variable se hace fuera de la función con la siguiente declaración:

func sample(number: Int) {
   print(number)
}

sample(number: 1)
sample(number: 2)
sample(number: 3)

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

1
2
3

Nombres de parámetros externos

Los nombres de parámetros externos nos permiten nombrar parámetros de una función para que su propósito sea más claro. Por ejemplo, a continuación, puede nombrar dos parámetros de función y luego llamar a esa función de la siguiente manera:

func pow(firstArg a: Int, secondArg b: Int) -> Int {
   var res = a
   for _ in 1..<b {
      res = res * a
   }
   print(res)
   return res
}

pow(firstArg:5, secondArg:3)

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

125

Parámetros Variadic

Cuando queremos definir una función con varios argumentos, podemos declarar los miembros como parámetros 'variadic'. Los parámetros se pueden especificar como variables mediante (···) después del nombre del parámetro.

func vari<N>(members: N...){
   for i in members {
      print(i)
   }
}

vari(members: 4,3,5)
vari(members: 4.5, 3.1, 5.6)
vari(members: "Swift 4", "Enumerations", "Closures")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

4
3
5
4.5
3.1
5.6
Swift 4
Enumerations
Closures

Parámetros constantes, variables y de E / S

Las funciones por defecto consideran los parámetros como 'constantes', mientras que el usuario puede declarar los argumentos de las funciones también como variables. Ya discutimos que la palabra clave 'let' se usa para declarar parámetros constantes y los parámetros variables se definen con la palabra clave 'var'.

Los parámetros de E / S en Swift 4 brindan funcionalidad para retener los valores de los parámetros aunque sus valores se modifiquen después de la llamada a la función. Al comienzo de la definición del parámetro de función, se declara la palabra clave 'inout' para retener los valores de los miembros.

Deriva la palabra clave 'inout' ya que sus valores se pasan 'in' a la función y el cuerpo de la función accede y modifica sus valores y se devuelve 'out' de la función para modificar el argumento original.

Las variables solo se pasan como un argumento para el parámetro in-out, ya que solo sus valores se modifican dentro y fuera de la función. Por lo tanto, no es necesario declarar cadenas y literales como parámetros de entrada y salida. '&' antes de un nombre de variable se refiere a que estamos pasando el argumento al parámetro in-out.

func temp(a1: inout Int, b1: inout Int) {
   let t = a1
   a1 = b1
   b1 = t
}

var no = 2
var co = 10
temp(a1: &no, b1: &co)
print("Swapped values are \(no), \(co)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Swapped values are 10, 2

Tipos de funciones y su uso

Todas y cada una de las funciones siguen la función específica al considerar los parámetros de entrada y generan el resultado deseado.

func inputs(no1: Int, no2: Int) -> Int {
   return no1/no2
}

A continuación se muestra un ejemplo:

func inputs(no1: Int, no2: Int) -> Int {
   return no1/no2
}

print(inputs(no1: 20, no2: 10))
print(inputs(no1: 36, no2: 6))

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

2
6

Aquí la función se inicializa con dos argumentos no1 y no2 como tipos de datos enteros y su tipo de retorno también se declara como 'int'

Func inputstr(name: String) -> String {
   return name
}

Aquí la función se declara como string tipo de datos.

Las funciones también pueden tener void los tipos de datos y esas funciones no devolverán nada.

func inputstr() {
   print("Swift 4 Functions")
   print("Types and its Usage")
}
inputstr()

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Swift 4 Functions
Types and its Usage

La función anterior se declara como una función nula sin argumentos ni valores de retorno.

Uso de tipos de funciones

Las funciones se pasan primero con argumentos de tipo entero, flotante o de cadena y luego se pasan como constantes o variables a la función como se menciona a continuación.

var addition: (Int, Int) -> Int = sum

Aquí sum es un nombre de función que tiene variables enteras 'a' y 'b' que ahora se declara como una variable para la adición del nombre de la función. De ahora en adelante, tanto la función de suma como la función de suma tienen el mismo número de argumentos declarados como tipo de datos entero y también devuelven valores enteros como referencias.

func sum(a: Int, b: Int) -> Int {
   return a + b
}
var addition: (Int, Int) -> Int = sum
print("Result: \(addition(40, 89))")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Result: 129

Tipos de funciones como tipos de parámetros y tipos de retorno

También podemos pasar la función en sí como tipos de parámetros a otra función.

func sum(a: Int, b: Int) -> Int {
   return a + b
}
var addition: (Int, Int) -> Int = sum
print("Result: \(addition(40, 89))")

func another(addition: (Int, Int) -> Int, a: Int, b: Int) {
   print("Result: \(addition(a, b))")
}
another(sum, 10, 20)

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Result: 129
Result: 30

Funciones anidadas

Una función anidada proporciona la posibilidad de llamar a la función externa invocando la función interna.

func calcDecrement(forDecrement total: Int) -> () -> Int {
   var overallDecrement = 0
   func decrementer() -> Int {
      overallDecrement -= total
      return overallDecrement
   }
   return decrementer
}

let decrem = calcDecrement(forDecrement: 30)
print(decrem())

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

-30

Los cierres en Swift 4 son similares a los de las funciones autónomas organizadas como bloques y llamadas en cualquier lugar como los lenguajes C y Objective C. Las constantes y referencias de variables definidas dentro de las funciones se capturan y almacenan en cierres. Las funciones se consideran casos especiales de cierres y adoptan las tres formas siguientes:

Funciones globales Funciones anidadas Expresiones de cierre
Ten un nombre. No capture ningún valor Ten un nombre. Capturar valores de la función adjunta Los cierres sin nombre capturan valores de los bloques adyacentes

Las expresiones de cierre en el lenguaje Swift 4 siguen estilos de sintaxis nítidos, optimizados y ligeros que incluyen.

  • Inferir tipos de parámetros y valores de retorno del contexto.
  • Rendimientos implícitos de cierres de expresión única.
  • Nombres de argumentos taquigráficos y
  • Sintaxis de cierre final

Sintaxis

A continuación se muestra una sintaxis genérica para definir el cierre que acepta parámetros y devuelve un tipo de datos:

{
   (parameters) −> return type in
   statements
}

A continuación se muestra un ejemplo simple:

let studname = { print("Welcome to Swift Closures") }
studname()

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Welcome to Swift Closures

El siguiente cierre acepta dos parámetros y devuelve un valor bool:

{     
   (Int, Int) −> Bool in
   Statement1
   Statement 2
   ---
   Statement n
}

A continuación se muestra un ejemplo simple:

let divide = {
   (val1: Int, val2: Int) -> Int in 
   return val1 / val2 
}

let result = divide(200, 20)
print (result)

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

10

Expresiones en cierres

Las funciones anidadas proporcionan una forma conveniente de nombrar y definir bloques de código. En lugar de representar la declaración de función completa y las construcciones de nombre se utilizan para denotar funciones más cortas. La representación de la función en una declaración breve clara con sintaxis enfocada se logra a través de expresiones de cierre.

Programa de orden ascendente

La clasificación de una cadena se logra mediante la función reservada de teclas Swift 4s "sorted" que ya está disponible en la biblioteca estándar. La función ordenará las cadenas dadas en orden ascendente y devolverá los elementos en una nueva matriz con el mismo tamaño y tipo de datos mencionados en la matriz anterior. La matriz anterior sigue siendo la misma.

Dos argumentos están representados dentro de la función ordenada:

  • Valores de tipo conocido representados como matrices.

  • El contenido de la matriz (Int, Int) y devuelve un valor booleano (Bool) si la matriz está ordenada correctamente, devolverá un valor verdadero, de lo contrario, devolverá falso.

Una función normal con una cadena de entrada se escribe y se pasa a la función ordenada para ordenar las cadenas en la nueva matriz que se muestra a continuación:

func ascend(s1: String, s2: String) -> Bool {
   return s1 > s2
}

let stringcmp = ascend(s1: "Swift 4", s2: "great")
print (stringcmp)

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

true

La matriz inicial que se clasificará para el helado se indica como "Swift 4" y "excelente". La función para ordenar la matriz se declara como tipo de datos de cadena y su tipo de retorno se menciona como booleano. Ambas cadenas se comparan y clasifican en orden ascendente y se almacenan en una nueva matriz. Si la clasificación se realiza correctamente, la función devolverá un valor verdadero; de lo contrario, devolverá falso.

La sintaxis de la expresión de cierre utiliza:

  • parámetros constantes,
  • parámetros variables, y
  • parámetros inout.

La expresión de cierre no admitía valores predeterminados. Los parámetros variables y las tuplas también se pueden utilizar como tipos de parámetros y tipos de retorno.

let sum = {
   (no1: Int, no2: Int) -> Int in 
   return no1 + no2 
}

let digits = sum(10, 20)
print(digits)

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

30

Los parámetros y declaraciones de tipo de retorno que se mencionan en la declaración de la función también se pueden representar mediante la función de expresión de cierre en línea con la palabra clave 'in'. Una vez que se declaran los tipos de parámetro y retorno, la palabra clave 'in' se usa para indicar que el cuerpo del cierre.

Rendimientos implícitos de una sola expresión

Aquí, el tipo de función del segundo argumento de la función ordenada deja claro que el cierre debe devolver un valor Bool. Debido a que el cuerpo del cierre contiene una sola expresión (s1> s2) que devuelve un valor bool, no hay ambigüedad y la palabra clave return se puede omitir.

Para devolver una declaración de expresión única en cierres de expresión, se omite la palabra clave 'return' en su parte de declaración.

var count:[Int] = [5, 10, -6, 75, 20]
let descending = count.sorted(by: { n1, n2 in n1 > n2 })
let ascending = count.sorted(by: { n1, n2 in n1 < n2 })

print(descending)
print(ascending)

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

[75, 20, 10, 5, -6]
[-6, 5, 10, 20, 75]

La declaración en sí define claramente que cuando la cadena1 es mayor que la cadena 2, devuelve verdadero; de lo contrario, es falsa, por lo que se omite aquí la declaración de devolución.

Cierres de tipo conocido

Considere la suma de dos números. Sabemos que la suma devolverá el tipo de datos entero. Por lo tanto, los cierres de tipo conocido se declaran como:

let sub = {
   (no1: Int, no2: Int) -> Int in 
   return no1 - no2 
}

let digits = sub(10, 20)
print(digits)

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

-10

Declaración de nombres de argumentos taquigráficos como cierres

Swift 4 proporciona automáticamente nombres abreviados de argumentos a los cierres en línea, que se pueden usar para hacer referencia a los valores de los argumentos del cierre con los nombres $ 0, $1, $2 y así sucesivamente.

var shorthand: (String, String) -> String
shorthand = { $1 }
print(shorthand("100", "200"))

Aquí, $ 0 y $ 1 se refieren al primer y segundo argumento String del cierre.

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

200

Swift 4 facilita al usuario representar cierres en línea como nombres abreviados de argumentos al representar $ 0, $1, $2 --- $ n.

La lista de argumentos de cierres se omite en la sección de definición cuando representamos nombres abreviados de argumentos dentro de expresiones de cierre. Según el tipo de función, se derivarán los nombres abreviados de los argumentos. Dado que el argumento abreviado se define en el cuerpo de la expresión, se omite la palabra clave 'in'.

Cierres como funciones del operador

Swift 4 proporciona una manera fácil de acceder a los miembros simplemente proporcionando funciones de operador como cierres. En los ejemplos anteriores, la palabra clave 'Bool' se usa para devolver 'verdadero' cuando las cadenas son iguales; de lo contrario, devuelve 'falso'.

La expresión se hace aún más simple por la función del operador en el cierre como -

let numb = [98, -20, -30, 42, 18, 35]
var sortedNumbers = numb.sorted ({
   (left: Int, right: Int) -> Bool in
   return left < right
})

let asc = numb.sorted(<)
print(asc)

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

[-30, -20, 18, 35, 42, 98]

Cierres como remolques

Pasar el argumento final de la función a una expresión de cierre se declara con la ayuda de 'Trailing Closures'. Está escrito fuera de la función () con {}. Su uso es necesario cuando no es posible escribir la función en línea en una sola línea.

reversed = sorted(names) { $0 > $1}

donde {$ 0> $ 1} se representan como cierres finales declarados fuera de (nombres).

import Foundation
var letters = ["North", "East", "West", "South"]

let twoletters = letters.map({ 
   (state: String) -> String in
   return state.substringToIndex(advance(state.startIndex, 2)).uppercaseString
})

let stletters = letters.map() { 
   $0.substringToIndex(advance($0.startIndex, 2)).uppercaseString 
}
print(stletters)

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

[NO, EA, WE, SO]

Captura de valores y tipos de referencia

En Swift 4, la captura de constantes y valores de variables se realiza con la ayuda de cierres. Además, hace referencia y modifica los valores de esas constantes y variables dentro del cuerpo de cierre, aunque las variables ya no existan.

La captura de valores constantes y variables se logra mediante el uso de una función anidada escribiendo la función con en el cuerpo de otra función.

Una función anidada captura:

  • Argumentos de funciones externas.
  • Capture constantes y variables definidas dentro de la función Outer.

En Swift 4, cuando se declara una constante o variable dentro de una función, el cierre también crea automáticamente una referencia a esas variables. También proporciona la posibilidad de hacer referencia a más de dos variables como el mismo cierre de la siguiente manera:

let decrem = calcDecrement(forDecrement: 18)
decrem()

aquí oneDecrement y las variables de Decremento señalarán el mismo bloque de memoria como referencia de cierre.

func calcDecrement(forDecrement total: Int) -> () -> Int {
   var overallDecrement = 100
   func decrementer() -> Int {
      overallDecrement -= total
      print(overallDecrement)
      return overallDecrement
   }
   return decrementer
}

let decrem = calcDecrement(forDecrement: 18)
decrem()
decrem()
decrem()

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

82
64
46

Cuando todas y cada una de las veces que se llama a la función externa calcDecrement, invoca la función decrementer () y disminuye el valor en 18 y devuelve el resultado con la ayuda de la función externa calcDecrement. Aquí calcDecrement actúa como un cierre.

Aunque la función decrementer () no tiene ningún argumento, el cierre por defecto se refiere a las variables 'globalDecrement' y 'total' capturando sus valores existentes. La copia de los valores de las variables especificadas se almacena con la función new decrementer (). Swift 4 maneja las funciones de administración de memoria asignando y desasignando espacios de memoria cuando las variables no están en uso.

Una enumeración es un tipo de datos definido por el usuario que consta de un conjunto de valores relacionados. Palabra claveenum se utiliza para definir el tipo de datos enumerados.

Funcionalidad de enumeración

La enumeración en Swift 4 también se parece a la estructura de C y Objective C.

  • Se declara en una clase y se accede a sus valores a través de la instancia de esa clase.

  • El valor del miembro inicial se define mediante inicializadores de enumeración.

  • Su funcionalidad también se amplía al garantizar la funcionalidad del protocolo estándar.

Sintaxis

Las enumeraciones se introducen con la palabra clave enum y colocan su definición completa dentro de un par de llaves:

enum enumname {
   // enumeration values are described here
}

Por ejemplo, puede definir una enumeración para los días de la semana de la siguiente manera:

enum DaysofaWeek {
   case Sunday
   case Monday
   ---
   case Saturday
}

Ejemplo

enum names {
   case Swift
   case Closures
}

var lang = names.Closures
lang = .Closures

switch lang {
   case .Swift:
      print("Welcome to Swift")
   case .Closures:
      print("Welcome to Closures")
   default:
      print("Introduction")
}

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Welcome to Closures

La enumeración Swift 4 no asigna a sus miembros un valor predeterminado como C y Objetivo C. En cambio, los miembros se definen explícitamente por sus nombres de enumeración. El nombre de la enumeración debe comenzar con una letra mayúscula (por ejemplo, enum DaysofaWeek).

var weekDay = DaysofaWeek.Sunday

Aquí, el nombre de enumeración 'DaysofaWeek' se asigna a una variable weekday.Sunday. Le informa al compilador que el tipo de datos que pertenece a Sunday se asignará a los miembros de enumeración posteriores de esa clase en particular. Una vez que se define el tipo de datos del miembro enum, se puede acceder a los miembros pasando valores y cálculos adicionales.

Enumeración con instrucción Switch

La declaración Swift 4 'Switch' también sigue a la selección de múltiples vías. Solo se accede a una variable en un momento determinado en función de la condición especificada. El caso predeterminado en la instrucción switch se usa para atrapar casos no especificados.

enum Climate {
   case India
   case America
   case Africa
   case Australia
}

var season = Climate.America
season = .America
switch season {
   case .India:
      print("Climate is Hot")
   case .America:
      print("Climate is Cold")
   case .Africa:
      print("Climate is Moderate")
   case .Australia:
      print("Climate is Rainy")
   
}

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Climate is Cold

El programa primero define Clima como el nombre de la enumeración. Entonces sus miembros como 'India', 'América', 'África' y 'Australia' son declarados pertenecientes a la clase 'Clima'. Ahora el miembro América está asignado a una variable de temporada. Además, Switch case verá los valores correspondientes a .America y se ramificará a esa declaración en particular. La salida se mostrará como "El clima es frío". Asimismo, se puede acceder a todos los miembros mediante declaraciones de cambio. Cuando no se cumple la condición, se imprime de forma predeterminada "El clima no es predecible".

La enumeración se puede clasificar adicionalmente en valores asociados y valores brutos.

Diferencia entre valores asociados y valores brutos

Valores asociados Valores crudos
Diferentes tipos de datos Mismos tipos de datos
Ejemplo: enumeración {10,0.8, "Hola"} Ej: enum {10,35,50}
Los valores se crean en base a constante o variable Valores rellenados previamente
Varía cuando se declara cada vez El valor para el miembro es el mismo

Enumeración con valores asociados

enum Student {
   case Name(String)
   case Mark(Int,Int,Int)
}

var studDetails = Student.Name("Swift 4")
var studMarks = Student.Mark(98,97,95)

switch studMarks {
   case .Name(let studName):
      print("Student name is: \(studName).")
   case .Mark(let Mark1, let Mark2, let Mark3):
      print("Student Marks are: \(Mark1),\(Mark2),\(Mark3).")
}

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Student Marks are: 98,97,95.

Considere, por ejemplo, acceder al nombre de los estudiantes y las marcas aseguradas en tres asignaturas. El nombre de enumeración se declara como estudiante y los miembros presentes en la clase de enumeración son nombres que pertenecen al tipo de datos de cadena, las marcas se representan como mark1, mark2 y mark3 del tipo de datos Integer. Para acceder al nombre del estudiante o las notas que ha obtenido

var studDetails = Student.Name("Swift")
var studMarks = Student.Mark(98,97,95)

Ahora, el caso del interruptor imprimirá el nombre del estudiante si se ejecuta ese bloque de caso, de lo contrario, imprimirá las marcas obtenidas por el estudiante. Si ambas condiciones fallan, se ejecutará el bloque predeterminado.

Enumeración con valores brutos

Los valores brutos pueden ser cadenas, caracteres o cualquiera de los tipos de números enteros o de punto flotante. Cada valor bruto debe ser único dentro de su declaración de enumeración. Cuando se utilizan números enteros para valores brutos, se incrementan automáticamente si no se especifica ningún valor para algunos de los miembros de la enumeración.

enum Month: Int {
   case January = 1, February, March, April, May, June, July, August,
      September, October, November, December
}

let yearMonth = Month.May.rawValue
print("Value of the Month is: \(yearMonth).")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Value of the Month is: 5.

Swift 4 proporciona un bloque de construcción flexible para hacer uso de constructos como estructuras. Haciendo uso de estas estructuras una vez se pueden definir métodos y propiedades de construcciones.

A diferencia de C y Objective C

  • La estructura no necesita requerir archivos de implementación e interfaz.

  • La estructura nos permite crear un solo archivo y extender su interfaz automáticamente a otros bloques.

En Estructura, los valores de las variables se copian y pasan en códigos posteriores devolviendo una copia de los valores antiguos para que los valores no se puedan alterar.

Sintaxis

Structures are defined with a 'Struct' Keyword.
struct nameStruct {
   Definition 1
   Definition 2
   ---
   Definition N
}

Definición de una estructura

Por ejemplo, supongamos que tenemos que acceder al registro de los estudiantes que contiene las calificaciones de tres materias y averiguar el total de tres materias. Aquí markStruct se utiliza para inicializar una estructura con tres marcas como tipo de datos 'Int'.

struct MarkStruct {
   var mark1: Int
   var mark2: Int
   var mark3: Int
}

Acceder a la estructura y sus propiedades

Se accede a los miembros de la estructura por su nombre de estructura. Las instancias de la estructura se inicializan con la palabra clave 'let'.

struct studentMarks {
   var mark1 = 100
   var mark2 = 200
   var mark3 = 300
}

let marks = studentMarks()
print("Mark1 is \(marks.mark1)")
print("Mark2 is \(marks.mark2)")
print("Mark3 is \(marks.mark3)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Mark1 is 100
Mark2 is 200
Mark3 is 300

Se accede a las marcas de los estudiantes mediante el nombre de estructura 'StudentMarks'. Los miembros de la estructura se inicializan como mark1, mark2, mark3 con valores de tipo entero. Luego, la estructura studentMarks () se pasa a las 'marcas' con la palabra clave 'dejar'. De ahora en adelante, las 'marcas' contendrán los valores de los miembros de la estructura. Ahora, los valores se imprimen accediendo a los valores de los miembros de la estructura mediante '.' con sus nombres inicializados.

struct MarksStruct {
   var mark: Int

   init(mark: Int) {
      self.mark = mark
   }
}

var aStruct = MarksStruct(mark: 98)
var bStruct = aStruct     // aStruct and bStruct are two structs with the same value!
bStruct.mark = 97

print(aStruct.mark)      // 98
print(bStruct.mark)      // 97

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

98
97

Mejores prácticas de uso de estructuras

El lenguaje Swift 4 proporciona la funcionalidad para definir estructuras como tipos de datos personalizados para construir los bloques de funciones. Las instancias de estructura se pasan por su valor a los bloques definidos para su posterior manipulación.

Necesidad de tener estructuras

  • Encapsular valores de datos simples.

  • Copiar los datos encapsulados y sus propiedades asociadas por 'valores' en lugar de por 'referencias'.

  • Estructura para 'Copiar' y 'Referencia'.

Las estructuras en Swift 4 transmiten a sus miembros sus valores en lugar de sus referencias.

struct markStruct {
   var mark1: Int
   var mark2: Int
   var mark3: Int

   init(mark1: Int, mark2: Int, mark3: Int) {
      self.mark1 = mark1
      self.mark2 = mark2
      self.mark3 = mark3
   }
}

var marks = markStruct(mark1: 98, mark2: 96, mark3:100)
print(marks.mark1)
print(marks.mark2)
print(marks.mark3)

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

98
96
100

Otro ejemplo

struct markStruct {
   var mark1: Int
   var mark2: Int
   var mark3: Int
   
   init(mark1: Int, mark2: Int, mark3: Int) {
      self.mark1 = mark1
      self.mark2 = mark2
      self.mark3 = mark3
   }
}

var fail = markStruct(mark1: 34, mark2: 42, mark3: 13)

print(fail.mark1)
print(fail.mark2)
print(fail.mark3)

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

34
42
13

La estructura 'markStruct' se define primero con sus miembros mark1, mark2 y mark3. Ahora las variables de las clases miembro se inicializan para contener valores enteros. Luego, la copia de los miembros de la estructura se crea con la palabra clave "self". Una vez que se crea la copia de los miembros de la estructura, el bloque de estructura con sus marcas de parámetro se pasa a la variable 'marcas' que ahora contendrá las marcas de los estudiantes. Luego, las marcas se imprimen como 98, 96, 100. En el siguiente paso para los mismos miembros de estructura, se usa otra instancia denominada "falla" para señalar los mismos miembros de estructura con diferentes marcas. Entonces, los resultados ahora se imprimen como 34, 42, 13. Esto explica claramente que las estructuras tendrán una copia de las variables miembro y luego pasarán los miembros a sus próximos bloques de funciones.

Las clases en Swift 4 son bloques de construcción de construcciones flexibles. De manera similar a las constantes, variables y funciones, el usuario puede definir propiedades y métodos de clase. Swift 4 nos proporciona la funcionalidad de que, al declarar clases, los usuarios no necesitan crear interfaces o archivos de implementación. Swift 4 nos permite crear clases como un solo archivo y las interfaces externas se crearán por defecto una vez que se inicialicen las clases.

Beneficios de tener clases

  • La herencia adquiere las propiedades de una clase a otra clase

  • La conversión de tipos permite al usuario verificar el tipo de clase en tiempo de ejecución

  • Los desinicializadores se encargan de liberar recursos de memoria

  • El recuento de referencias permite que la instancia de clase tenga más de una referencia

Características comunes de clases y estructuras

  • Las propiedades se definen para almacenar valores
  • Los subíndices se definen para proporcionar acceso a los valores.
  • Los métodos se inicializan para mejorar la funcionalidad
  • Los inicializadores definen el estado inicial
  • La funcionalidad se expande más allá de los valores predeterminados
  • Confirmación de los estándares de funcionalidad del protocolo

Sintaxis

Class classname {
   Definition 1
   Definition 2
   --- 
   Definition N
}

Definición de clase

class student {
   var studname: String
   var mark: Int 
   var mark2: Int 
}

La sintaxis para crear instancias

let studrecord = student()

Ejemplo

class MarksStruct {
   var mark: Int
   init(mark: Int) {
      self.mark = mark
   }
}

class studentMarks {
   var mark = 300
}

let marks = studentMarks()
print("Mark is \(marks.mark)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Mark is 300

Acceder a las propiedades de clase como tipos de referencia

Se puede acceder a las propiedades de la clase mediante el '.' sintaxis. El nombre de la propiedad está separado por un '.' después del nombre de la instancia.

class MarksStruct {
   var mark: Int
   init(mark: Int) {
      self.mark = mark
   }
}

class studentMarks {
   var mark1 = 300
   var mark2 = 400
   var mark3 = 900
}

let marks = studentMarks()
print("Mark1 is \(marks.mark1)")
print("Mark2 is \(marks.mark2)")
print("Mark3 is \(marks.mark3)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Mark1 is 300
Mark2 is 400
Mark3 is 900

Operadores de identidad de clase

Las clases en Swift 4 se refieren a múltiples constantes y variables que apuntan a una sola instancia. Para conocer las constantes y variables que apuntan a una instancia de clase particular, se utilizan operadores de identidad. Las instancias de clase siempre se pasan por referencia. En las clases, las instancias NSString, NSArray y NSDictionary siempre se asignan y se transmiten como una referencia a una instancia existente, en lugar de como una copia.

Idéntico a los operadores No idéntico a los operadores
El operador utilizado es (===) El operador utilizado es (! ==)
Devuelve verdadero cuando dos constantes o variables apuntan a una misma instancia Devuelve verdadero cuando dos constantes o variables apuntan a una instancia diferente
class SampleClass: Equatable {
   let myProperty: String
   init(s: String) {
      myProperty = s
   }
}

func ==(lhs: SampleClass, rhs: SampleClass) -> Bool {
   return lhs.myProperty == rhs.myProperty
}

let spClass1 = SampleClass(s: "Hello")
let spClass2 = SampleClass(s: "Hello")

spClass1 === spClass2 // false
print("\(spClass1)")

spClass1 !== spClass2 // true
print("\(spClass2)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

main.SampleClass
main.SampleClass

El lenguaje Swift 4 proporciona propiedades de clase, enumeración o estructura para asociar valores. Las propiedades se pueden clasificar en propiedades almacenadas y propiedades calculadas.

Diferencia entre propiedades almacenadas y propiedades calculadas

Propiedad almacenada Propiedad calculada
Almacene valores constantes y variables como instancia Calcule un valor en lugar de almacenar el valor
Proporcionado por clases y estructuras Proporcionado por clases, enumeraciones y estructuras

Tanto las propiedades almacenadas como las calculadas están asociadas con el tipo de instancia. Cuando las propiedades están asociadas con sus valores de tipo, se define como 'Propiedades de tipo'. Las propiedades almacenadas y calculadas generalmente se asocian con instancias de un tipo particular. Sin embargo, las propiedades también se pueden asociar con el tipo en sí. Estas propiedades se conocen como propiedades de tipo. También se utilizan observadores de propiedades

  • Para observar el valor de las propiedades almacenadas
  • Para observar la propiedad de la subclase heredada derivada de la superclase

Propiedades almacenadas

Swift 4 introduce el concepto de propiedad almacenada para almacenar las instancias de constantes y variables. Las propiedades almacenadas de las constantes se definen con la palabra clave 'let' y las propiedades almacenadas de las variables se definen con la palabra clave 'var'.

  • Durante la definición, la propiedad almacenada proporciona un 'valor predeterminado'
  • Durante la inicialización, el usuario puede inicializar y modificar los valores iniciales.
struct Number {
   var digits: Int
   let pi = 3.1415
}

var n = Number(digits: 12345)
n.digits = 67

print("\(n.digits)")
print("\(n.pi)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

67
3.1415

Considere la siguiente línea en el código anterior:

let pi = 3.1415

Aquí, la variable pi se inicializa como un valor de propiedad almacenado con la instancia pi = 3.1415. Por lo tanto, siempre que se haga referencia a la instancia, solo tendrá el valor 3.1415.

Otro método para tener una propiedad almacenada es tener estructuras constantes. Entonces, toda la instancia de las estructuras se considerará como 'Propiedades almacenadas de constantes'.

struct Number {
   var digits: Int
   let numbers = 3.1415
}

var n = Number(digits: 12345)
n.digits = 67

print("\(n.digits)")
print("\(n.numbers)")
n.numbers = 8.7

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

error: cannot assign to 'numbers' in 'n'
n.numbers = 8.7

En lugar de reinicializar el 'número' a 8.7, devolverá un mensaje de error que indica que el 'número' se declara como constante.

Propiedad almacenada perezosa

Swift 4 proporciona una propiedad flexible llamada 'Propiedad almacenada diferida' donde no calculará los valores iniciales cuando la variable se inicialice por primera vez. El modificador 'lazy' se usa antes de la declaración de variable para tenerlo como una propiedad almacenada lazy.

Se utilizan propiedades perezosas -

  • Para retrasar la creación de objetos.
  • Cuando la propiedad depende de otras partes de una clase, que aún no se conocen
class sample {
   lazy var no = number()    // `var` declaration is required.
}

class number {
   var name = "Swift 4"
}

var firstsample = sample()
print(firstsample.no.name)

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Swift 4

Variables de instancia

En Objective C, las propiedades almacenadas también tienen variables de instancia con fines de respaldo para almacenar los valores declarados en la propiedad almacenada.

Swift 4 integra ambos conceptos en una sola declaración de 'propiedad almacenada'. En lugar de tener una variable de instancia correspondiente y un valor de respaldo, la 'propiedad almacenada' contiene toda la información integrada definida en una sola ubicación sobre la propiedad de las variables por nombre de variable, tipo de datos y funcionalidades de administración de memoria.

Propiedades calculadas

En lugar de almacenar los valores, las propiedades calculadas proporcionan un captador y un definidor opcional para recuperar y establecer otras propiedades y valores indirectamente.

class sample {
   var no1 = 0.0, no2 = 0.0
   var length = 300.0, breadth = 150.0

   var middle: (Double, Double) {
      get {
         return (length / 2, breadth / 2)
      }
      
      set(axis){
         no1 = axis.0 - (length / 2)
         no2 = axis.1 - (breadth / 2)
      }
   }
}

var result = sample()
print(result.middle)
result.middle = (0.0, 10.0)

print(result.no1)
print(result.no2)

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

(150.0, 75.0)
-150.0
-65.0

Cuando una propiedad calculada deja el nuevo valor como indefinido, el valor predeterminado se establecerá para esa variable en particular.

Propiedades calculadas como propiedades de solo lectura

Una propiedad de solo lectura en una propiedad calculada se define como una propiedad con getter pero sin setter. Siempre se usa para devolver un valor. Además, se accede a las variables a través de un '.' Sintaxis pero no se puede establecer en otro valor.

class film {
   var head = ""
   var duration = 0.0
   var metaInfo: [String:String] {
      return [
         "head": self.head,
         "duration":"\(self.duration)"
      ]
   }
}

var movie = film()
movie.head = "Swift 4 Properties"
movie.duration = 3.09

print(movie.metaInfo["head"]!)
print(movie.metaInfo["duration"]!)

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Swift 4 Properties
3.09

Propiedades calculadas como observadores de propiedades

En Swift 4 para observar y responder a los valores de las propiedades, se utilizan Observadores de propiedades. Todas y cada una de las veces que se establecen valores de propiedad, se llama a los observadores de propiedades. Excepto las propiedades almacenadas diferidas, podemos agregar observadores de propiedades a la propiedad 'heredada' mediante el método 'invalidación'.

Los observadores de propiedades pueden definirse por

  • Antes de almacenar el valor - willset

  • Después de almacenar el nuevo valor - didset

  • Cuando se establece una propiedad en un inicializador willset y no se pueden llamar observadores didset.

class Samplepgm {
   var counter: Int = 0 {
      willSet(newTotal){
         print("Total Counter is: \(newTotal)")
      }
      
      didSet {
         if counter > oldValue {
            print("Newly Added Counter \(counter - oldValue)")
         }
      }
   }
}

let NewCounter = Samplepgm()
NewCounter.counter = 100
NewCounter.counter = 800

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Total Counter is: 100
Newly Added Counter 100
Total Counter is: 800
Newly Added Counter 700

Variables locales y globales

Las variables locales y globales se declaran para calcular y observar las propiedades.

Variables locales Variables globales
Variables que se definen dentro de una función, método o contexto de cierre. Variables que se definen fuera del contexto de función, método, cierre o tipo.
Se utiliza para almacenar y recuperar valores. Se utiliza para almacenar y recuperar valores.
Las propiedades almacenadas se utilizan para obtener y establecer los valores. Las propiedades almacenadas se utilizan para obtener y establecer los valores.
También se utilizan propiedades calculadas. También se utilizan propiedades calculadas.

Propiedades de tipo

Las propiedades se definen en la sección Definición de tipo con llaves {} y el alcance de las variables también se definió previamente. Para definir propiedades de tipo para tipos de valor, se usa la palabra clave 'estática' y para los tipos de clase se usa la palabra clave 'clase'.

Sintaxis

struct Structname {
   static var storedTypeProperty = " "
   static var computedTypeProperty: Int {
      // return an Int value here
   }
}

enum Enumname {
   static var storedTypeProperty = " "
   static var computedTypeProperty: Int {
      // return an Int value here
   }
}

class Classname {
   class var computedTypeProperty: Int {
      // return an Int value here
   }
}

Consultar y configurar propiedades

Al igual que las propiedades de instancia, las propiedades de tipo se consultan y se establecen con '.' Sintaxis solo en el tipo en lugar de apuntar a la instancia.

struct StudMarks {
   static let markCount = 97
   static var totalCount = 0
   
   var InternalMarks: Int = 0 {
      didSet {
         if InternalMarks > StudMarks.markCount {
            InternalMarks = StudMarks.markCount
         }
         if InternalMarks > StudMarks.totalCount {
            StudMarks.totalCount = InternalMarks
         }
      }
   }
}

var stud1Mark1 = StudMarks()
var stud1Mark2 = StudMarks()

stud1Mark1.InternalMarks = 98
print(stud1Mark1.InternalMarks)

stud1Mark2.InternalMarks = 87
print(stud1Mark2.InternalMarks)

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

97
87

En el lenguaje Swift 4, las funciones asociadas con tipos particulares se denominan métodos. En Objective C, las Clases se utilizan para definir métodos, mientras que el lenguaje Swift 4 proporciona al usuario flexibilidad para tener métodos para Clases, Estructuras y Enumeraciones.

Métodos de instancia

En el lenguaje Swift 4, se accede a las instancias de Clases, Estructuras y Enumeración a través de los métodos de instancia.

Los métodos de instancia proporcionan funcionalidad

  • Para acceder y modificar las propiedades de la instancia
  • funcionalidad relacionada con la necesidad de la instancia

El método de instancia se puede escribir dentro de las llaves {}. Tiene acceso implícito a métodos y propiedades de la instancia de tipo. Cuando se llama a una instancia específica del tipo, obtendrá acceso a esa instancia en particular.

Sintaxis

func funcname(Parameters) -> returntype {
   Statement1
   Statement2
   ---
   Statement N
   return parameters
}

Ejemplo

class calculations {
   let a: Int
   let b: Int
   let res: Int

   init(a: Int, b: Int) {
      self.a = a
      self.b = b
      res = a + b
   }
   
   func tot(c: Int) -> Int {
      return res - c
   }
   
   func result() {
      print("Result is: \(tot(c: 20))")
      print("Result is: \(tot(c: 50))")
   }
}
let pri = calculations(a: 600, b: 300)
pri.result()

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Result is: 880
Result is: 850

Cálculos de clase define dos métodos de instancia:

  • init () está definido para sumar dos números ayb y almacenarlo en el resultado 'res'
  • tot () se usa para restar la 'res' de pasar el valor 'c'

Finalmente, para imprimir los métodos de cálculo con valores para ay b se llama. Se accede a los métodos de instancia con '.' sintaxis de puntos

Nombres de parámetros locales y externos

Las funciones Swift 4 describen declaraciones tanto locales como globales para sus variables. De manera similar, las convenciones de nomenclatura de Swift 4 Methods también se parecen a las de Objective C. Pero las características de las declaraciones de nombres de parámetros locales y globales son diferentes para funciones y métodos. El primer parámetro en Swift 4 se conoce por nombres de preposición como 'con', 'para' y 'por' para acceder fácilmente a las convenciones de nomenclatura.

Swift 4 proporciona flexibilidad en los métodos al declarar el nombre del primer parámetro como nombres de parámetros locales y los nombres de parámetros restantes como nombres de parámetros globales. Aquí los métodos Swift 4 declaran 'no1' como nombres de parámetros locales. 'no2' se utiliza para declaraciones globales y se accede a él a través del programa.

class division {
   var count: Int = 0
   func incrementBy(no1: Int, no2: Int) {
      count = no1 / no2
      print(count)
   }
}

let counter = division()
counter.incrementBy(no1: 1800, no2: 3)
counter.incrementBy(no1: 1600, no2: 5)
counter.incrementBy(no1: 11000, no2: 3)

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

600
320
3666

Nombre del parámetro externo con el símbolo # y _

Aunque los métodos de Swift 4 proporcionan los nombres de los primeros parámetros para las declaraciones locales, el usuario tiene la posibilidad de modificar los nombres de los parámetros de declaraciones locales a globales. Esto se puede hacer anteponiendo el símbolo '#' al nombre del primer parámetro. Al hacerlo, se puede acceder al primer parámetro de forma global en todos los módulos.

Cuando el usuario necesita acceder a los nombres de los parámetros posteriores con un nombre externo, el nombre de los métodos se anula con la ayuda del símbolo '_'.

class multiplication {
   var count: Int = 0
   func incrementBy(no1: Int, no2: Int) {
      count = no1 * no2
      print(count)
   }
}

let counter = multiplication()

counter.incrementBy(no1: 800, no2: 3)
counter.incrementBy(no1: 100, no2: 5)
counter.incrementBy(no1: 15000, no2: 3)

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

2400
500
45000

Propiedad propia en métodos

Los métodos tienen una propiedad implícita conocida como 'self' para todas sus instancias de tipo definidas. La propiedad 'Self' se utiliza para hacer referencia a las instancias actuales para sus métodos definidos.

class calculations {
   let a: Int
   let b: Int
   let res: Int

   init(a: Int, b: Int) {
      self.a = a
      self.b = b
      res = a + b
      print("Inside Self Block: \(res)")
   }
   
   func tot(c: Int) -> Int {
      return res - c
   }
   
   func result() {
      print("Result is: \(tot(c: 20))")
      print("Result is: \(tot(c: 50))")
   }
}

let pri = calculations(a: 600, b: 300)
let sum = calculations(a: 1200, b: 300)

pri.result()
sum.result()

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Inside Self Block: 900
Inside Self Block: 1500
Result is: 880
Result is: 850
Result is: 1480
Result is: 1450

Modificación de tipos de valor a partir de métodos de instancia

En Swift 4, las estructuras del lenguaje y las enumeraciones pertenecen a tipos de valores que no pueden ser alterados por sus métodos de instancia. Sin embargo, el lenguaje Swift 4 proporciona flexibilidad para modificar los tipos de valores mediante el comportamiento 'mutante'. Mutate realizará cualquier cambio en los métodos de instancia y volverá a la forma original después de la ejecución del método. Además, por la propiedad 'self' se crea una nueva instancia para su función implícita y reemplazará el método existente después de su ejecución

struct area {
   var length = 1
   var breadth = 1
   
   func area() -> Int {
      return length * breadth
   }
   mutating func scaleBy(res: Int) {
      length *= res
      breadth *= res
      print(length)
      print(breadth)
   }
}

var val = area(length: 3, breadth: 5)
val.scaleBy(res: 3)
val.scaleBy(res: 30)
val.scaleBy(res: 300)

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

9
15
270
450
81000
135000

Propiedad propia para el método de mutación

Los métodos de mutación combinados con la propiedad 'self' asignan una nueva instancia al método definido.

struct area {
   var length = 1
   var breadth = 1
   func area() -> Int {
      return length * breadth
   }
   mutating func scaleBy(res: Int) {
      self.length *= res
      self.breadth *= res
      print(length)
      print(breadth)
   }
}

var val = area(length: 3, breadth: 5)
val.scaleBy(res: 13)

Cuando ejecutamos el programa anterior usando playground, obtenemos el siguiente resultado. -

39
65

Métodos de tipo

Cuando se llama a una instancia particular de un método, se llama como método de instancia; y cuando el método llama a un tipo particular de método, se llama como 'Métodos de tipo'. Los métodos de tipo para 'clases' se definen con la palabra clave 'func' y los métodos de tipo de estructuras y enumeraciones se definen con la palabra clave 'estática' antes de la palabra clave 'func'.

Los métodos de tipo son llamados y accesibles por '.' sintaxis donde en lugar de llamar a una instancia en particular se invoca todo el método.

class Math {
   class func abs(number: Int) -> Int {
      if number < 0 {
         return (-number)
      } else {
         return number
      }
   }
}

struct absno {
   static func abs(number: Int) -> Int {
      if number < 0 {
         return (-number)
      } else {
         return number
      }
   }
}

let no = Math.abs(number: -35)
let num = absno.abs(number: -5)

print(no)
print(num)

Cuando ejecutamos el programa anterior usando playground, obtenemos el siguiente resultado. -

35
5

El acceso a los elementos miembros de una colección, secuencia y lista en Clases, Estructuras y Enumeraciones se realiza con la ayuda de subíndices. Estos subíndices se utilizan para almacenar y recuperar los valores con la ayuda de index. Se accede a los elementos de matriz con la ayuda de someArray [índice] y se puede acceder a sus elementos miembros subsiguientes en una instancia de Dictionary como someDicitonary [clave].

Para un solo tipo, los subíndices pueden variar de declaraciones simples a múltiples. Podemos usar el subíndice apropiado para sobrecargar el tipo de valor de índice pasado al subíndice. Los subíndices también varían de una dimensión a una dimensión múltiple según los requisitos de los usuarios para sus declaraciones de tipo de datos de entrada.

Sintaxis de declaración de subíndice y su uso

Repasemos las propiedades calculadas. Los subíndices también siguen la misma sintaxis que la de las propiedades calculadas. Para consultar instancias de tipo, los subíndices se escriben dentro de un corchete seguido del nombre de la instancia. La sintaxis del subíndice sigue la misma estructura sintáctica que la del 'método de instancia' y la sintaxis de 'propiedad calculada'. La palabra clave 'subíndice' se utiliza para definir subíndices y el usuario puede especificar uno o varios parámetros con sus tipos de retorno. Los subíndices pueden tener propiedades de lectura-escritura o de solo lectura y las instancias se almacenan y recuperan con la ayuda de las propiedades 'getter' y 'setter' como las propiedades calculadas.

Sintaxis

subscript(index: Int) −> Int {
   get {
      // used for subscript value declarations
   }
   set(newValue) {
      // definitions are written here
   }
}

Ejemplo 1

struct subexample {
   let decrementer: Int
   subscript(index: Int) -> Int {
      return decrementer / index
   }
}
let division = subexample(decrementer: 100)

print("The number is divisible by \(division[9]) times")
print("The number is divisible by \(division[2]) times")
print("The number is divisible by \(division[3]) times")
print("The number is divisible by \(division[5]) times")
print("The number is divisible by \(division[7]) times")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

The number is divisible by 11 times
The number is divisible by 50 times
The number is divisible by 33 times
The number is divisible by 20 times
The number is divisible by 14 times

Ejemplo 2

class daysofaweek {
   private var days = ["Sunday", "Monday", "Tuesday", "Wednesday",
      "Thursday", "Friday", "saturday"]
   subscript(index: Int) -> String {
      get {
         return days[index]
      }
      set(newValue) {
         self.days[index] = newValue
      }
   }
}
var p = daysofaweek()

print(p[0])
print(p[1])
print(p[2])
print(p[3])

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Sunday
Monday
Tuesday
Wednesday

Opciones en subíndice

Los subíndices toman de uno a varios parámetros de entrada y estos parámetros de entrada también pertenecen a cualquier tipo de datos. También pueden utilizar parámetros variables y variadic. Los subíndices no pueden proporcionar valores de parámetros predeterminados ni utilizar parámetros de entrada y salida.

La definición de varios subíndices se denomina "sobrecarga de subíndices", donde una clase o estructura puede proporcionar múltiples definiciones de subíndices según sea necesario. Estos múltiples subíndices se infieren en función de los tipos de valores que se declaran entre las llaves del subíndice.

struct Matrix {
   let rows: Int, columns: Int
   var print: [Double]
   init(rows: Int, columns: Int) {
      self.rows = rows
      self.columns = columns
      print = Array(count: rows * columns, repeatedValue: 0.0)
   }
   subscript(row: Int, column: Int) -> Double {
      get {
         return print[(row * columns) + column]
      }
      set {
         print[(row * columns) + column] = newValue
      }
   }
}
var mat = Matrix(rows: 3, columns: 3)

mat[0,0] = 1.0
mat[0,1] = 2.0
mat[1,0] = 3.0
mat[1,1] = 5.0

print("\(mat[0,0])")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

1.0

El subíndice Swift 4 admite declaraciones de un solo parámetro a múltiples parámetros para los tipos de datos apropiados. El programa declara la estructura 'Matrix' como una matriz de matriz de 2 * 2 dimensiones para almacenar tipos de datos 'Double'. El parámetro Matrix se ingresa con tipos de datos Integer para declarar filas y columnas.

Se crea una nueva instancia de Matrix pasando el recuento de filas y columnas a la inicialización como se muestra a continuación.

var mat = Matrix(rows: 3, columns: 3)

Los valores de la matriz se pueden definir pasando valores de fila y columna al subíndice, separados por una coma, como se muestra a continuación.

mat[0,0] = 1.0  
mat[0,1] = 2.0
mat[1,0] = 3.0
mat[1,1] = 5.0

La capacidad de tomar más forma se define como herencia. Generalmente, una clase puede heredar métodos, propiedades y funcionalidades de otra clase. Las clases se pueden categorizar aún más en subclase y superclase.

  • Sub Class - cuando una clase hereda propiedades, métodos y funciones de otra clase, se llama subclase

  • Super Class - La clase que contiene propiedades, métodos y funciones para heredar otras clases de sí misma se llama como una superclase

Las clases de Swift 4 contienen una superclase que llama y accede a métodos, propiedades, funciones y métodos primarios. Además, los observadores de propiedades también se utilizan para agregar una propiedad y modificar los métodos de propiedad almacenados o calculados.

Clase base

Una clase que no hereda métodos, propiedades o funciones de otra clase se denomina 'Clase base'.

class StudDetails {
   var stname: String!
   var mark1: Int!
   var mark2: Int!
   var mark3: Int!
   
   init(stname: String, mark1: Int, mark2: Int, mark3: Int) {
      self.stname = stname
      self.mark1 = mark1
      self.mark2 = mark2
      self.mark3 = mark3
   }
}

let stname = "Swift 4"
let mark1 = 98
let mark2 = 89
let mark3 = 76

print(stname)
print(mark1)
print(mark2)
print(mark3)

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Swift 4
98
89
76

La clase con nombre de clase StudDetails se define aquí como una clase base que se utiliza para contener el nombre de los estudiantes, y tres asignaturas marcan como mark1, mark2 y mark3. La palabra clave 'let' se usa para inicializar el valor de la clase base y el valor de la clase base se muestra en el patio de recreo con la ayuda de la función 'imprimir'.

Subclase

El acto de basar una nueva clase en una clase existente se define como 'Subclase'. La subclase hereda las propiedades, métodos y funciones de su clase base. Para definir una subclase ':' se usa antes del nombre de la clase base

class StudDetails {
   var mark1: Int;
   var mark2: Int;
   
   init(stm1:Int, results stm2:Int) {
      mark1 = stm1;
      mark2 = stm2;
   }
   func print() {
      print("Mark1:\(mark1), Mark2:\(mark2)")
   }
}

class display : StudDetails {
   init() {
      super.init(stm1: 93, results: 89)
   }
}

let marksobtained = display()
marksobtained.print()

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Mark1:93, Mark2:89

La clase 'StudDetails' se define como una superclase donde se declaran las calificaciones de los estudiantes y la subclase 'display' se usa para heredar las calificaciones de su superclase. La subclase define las calificaciones de los estudiantes y llama al método print () para mostrar las calificaciones de los estudiantes.

Primordial

Acceder a la subclase de instancia de superclase, métodos de tipo, instancia, propiedades de tipo y subíndices proporciona el concepto de anulación. La palabra clave 'override' se usa para invalidar los métodos declarados en la superclase.

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

La palabra clave 'super' se utiliza como prefijo para acceder a los métodos, propiedades y subíndices declarados en la superclase

Primordial Acceso a métodos, propiedades y subíndices
Métodos super.somemethod ()
Propiedades super.someProperty ()
Subíndices super [someIndex]

Anulación de métodos

Los métodos heredados de instancia y tipo pueden ser reemplazados por la palabra clave 'override' a nuestros métodos definidos en nuestra subclase. Aquí print () se anula en la subclase para acceder a la propiedad type mencionada en la superclase print (). También se crea una nueva instancia de la superclase cricket () como 'cricinstance'.

class cricket {
   func print() {
      print("Welcome to Swift 4 Super Class")
   }
}

class tennis: cricket {
   override func print() {
      print("Welcome to Swift 4 Sub Class")
   }
}

let cricinstance = cricket()
cricinstance.print()

let tennisinstance = tennis()
tennisinstance.print()

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Welcome to Swift Super Class
Welcome to Swift Sub Class

Anulación de propiedad

Puede anular una propiedad de clase o instancia heredada para proporcionar su propio captador y definidor personalizado para esa propiedad, o para agregar observadores de propiedad para permitir que la propiedad primordial observe cuándo cambia el valor de la propiedad subyacente.

Anulación de captadores y definidores de propiedades

Swift 4 permite al usuario proporcionar un captador y definidor personalizado para anular la propiedad heredada, ya sea una propiedad almacenada o calculada. La subclase no conoce el nombre y el tipo de propiedad heredada. Por lo tanto, es esencial que el usuario especifique en la subclase, el nombre y el tipo de la propiedad principal especificada en la superclase.

Esto se puede hacer de dos formas:

  • Cuando se define setter para anular la propiedad, el usuario también tiene que definir getter.

  • Cuando no queremos modificar el getter de propiedad heredada, simplemente podemos pasar el valor heredado por la sintaxis 'super.someProperty' a la superclase.

class Circle {
   var radius = 12.5
   var area: String {
      return "of rectangle for \(radius) "
   }
}

class Rectangle: Circle {
   var print = 7
   override var area: String {
      return super.area + " is now overridden as \(print)"
   }
}

let rect = Rectangle()
rect.radius = 25.0
rect.print = 3
print("Radius \(rect.area)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Radius of rectangle for 25.0  is now overridden as 3

Observadores de propiedades primordiales

Cuando es necesario agregar una nueva propiedad para una propiedad heredada, se introduce el concepto de "anulación de propiedad" en Swift 4. Esto notifica al usuario cuando se modifica el valor de la propiedad heredada. Pero la invalidación no es aplicable para propiedades almacenadas constantes heredadas y propiedades computadas heredadas de solo lectura.

class Circle {
   var radius = 12.5
   var area: String {
     return "of rectangle for \(radius) "
   }
}

class Rectangle: Circle {
   var print = 7
   override var area: String {
      return super.area + " is now overridden as \(print)"
   }
}

let rect = Rectangle()
rect.radius = 25.0
rect.print = 3
print("Radius \(rect.area)")

class Square: Rectangle {
   override var radius: Double {
      didSet {
         print = Int(radius/5.0)+1
      }
   }
}

let sq = Square()
sq.radius = 100.0
print("Radius \(sq.area)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Radius of rectangle for 25.0  is now overridden as 3
Radius of rectangle for 100.0  is now overridden as 21

Propiedad final para evitar la anulación

Cuando el usuario no necesita que otros accedan a métodos, propiedades o subíndices de superclase, Swift 4 introduce la propiedad 'final' para evitar la anulación. Una vez que se declara la propiedad 'final', los subíndices no permitirán que se anulen los métodos, propiedades y subíndices de la superclase. No existe ninguna disposición para tener una propiedad 'final' en 'superclase'. Cuando se declara la propiedad 'final', el usuario está restringido a crear más subclases.

final class Circle {
   final var radius = 12.5
   var area: String {
      return "of rectangle for \(radius) "
   }
}

class Rectangle: Circle {
   var print = 7
   override var area: String {
      return super.area + " is now overridden as \(print)"
   }
}

let rect = Rectangle()
rect.radius = 25.0
rect.print = 3
print("Radius \(rect.area)")

class Square: Rectangle {
   override var radius: Double {
      didSet {
         print = Int(radius/5.0)+1
      }
   }
}

let sq = Square()
sq.radius = 100.0
print("Radius \(sq.area)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

<stdin>:14:18: error: var overrides a 'final' var
override var area: String {
^
<stdin>:7:9: note: overridden declaration is here
var area: String {
^
<stdin>:12:11: error: inheritance from a final class 'Circle'
class Rectangle: Circle {
^
<stdin>:25:14: error: var overrides a 'final' var
override var radius: Double {
^
<stdin>:6:14: note: overridden declaration is here
final var radius = 12.5

Dado que la superclase se declara como 'final' y sus tipos de datos también se declaran como 'finales', el programa no permitirá crear más subclases y arrojará errores.

Las clases, estructuras y enumeraciones una vez declaradas en Swift 4 se inicializan para preparar la instancia de una clase. El valor inicial se inicializa para la propiedad almacenada y también para las nuevas instancias, los valores se inicializan para continuar. La palabra clave para crear la función de inicialización se lleva a cabo mediante el método 'init ()'. El inicializador Swift 4 se diferencia de Objective-C en que no devuelve ningún valor. Su función es verificar la inicialización de instancias recién creadas antes de su procesamiento. Swift 4 también proporciona un proceso de 'desinicialización' para realizar operaciones de administración de memoria una vez que se desasignan las instancias.

Rol de inicializador para propiedades almacenadas

La propiedad almacenada tiene que inicializar las instancias para sus clases y estructuras antes de procesar las instancias. Las propiedades almacenadas utilizan el inicializador para asignar e inicializar valores, lo que elimina la necesidad de llamar a los observadores de propiedades. El inicializador se usa en la propiedad almacenada

  • Para crear un valor inicial.

  • Para asignar un valor de propiedad predeterminado dentro de la definición de propiedad.

  • Para inicializar una instancia para un tipo de datos particular, se usa 'init ()'. No se pasan argumentos dentro de la función init ().

Sintaxis

init() {
   //New Instance initialization goes here
}

Ejemplo

struct rectangle {
   var length: Double
   var breadth: Double
   init() {
      length = 6
      breadth = 12
   }
}

var area = rectangle()
print("area of rectangle is \(area.length*area.breadth)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

area of rectangle is 72.0

Aquí, la estructura 'rectángulo' se inicializa con los miembros de longitud y anchura como tipos de datos 'Doble'. El método Init () se utiliza para inicializar los valores de la longitud y el doble de los miembros recién creados. El área del rectángulo se calcula y se devuelve llamando a la función rectángulo.

Establecer valores de propiedad de forma predeterminada

El lenguaje Swift 4 proporciona la función Init () para inicializar los valores de propiedad almacenados. Además, el usuario tiene la posibilidad de inicializar los valores de propiedad de forma predeterminada mientras declara los miembros de la clase o estructura. Cuando la propiedad toma el mismo valor solo en todo el programa, podemos declararlo solo en la sección de declaración en lugar de inicializarlo en init (). Establecer valores de propiedad de forma predeterminada habilita al usuario cuando se define la herencia para clases o estructuras.

struct rectangle {
   var length = 6
   var breadth = 12
}

var area = rectangle()
print("area of rectangle is \(area.length*area.breadth)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

area of rectangle is 72

Aquí, en lugar de declarar la longitud y la amplitud en init (), los valores se inicializan en la declaración misma.

Inicialización de parámetros

En el lenguaje Swift 4, el usuario tiene la posibilidad de inicializar parámetros como parte de la definición del inicializador usando init ().

struct Rectangle {
   var length: Double
   var breadth: Double
   var area: Double
   
   init(fromLength length: Double, fromBreadth breadth: Double) {
      self.length = length
      self.breadth = breadth
      area = length * breadth
   }
   init(fromLeng leng: Double, fromBread bread: Double) {
      self.length = leng
      self.breadth = bread
      area = leng * bread
   }
}

let ar = Rectangle(fromLength: 6, fromBreadth: 12)
print("area is: \(ar.area)")

let are = Rectangle(fromLeng: 36, fromBread: 12)
print("area is: \(are.area)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

area is: 72.0
area is: 432.0

Parámetros locales y externos

Los parámetros de inicialización tienen nombres de parámetros tanto locales como globales similares a los de los parámetros de función y método. La declaración de parámetro local se usa para acceder dentro del cuerpo de inicialización y la declaración de parámetro externo se usa para llamar al inicializador. Los inicializadores de Swift 4 difieren del inicializador de funciones y métodos en que no identifican qué inicializador se utiliza para llamar a qué funciones.

Para superar esto, Swift 4 introduce un nombre externo automático para todos y cada uno de los parámetros en init (). Este nombre externo automático es equivalente al nombre local escrito antes de cada parámetro de inicialización.

struct Days {
   let sunday, monday, tuesday: Int
   init(sunday: Int, monday: Int, tuesday: Int) {
      self.sunday = sunday
      self.monday = monday
      self.tuesday = tuesday
   }
   init(daysofaweek: Int) {
      sunday = daysofaweek
      monday = daysofaweek
      tuesday = daysofaweek
   }
}

let week = Days(sunday: 1, monday: 2, tuesday: 3)
print("Days of a Week is: \(week.sunday)")
print("Days of a Week is: \(week.monday)")
print("Days of a Week is: \(week.tuesday)")

let weekdays = Days(daysofaweek: 4)
print("Days of a Week is: \(weekdays.sunday)")
print("Days of a Week is: \(weekdays.monday)")
print("Days of a Week is: \(weekdays.tuesday)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Days of a Week is: 1
Days of a Week is: 2
Days of a Week is: 3
Days of a Week is: 4
Days of a Week is: 4
Days of a Week is: 4

Parámetros sin nombres externos

Cuando no se necesita un nombre externo para un guión bajo de inicialización, se usa '_' para anular el comportamiento predeterminado.

struct Rectangle {
   var length: Double
   
   init(frombreadth breadth: Double) {
      length = breadth * 10
   }
   init(frombre bre: Double) {
      length = bre * 30
   }
   init(_ area: Double) {
      length = area
   }
}

let rectarea = Rectangle(180.0)
print("area is: \(rectarea.length)")

let rearea = Rectangle(370.0)
print("area is: \(rearea.length)")

let recarea = Rectangle(110.0)
print("area is: \(recarea.length)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

area is: 180.0
area is: 370.0
area is: 110.0

Tipos de propiedad opcionales

Cuando la propiedad almacenada en alguna instancia no devuelve ningún valor, esa propiedad se declara con un tipo "opcional" que indica que "no se devuelve ningún valor" para ese tipo en particular. Cuando la propiedad almacenada se declara como 'opcional', automáticamente inicializa el valor para que sea 'nulo' durante la inicialización.

struct Rectangle {
   var length: Double?
   
   init(frombreadth breadth: Double) {
      length = breadth * 10
   }
   init(frombre bre: Double) {
      length = bre * 30
   }
   init(_ area: Double) {
      length = area
   }
}

let rectarea = Rectangle(180.0)
print("area is: \(rectarea.length)")

let rearea = Rectangle(370.0)
print("area is: \(rearea.length)")

let recarea = Rectangle(110.0)
print("area is: \(recarea.length)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

area is: Optional(180.0)
area is: Optional(370.0)
area is: Optional(110.0)

Modificación de propiedades constantes durante la inicialización

La inicialización también permite al usuario modificar el valor de la propiedad constante. Durante la inicialización, la propiedad de clase permite que sus instancias de clase sean modificadas por la superclase y no por la subclase. Considere, por ejemplo, que en el programa anterior 'longitud' se declara como 'variable' en la clase principal. La siguiente variable de programa 'longitud' se modifica como variable 'constante'.

struct Rectangle {
   let length: Double?
   
   init(frombreadth breadth: Double) {
      length = breadth * 10
   }
   init(frombre bre: Double) {
      length = bre * 30
   }
   init(_ area: Double) {
      length = area
   }
}

let rectarea = Rectangle(180.0)
print("area is: \(rectarea.length)")

let rearea = Rectangle(370.0)
print("area is: \(rearea.length)")

let recarea = Rectangle(110.0)
print("area is: \(recarea.length)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

area is: Optional(180.0)
area is: Optional(370.0)
area is: Optional(110.0)

Inicializadores predeterminados

Los inicializadores predeterminados proporcionan una nueva instancia a todas sus propiedades declaradas de clase base o estructura con valores predeterminados.

class defaultexample {
   var studname: String?
   var stmark = 98
   var pass = true
}
var result = defaultexample()

print("result is: \(result.studname)")
print("result is: \(result.stmark)")
print("result is: \(result.pass)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado. -

result is: nil
result is: 98
result is: true

El programa anterior se define con el nombre de clase como 'ejemplo predeterminado'. Tres funciones miembro se inicializan de forma predeterminada como 'studname?' para almacenar valores 'nil', 'stmark' como 98 y 'pass' como valor booleano 'true'. Asimismo, los valores de los miembros de la clase se pueden inicializar de forma predeterminada antes de procesar los tipos de miembros de la clase.

Inicializadores Memberwise para tipos de estructura

Cuando el usuario no proporciona los inicializadores personalizados, los tipos de estructura en Swift 4 recibirán automáticamente el 'inicializador de miembros'. Su función principal es inicializar las nuevas instancias de estructura con la inicialización por miembros predeterminada y luego las propiedades de la nueva instancia se pasan a la inicialización por miembros por nombre.

struct Rectangle {
   var length = 100.0, breadth = 200.0
}
let area = Rectangle(length: 24.0, breadth: 32.0)

print("Area of rectangle is: \(area.length)")
print("Area of rectangle is: \(area.breadth)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Area of rectangle is: 24.0
Area of rectangle is: 32.0

Las estructuras se inicializan de forma predeterminada para sus funciones de pertenencia durante la inicialización para 'longitud' como '100.0' y 'amplitud' como '200.0'. Pero los valores se anulan durante el procesamiento de las variables longitud y amplitud como 24.0 y 32.0.

Delegación de inicializador para tipos de valor

La delegación de inicializadores se define como llamar a inicializadores desde otros inicializadores. Su función principal es actuar como reutilización para evitar la duplicación de código en varios inicializadores.

struct Stmark {
   var mark1 = 0.0, mark2 = 0.0
}
struct stdb {
   var m1 = 0.0, m2 = 0.0
}

struct block {
   var average = stdb()
   var result = Stmark()
   init() {}
   init(average: stdb, result: Stmark) {
      self.average = average
      self.result = result
   }

   init(avg: stdb, result: Stmark) {
      let tot = avg.m1 - (result.mark1 / 2)
      let tot1 = avg.m2 - (result.mark2 / 2)
      self.init(average: stdb(m1: tot, m2: tot1), result: result)
   }
}

let set1 = block()
print("student result is: \(set1.average.m1, set1.average.m2)
\(set1.result.mark1, set1.result.mark2)")

let set2 = block(average: stdb(m1: 2.0, m2: 2.0),
result: Stmark(mark1: 5.0, mark2: 5.0))
print("student result is: \(set2.average.m1, set2.average.m2)
\(set2.result.mark1, set2.result.mark2)")

let set3 = block(avg: stdb(m1: 4.0, m2: 4.0),
result: Stmark(mark1: 3.0, mark2: 3.0))
print("student result is: \(set3.average.m1, set3.average.m2)
\(set3.result.mark1, set3.result.mark2)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

(0.0,0.0) (0.0,0.0)
(2.0,2.0) 5.0,5.0)
(2.5,2.5) (3.0,3.0)

Reglas para la delegación del inicializador

Tipos de valor Tipos de clases
La herencia no se admite para tipos de valor como estructuras y enumeraciones. La referencia a otros inicializadores se realiza a través de self.init Se admite la herencia. Comprueba que todos los valores de propiedad almacenados estén inicializados

Herencia e inicialización de clases

Los tipos de clase tienen dos tipos de inicializadores para comprobar si las propiedades almacenadas definidas reciben un valor inicial, a saber, inicializadores designados e inicializadores de conveniencia.

Inicializadores designados e inicializadores de conveniencia

Inicializador designado Inicializador de conveniencia
Considerado como inicializaciones primarias para una clase Considerado como compatible con la inicialización de una clase
Todas las propiedades de la clase se inicializan y se llama al inicializador de superclase apropiado para una posterior inicialización El inicializador designado se llama con un inicializador de conveniencia para crear una instancia de clase para un caso de uso específico o un tipo de valor de entrada
Se define al menos un inicializador designado para cada clase No es necesario tener inicializadores de conveniencia obligatorios definidos cuando la clase no requiere inicializadores.
Init (parámetros) {declaraciones} conveniencia init (parámetros) {declaraciones}

Programa para inicializadores designados

class mainClass {
   var no1 : Int // local storage
   init(no1 : Int) {
      self.no1 = no1 // initialization
   }
}

class subClass : mainClass {
   var no2 : Int // new subclass storage
   init(no1 : Int, no2 : Int) {
      self.no2 = no2 // initialization
      super.init(no1:no1) // redirect to superclass
   }
}

let res = mainClass(no1: 10)
let print = subClass(no1: 10, no2: 20)

print("res is: \(res.no1)")
print("res is: \(print.no1)")
print("res is: \(print.no2)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

res is: 10
res is: 10
res is: 20

Programa para inicializadores de conveniencia

class mainClass {
   var no1 : Int // local storage
   init(no1 : Int) {
      self.no1 = no1 // initialization
   }
}

class subClass : mainClass {
   var no2 : Int
   init(no1 : Int, no2 : Int) {
      self.no2 = no2
      super.init(no1:no1)
   }
   // Requires only one parameter for convenient method
   override convenience init(no1: Int) {
      self.init(no1:no1, no2:0)
   }
}

let res = mainClass(no1: 20)
let print = subClass(no1: 30, no2: 50)

print("res is: \(res.no1)")
print("res is: \(print.no1)")
print("res is: \(print.no2)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

res is: 20
res is: 30
res is: 50

Herencia y anulación del inicializador

Swift 4 no permite que sus subclases hereden sus inicializadores de superclase para sus tipos de miembros de forma predeterminada. La herencia es aplicable a los inicializadores de clase Super solo hasta cierto punto, lo que se discutirá en Herencia del inicializador automático.

Cuando el usuario necesita tener inicializadores definidos en superclase, el usuario debe definir la subclase con inicializadores como implementación personalizada. Cuando la subclase debe realizar la anulación a la superclase, se debe declarar la palabra clave 'anular'.

class sides {
   var corners = 4
   var description: String {
      return "\(corners) sides"
   }
}

let rectangle = sides()
print("Rectangle: \(rectangle.description)")

class pentagon: sides {
   override init() {
      super.init()
      corners = 5
   }
}

let bicycle = pentagon()
print("Pentagon: \(bicycle.description)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Rectangle: 4 sides
Pentagon: 5 sides

Inicializadores designados y convenientes en acción

class Planet {
   var name: String
   init(name: String) {
      self.name = name
   }
   convenience init() {
      self.init(name: "[No Planets]")
   }
}

let plName = Planet(name: "Mercury")
print("Planet name is: \(plName.name)")

let noplName = Planet()
print("No Planets like that: \(noplName.name)")

class planets: Planet {
   var count: Int
   init(name: String, count: Int) {
      self.count = count
      super.init(name: name)
   }
   override convenience init(name: String) {
      self.init(name: name, count: 1)
   }
}

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Planet name is: Mercury
No Planets like that: [No Planets]

Inicializador fallido

El usuario debe ser notificado cuando haya fallas en el inicializador al definir una clase, estructura o valores de enumeración. La inicialización de variables a veces se convierte en una falla debido a:

  • Valores de parámetro no válidos.
  • Ausencia de fuente externa requerida.
  • Condición que impide que la inicialización se realice correctamente.

Para detectar las excepciones generadas por el método de inicialización, Swift 4 produce una inicialización flexible llamada 'inicializador fallido' para notificar al usuario que algo pasa desapercibido al inicializar la estructura, clase o miembros de enumeración. La palabra clave para detectar el inicializador fallido es 'init?'. Además, los inicializadores fallidos y no fallidos no se pueden definir con los mismos tipos y nombres de parámetros.

struct studrecord {
   let stname: String
   init?(stname: String) {
      if stname.isEmpty {return nil }
      self.stname = stname
   }
}
let stmark = studrecord(stname: "Swing")

if let name = stmark {
   print("Student name is specified")
}
let blankname = studrecord(stname: "")

if blankname == nil {
   print("Student name is left blank")
}

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Student name is specified
Student name is left blank

Inicializadores fallidos para enumeraciones

El lenguaje Swift 4 proporciona la flexibilidad de tener inicializadores Failable para enumeraciones también para notificar al usuario cuando los miembros de la enumeración quedan sin inicializar valores.

enum functions {
   case a, b, c, d
   init?(funct: String) {
      switch funct {
      case "one":
         self = .a
      case "two":
         self = .b
      case "three":
         self = .c
      case "four":
         self = .d
      default:
         return nil
      }
   }
}
let result = functions(funct: "two")

if result != nil {
   print("With In Block Two")
}
let badresult = functions(funct: "five")

if badresult == nil {
   print("Block Does Not Exist")
}

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

With In Block Two
Block Does Not Exist

Inicializadores fallidos para clases

Un inicializador que falla cuando se declara con enumeraciones y estructuras alerta de un error de inicialización en cualquier circunstancia dentro de su implementación. Sin embargo, el inicializador que falla en las clases alertará sobre la falla solo después de que las propiedades almacenadas se hayan establecido en un valor inicial.

class studrecord {
   let studname: String!
   init?(studname: String) {
      self.studname = studname
      if studname.isEmpty { return nil }
   }
}

if let stname = studrecord(studname: "Failable Initializers") {
   print("Module is \(stname.studname)")
}

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Module is Optional("Failable Initializers")

Anulación de un inicializador fallido

Al igual que en el caso de inicializar, el usuario también tiene la posibilidad de anular un inicializador fallido de superclase dentro de la subclase. La inicialización fallida de superclase también se puede anular con un inicializador no fallido de subclase.

El inicializador de subclase no puede delegar hasta el inicializador de superclase cuando se reemplaza un inicializador de superclase que falla con una inicialización de subclase que no falla.

Un inicializador que no falla nunca puede delegar en un inicializador que falla.

El programa que se proporciona a continuación describe los inicializadores fallidos y no fallidos.

class Planet {
   var name: String
   
   init(name: String) {
      self.name = name
   }
   convenience init() {
      self.init(name: "[No Planets]")
   }
}
let plName = Planet(name: "Mercury")
print("Planet name is: \(plName.name)")

let noplName = Planet()
print("No Planets like that: \(noplName.name)")
   
class planets: Planet {
   var count: Int
   
   init(name: String, count: Int) {
      self.count = count
      super.init(name: name)
   }
   override convenience init(name: String) {
      self.init(name: name, count: 1)
   }
}

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Planet name is: Mercury
No Planets like that: [No Planets]

El init! Inicializador fallido

Swift 4 proporciona 'init?' para definir un inicializador fallable de instancia opcional. Para definir una instancia opcional implícitamente desenvuelta del tipo específico 'init!' está especificado.

struct studrecord {
let stname: String

   init!(stname: String) {
      if stname.isEmpty {return nil }
      self.stname = stname
   }
}
let stmark = studrecord(stname: "Swing")

if let name = stmark {
   print("Student name is specified")
}

let blankname = studrecord(stname: "")

if blankname == nil {
   print("Student name is left blank")
}

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Student name is specified
Student name is left blank

Inicializadores requeridos

Para declarar todas y cada una de las subclases de la palabra clave initialize 'required' debe definirse antes de la función init ().

class classA {
   required init() {
      var a = 10
      print(a)
   }
}

class classB: classA {
   required init() {
      var b = 30
      print(b)
   }
}

let res = classA()
let print = classB()

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

10
30
10

Antes de que se deba desasignar una instancia de clase, se debe llamar a 'desinicializador' para desasignar el espacio de memoria. La palabra clave 'deinit' se utiliza para desasignar los espacios de memoria ocupados por los recursos del sistema. La desinicialización solo está disponible en tipos de clase.

Desinicialización para desasignar espacio de memoria

Swift 4 desasigna automáticamente sus instancias cuando ya no son necesarias, para liberar recursos. Swift 4 maneja la administración de memoria de instancias a través del conteo automático de referencias (ARC), como se describe en Conteo automático de referencias. Normalmente, no es necesario realizar una limpieza manual cuando se desasignan las instancias. Sin embargo, cuando esté trabajando con sus propios recursos, es posible que deba realizar una limpieza adicional usted mismo. Por ejemplo, si crea una clase personalizada para abrir un archivo y escribir algunos datos en él, es posible que deba cerrar el archivo antes de que se desasigne la instancia de la clase.

var counter = 0; // for reference counting
class baseclass {
   init() {
      counter++;
   }
   deinit {
      counter--;
   }
}
var print: baseclass? = baseclass()

print(counter)
print = nil
print(counter)

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

1
0

Cuando se omite la instrucción print = nil, los valores del contador se mantienen iguales ya que no se desinicializa.

var counter = 0; // for reference counting

class baseclass {
   init() {
      counter++;
   }
   deinit {
      counter--;
   }
}
var print: baseclass? = baseclass()
print(counter)
print(counter)

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

1
1

Las funciones de administración de memoria y su uso se manejan en el lenguaje Swift 4 a través del conteo automático de referencias (ARC). ARC se utiliza para inicializar y desinicializar los recursos del sistema, liberando así los espacios de memoria utilizados por las instancias de clase cuando las instancias ya no son necesarias. ARC realiza un seguimiento de la información sobre las relaciones entre nuestras instancias de código para administrar los recursos de memoria de manera efectiva.

Funciones de ARC

  • ARC asigna una parte de la memoria para almacenar la información cada vez que init () crea una nueva instancia de clase.

  • La información sobre el tipo de instancia y sus valores se almacena en la memoria.

  • Cuando la instancia de la clase ya no es necesaria, automáticamente libera el espacio de memoria mediante deinit () para un mayor almacenamiento y recuperación de la instancia de la clase.

  • ARC realiza un seguimiento de las propiedades, constantes y variables de las instancias de clase que se refieren actualmente, de modo que deinit () se aplica solo a las instancias no utilizadas.

  • ARC mantiene una 'fuerte referencia' a esas propiedades de instancia de clase, constantes y variables para restringir la desasignación cuando la instancia de clase está actualmente en uso.

Programa ARC

class StudDetails {
   var stname: String!
   var mark: Int!
   
   init(stname: String, mark: Int) {
      self.stname = stname
      self.mark = mark
   }
   deinit {
      print("Deinitialized \(self.stname)")
      print("Deinitialized \(self.mark)")
   }
}

let stname = "Swift 4"
let mark = 98

print(stname)
print(mark)

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Swift 4
98

Instancias de clase ARC Strong Reference Cycles

class studmarks {
   let name: String
   var stud: student?
   
   init (name: String) {
      print("Initializing: \(name)")
      self.name = name
   }
   deinit {
      print("Deallocating: \(self.name)")
   }
}

class student {
   let name: String
   var strname: studmarks?
   
   init (name: String) {
      print("Initializing: \(name)")
      self.name = name
   }
   deinit {
      print("Deallocating: \(self.name)")
   }
}

var shiba: studmarks?
var mari: student?

shiba = studmarks(name: "Swift 4")
mari = student(name: "ARC")

shiba!.stud = mari
mari!.strname = shiba

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Initializing: Swift 4
Initializing: ARC

Referencias ARC débiles y sin dueño

Las propiedades de tipo de clase tienen dos formas de resolver fuertes ciclos de referencia:

  • Referencias débiles
  • Referencias sin propietario

Estas referencias se utilizan para permitir que una instancia haga referencia a otras instancias en un ciclo de referencia. Entonces, las instancias pueden referirse a todas y cada una de las instancias en lugar de preocuparse por un ciclo de referencia fuerte. Cuando el usuario sabe que alguna instancia puede devolver valores 'nulos', podemos señalar eso usando una referencia débil. Cuando la instancia va a devolver algo en lugar de nil, entonces declárelo con una referencia sin propietario.

Programa de referencia débil

class module {
   let name: String
   init(name: String) { self.name = name }
   var sub: submodule?
   deinit { print("\(name) Is The Main Module") }
}

class submodule {
   let number: Int
   init(number: Int) { self.number = number }
   weak var topic: module?

   deinit { print("Sub Module with its topic number is \(number)") }
}

var toc: module?
var list: submodule?
toc = module(name: "ARC")
list = submodule(number: 4)
toc!.sub = list
list!.topic = toc

toc = nil
list = nil

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

ARC Is The Main Module
Sub Module with its topic number is 4

Programa de referencia sin propietario

class student {
   let name: String
   var section: marks?
   init(name: String) {
      self.name = name
   }
   deinit { print("\(name)") }
}

class marks {
   let marks: Int
   unowned let stname: student
   
   init(marks: Int, stname: student) {
      self.marks = marks
      self.stname = stname
   }
   deinit { print("Marks Obtained by the student is \(marks)") }
}

var module: student?
module = student(name: "ARC")
module!.section = marks(marks: 98, stname: module!)
module = nil

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

ARC
Marks Obtained by the student is 98

Ciclos de referencia fuertes para cierres

Cuando asignamos un cierre a la propiedad de instancia de clase y al cuerpo del cierre para capturar una instancia particular, puede ocurrir un ciclo de referencia fuerte. La fuerte referencia al cierre se define por 'self.someProperty' o 'self.someMethod ()'. Los ciclos de referencia fuertes se utilizan como tipos de referencia para los cierres.

class HTMLElement {
   let samplename: String
   let text: String?
   
   lazy var asHTML: () -> String = {
      if let text = self.text {
         return "<\(self.samplename)>\(text)</\(self.samplename)>"
      } else {
         return "<\(self.samplename) />"
      }
   }
   init(samplename: String, text: String? = nil) {
      self.samplename = samplename
      self.text = text
   }
   deinit {
      print("\(samplename) is being deinitialized")
   }
}

var paragraph: HTMLElement? = HTMLElement(samplename: "p", text: "Welcome to Closure SRC")
print(paragraph!.asHTML())

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

<p>Welcome to Closure SRC</p>

Referencias débiles y sin dueño

Cuando el cierre y la instancia se refieren entre sí, el usuario puede definir la captura en un cierre como una referencia sin dueño. Entonces no permitiría al usuario desasignar la instancia al mismo tiempo. Cuando la instancia en algún momento devuelva un valor 'nulo', defina el cierre con la instancia débil.

class HTMLElement {
   let module: String
   let text: String?
   
   lazy var asHTML: () -> String = {
      [unowned self] in
      if let text = self.text {
         return "<\(self.module)>\(text)</\(self.module)>"
      } else {
         return "<\(self.module) />"
      }
   }
   init(module: String, text: String? = nil) {
      self.module = module
      self.text = text
   }
   deinit {
      print("\(module) the deinit()")
   }
}

var paragraph: HTMLElement? = HTMLElement(module: "Inside", text: "ARC Weak References")
print(paragraph!.asHTML())
paragraph = nil

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

<Inside>ARC Weak References</Inside>
Inside the deinit()

El proceso de consultar, llamar a propiedades, subíndices y métodos en un opcional que puede ser "nulo" se define como encadenamiento opcional. El encadenamiento opcional devuelve dos valores:

  • si el opcional contiene un 'valor', llamar a su propiedad, métodos y subíndices relacionados devuelve valores

  • si el opcional contiene un valor 'nil', todas sus propiedades, métodos y subíndices relacionados devuelven nil

Dado que varias consultas a métodos, propiedades y subíndices se agrupan, la falla en una cadena afectará a toda la cadena y dará como resultado un valor "nulo".

Encadenamiento opcional como alternativa al desenvolvimiento forzado

El encadenamiento opcional se especifica después del valor opcional con '?' para llamar a una propiedad, método o subíndice cuando el valor opcional devuelve algunos valores.

Encadenamiento opcional '?' Acceso a métodos, propiedades y subíndices Encadenamiento opcional '!' forzar el desenvolvimiento
? se coloca después del valor opcional para llamar a la propiedad, método o subíndice ! se coloca después del valor opcional para llamar a la propiedad, método o subíndice para forzar el desenvolvimiento del valor
Falla graciosamente cuando el opcional es 'nil' El desenvolvimiento forzado desencadena un error de tiempo de ejecución cuando el opcional es 'nil'

Programa para encadenamiento opcional con '!'

class ElectionPoll {
   var candidate: Pollbooth?
}

lass Pollbooth {
   var name = "MP"
}

let cand = ElectionPoll()
let candname = cand.candidate!.name

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

fatal error: unexpectedly found nil while unwrapping an Optional value
0 Swift 4 0x0000000103410b68
llvm::sys::PrintStackTrace(__sFILE*) + 40
1 Swift 4 0x0000000103411054 SignalHandler(int) + 452
2 libsystem_platform.dylib 0x00007fff9176af1a _sigtramp + 26
3 libsystem_platform.dylib 0x000000000000000b _sigtramp + 1854492939
4 libsystem_platform.dylib 0x00000001074a0214 _sigtramp + 1976783636
5 Swift 4 0x0000000102a85c39
llvm::JIT::runFunction(llvm::Function*, std::__1::vector > const&) + 329
6 Swift 4 0x0000000102d320b3
llvm::ExecutionEngine::runFunctionAsMain(llvm::Function*,
std::__1::vector<std::__1::basic_string, std::__1::allocator >,
std::__1::allocator<std::__1::basic_string, std::__1::allocator > > > const&,
char const* const*) + 1523
7 Swift 4 0x000000010296e6ba Swift 4::RunImmediately(Swift
4::CompilerInstance&, std::__1::vector<std::__1::basic_string,
std::__1::allocator >, std::__1::allocator<std::__1::basic_string,
std::__1::allocator > > > const&, Swift 4::IRGenOptions&, Swift 4::SILOptions
const&) + 1066
8 Swift 4 0x000000010275764b frontend_main(llvm::ArrayRef,
char const*, void*) + 5275
9 Swift 4 0x0000000102754a6d main + 1677
10 libdyld.dylib 0x00007fff8bb9e5c9 start + 1
11 libdyld.dylib 0x000000000000000c start + 1950751300
Stack dump:
0. Program arguments:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/
usr/bin/Swift 4 -frontend -interpret - -target x86_64-apple-darwin14.0.0 -
target-cpu core2 -sdk
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/
SDKs/MacOSX10.10.sdk -module-name main
/bin/sh: line 47: 15672 Done cat <<'SWIFT 4'
import Foundation
</std::__1::basic_string</std::__1::basic_string</std::__1::basic_string</std::
__1::basic_string

El programa anterior declara 'encuesta electoral' como nombre de clase y contiene 'candidato' como función de membresía. La subclase se declara como 'cabina de votación' y 'nombre' como su función de membresía que se inicializa como 'MP'. La llamada a la superclase se inicializa creando una instancia 'cand' con opcional '!'. Dado que los valores no se declaran en su clase base, el valor 'nil' se almacena y devuelve un error fatal por el procedimiento de desenvolvimiento forzado.

Programa para encadenamiento opcional con '?'

class ElectionPoll {
   var candidate: Pollbooth?
}

class Pollbooth {
   var name = "MP"
}
let cand = ElectionPoll()

if let candname = cand.candidate?.name {
   print("Candidate name is \(candname)")
} else {
   print("Candidate name cannot be retreived")
}

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Candidate name cannot be retreived

El programa anterior declara 'encuesta electoral' como nombre de clase y contiene 'candidato' como función de membresía. La subclase se declara como 'cabina de votación' y 'nombre' como su función de membresía que se inicializa como 'MP'. La llamada a la superclase se inicializa creando una instancia 'cand' con opcional '?'. Dado que los valores no están declarados en su clase base, el bloque controlador else almacena e imprime en la consola.

Definición de clases de modelo para propiedades de acceso y encadenamiento opcionales

El lenguaje Swift 4 también proporciona el concepto de encadenamiento opcional, para declarar más de una subclases como clases modelo. Este concepto será de gran utilidad para definir modelos complejos y acceder a las propiedades, métodos y subpropiedades de subíndices.

class rectangle {
   var print: circle?
}

class circle {
   var area = [radius]()
   var cprint: Int {
      return area.count
   }
   subscript(i: Int) -> radius {
      get {
         return area[i]
      }
      set {
         area[i] = newValue
      }
   }
   func circleprint() {
      print("The number of rooms is \(cprint)")
   }
   var rectarea: circumference?
}

class radius {
   let radiusname: String
   init(radiusname: String) { self.radiusname = radiusname }
}

class circumference {
   var circumName: String?
   var circumNumber: String?
   var street: String?

   func buildingIdentifier() -> String? {
      if circumName != nil {
         return circumName
      } else if circumNumber != nil {
         return circumNumber
      } else {
         return nil
      }
   }
}

let rectname = rectangle()
if let rectarea = rectname.print?.cprint {
   print("Area of rectangle is \(rectarea)")
} else {
   print("Rectangle Area is not specified")
}

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Rectangle Area is not specified

Métodos de llamada mediante encadenamiento opcional

class rectangle {
   var print: circle?
}

class circle {
   var area = [radius]()
   var cprint: Int {
      return area.count
   }
   subscript(i: Int) -> radius {
      get {
         return area[i]
      }
      set {
         area[i] = newValue
      }
   }

   func circleprint() {
      print("Area of Circle is: \(cprint)")
   }
   var rectarea: circumference?
}

class radius {
   let radiusname: String
   init(radiusname: String) { self.radiusname = radiusname }
}

class circumference {
   var circumName: String?
   var circumNumber: String?
   var circumarea: String?
   
   func buildingIdentifier() -> String? {
      if circumName != nil {
         return circumName
      } else if circumNumber != nil {
         return circumNumber
      } else {
         return nil
      }
   }
}

let circname = rectangle()

if circname.print?.circleprint() != nil {
   print("Area of circle is specified)")
} else {
   print("Area of circle is not specified")
}

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Area of circle is not specified

La función circleprint () declarada dentro de la subclase circle () se llama creando una instancia llamada 'circname'. La función devolverá un valor si contiene algún valor; de lo contrario, devolverá algún mensaje de impresión definido por el usuario marcando la declaración 'if circname.print? .Circleprint ()! = Nil'.

Acceso a subíndices mediante encadenamiento opcional

El encadenamiento opcional se utiliza para establecer y recuperar un valor de subíndice para validar si la llamada a ese subíndice devuelve un valor. '?' se coloca antes de las llaves del subíndice para acceder al valor opcional en el subíndice particular.

Programa 1

class rectangle {
   var print: circle?
}

class circle {
   var area = [radius]()
   var cprint: Int {
      return area.count
   }
   subscript(i: Int) -> radius {
      get {
         return area[i]
      }
      set {
         area[i] = newValue
      }
   }
   func circleprint() {
      print("The number of rooms is \(cprint)")
   }
   var rectarea: circumference?
}

class radius {
   let radiusname: String
   init(radiusname: String) { self.radiusname =  radiusname }
}

class circumference {
   var circumName: String?
   var circumNumber: String?
   var circumarea: String?
   
   func buildingIdentifier() -> String? {
      if circumName != nil {
         return circumName
      } else if circumNumber != nil {
         return circumNumber
      } else {
         return nil
      }
   }
}

let circname = rectangle()

if let radiusName = circname.print?[0].radiusname {
   print("The first room name is \(radiusName).")
} else {
   print("Radius is not specified.")
}

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Radius is not specified.

En el programa anterior, no se especifican los valores de instancia para la función de pertenencia 'radiusName'. Por lo tanto, la llamada del programa a la función devolverá solo otra parte, mientras que para devolver los valores tenemos que definir los valores para la función de pertenencia particular.

Programa 2

class rectangle {
   var print: circle?
}

class circle {
   var area = [radius]()
   var cprint: Int {
      return area.count
   }
   subscript(i: Int) -> radius {
      get {
         return area[i]
      }
      set {
         area[i] = newValue
      }
   }
   func circleprint() {
      print("The number of rooms is \(cprint)")
   }
   var rectarea: circumference?
}

class radius {
   let radiusname: String
   init(radiusname: String) { self.radiusname = radiusname }
}

class circumference {
   var circumName: String?
   var circumNumber: String?
   var circumarea: String?
   
   func buildingIdentifier() -> String? {
      if circumName != nil {
         return circumName
      } else if circumNumber != nil {
         return circumNumber
      } else {
         return nil
      }
   }
}

let circname = rectangle()
circname.print?[0] = radius(radiusname: "Diameter")
let printing = circle()

printing.area.append(radius(radiusname: "Units"))
printing.area.append(radius(radiusname: "Meter"))
circname.print = printing

if let radiusName = circname.print?[0].radiusname {
   print("Radius is measured in \(radiusName).")
} else {
   print("Radius is not specified.")
}

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Radius is measured in Units.

En el programa anterior, se especifican los valores de instancia para la función de pertenencia 'radiusName'. Por lo tanto, la llamada del programa a la función ahora devolverá valores.

Acceso a subíndices de tipo opcional

class rectangle {
   var print: circle?
}

class circle {
   var area = [radius]()
   var cprint: Int {
      return area.count
   }

   subscript(i: Int) -> radius {
      get {
         return area[i]
      }
      set {
         area[i] = newValue
      }
   }
   func circleprint() {
      print("The number of rooms is \(cprint)")
   }
   var rectarea: circumference?
}

class radius {
   let radiusname: String
   init(radiusname: String) { self.radiusname = radiusname }
}

class circumference {
   var circumName: String?
   var circumNumber: String?
   var circumarea: String?
   
   func buildingIdentifier() -> String? {
      if circumName != nil {
         return circumName
      } else if circumNumber != nil {
         return circumNumber
      } else {
         return nil
      }
   }
}

let circname = rectangle()
circname.print?[0] = radius(radiusname: "Diameter")

let printing = circle()
printing.area.append(radius(radiusname: "Units"))
printing.area.append(radius(radiusname: "Meter"))
circname.print = printing

var area = ["Radius": [35, 45, 78, 101], "Circle": [90, 45, 56]]
area["Radius"]?[1] = 78
area["Circle"]?[1]--

print(area["Radius"]?[0])
print(area["Radius"]?[1])
print(area["Radius"]?[2])
print(area["Radius"]?[3])

print(area["Circle"]?[0])
print(area["Circle"]?[1])
print(area["Circle"]?[2])

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Optional(35)
Optional(78)
Optional(78)
Optional(101)
Optional(90)
Optional(44)
Optional(56)

Se puede acceder a los valores opcionales de los subíndices haciendo referencia a sus valores de subíndice. Se puede acceder a él como subíndice [0], subíndice [1], etc. Los valores predeterminados del subíndice para 'radio' se asignan primero como [35, 45, 78, 101] y para 'Círculo' [90, 45, 56]] . Luego, los valores del subíndice se cambian como Radio [0] a 78 y Círculo [1] a 45.

Vinculación de múltiples niveles de encadenamiento

También se pueden vincular múltiples subclases con sus métodos, propiedades y subíndices de superclase mediante encadenamiento opcional.

Se pueden vincular múltiples encadenamientos de opcionales -

Si recuperar el tipo no es opcional, el encadenamiento opcional devolverá un valor opcional. Por ejemplo, si String a través del encadenamiento opcional, devolverá String? Valor

class rectangle {
   var print: circle?
}

class circle {
   var area = [radius]()
   var cprint: Int {
      return area.count
   }
   subscript(i: Int) -> radius {
      get {
         return area[i]
      }
      set {
         area[i] = newValue
      }
   }
   func circleprint() {
      print("The number of rooms is \(cprint)")
   }
   var rectarea: circumference?
}

class radius {
   let radiusname: String
   init(radiusname: String) { self.radiusname = radiusname }
}

class circumference {
   var circumName: String?
   var circumNumber: String?
   var circumarea: String?

   func buildingIdentifier() -> String? {
      if circumName != nil {
         return circumName
      } else if circumNumber != nil {
         return circumNumber
      } else {
         return nil
      }
   }
}

let circname = rectangle()

if let radiusName = circname.print?[0].radiusname {
   print("The first room name is \(radiusName).")
} else {
   print("Radius is not specified.")
}

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Radius is not specified.

En el programa anterior, no se especifican los valores de instancia para la función de pertenencia 'radiusName'. Por lo tanto, la llamada del programa a la función devolverá solo otra parte, mientras que para devolver los valores tenemos que definir los valores para la función de pertenencia particular.

Si el tipo de recuperación ya es opcional, el encadenamiento opcional también devolverá un valor opcional. Por ejemplo, si String? ¿Se accede a través del encadenamiento opcional y devolverá String? Valor..

class rectangle {
   var print: circle?
}

class circle {
   var area = [radius]()
   var cprint: Int {
      return area.count
   }
   subscript(i: Int) -> radius {
      get {
         return area[i]
      }
      set {
         area[i] = newValue
      }
   }
   func circleprint() {
      print("The number of rooms is \(cprint)")
   }
   var rectarea: circumference?
}

class radius {
   let radiusname: String
   init(radiusname: String) { self.radiusname = radiusname }
}

class circumference {
   var circumName: String?
   var circumNumber: String?
   var circumarea: String?
   
   func buildingIdentifier() -> String? {
      if circumName != nil {
         return circumName
      } else if circumNumber != nil {
         return circumNumber
      } else {
         return nil
      }
   }
}

let circname = rectangle()
circname.print?[0] = radius(radiusname: "Diameter")
let printing = circle()

printing.area.append(radius(radiusname: "Units"))
printing.area.append(radius(radiusname: "Meter"))
circname.print = printing

if let radiusName = circname.print?[0].radiusname {
   print("Radius is measured in \(radiusName).")
} else {
   print("Radius is not specified.")
}

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Radius is measured in Units.

En el programa anterior, se especifican los valores de instancia para la función de pertenencia 'radiusName'. Por lo tanto, la llamada del programa a la función ahora devolverá valores.

Encadenamiento de métodos con valores de retorno opcionales

El encadenamiento opcional también se utiliza para acceder a métodos definidos por subclases.

class rectangle {
   var print: circle?
}

class circle {
   var area = [radius]()
   var cprint: Int {
      return area.count
   }
   subscript(i: Int) -> radius {
      get {
         return area[i]
      }
      set {
         area[i] = newValue
      }
   }
   func circleprint() {
      print("Area of Circle is: \(cprint)")
   }
   var rectarea: circumference?
}

class radius {
   let radiusname: String
   init(radiusname: String) { self.radiusname = radiusname }
}

class circumference {
   var circumName: String?
   var circumNumber: String?
   var circumarea: String?
   
   func buildingIdentifier() -> String? {
      if circumName != nil {
         return circumName
      } else if circumNumber != nil {
         return circumNumber
      } else {
         return nil
      }
   }
}

let circname = rectangle()

if circname.print?.circleprint() != nil {
   print("Area of circle is specified)")
} else {
   print("Area of circle is not specified")
}

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Area of circle is not specified

Para validar el tipo de instancia, entra en juego 'Type Casting' en el idioma Swift 4. Se utiliza para comprobar si el tipo de instancia pertenece a una superclase o subclase en particular o si está definido en su propia jerarquía.

La conversión de tipo Swift 4 proporciona dos operadores 'es' para verificar el tipo de un valor y 'como' y para convertir el valor de tipo a un tipo diferente. La conversión de tipos también comprueba si el tipo de instancia sigue un estándar de conformidad de protocolo particular.

Definición de una jerarquía de clases

La conversión de tipos se utiliza para verificar el tipo de instancias y averiguar si pertenece a un tipo de clase en particular. Además, verifica la jerarquía de clases y sus subclases para verificar y convertir esas instancias para convertirlas en una misma jerarquía.

class Subjects {
   var physics: String
   init(physics: String) {
      self.physics = physics
   }
}

class Chemistry: Subjects {
   var equations: String
   init(physics: String, equations: String) {
      self.equations = equations
      super.init(physics: physics)
   }
}

class Maths: Subjects {
   var formulae: String
   init(physics: String, formulae: String) {
      self.formulae = formulae
      super.init(physics: physics)
   }
}

let sa = [ Chemistry(physics: "solid physics", equations: "Hertz"),
   Maths(physics: "Fluid Dynamics", formulae: "Giga Hertz")]

let samplechem = Chemistry(physics: "solid physics", equations: "Hertz")
print("Instance physics is: \(samplechem.physics)")
print("Instance equation is: \(samplechem.equations)")

let samplemaths = Maths(physics: "Fluid Dynamics", formulae: "Giga Hertz")
print("Instance physics is: \(samplemaths.physics)")
print("Instance formulae is: \(samplemaths.formulae)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Instance physics is: solid physics
Instance equation is: Hertz
Instance physics is: Fluid Dynamics
Instance formulae is: Giga Hertz

Comprobación de tipo

La verificación de tipos se realiza con el operador 'es'. El operador de verificación de tipo 'es' comprueba si la instancia pertenece a un tipo de subclase en particular y devuelve 'verdadero' si pertenece a esa instancia; de lo contrario, devolverá 'falso'.

class Subjects {
   var physics: String
   init(physics: String) {
      self.physics = physics
   }
}

class Chemistry: Subjects {
   var equations: String
   init(physics: String, equations: String) {
      self.equations = equations
      super.init(physics: physics)
   }
}

class Maths: Subjects {
   var formulae: String
   init(physics: String, formulae: String) {
      self.formulae = formulae
      super.init(physics: physics)
   }
}

let sa = [
   Chemistry(physics: "solid physics", equations: "Hertz"),
   Maths(physics: "Fluid Dynamics", formulae: "Giga Hertz"),
   Chemistry(physics: "Thermo physics", equations: "Decibels"),
   Maths(physics: "Astro Physics", formulae: "MegaHertz"),
   Maths(physics: "Differential Equations", formulae: "Cosine Series")]

let samplechem = Chemistry(physics: "solid physics", equations: "Hertz")
print("Instance physics is: \(samplechem.physics)")
print("Instance equation is: \(samplechem.equations)")

let samplemaths = Maths(physics: "Fluid Dynamics", formulae: "Giga Hertz")
print("Instance physics is: \(samplemaths.physics)")
print("Instance formulae is: \(samplemaths.formulae)")

var chemCount = 0
var mathsCount = 0
for item in sa {
   if item is Chemistry {
      ++chemCount
   } else if item is Maths {
      ++mathsCount
   }
}

print("Subjects in chemistry contains \(chemCount) topics and maths contains \(mathsCount) topics")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Instance physics is: solid physics
Instance equation is: Hertz
Instance physics is: Fluid Dynamics
Instance formulae is: Giga Hertz
Subjects in chemistry contains 2 topics and maths contains 3 topics

Downcasting

Se puede reducir el tipo de subclase con dos operadores (como? Y como!). 'Como?' devuelve un valor opcional cuando el valor devuelve nulo. Se utiliza para comprobar el abatimiento exitoso.

'¡como!' devuelve el desenvolvimiento forzado como se explica en el encadenamiento opcional cuando el abatimiento devuelve un valor nulo. Se utiliza para desencadenar un error de tiempo de ejecución en caso de falla abatida

class Subjects {
   var physics: String
   init(physics: String) {
      self.physics = physics
   }
}

class Chemistry: Subjects {
   var equations: String
   init(physics: String, equations: String) {
      self.equations = equations
      super.init(physics: physics)
   }
}

class Maths: Subjects {
   var formulae: String
   init(physics: String, formulae: String) {
      self.formulae = formulae
      super.init(physics: physics)
   }
}

let sa = [
   Chemistry(physics: "solid physics", equations: "Hertz"),
   Maths(physics: "Fluid Dynamics", formulae: "Giga Hertz"),
   Chemistry(physics: "Thermo physics", equations: "Decibels"),
   Maths(physics: "Astro Physics", formulae: "MegaHertz"),
   Maths(physics: "Differential Equations", formulae: "Cosine Series")]

let samplechem = Chemistry(physics: "solid physics", equations: "Hertz")
print("Instance physics is: \(samplechem.physics)")
print("Instance equation is: \(samplechem.equations)")

let samplemaths = Maths(physics: "Fluid Dynamics", formulae: "Giga Hertz")
print("Instance physics is: \(samplemaths.physics)")
print("Instance formulae is: \(samplemaths.formulae)")

var chemCount = 0
var mathsCount = 0

for item in sa {
   if let print = item as? Chemistry {
      print("Chemistry topics are: '\(print.physics)', \(print.equations)")
   } else if let example = item as? Maths {
      print("Maths topics are: '\(example.physics)', \(example.formulae)")
   }
}

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Instance physics is: solid physics
Instance equation is: Hertz
Instance physics is: Fluid Dynamics
Instance formulae is: Giga Hertz
Chemistry topics are: 'solid physics', Hertz
Maths topics are: 'Fluid Dynamics', Giga Hertz
Chemistry topics are: 'Thermo physics', Decibels
Maths topics are: 'Astro Physics', MegaHertz
Maths topics are: 'Differential Equations', Cosine Series

Tipificación: cualquier objeto

La palabra clave 'Cualquiera' se utiliza para representar una instancia que pertenece a cualquier tipo, incluidos los tipos de función.

class Subjects {
   var physics: String
   init(physics: String) {
      self.physics = physics
   }
}

class Chemistry: Subjects {
   var equations: String
   init(physics: String, equations: String) {
      self.equations = equations
      super.init(physics: physics)
   }
}

class Maths: Subjects {
   var formulae: String
   init(physics: String, formulae: String) {
      self.formulae = formulae
      super.init(physics: physics)
   }
}

let sa = [
   Chemistry(physics: "solid physics", equations: "Hertz"),
   Maths(physics: "Fluid Dynamics", formulae: "Giga Hertz"),
   Chemistry(physics: "Thermo physics", equations: "Decibels"),
   Maths(physics: "Astro Physics", formulae: "MegaHertz"),
   Maths(physics: "Differential Equations", formulae: "Cosine Series")]

let samplechem = Chemistry(physics: "solid physics", equations: "Hertz")
print("Instance physics is: \(samplechem.physics)")
print("Instance equation is: \(samplechem.equations)")

let samplemaths = Maths(physics: "Fluid Dynamics", formulae: "Giga Hertz")
print("Instance physics is: \(samplemaths.physics)")
print("Instance formulae is: \(samplemaths.formulae)")

var chemCount = 0
var mathsCount = 0

for item in sa {
   if let print = item as? Chemistry {
      print("Chemistry topics are: '\(print.physics)', \(print.equations)")
   } else if let example = item as? Maths {
      print("Maths topics are: '\(example.physics)', \(example.formulae)")
   }
}

var exampleany = [Any]()

exampleany.append(12)
exampleany.append(3.14159)
exampleany.append("Example for Any")
exampleany.append(Chemistry(physics: "solid physics", equations: "Hertz"))

for print in exampleany {
   switch print {
      case let someInt as Int:
         print("Integer value is \(someInt)")
      case let someDouble as Double where someDouble > 0:
         print("Pi value is \(someDouble)")
      case let someString as String:
         print("\(someString)")
      case let phy as Chemistry:   
         print("Topics '\(phy.physics)', \(phy.equations)")
      default:
         print("None")
   }
}

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Instance physics is: solid physics
Instance equation is: Hertz
Instance physics is: Fluid Dynamics
Instance formulae is: Giga Hertz
Chemistry topics are: 'solid physics', Hertz
Maths topics are: 'Fluid Dynamics', Giga Hertz
Chemistry topics are: 'Thermo physics', Decibels
Maths topics are: 'Astro Physics', MegaHertz
Maths topics are: 'Differential Equations', Cosine Series
Integer value is 12
Pi value is 3.14159
Example for Any
Topics 'solid physics', Hertz

AnyObject

Para representar la instancia de cualquier tipo de clase, se utiliza la palabra clave 'AnyObject'.

class Subjects {
   var physics: String
   init(physics: String) {
      self.physics = physics
   }
}

class Chemistry: Subjects {
   var equations: String
   init(physics: String, equations: String) {
      self.equations = equations
      super.init(physics: physics)
   }
}

class Maths: Subjects {
   var formulae: String
   init(physics: String, formulae: String) {
      self.formulae = formulae
      super.init(physics: physics)
   }
}

let saprint: [AnyObject] = [Chemistry(physics: "solid physics", equations: "Hertz"),
   Maths(physics: "Fluid Dynamics", formulae: "Giga Hertz"),
   Chemistry(physics: "Thermo physics", equations: "Decibels"),
   Maths(physics: "Astro Physics", formulae: "MegaHertz"),
   Maths(physics: "Differential Equations", formulae: "Cosine Series")]

let samplechem = Chemistry(physics: "solid physics", equations: "Hertz")
print("Instance physics is: \(samplechem.physics)")
print("Instance equation is: \(samplechem.equations)")

let samplemaths = Maths(physics: "Fluid Dynamics", formulae: "Giga Hertz")
print("Instance physics is: \(samplemaths.physics)")
print("Instance formulae is: \(samplemaths.formulae)")

var chemCount = 0
var mathsCount = 0

for item in saprint {
   if let print = item as? Chemistry {
      print("Chemistry topics are: '\(print.physics)', \(print.equations)")
   } else if let example = item as? Maths {
      print("Maths topics are: '\(example.physics)', \(example.formulae)")
   }
}

var exampleany = [Any]()
exampleany.append(12)
exampleany.append(3.14159)
exampleany.append("Example for Any")
exampleany.append(Chemistry(physics: "solid physics", equations: "Hertz"))

for print in exampleany {
   switch print {
      case let someInt as Int:
         print("Integer value is \(someInt)")
      case let someDouble as Double where someDouble > 0:
         print("Pi value is \(someDouble)")
      case let someString as String:
         print("\(someString)")
      case let phy as Chemistry:
         print("Topics '\(phy.physics)', \(phy.equations)")
      default:
         print("None")
   }
}

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Instance physics is: solid physics
Instance equation is: Hertz
Instance physics is: Fluid Dynamics
Instance formulae is: Giga Hertz
Chemistry topics are: 'solid physics', Hertz
Maths topics are: 'Fluid Dynamics', Giga Hertz
Chemistry topics are: 'Thermo physics', Decibels
Maths topics are: 'Astro Physics', MegaHertz
Maths topics are: 'Differential Equations', Cosine Series
Integer value is 12
Pi value is 3.14159
Example for Any
Topics 'solid physics', Hertz

La funcionalidad de una clase, estructura o tipo de enumeración existente se puede agregar con la ayuda de extensiones. La funcionalidad de tipo se puede agregar con extensiones, pero no es posible anular la funcionalidad con las extensiones.

Swift Extension Functionalities -

  • Adición de propiedades calculadas y propiedades de tipo calculado
  • Definición de métodos de instancia y tipo.
  • Proporcionar nuevos inicializadores.
  • Definición de subíndices
  • Definición y uso de nuevos tipos anidados
  • Hacer que un tipo existente se ajuste a un protocolo

Las extensiones se declaran con la palabra clave 'extensión'

Sintaxis

extension SomeType {
   // new functionality can be added here
}

El tipo existente también se puede agregar con extensiones para convertirlo en un protocolo estándar y su sintaxis es similar a la de las clases o estructuras.

extension SomeType: SomeProtocol, AnotherProtocol {
   // protocol requirements is described here
}

Propiedades calculadas

Las propiedades de 'instancia' y 'tipo' calculadas también se pueden ampliar con la ayuda de extensiones.

extension Int {
   var add: Int {return self + 100 }
   var sub: Int { return self - 10 }
   var mul: Int { return self * 10 }
   var div: Int { return self / 5 }
}

let addition = 3.add
print("Addition is \(addition)")

let subtraction = 120.sub
print("Subtraction is \(subtraction)")

let multiplication = 39.mul
print("Multiplication is \(multiplication)")

let division = 55.div
print("Division is \(division)")

let mix = 30.add + 34.sub
print("Mixed Type is \(mix)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Addition is 103
Subtraction is 110
Multiplication is 390
Division is 11
Mixed Type is 154

Inicializadores

Swift 4 ofrece la flexibilidad de agregar nuevos inicializadores a un tipo existente mediante extensiones. El usuario puede agregar sus propios tipos personalizados para ampliar los tipos ya definidos y también son posibles opciones de inicialización adicionales. Las extensiones solo admiten init (). deinit () no es compatible con las extensiones.

struct sum {
   var num1 = 100, num2 = 200
}

struct diff {
   var no1 = 200, no2 = 100
}

struct mult {
   var a = sum()
   var b = diff()
}

let calc = mult()
print ("Inside mult block \(calc.a.num1, calc.a.num2)")
print("Inside mult block \(calc.b.no1, calc.b.no2)")

let memcalc = mult(a: sum(num1: 300, num2: 500),b: diff(no1: 300, no2: 100))
print("Inside mult block \(memcalc.a.num1, memcalc.a.num2)")
print("Inside mult block \(memcalc.b.no1, memcalc.b.no2)")

extension mult {
   init(x: sum, y: diff) {
      let X = x.num1 + x.num2
      let Y = y.no1 + y.no2
   }
}

let a = sum(num1: 100, num2: 200)
print("Inside Sum Block:\( a.num1, a.num2)")

let b = diff(no1: 200, no2: 100)
print("Inside Diff Block: \(b.no1, b.no2)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Inside mult block (100, 200)
Inside mult block (200, 100)
Inside mult block (300, 500)
Inside mult block (300, 100)
Inside Sum Block:(100, 200)
Inside Diff Block: (200, 100)

Métodos

Se pueden agregar nuevos métodos de instancia y métodos de tipo a la subclase con la ayuda de extensiones.

extension Int {
   func topics(summation: () -> ()) {
      for _ in 0..<self {
         summation()
      }
   }
}

4.topics(summation: {
   print("Inside Extensions Block")
})

3.topics(summation: {
   print("Inside Type Casting Block")
})

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Inside Extensions Block
Inside Extensions Block
Inside Extensions Block
Inside Extensions Block
Inside Type Casting Block
Inside Type Casting Block
Inside Type Casting Block

La función topics () toma un argumento de tipo '(suma: () → ())' para indicar que la función no toma ningún argumento y no devolverá ningún valor. Para llamar a esa función varias veces, se inicializa el bloque for y se inicializa la llamada al método con topic ().

Métodos de instancia de mutación

Los métodos de instancia también se pueden modificar cuando se declaran como extensiones.

Los métodos de estructura y enumeración que se modifican a sí mismos o sus propiedades deben marcar el método de instancia como mutante, al igual que los métodos mutados de una implementación original.

extension Double {
   mutating func square() {
      let pi = 3.1415
      self = pi * self * self
   }
}

var Trial1 = 3.3
Trial1.square()
print("Area of circle is: \(Trial1)")

var Trial2 = 5.8
Trial2.square()
print("Area of circle is: \(Trial2)")

var Trial3 = 120.3
Trial3.square()
print("Area of circle is: \(Trial3)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Area of circle is: 34.210935
Area of circle is: 105.68006
Area of circle is: 45464.070735

Subíndices

También es posible agregar nuevos subíndices a instancias ya declaradas con extensiones.

extension Int {
   subscript(var multtable: Int) -> Int {
      var no1 = 1
      while multtable > 0 {
         no1 *= 10
         --multtable
      }
      return (self / no1) % 10
   }
}

print(12[0])
print(7869[1])
print(786543[2])

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

2
6
5

Tipos anidados

Los tipos anidados para instancias de clase, estructura y enumeración también se pueden ampliar con la ayuda de extensiones.

extension Int {
   enum calc {
      case add
      case sub
      case mult
      case div
      case anything
   }
   var print: calc {
      switch self {
         case 0:
            return .add
         case 1:
            return .sub
         case 2:
            return .mult
         case 3:
            return .div
         default:
            return .anything
      }
   }
}

func result(numb: [Int]) {
   for i in numb {
      switch i.print {
         case .add:
            print(" 10 ")
         case .sub:
            print(" 20 ")
         case .mult:
            print(" 30 ")
         case .div:
            print(" 40 ")
         default:
            print(" 50 ")
      }
   }
}
result(numb: [0, 1, 2, 3, 4, 7])

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

10
20
30
40
50
50

Los protocolos proporcionan un modelo de métodos, propiedades y otras funciones de requisitos. Simplemente se describe como un esqueleto de métodos o propiedades en lugar de implementación. La implementación de métodos y propiedades se puede realizar además mediante la definición de clases, funciones y enumeraciones. La conformidad de un protocolo se define como los métodos o propiedades que satisfacen los requisitos del protocolo.

Sintaxis

Los protocolos también siguen una sintaxis similar a la de las clases, estructuras y enumeraciones:

protocol SomeProtocol {
   // protocol definition 
}

Los protocolos se declaran después de los nombres de clase, estructura o tipo de enumeración. También son posibles declaraciones de protocolo único y múltiple. Si se definen varios protocolos, deben estar separados por comas.

struct SomeStructure: Protocol1, Protocol2 {
   // structure definition 
}

Cuando se debe definir un protocolo para la superclase, el nombre del protocolo debe seguir al nombre de la superclase con una coma.

class SomeClass: SomeSuperclass, Protocol1, Protocol2 {
   // class definition 
}

Requisitos de propiedad y método

El protocolo se utiliza para especificar una propiedad de tipo de clase particular o una propiedad de instancia. Solo especifica el tipo o la propiedad de instancia por sí sola en lugar de especificar si es una propiedad almacenada o calculada. Además, se utiliza para especificar si la propiedad es 'obtenible' o 'configurable'.

Los requisitos de propiedad se declaran mediante la palabra clave 'var' como variables de propiedad. {get set} se usa para declarar propiedades obtenibles y configurables después de su declaración de tipo. Gettable es mencionado por la propiedad {get} después de su declaración de tipo.

protocol classa {
   var marks: Int { get set }
   var result: Bool { get }
   
   func attendance() -> String
   func markssecured() -> String
}

protocol classb: classa {
   var present: Bool { get set }
   var subject: String { get set }
   var stname: String { get set }
}

class classc: classb {
   var marks = 96
   let result = true
   var present = false
   var subject = "Swift 4 Protocols"
   var stname = "Protocols"

   func attendance() -> String {
      return "The \(stname) has secured 99% attendance"
   }
   func markssecured() -> String {
      return "\(stname) has scored \(marks)"
   }
}

let studdet = classc()
studdet.stname = "Swift 4"
studdet.marks = 98
studdet.markssecured()

print(studdet.marks)
print(studdet.result)
print(studdet.present)
print(studdet.subject)
print(studdet.stname)

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

98
true
false
Swift 4 Protocols
Swift 4

Requisitos del método de mutación

protocol daysofaweek {
   mutating func print()
}

enum days: daysofaweek {
   case sun, mon, tue, wed, thurs, fri, sat 
   mutating func print() {
      switch self {
         case sun:
            self = sun
            print("Sunday")
         case mon:
            self = mon
            print("Monday")
         case tue:
            self = tue
            print("Tuesday")
         case wed:
            self = wed
            print("Wednesday")
         case mon:
            self = thurs
            print("Thursday")
         case tue:
            self = fri
            print("Friday")
         case sat:
            self = sat
            print("Saturday")
         default:
            print("NO Such Day")
      }
   }
}

var res = days.wed
res.print()

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Wednesday

Requisitos del inicializador

Swing permite al usuario inicializar protocolos para seguir una conformidad de tipo similar a la de los inicializadores normales.

Sintaxis

protocol SomeProtocol {
   init(someParameter: Int)
}

Por ejemplo

protocol tcpprotocol {
   init(aprot: Int)
}

Implementaciones de clase de requisitos de inicializador de protocolo

El inicializador designado o de conveniencia permite al usuario inicializar un protocolo para cumplir con su estándar mediante la palabra clave reservada 'requerida'.

class SomeClass: SomeProtocol {
   required init(someParameter: Int) {
      // initializer implementation statements
   }
}

protocol tcpprotocol {
   init(aprot: Int)
}

class tcpClass: tcpprotocol {
   required init(aprot: Int) {
   }
}

La conformidad del protocolo está asegurada en todas las subclases para la implementación explícita o heredada mediante el modificador "requerido".

Cuando una subclase anula su requisito de inicialización de superclase, se especifica mediante la palabra clave modificadora 'anular'.

protocol tcpprotocol {
   init(no1: Int)
}

class mainClass {
   var no1: Int        // local storage
   init(no1: Int) {
      self.no1 = no1  // initialization
   }
}

class subClass: mainClass, tcpprotocol {
   var no2: Int
   init(no1: Int, no2 : Int) {
      self.no2 = no2
      super.init(no1:no1)
   }
   // Requires only one parameter for convenient method
   required override convenience init(no1: Int) {
      self.init(no1:no1, no2:0)
   }
}

let res = mainClass(no1: 20)
let print = subClass(no1: 30, no2: 50)

print("res is: \(res.no1)")
print("res is: \(print.no1)")
print("res is: \(print.no2)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

res is: 20
res is: 30
res is: 50

Protocolos como tipos

En lugar de implementar funcionalidades en un protocolo, se utilizan como tipos para funciones, clases, métodos, etc.

Se puede acceder a los protocolos como tipos en:

  • Función, método o inicialización como parámetro o tipo de retorno

  • Constante, variable o propiedad

  • Matrices, diccionarios u otros contenedores como elementos

protocol Generator {
   typealias members
   func next() -> members?
}

var items = [10,20,30].generate()
while let x = items.next() {
   print(x)
}

for lists in map([1,2,3], {i in i*5}) {
   print(lists)
}

print([100,200,300])
print(map([1,2,3], {i in i*10}))

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

10
20
30
5
10
15
[100, 200, 300]
[10, 20, 30]

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

El tipo existente puede adoptarse y ajustarse a un nuevo protocolo mediante el uso de extensiones. Se pueden agregar nuevas propiedades, métodos y subíndices a los tipos existentes con la ayuda de extensiones.

protocol AgeClasificationProtocol {
   var age: Int { get }
   func agetype() -> String
}
class Person {
   let firstname: String
   let lastname: String
   var age: Int
   
   init(firstname: String, lastname: String) {
      self.firstname = firstname
      self.lastname = lastname
      self.age = 10
   }
}

extension Person : AgeClasificationProtocol {
   func fullname() -> String {
      var c: String
      c = firstname + " " + lastname
      return c
   }
   func agetype() -> String {
      switch age {
         case 0...2:
            return "Baby"
         case 2...12:
            return "Child"
         case 13...19:
            return "Teenager"
         case let x where x > 65:
            return "Elderly"
         default:
            return "Normal"
      }
   }
}

Herencia del protocolo

Swift 4 permite que los protocolos hereden propiedades de sus propiedades definidas. Es similar a la herencia de clases, pero con la opción de listar varios protocolos heredados separados por comas.

protocol classa {
   var no1: Int { get set }
   func calc(sum: Int)
}
protocol result {
   func print(target: classa)
}
class student2: result {
   func print(target: classa) {
      target.calc(sum: 1)
   }
}
class classb: result {
   func print(target: classa) {
      target.calc(sum: 5)
   }
}

class student: classa {
   var no1: Int = 10
   
   func calc(sum: Int) {
      no1 -= sum
      print("Student attempted \(sum) times to pass")
         
      if no1 <= 0 {
         print("Student is absent for exam")
      }
   }
}

class Player {
   var stmark: result!

   init(stmark: result) {
      self.stmark = stmark
   }
   func print(target: classa) {
      stmark.print(target: target)
   }
}

var marks = Player(stmark: student2())
var marksec = student()

marks.print(target: marksec)
marks.print(target: marksec)
marks.print(target: marksec)
marks.stmark = classb()
marks.print(target: marksec)
marks.print(target: marksec)
marks.print(target: marksec)

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Student attempted 1 times to pass
Student attempted 1 times to pass
Student attempted 1 times to pass
Student attempted 5 times to pass
Student attempted 5 times to pass
Student is absent for exam
Student attempted 5 times to pass
Student is absent for exam

Protocolos de clase única

Cuando se definen protocolos y el usuario desea definir un protocolo con clases, se debe agregar definiendo primero la clase seguida de la lista de herencia del protocolo.

protocol tcpprotocol {
   init(no1: Int)
}
class mainClass {
   var no1: Int        // local storage
   init(no1: Int) {
      self.no1 = no1  // initialization
   }
}
class subClass: mainClass, tcpprotocol {
   var no2: Int
   init(no1: Int, no2 : Int) {
      self.no2 = no2
      super.init(no1:no1)
   }
   
   // Requires only one parameter for convenient method
   required override convenience init(no1: Int) {
      self.init(no1:no1, no2:0)
   }
}

let res = mainClass(no1: 20)
let print = subClass(no1: 30, no2: 50)

print("res is: \(res.no1)")
print("res is: \(print.no1)")
print("res is: \(print.no2)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

res is: 20
res is: 30
res is: 50

Composición del protocolo

Swift 4 permite llamar a múltiples protocolos a la vez con la ayuda de la composición del protocolo.

Sintaxis

protocol<SomeProtocol, AnotherProtocol>

Ejemplo

protocol stname {
   var name: String { get }
}
protocol stage {
   var age: Int { get }
}
struct Person: stname, stage {
   var name: String
   var age: Int
}
func print(celebrator: stname & stage) {
   print("\(celebrator.name) is \(celebrator.age) years old")
}
let studname = Person(name: "Priya", age: 21)
print(studname)

let stud = Person(name: "Rehan", age: 29)
print(stud)

let student = Person(name: "Roshan", age: 19)
print(student)

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Person(name: "Priya", age: 21)
Person(name: "Rehan", age: 29)
Person(name: "Roshan", age: 19)

Comprobación de la conformidad del protocolo

La conformidad del protocolo se prueba mediante operadores 'is' y 'as' similares a los de la fundición de tipos.

  • El operador is devuelve verdadero si una instancia cumple con el estándar del protocolo y devuelve falso si falla.

  • los as? La versión del operador downcast devuelve un valor opcional del tipo de protocolo, y este valor es nulo si la instancia no se ajusta a ese protocolo.

  • La versión as del operador abatido obliga al abatido al tipo de protocolo y desencadena un error de tiempo de ejecución si el abatimiento no tiene éxito.

import Foundation

@objc protocol rectangle {
   var area: Double { get }
}
@objc class Circle: rectangle {
   let pi = 3.1415927
   var radius: Double
   var area: Double { return pi * radius * radius }
   init(radius: Double) { self.radius = radius }
}
@objc class result: rectangle {
   var area: Double
   init(area: Double) { self.area = area }
}
class sides {
   var rectsides: Int
   init(rectsides: Int) { self.rectsides = rectsides }
}
let objects: [AnyObject] = [Circle(radius: 2.0),result(area:198),sides(rectsides: 4)]

for object in objects {
   if let objectWithArea = object as? rectangle {
      print("Area is \(objectWithArea.area)")
   } else {
      print("Rectangle area is not defined")
   }
}

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Area is 12.5663708
Area is 198.0
Rectangle area is not defined

El lenguaje Swift 4 proporciona funciones "genéricas" para escribir funciones y tipos flexibles y reutilizables. Los genéricos se utilizan para evitar la duplicación y proporcionar abstracción. Las bibliotecas estándar de Swift 4 se crean con código genérico. Los tipos Swift 4s 'Arrays' y 'Dictionary' pertenecen a colecciones genéricas. Con la ayuda de matrices y diccionarios, las matrices se definen para contener valores 'Int' y valores de 'Cadena' o cualquier otro tipo.

func exchange(a: inout Int, b: inout Int) {
   let temp = a
   a = b
   b = temp
}

var numb1 = 100
var numb2 = 200

print("Before Swapping values are: \(numb1) and \(numb2)")
exchange(a: &numb1, b: &numb2)
print("After Swapping values are: \(numb1) and \(numb2)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Before Swapping values are: 100 and 200
After Swapping values are: 200 and 100

Funciones genéricas: parámetros de tipo

Las funciones genéricas se pueden utilizar para acceder a cualquier tipo de datos como 'Int' o 'String'.

func exchange<T>(a: inout T, b: inout T) {
   let temp = a
   a = b
   b = temp
}
var numb1 = 100
var numb2 = 200

print("Before Swapping Int values are: \(numb1) and \(numb2)")
exchange(a: &numb1, b: &numb2)
print("After Swapping Int values are: \(numb1) and \(numb2)")

var str1 = "Generics"
var str2 = "Functions"

print("Before Swapping String values are: \(str1) and \(str2)")
exchange(a: &str1, b: &str2)
print("After Swapping String values are: \(str1) and \(str2)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Before Swapping Int values are: 100 and 200
After Swapping Int values are: 200 and 100
Before Swapping String values are: Generics and Functions
After Swapping String values are: Functions and Generics

La función exchange () se usa para intercambiar valores que se describen en el programa anterior y <T> se usa como parámetro de tipo. Por primera vez, se llama a la función exchange () para devolver valores 'Int' y la segunda llamada a la función exchange () devolverá valores 'String'. Se pueden incluir varios tipos de parámetros dentro de los corchetes angulares separados por comas.

Los parámetros de tipo se denominan definidos por el usuario para conocer el propósito del parámetro de tipo que contiene. Swift 4 proporciona <T> como nombre de parámetro de tipo genérico. Sin embargo, los parámetros de tipo como Matrices y Diccionarios también se pueden nombrar como clave, valor para identificar que pertenecen al tipo 'Diccionario'.

struct TOS<T> {
   var items = [T]()
   mutating func push(item: T) {
      items.append(item)
   }
   mutating func pop() -> T {
      return items.removeLast()
   }
}

var tos = TOS<String>()
tos.push(item: "Swift 4")
print(tos.items)

tos.push(item: "Generics")
print(tos.items)

tos.push(item: "Type Parameters")
print(tos.items)

tos.push(item: "Naming Type Parameters")
print(tos.items)

let deletetos = tos.pop()

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

[Swift 4]
[Swift 4, Generics]
[Swift 4, Generics, Type Parameters]
[Swift 4, Generics, Type Parameters, Naming Type Parameters]

Ampliación de un tipo genérico

La extensión de la propiedad de la pila para conocer la parte superior del elemento se incluye con la palabra clave 'extensión'.

struct TOS<T> {
   var items = [T]()
   mutating func push(item: T) {
      items.append(item)
   }
   mutating func pop() -> T {
      return items.removeLast()
   }
}
var tos = TOS<String>()
tos.push(item: "Swift 4")
print(tos.items)

tos.push(item: "Generics")
print(tos.items)

tos.push(item: "Type Parameters")
print(tos.items)

tos.push(item: "Naming Type Parameters")
print(tos.items)

extension TOS {
   var first: T? {
      return items.isEmpty ? nil : items[items.count - 1]
   }
}
if let first = tos.first {
   print("The top item on the stack is \(first).")
}

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

["Swift 4"]
["Swift 4", "Generics"]
["Swift 4", "Generics", "Type Parameters"]
["Swift 4", "Generics", "Type Parameters", "Naming Type Parameters"]
The top item on the stack is Naming Type Parameters.

Restricciones de tipo

El lenguaje Swift 4 permite 'restricciones de tipo' para especificar si el parámetro de tipo hereda de una clase específica o para garantizar el estándar de conformidad del protocolo.

func exchange<T>(a: inout T, b: inout T) {
   let temp = a
   a = b
   b = temp
}
var numb1 = 100
var numb2 = 200

print("Before Swapping Int values are: \(numb1) and \(numb2)")
exchange(a: &numb1, b: &numb2)
print("After Swapping Int values are: \(numb1) and \(numb2)")

var str1 = "Generics"
var str2 = "Functions"

print("Before Swapping String values are: \(str1) and \(str2)")
exchange(a: &str1, b: &str2)
print("After Swapping String values are: \(str1) and \(str2)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Before Swapping Int values are: 100 and 200
After Swapping Int values are: 200 and 100
Before Swapping String values are: Generics and Functions
After Swapping String values are: Functions and Generics

Tipos asociados

Swift 4 permite que los tipos asociados se declaren dentro de la definición del protocolo mediante la palabra clave 'associatedtype'.

protocol Container {
   associatedtype ItemType
   mutating func append(item: ItemType)
   var count: Int { get }
   subscript(i: Int) -> ItemType { get }
}
struct TOS<T>: Container {
   // original Stack<T> implementation
   var items = [T]()
   mutating func push(item: T) {
      items.append(item)
   }
   mutating func pop() -> T {
      return items.removeLast()
   }
   
   // conformance to the Container protocol
   mutating func append(item: T) {
      self.push(item: item)
   }
   var count: Int {
      return items.count
   }
   subscript(i: Int) -> T {
      return items[i]
   }
}
var tos = TOS<String>()
tos.push(item: "Swift 4")
print(tos.items)

tos.push(item: "Generics")
print(tos.items)

tos.push(item: "Type Parameters")
print(tos.items)

tos.push(item: "Naming Type Parameters")
print(tos.items)

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

[Swift 4]
[Swift 4, Generics]
[Swift 4, Generics, Type Parameters]
[Swift 4, Generics, Type Parameters, Naming Type Parameters]

Donde las cláusulas

Las restricciones de tipo permiten al usuario definir requisitos sobre los parámetros de tipo asociados con una función o tipo genérico. Para definir los requisitos para los tipos asociados, las cláusulas 'donde' se declaran como parte de la lista de parámetros de tipo. La palabra clave 'donde' se coloca inmediatamente después de la lista de parámetros de tipo seguida de restricciones de tipos asociados, relaciones de igualdad entre tipos y tipos asociados.

protocol Container {
   associatedtype ItemType
   mutating func append(item: ItemType)
   var count: Int { get }
   subscript(i: Int) -> ItemType { get }
}
struct Stack<T>: Container {
   // original Stack<T> implementation
   var items = [T]()
   mutating func push(item: T) {
      items.append(item)
   }
   mutating func pop() -> T {
      return items.removeLast()
   }

   // conformance to the Container protocol
   mutating func append(item: T) {
      self.push(item: item)
   }
   var count: Int {
      return items.count
   }
   subscript(i: Int) -> T {
      return items[i]
   }
}
func allItemsMatch<
C1: Container, C2: Container
where C1.ItemType == C2.ItemType, C1.ItemType: Equatable>
(someContainer: C1, anotherContainer: C2) -> Bool {
   // check that both containers contain the same number of items
   if someContainer.count != anotherContainer.count {
      return false
   }
   
   // check each pair of items to see if they are equivalent
   for i in 0..<someContainer.count {
      if someContainer[i] != anotherContainer[i] {
         return false
      }
   }
   // all items match, so return true
   return true
}  
var tos = Stack<String>()

tos.push(item: "Swift 4")
print(tos.items)

tos.push(item: "Generics")
print(tos.items)

tos.push(item: "Where Clause")
print(tos.items)

var eos = ["Swift 4", "Generics", "Where Clause"]
print(eos)

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

[Swift 4]
[Swift 4, Generics]
[Swift 4, Generics, Where Clause]
[Swift 4, Generics, Where Clause]

Para restringir el acceso a bloques de código, módulos y abstracción se realiza a través del control de acceso. Se puede acceder a clases, estructuras y enumeraciones según sus propiedades, métodos, inicializadores y subíndices mediante mecanismos de control de acceso. Las constantes, variables y funciones en un protocolo están restringidas y se permite el acceso como global y local a través del control de acceso. El control de acceso aplicado a propiedades, tipos y funciones puede denominarse "entidades".

El modelo de control de acceso se basa en módulos y archivos fuente.

El módulo se define como una sola unidad de distribución de código y se puede importar utilizando la palabra clave 'importar'. Un archivo fuente se define como un solo archivo de código fuente dentro de un módulo para acceder a múltiples tipos y funciones.

Swift 4 language proporciona tres niveles de acceso diferentes. Son de acceso Público, Interno y Privado.

S. No Niveles de acceso y definición
1

Public

Permite que las entidades se procesen en cualquier archivo de origen desde su módulo de definición, un archivo de origen de otro módulo que importa el módulo de definición.

2

Internal

Permite que las entidades se utilicen dentro de cualquier archivo fuente desde su módulo de definición, pero no en ningún archivo fuente fuera de ese módulo.

3

Private

Restringe el uso de una entidad a su propio archivo fuente de definición. El acceso privado juega un papel importante para ocultar los detalles de implementación de una funcionalidad de código específico.

Sintaxis

public class SomePublicClass {}
internal class SomeInternalClass {}
private class SomePrivateClass {}

public var somePublicVariable = 0
internal let someInternalConstant = 0
private func somePrivateFunction() {}

Control de acceso para tipos de funciones

Algunas funciones pueden tener argumentos declarados dentro de la función sin ningún valor de retorno. El siguiente programa declara ayb como argumentos de la función sum (). Dentro de la función en sí, los valores para los argumentos ayb se pasan invocando la llamada a la función sum () y sus valores se imprimen eliminando así los valores de retorno. Para que el tipo de retorno de la función sea privado, declare el nivel de acceso general de la función con el modificador privado.

private func sum(a: Int, b: Int) {
   let a = a + b
   let b = a - b
   print(a, b)
}

sum(a: 20, b: 10)
sum(a: 40, b: 10)
sum(a: 24, b: 6)

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

30 20
50 40
30 24

Control de acceso para tipos de enumeración

public enum Student {
   case Name(String)
   case Mark(Int,Int,Int)
}
var studDetails = Student.Name("Swift 4")
var studMarks = Student.Mark(98,97,95)

switch studMarks {
   case .Name(let studName):
      print("Student name is: \(studName).")
   case .Mark(let Mark1, let Mark2, let Mark3):
      print("Student Marks are: \(Mark1),\(Mark2),\(Mark3).")
   
}

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Student Marks are: 98,97,95

La enumeración en el idioma Swift 4 recibe automáticamente el mismo nivel de acceso para casos individuales de una enumeración. Considere, por ejemplo, acceder al nombre de los estudiantes y las marcas aseguradas en tres asignaturas. El nombre de enumeración se declara como estudiante y los miembros presentes en la clase de enumeración son nombres que pertenecen al tipo de datos de cadena, las marcas se representan como mark1, mark2 y mark3 del tipo de datos Integer. Para acceder al nombre del estudiante o las notas que ha obtenido. Ahora, el caso del interruptor imprimirá el nombre del estudiante si se ejecuta ese bloque de caso, de lo contrario, imprimirá las marcas obtenidas por el estudiante. Si ambas condiciones fallan, se ejecutará el bloque predeterminado.

Control de acceso para subclases

Swift 4 permite al usuario crear una subclase de cualquier clase a la que se pueda acceder en el contexto de acceso actual. Una subclase no puede tener un nivel de acceso más alto que su superclase. El usuario no puede escribir una subclase pública de una superclase interna.

public class cricket {
   internal func printIt() {
      print("Welcome to Swift 4 Super Class")
   }
}

internal class tennis: cricket {
   override internal func printIt() {
      print("Welcome to Swift 4 Sub Class")
   }
}

let cricinstance = cricket()
cricinstance.printIt()

let tennisinstance = tennis()
tennisinstance.printIt()

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Welcome to Swift Super Class
Welcome to Swift Sub Class

Control de acceso para constantes, variables, propiedades y subíndices

La constante, variable o propiedad de Swift 4 no se puede definir como pública más que su tipo. No es válido escribir una propiedad pública con un tipo privado. De manera similar, un subíndice no puede ser más público que su índice o tipo de retorno.

Cuando una constante, variable, propiedad o subíndice hace uso de un tipo privado, la constante, variable, propiedad o subíndice también debe marcarse como privado:

private var privateInstance = SomePrivateClass()

Getters y Setters

Los captadores y definidores de constantes, variables, propiedades y subíndices reciben automáticamente el mismo nivel de acceso que la constante, variable, propiedad o subíndice al que pertenecen.

class Samplepgm {
   var counter: Int = 0{
      willSet(newTotal) {
         print("Total Counter is: \(newTotal)")
      }
      didSet {
         if counter > oldValue {
            print("Newly Added Counter \(counter - oldValue)")
         }
      }
   }
}

let NewCounter = Samplepgm()
NewCounter.counter = 100
NewCounter.counter = 800

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

Total Counter is: 100
Newly Added Counter 100
Total Counter is: 800
Newly Added Counter 700

Control de acceso para inicializadores e inicializadores predeterminados

A los inicializadores personalizados se les puede asignar un nivel de acceso menor o igual al tipo que inicializan. Un inicializador obligatorio debe tener el mismo nivel de acceso que la clase a la que pertenece. Los tipos de parámetros de un inicializador no pueden ser más privados que el propio nivel de acceso del inicializador.

Para declarar todas y cada una de las subclases de la palabra clave initialize 'required' debe definirse antes de la función init ().

class classA {
   required init() {
      let a = 10
      print(a)
   }
}
class classB: classA {
   required init() {
      let b = 30
      print(b)
   }
}
let res = classA()
let print = classB()

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

10
30
10

Un inicializador predeterminado tiene el mismo nivel de acceso que el tipo que inicializa, a menos que ese tipo esté definido como público. Cuando la inicialización predeterminada se define como pública, se considera interna. Cuando el usuario necesita que un tipo público se pueda inicializar con un inicializador sin argumentos en otro módulo, proporcione explícitamente un inicializador sin argumentos público como parte de la definición del tipo.

Control de acceso para protocolos

Cuando definimos un nuevo protocolo para heredar funcionalidades de un protocolo existente, ambos deben declararse con los mismos niveles de acceso para heredar las propiedades del otro. El control de acceso de Swift 4 no permitirá a los usuarios definir un protocolo "público" que herede de un protocolo "interno".

public protocol tcpprotocol {
   init(no1: Int)
}
public class mainClass {
   var no1: Int      // local storage
   init(no1: Int) {
      self.no1 = no1 // initialization
   }
}
class subClass: mainClass, tcpprotocol {
   var no2: Int
   init(no1: Int, no2 : Int) {
      self.no2 = no2
      super.init(no1:no1)
   }
   
   // Requires only one parameter for convenient method
   required override convenience init(no1: Int) {
      self.init(no1:no1, no2:0)
   }
}

let res = mainClass(no1: 20)
let print = subClass(no1: 30, no2: 50)

print("res is: \(res.no1)")
print("res is: \(print.no1)")
print("res is: \(print.no2)")

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

res is: 20
res is: 30
res is: 50

Control de acceso para extensiones

Swift 4 no permite a los usuarios proporcionar un modificador de nivel de acceso explícito para una extensión cuando el usuario usa esa extensión para agregar conformidad con el protocolo. El nivel de acceso predeterminado para cada implementación de requisitos de protocolo dentro de la extensión se proporciona con su propio nivel de acceso de protocolo.

Control de acceso para genéricos

Los genéricos permiten al usuario especificar niveles mínimos de acceso para acceder a las restricciones de tipo en sus parámetros de tipo.

public struct TOS<T> {
   var items = [T]()
   mutating func push(item: T) {
      items.append(item)
   }
   mutating func pop() -> T {
      return items.removeLast()
   }
}

var tos = TOS<String>()
tos.push(item: "Swift 4")
print(tos.items)

tos.push(item: "Generics")
print(tos.items)

tos.push(item: "Type Parameters")
print(tos.items)

tos.push(item: "Naming Type Parameters")
print(tos.items)
let deletetos = tos.pop()

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

[Swift 4]
[Swift 4, Generics]
[Swift 4, Generics, Type Parameters]
[Swift 4, Generics, Type Parameters, Naming Type Parameters]

Control de acceso para alias de tipo

El usuario puede definir alias de tipos para tratar distintos tipos de control de acceso. El usuario puede definir el mismo nivel de acceso o diferentes niveles de acceso. Cuando el alias de tipo es 'privado', sus miembros asociados pueden declararse como 'privados, internos de tipo público'. Cuando el alias de tipo es público, los miembros no pueden ser alias como un nombre 'interno' o 'privado'

Los alias de tipo que defina se tratan como tipos distintos a los efectos del control de acceso. Un alias de tipo puede tener un nivel de acceso menor o igual que el nivel de acceso del tipo al que alias. Por ejemplo, un alias de tipo privado puede alias un tipo privado, interno o público, pero un alias de tipo público no puede alias un tipo interno o privado.

public protocol Container {
   associatedtype ItemType
   mutating func append(item: ItemType)
   var count: Int { get }
   subscript(i: Int) -> ItemType { get }
}
struct Stack<T>: Container {
   // original Stack<T> implementation
   var items = [T]()
   mutating func push(item: T) {
      items.append(item)
   }
   mutating func pop() -> T {
      return items.removeLast()
   }
   
   // conformance to the Container protocol
   mutating func append(item: T) {
      self.push(item: item)
   }
   var count: Int {
      return items.count
   }
   subscript(i: Int) -> T {
      return items[i]
   }
}
func allItemsMatch<
   C1: Container, C2: Container
   where C1.ItemType == C2.ItemType, C1.ItemType: Equatable>
   (someContainer: C1, anotherContainer: C2) -> Bool {
   
   // check that both containers contain the same number of items
   if someContainer.count != anotherContainer.count {
      return false
   }
   
   // check each pair of items to see if they are equivalent
   for i in 0..<someContainer.count {
      if someContainer[i] != anotherContainer[i] {
         return false
      }
   }
   // all items match, so return true
   return true
}
var tos = Stack<String>()
tos.push(item: "Swift 4")
print(tos.items)

tos.push(item: "Generics")
print(tos.items)

tos.push(item: "Where Clause")
print(tos.items)

var eos = ["Swift 4", "Generics", "Where Clause"]
print(eos)

Cuando ejecutamos el programa anterior usando el patio de recreo, obtenemos el siguiente resultado:

[Swift 4]
[Swift 4, Generics]
[Swift 4, Generics, Where Clause]
[Swift 4, Generics, Where Clause]

Codificación y decodificación rápida

Swift 4 presenta un nuevo Codable Protocolo, que le permite serializar y deserializar tipos de datos personalizados sin escribir ningún código especial y sin tener que preocuparse por perder sus tipos de valor.

struct Language: Codable {
   var name: String
   var version: Int
}
let swift = Language(name: "Swift", version: 4)
let java = Language(name: "java", version: 8)
let R = Language(name: "R", version: 3

Tenga en cuenta que Langauage se ajusta al Protocolo de codificación. Ahora lo convertiremos en una representación de datos Json usando una línea simple.

let encoder = JSONEncoder()
if let encoded = try? encoder.encode(java) {
   //Perform some operations on this value.
}

Swift codificará automáticamente todos los valores dentro de su tipo de datos.

Puede decodificar los datos utilizando la función Decodificador como

let decoder = JSONDecoder()
if let decoded = try? decoder.decode(Language.self, from: encoded) {
   //Perform some operations on this value.
}

Tanto JSONEncoder como su contraparte de la lista de propiedades PropertyListEncoder tienen muchas opciones para personalizar cómo funcionan.