Unlimited WordPress themes, graphics, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. Swift
Code

iOS desde cero con Swift: más rápido en pocas palabras

by
Difficulty:BeginnerLength:LongLanguages:
This post is part of a series called iOS From Scratch With Swift.
iOS From Scratch With Swift: Swift in a Nutshell
iOS From Scratch With Swift: Exploring the iOS SDK

Spanish (Español) translation by Elías Nicolás (you can also view the original English article)

Si bien este tutorial se centra principalmente en las funciones y clausura, tomamos un breve desvío al final para explorar los protocolos y el control de acceso. Trabajaremos con protocolos más adelante en esta serie, por lo que es importante familiarizarse con ellos desde el principio.

Hace unos meses, escribí una serie sobre el lenguaje de programación Swift en el que analicé de cerca funciones y clausura. Este artículo resume lo que escribí en estos tutoriales. Si desea obtener más información sobre funciones y cierres, le recomiendo leer los artículos de esa serie:

Antes de sumergirnos en el tema de las funciones y los cierres, es hora de encender Xcode y crear uno. ¿Listo? Vamos a escribir código.

1. Funciones

¿Qué es una función?

Una función no es más que un bloque de código que se puede ejecutar cuando sea necesario. Me gustaría comenzar con un ejemplo para analizar la anatomía básica de una función en Swift. Agregue la siguiente definición de función a su patio de juegos.

Una función comienza con la palabra clave func y es seguida por el nombre de la función, printHelloWorld en el ejemplo anterior. Como en muchos otros idiomas, el nombre de la función es seguido por un par de paréntesis que contienen los parámetros de la función, la entrada de la función.

El cuerpo de la función está envuelto en un par de llaves. El cuerpo de la función printHelloWorld() contiene una declaración en la que imprimimos la cadena "Hello World!" en la salida estándar. Así es como se ve una función básica en Swift. Para invocar la función, escribimos su nombre seguido de un par de paréntesis.

Parámetros

Hagamos que el ejemplo anterior sea un poco más complejo agregando parámetros a la definición de la función. Al agregar parámetros, proporcionamos a la función valores de entrada que puede usar en su cuerpo. En el siguiente ejemplo, definimos la función printMessage(_ :), que acepta un parámetro, message, de tipo String.

Una función puede aceptar múltiples parámetros o valores de entrada. Los parámetros están envueltos por los paréntesis que siguen el nombre de la función. El nombre del parámetro es seguido por dos puntos y su tipo. Como recuerdas, esto es muy similar a declarar una variable o constante. Simplemente dice que el parámetro message es de tipo String.

Invocar la función es similar a lo que vimos anteriormente. La diferencia es que pasamos en un argumento.

El siguiente ejemplo se ve similar. La única diferencia es que la función define dos parámetros, message de tipo String y times de tipo Int.

Si bien el nombre de la función es idéntico al de la función printMessage(_ :) original, el tipo de función es diferente. Es importante que entiendas esta diferencia. Cada función tiene un tipo, que consiste en los tipos de parámetros y el tipo de retorno. Exploraremos los tipos de devolución en un momento. Las funciones pueden tener el mismo nombre siempre que su tipo sea diferente, como se muestra en las dos definiciones de funciones anteriores.

El tipo de la primera función es (String) -> () mientras que el tipo de la segunda función es (String, Int) -> (). El nombre de ambas funciones es el mismo. No te preocupes por el símbolo ->. Su significado quedará claro en unos momentos cuando analicemos los tipos en retorno.

La segunda función printMessage(_:times:) define dos parámetros, message de tipo String y times de tipo Int. Esta firma de función ilustra una de las características que Swift ha adoptado de Objective-C, función legible y nombres de métodos.

Tipos en devolución

Las funciones que hemos visto hasta ahora no nos devuelven nada cuando las invocamos. Vamos a crear una función que formatea una fecha. La función toma dos argumentos, una fecha de tipo NSDate y una cadena de formato de tipo String. Como las clases NSDate y NSDateFormatter están definidas en el marco Foundation, necesitamos importar Foundation en la parte superior.

Hay algunas cosas que requieren alguna explicación. El símbolo -> indica que la función devuelve un valor. El tipo del valor se define después del simbolo ->, String.

La función acepta dos argumentos y el segundo tiene un valor predeterminado. Esto se indica mediante la asignación que sigue al tipo del segundo argumento. El valor predeterminado de format es "YY/MM/dd". Esto significa que podemos invocar la función con un solo argumento. La autocompletación de Xcode ilustra esto.

Default Value for Parameter

Si una función no tiene un tipo de retorno, el símbolo -> se omite. Es por eso que la función printHelloWorld() no tiene un símbolo -> en su definición de método.

Nombres de parámetros locales y externos

Anteriormente en este tutorial, definimos la función printMessage(_:). Aunque le hemos dado un nombre al parámetro, message, no usamos ese nombre cuando llamamos a la función. En cambio, solo pasamos el valor para el parámetro de message.

El nombre que definimos en la definición de la función es un nombre de parámetro local. El valor del parámetro solo puede referenciarse con este nombre en el cuerpo de la función. Pero los parámetros de función son un poco más flexibles que eso.

Objective-C es conocido por sus largos nombres de método. Si bien esto puede parecer torpe y poco elegante para los de afuera, hace que los métodos sean fáciles de entender y, si se los elige bien, son muy descriptivos. Si crees que perdiste este beneficio al cambiar a Swift, entonces te sorprenderas.

Cuando una función acepta varios parámetros, no siempre es obvio qué argumento corresponde a qué parámetro. Eche un vistazo al siguiente ejemplo para comprender mejor el problema.

La función power(_:b:) aumenta el valor de a por el exponente b. Ambos parámetros son de tipo Int. Si bien la mayoría de las personas pasará intuitivamente el valor base como primer argumento y el exponente como segundo argumento, esto no queda claro a partir del tipo, nombre o firma de la función.

Para evitar confusiones, podemos dar los parámetros de una función nombres externos. Luego podemos usar estos nombres externos cuando se llama a la función para indicar inequívocamente qué argumento corresponde a qué parámetro. Echa un vistazo al ejemplo actualizado a continuación.

Tenga en cuenta que el cuerpo de la función no ha cambiado, porque los nombres locales no se han cambiado. Sin embargo, cuando invocamos la función actualizada, la diferencia es clara y el resultado es mucho menos confuso.

Aunque los tipos de ambas funciones son las mismas, (Int, Int) -> Int, las funciones son diferentes. En otras palabras, la segunda función no es una redeclaración de la primera función. La sintaxis para invocar la segunda función puede recordarles a algunos de ustedes el Objetivo-C. No solo se describen claramente los argumentos, la combinación de nombres de funciones y parámetros describe el propósito de la función.

En Swift, el primer parámetro tiene, por defecto, ningún nombre de parámetro externo. Es por eso que la firma de la función printMessage(_:) incluye un _ para el primer parámetro. Si queremos definir un nombre de parámetro externo para el primer parámetro, la definición del método se vería un poco diferente.

Funciones globales y anidadas

Los ejemplos que hemos visto hasta ahora se conocen como funciones globales, porque están definidos en un ámbito global. Las funciones también se pueden anidar. Las funciones anidadas solo pueden invocarse desde el ámbito en el que están definidas. Esto significa que una función anidada solo puede invocarse desde la función en la que está definida. El siguiente ejemplo aclara esto.

2. Clausuras

¿Qué es una clausura?

Si has trabajado con bloques en C y Objective-C o clausuras en JavaScript, entonces no tendrás problemas para enfrentarte al concepto de clausuras. Ya hemos trabajado con clausuras en este artículo, porque las funciones también son clausuras. Comencemos con lo básico e inspeccionemos la anatomía de una clausura.

Una clausura es un bloque de funcionalidad que puede pasar en su código. Puede pasar una clausura como argumento de una función o puede almacenarlo como propiedad de un objeto. Las clasuruas tienen muchos casos de uso.

El nombre Clausura hace alusión a una de las características clave de las clausuras. Una clausura captura las variables y constantes del contexto en el que está definido. Esto a veces se denomina como clausuras de esas variables y constantes.

Sintaxis

La sintaxis básica de un cierre no es difícil. Eche un vistazo al siguiente ejemplo.

Lo primero que notará es que todo la clausura está envuelta en un par de llaves. Los parámetros de la clausura están envueltos en un par de paréntesis, separados del tipo de retorno por el símbolo ->. La clausura anterior acepta un argumento, a, de tipo Int y devuelve un Int. El cuerpo comienza después de la palabra clave in.

Las clausuras nombrados, es decir, las funciones globales y anidadas, se ven un poco diferentes. El siguiente ejemplo ilustra estas diferencias.

Las diferencias más destacadas son el uso de la palabra clave func y la posición de los parámetros y el tipo del retorno. Una clausura comienza y termina con una llave, envolviendo los parámetros, el tipo de retorno y el cuerpo. A pesar de estas diferencias, recuerde que cada función es una clausura. Sin embargo, no todos son una función.

Clausuras como parámetros

Las clausuras son potentes y el siguiente ejemplo ilustra lo útiles que pueden ser. En el ejemplo, creamos una matriz de estados. Invocamos la función map() en la matriz para crear una nueva matriz que solo contiene las dos primeras letras de cada estado como una cadena en mayúscula.

En el ejemplo anterior, la función map() se invoca en la matriz states , transforma sus contenidos y devuelve una nueva matriz que contiene los valores transformados. El ejemplo también muestra el poder de la inferencia de tipos de Swift. Como invocamos la función map() en una matriz de cadenas, Swift sabe que el argumento de state es de tipo String. Esto significa que podemos omitir el tipo como se muestra en el ejemplo actualizado a continuación.

Hay algunas cosas más que podemos omitir del ejemplo anterior, lo que da como resultado el siguiente de una linea.

Déjame explicarte lo que está sucediendo. El compilador puede inferir que devolvemos una cadena del cierre que pasamos a la función map(), lo que significa que no hay razón para incluir el tipo de devolución en la definición de expresión de clausura. Sin embargo, solo podemos hacer esto si el cuerpo de la clausura incluye una sola declaración. En ese caso, podemos poner esa declaración en la misma línea que la definición de la clausura, como se muestra en el ejemplo anterior. Como no hay ningún tipo de devolución en la definición y ningún símbolo -> que preceda al tipo de devolución, podemos omitir los paréntesis que encierran los parámetros de la clausura.

Nombres de argumentos abreviados

Sin embargo, no se detiene aquí. Podemos utilizar nombres de argumentos abreviados para simplificar aún más la expresión de clausura anterior. Al usar una expresión de clausura en línea, como en el ejemplo anterior, podemos omitir la lista de parámetros, incluida la palabra clave in que separa los parámetros del cuerpo de clausura.

En el cuerpo de cierre, hacemos referencia a los argumentos usando nombres de argumentos abreviados que nos proporciona Swift. El primer argumento es referenciado por $0, el segundo por $1, etc.

En el ejemplo actualizado a continuación, he omitido la lista de parámetros y la palabra clave in, y reemplacé el argumento state en el cuerpo de clausura con el nombre de argumento abreviado $0. La declaración resultante es más conciso sin comprometer la legibilidad.

Clausuras que se arrastran

El lenguaje de programación Swift también define un concepto conocido como clausuras finales. Si pasa una clausura como el último argumento de una función, puede colocar esa clausura fuera del paréntesis de la llamada a la función. El siguiente ejemplo demuestra cómo funciona esto.

Si el único argumento de la llamada a la función es el cierre, entonces incluso es posible omitir los paréntesis de la llamada a la función.

Tenga en cuenta que esto también funciona para clausuras que contienen declaraciones múltiples. De hecho, esa es la razón principal por la que las clausuras finales están disponibles en Swift. Si una clausura es larga o compleja y es el último argumento de una función, a menudo es mejor usar la sintaxis de clausura final.

3. Protocolos

Los protocolos son un componente importante del lenguaje de programación Swift. El concepto no es difícil de entender si está familiarizado con los protocolos en Objective-C o las interfaces en Java. Un protocolo define un diseño o interfaz enfocado en una tarea particular. Lo hace al definir las propiedades y los métodos necesarios para realizar esa tarea.

Definir un protocolo es similar a definir una clase o estructura. En el siguiente ejemplo, definimos el protocolo Repairable. El protocolo define dos propiedades, time y cost, y un método repair(). La propiedad time es de solo lectura mientras que la propiedad cost es Lectura-Escritura.

Una clase o estructura puede adoptar un protocolo conformándose a él. Esto significa que se requiere implementar las propiedades y métodos definidos por el protocolo. Actualicemos la clase Boat que implementamos en el tutorial anterior.

Así de fácil es adaptar un tipo a un protocolo. Aunque un protocolo no se puede instanciar como una clase o estructura, un protocolo es un tipo válido. Observe el siguiente ejemplo en el que el protocolo Repairable se usa como el tipo de argumento de una función.

Davis Allie escribió recientemente un excelente artículo sobre programación orientada a protocolos en Swift. Si está interesado en aprender más acerca de los protocolos y su potencial en Swift, entonces le sugiero que lea el artículo de Davis.

4. Control de acceso

Me gustaría concluir esta introducción a Swift hablando de control de acceso. Como su nombre lo indica, el control de acceso define qué código tiene acceso a qué código. Los niveles de control de acceso se aplican a métodos, funciones, tipos, etc. Apple simplemente se refiere a las entidades. Hay tres niveles de control de acceso, público, interno y privado.

  • Público: las entidades definidas en el mismo módulo y otros módulos, como un proyecto, un marco o una biblioteca, pueden acceder a las entidades marcadas como públicas. Este nivel de control de acceso es ideal para exponer la interfaz de un marco.
  • Interno: este es el nivel de control de acceso predeterminado. En otras palabras, si no se especifica un nivel de control de acceso, se aplica el nivel de control de acceso interno. Solo las entidades definidas en el mismo módulo pueden acceder a una entidad con un nivel de acceso interno.
  • Privado: una entidad declarada como privada solo es accesible para las entidades definidas en el mismo archivo fuente.

Eche un vistazo al siguiente ejemplo en el que he actualizado la clase Boat. La clase en sí está marcada como pública, lo que significa que es accesible desde cualquier lugar. La propiedad cost se marca implícitamente como interna porque no hemos especificado un nivel de control de acceso. Lo mismo es cierto para el método deployLifeboats().

El método scheduleMaintenance() está marcado como privado, lo que significa que solo puede ser invocado por las entidades definidas en el archivo fuente en el que se define la clase Boat. Es importante entender esto, porque es ligeramente diferente de lo que otros lenguajes de programación consideran un método o propiedad privada.

Si marcamos la clase Boat como interna al eliminar la palabra clave public, el compilador nos mostrará una advertencia. Nos dice que no podemos marcar speed y que lifeboats son públicos siempre que Boat se marque como interno. El compilador tiene razón, por supuesto. No tiene sentido marcar las propiedades de una clase interna como pública.

Access Control Warning

Conclusión

El lenguaje de programación Swift es fácil de aprender, pero hay mucho más que lo que hemos cubierto en los últimos dos tutoriales. Aprenderá más sobre Swift una vez que comencemos a crear aplicaciones. En el siguiente artículo, echamos un vistazo más de cerca al iOS SDK.

Si tiene preguntas o comentarios, puede dejarlos en los comentarios a continuación o comunicarse conmigo en Twitter.

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.